13 #include <QtCore/qglobal.h>
14 #include <QtCore/QString>
15 #include <QtCore/QUrl>
16 #include <QtCore/QJsonObject>
17 #include <QtCore/QJsonArray>
19 #include <render/Args.h>
20 #include <gpu/Shader.h>
21 #include <gpu/Pipeline.h>
22 #include <gpu/Batch.h>
23 #include <material-networking/ShaderCache.h>
24 #include <material-networking/TextureCache.h>
25 #include "ProceduralMaterialCache.h"
27 using UniformLambdas = std::list<std::function<void(gpu::Batch& batch)>>;
28 const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 };
47 struct ProceduralData {
48 static QJsonValue getProceduralData(
const QString& proceduralJson);
49 static ProceduralData parse(
const QString& userDataJson);
50 void parse(
const QJsonObject&);
53 uint8_t version { 0 };
54 QUrl fragmentShaderUrl;
60 class ProceduralProgramKey {
69 typedef std::bitset<NUM_FLAGS> Flags;
73 bool isTransparent()
const {
return _flags[IS_TRANSPARENT]; }
74 bool isSkinned()
const {
return _flags[IS_SKINNED]; }
75 bool isSkinnedDQ()
const {
return _flags[IS_SKINNED_DQ]; }
77 ProceduralProgramKey(
bool transparent =
false,
bool isSkinned =
false,
bool isSkinnedDQ =
false) {
78 _flags.set(IS_TRANSPARENT, transparent);
79 _flags.set(IS_SKINNED, isSkinned);
80 _flags.set(IS_SKINNED_DQ, isSkinnedDQ);
84 struct std::hash<ProceduralProgramKey> {
85 size_t operator()(
const ProceduralProgramKey& key)
const {
86 return std::hash<std::bitset<ProceduralProgramKey::FlagBit::NUM_FLAGS>>()(key._flags);
89 inline bool operator==(
const ProceduralProgramKey& a,
const ProceduralProgramKey& b) {
90 return a._flags == b._flags;
92 inline bool operator!=(
const ProceduralProgramKey& a,
const ProceduralProgramKey& b) {
93 return a._flags != b._flags;
100 Procedural(
bool useAA =
true);
101 void setProceduralData(
const ProceduralData& proceduralData);
103 bool isReady()
const;
104 bool isEnabled()
const {
return _enabled; }
105 void prepare(gpu::Batch& batch,
const glm::vec3& position,
const glm::vec3& size,
const glm::quat& orientation,
106 const uint64_t& created,
const ProceduralProgramKey key = ProceduralProgramKey());
108 glm::vec4 getColor(
const glm::vec4& entityColor)
const;
110 bool hasVertexShader()
const;
111 void setBoundOperator(
const std::function<AABox(
RenderArgs*)>& boundOperator) { _boundOperator = boundOperator; }
112 bool hasBoundOperator()
const {
return (
bool)_boundOperator; }
113 AABox getBound(
RenderArgs* args) {
return _boundOperator(args); }
115 void setVertexReplacements(
const std::unordered_map<std::string, std::string>& replacements);
116 void setFragmentReplacements(
const std::unordered_map<std::string, std::string>& replacements);
118 gpu::Shader::Source _vertexSource;
119 gpu::Shader::Source _vertexSourceSkinned;
120 gpu::Shader::Source _vertexSourceSkinnedDQ;
121 gpu::Shader::Source _opaqueFragmentSource;
122 gpu::Shader::Source _transparentFragmentSource;
124 QString _errorFallbackFragmentPath;
126 gpu::StatePointer _opaqueState { std::make_shared<gpu::State>() };
127 gpu::StatePointer _transparentState { std::make_shared<gpu::State>() };
129 static std::function<void(gpu::StatePointer,
bool)> opaqueStencil;
130 static std::function<void(gpu::StatePointer)> transparentStencil;
132 static bool enableProceduralShaders;
138 struct StandardInputs {
142 float timeSinceLastCompile;
143 float timeSinceFirstCompile;
144 float timeSinceEntityCreation;
150 static_assert(0 == offsetof(StandardInputs, date),
"ProceduralOffsets");
151 static_assert(16 == offsetof(StandardInputs, position),
"ProceduralOffsets");
152 static_assert(32 == offsetof(StandardInputs, scale),
"ProceduralOffsets");
153 static_assert(48 == offsetof(StandardInputs, timeSinceLastCompile),
"ProceduralOffsets");
154 static_assert(52 == offsetof(StandardInputs, timeSinceFirstCompile),
"ProceduralOffsets");
155 static_assert(56 == offsetof(StandardInputs, timeSinceEntityCreation),
"ProceduralOffsets");
156 static_assert(60 == offsetof(StandardInputs, frameCount),
"ProceduralOffsets");
157 static_assert(64 == offsetof(StandardInputs, resolution),
"ProceduralOffsets");
158 static_assert(128 == offsetof(StandardInputs, orientation),
"ProceduralOffsets");
161 ProceduralData _data;
163 bool _enabled {
false };
164 uint64_t _lastCompile { 0 };
165 uint64_t _firstCompile { 0 };
166 int32_t _frameCount { 0 };
169 QString _vertexShaderSource;
170 QString _vertexShaderPath;
171 uint64_t _vertexShaderModified { 0 };
172 NetworkShaderPointer _networkVertexShader;
173 QString _fragmentShaderSource;
174 QString _fragmentShaderPath;
175 uint64_t _fragmentShaderModified { 0 };
176 NetworkShaderPointer _networkFragmentShader;
177 bool _shaderDirty {
true };
178 bool _uniformsDirty {
true };
180 QString _errorFallbackFragmentSource;
183 UniformLambdas _uniforms;
184 NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
185 Sampler _samplers[MAX_PROCEDURAL_TEXTURE_CHANNELS];
186 std::unordered_map<std::string, std::string> _vertexReplacements;
187 std::unordered_map<std::string, std::string> _fragmentReplacements;
188 std::unordered_map<std::string, int> _slotMap;
190 std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _proceduralPipelines;
191 std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _errorPipelines;
192 std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _disabledPipelines;
194 StandardInputs _standardInputs;
195 gpu::BufferPointer _standardInputsBuffer;
198 glm::vec3 _entityDimensions;
199 glm::vec3 _entityPosition;
200 glm::mat3 _entityOrientation;
201 uint64_t _entityCreated;
204 void setupUniforms();
206 ProceduralProgramKey _prevKey;
208 std::function<AABox(
RenderArgs*)> _boundOperator {
nullptr };
210 mutable std::mutex _mutex;
215 class ProceduralMaterial :
public NetworkMaterial {
217 ProceduralMaterial() : NetworkMaterial() { initializeProcedural(); }
218 ProceduralMaterial(
const NetworkMaterial& material) : NetworkMaterial(material) { initializeProcedural(); }
220 virtual bool isProcedural()
const override {
return true; }
221 virtual bool isEnabled()
const override {
return _procedural.isEnabled(); }
222 virtual bool isReady()
const override {
return _procedural.isReady(); }
223 virtual QString getProceduralString()
const override {
return _proceduralString; }
225 void setProceduralData(
const QString& data) {
226 _proceduralString = data;
227 _procedural.setProceduralData(ProceduralData::parse(data));
229 virtual glm::vec4 getColor(
const glm::vec4& color)
const {
return _procedural.getColor(color); }
230 virtual bool hasVertexShader()
const {
return _procedural.hasVertexShader(); }
231 virtual void prepare(gpu::Batch& batch,
const glm::vec3& position,
const glm::vec3& size,
const glm::quat& orientation,
232 const uint64_t& created,
const ProceduralProgramKey key = ProceduralProgramKey()) {
233 _procedural.prepare(batch, position, size, orientation, created, key);
236 virtual void initializeProcedural();
238 void setBoundOperator(
const std::function<AABox(
RenderArgs*)>& boundOperator) { _procedural.setBoundOperator(boundOperator); }
239 bool hasBoundOperator()
const {
return _procedural.hasBoundOperator(); }
240 AABox getBound(
RenderArgs* args) {
return _procedural.getBound(args); }
243 QString _proceduralString;
244 Procedural _procedural;
246 typedef std::shared_ptr<ProceduralMaterial> ProceduralMaterialPointer;