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);
85 struct hash<ProceduralProgramKey> {
86 size_t operator()(
const ProceduralProgramKey& key)
const {
87 return std::hash<std::bitset<ProceduralProgramKey::FlagBit::NUM_FLAGS>>()(key._flags);
91 inline bool operator==(
const ProceduralProgramKey& a,
const ProceduralProgramKey& b) {
92 return a._flags == b._flags;
94 inline bool operator!=(
const ProceduralProgramKey& a,
const ProceduralProgramKey& b) {
95 return a._flags != b._flags;
102 Procedural(
bool useAA =
true);
103 void setProceduralData(
const ProceduralData& proceduralData);
105 bool isReady()
const;
106 bool isEnabled()
const {
return _enabled; }
107 void prepare(gpu::Batch& batch,
const glm::vec3& position,
const glm::vec3& size,
const glm::quat& orientation,
108 const uint64_t& created,
const ProceduralProgramKey key = ProceduralProgramKey());
110 glm::vec4 getColor(
const glm::vec4& entityColor)
const;
112 bool hasVertexShader()
const;
113 void setBoundOperator(
const std::function<AABox(RenderArgs*)>& boundOperator) { _boundOperator = boundOperator; }
114 bool hasBoundOperator()
const {
return (
bool)_boundOperator; }
115 AABox getBound(RenderArgs* args) {
return _boundOperator(args); }
117 void setVertexReplacements(
const std::unordered_map<std::string, std::string>& replacements);
118 void setFragmentReplacements(
const std::unordered_map<std::string, std::string>& replacements);
120 gpu::Shader::Source _vertexSource;
121 gpu::Shader::Source _vertexSourceSkinned;
122 gpu::Shader::Source _vertexSourceSkinnedDQ;
123 gpu::Shader::Source _opaqueFragmentSource;
124 gpu::Shader::Source _transparentFragmentSource;
126 QString _errorFallbackFragmentPath;
128 gpu::StatePointer _opaqueState { std::make_shared<gpu::State>() };
129 gpu::StatePointer _transparentState { std::make_shared<gpu::State>() };
131 static std::function<void(gpu::StatePointer,
bool)> opaqueStencil;
132 static std::function<void(gpu::StatePointer)> transparentStencil;
134 static bool enableProceduralShaders;
140 struct StandardInputs {
144 float timeSinceLastCompile;
145 float timeSinceFirstCompile;
146 float timeSinceEntityCreation;
152 static_assert(0 == offsetof(StandardInputs, date),
"ProceduralOffsets");
153 static_assert(16 == offsetof(StandardInputs, position),
"ProceduralOffsets");
154 static_assert(32 == offsetof(StandardInputs, scale),
"ProceduralOffsets");
155 static_assert(48 == offsetof(StandardInputs, timeSinceLastCompile),
"ProceduralOffsets");
156 static_assert(52 == offsetof(StandardInputs, timeSinceFirstCompile),
"ProceduralOffsets");
157 static_assert(56 == offsetof(StandardInputs, timeSinceEntityCreation),
"ProceduralOffsets");
158 static_assert(60 == offsetof(StandardInputs, frameCount),
"ProceduralOffsets");
159 static_assert(64 == offsetof(StandardInputs, resolution),
"ProceduralOffsets");
160 static_assert(128 == offsetof(StandardInputs, orientation),
"ProceduralOffsets");
163 ProceduralData _data;
165 bool _enabled {
false };
166 uint64_t _lastCompile { 0 };
167 uint64_t _firstCompile { 0 };
168 int32_t _frameCount { 0 };
171 QString _vertexShaderSource;
172 QString _vertexShaderPath;
173 uint64_t _vertexShaderModified { 0 };
174 NetworkShaderPointer _networkVertexShader;
175 QString _fragmentShaderSource;
176 QString _fragmentShaderPath;
177 uint64_t _fragmentShaderModified { 0 };
178 NetworkShaderPointer _networkFragmentShader;
179 bool _shaderDirty {
true };
180 bool _uniformsDirty {
true };
182 QString _errorFallbackFragmentSource;
185 UniformLambdas _uniforms;
186 NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
187 Sampler _samplers[MAX_PROCEDURAL_TEXTURE_CHANNELS];
188 std::unordered_map<std::string, std::string> _vertexReplacements;
189 std::unordered_map<std::string, std::string> _fragmentReplacements;
190 std::unordered_map<std::string, int> _slotMap;
192 std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _proceduralPipelines;
193 std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _errorPipelines;
194 std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _disabledPipelines;
196 StandardInputs _standardInputs;
197 gpu::BufferPointer _standardInputsBuffer;
200 glm::vec3 _entityDimensions;
201 glm::vec3 _entityPosition;
202 glm::mat3 _entityOrientation;
203 uint64_t _entityCreated;
206 void setupUniforms();
208 ProceduralProgramKey _prevKey;
210 std::function<AABox(RenderArgs*)> _boundOperator {
nullptr };
212 mutable std::mutex _mutex;
217 class ProceduralMaterial :
public NetworkMaterial {
219 ProceduralMaterial() : NetworkMaterial() { initializeProcedural(); }
220 ProceduralMaterial(
const NetworkMaterial& material) : NetworkMaterial(material) { initializeProcedural(); }
222 virtual bool isProcedural()
const override {
return true; }
223 virtual bool isEnabled()
const override {
return _procedural.isEnabled(); }
224 virtual bool isReady()
const override {
return _procedural.isReady(); }
225 virtual QString getProceduralString()
const override {
return _proceduralString; }
227 void setProceduralData(
const QString& data) {
228 _proceduralString = data;
229 _procedural.setProceduralData(ProceduralData::parse(data));
231 virtual glm::vec4 getColor(
const glm::vec4& color)
const {
return _procedural.getColor(color); }
232 virtual bool hasVertexShader()
const {
return _procedural.hasVertexShader(); }
233 virtual void prepare(gpu::Batch& batch,
const glm::vec3& position,
const glm::vec3& size,
const glm::quat& orientation,
234 const uint64_t& created,
const ProceduralProgramKey key = ProceduralProgramKey()) {
235 _procedural.prepare(batch, position, size, orientation, created, key);
238 virtual void initializeProcedural();
240 void setBoundOperator(
const std::function<AABox(RenderArgs*)>& boundOperator) { _procedural.setBoundOperator(boundOperator); }
241 bool hasBoundOperator()
const {
return _procedural.hasBoundOperator(); }
242 AABox getBound(RenderArgs* args) {
return _procedural.getBound(args); }
245 QString _proceduralString;
246 Procedural _procedural;
248 typedef std::shared_ptr<ProceduralMaterial> ProceduralMaterialPointer;