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;
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;
111 uint64_t getFadeStartTime()
const {
return _fadeStartTime; }
112 bool isFading()
const {
return _doesFade && _isFading; }
113 void setIsFading(
bool isFading) { _isFading = isFading; }
114 void setDoesFade(
bool doesFade) { _doesFade = doesFade; }
116 bool hasVertexShader()
const;
117 void setBoundOperator(
const std::function<AABox(RenderArgs*)>& boundOperator) { _boundOperator = boundOperator; }
118 bool hasBoundOperator()
const {
return (
bool)_boundOperator; }
119 AABox getBound(RenderArgs* args) {
return _boundOperator(args); }
121 gpu::Shader::Source _vertexSource;
122 gpu::Shader::Source _vertexSourceSkinned;
123 gpu::Shader::Source _vertexSourceSkinnedDQ;
124 gpu::Shader::Source _opaqueFragmentSource;
125 gpu::Shader::Source _transparentFragmentSource;
127 gpu::StatePointer _opaqueState { std::make_shared<gpu::State>() };
128 gpu::StatePointer _transparentState { std::make_shared<gpu::State>() };
130 static std::function<void(gpu::StatePointer)> opaqueStencil;
131 static std::function<void(gpu::StatePointer)> transparentStencil;
137 struct StandardInputs {
141 float timeSinceLastCompile;
142 float timeSinceFirstCompile;
143 float timeSinceEntityCreation;
149 static_assert(0 == offsetof(StandardInputs, date),
"ProceduralOffsets");
150 static_assert(16 == offsetof(StandardInputs, position),
"ProceduralOffsets");
151 static_assert(32 == offsetof(StandardInputs, scale),
"ProceduralOffsets");
152 static_assert(48 == offsetof(StandardInputs, timeSinceLastCompile),
"ProceduralOffsets");
153 static_assert(52 == offsetof(StandardInputs, timeSinceFirstCompile),
"ProceduralOffsets");
154 static_assert(56 == offsetof(StandardInputs, timeSinceEntityCreation),
"ProceduralOffsets");
155 static_assert(60 == offsetof(StandardInputs, frameCount),
"ProceduralOffsets");
156 static_assert(64 == offsetof(StandardInputs, resolution),
"ProceduralOffsets");
157 static_assert(128 == offsetof(StandardInputs, orientation),
"ProceduralOffsets");
160 ProceduralData _data;
162 bool _enabled {
false };
163 uint64_t _lastCompile { 0 };
164 uint64_t _firstCompile { 0 };
165 int32_t _frameCount { 0 };
168 QString _vertexShaderSource;
169 QString _vertexShaderPath;
170 uint64_t _vertexShaderModified { 0 };
171 NetworkShaderPointer _networkVertexShader;
172 QString _fragmentShaderSource;
173 QString _fragmentShaderPath;
174 uint64_t _fragmentShaderModified { 0 };
175 NetworkShaderPointer _networkFragmentShader;
176 bool _shaderDirty {
true };
177 bool _uniformsDirty {
true };
180 UniformLambdas _uniforms;
181 NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
183 std::unordered_map<ProceduralProgramKey, gpu::PipelinePointer> _proceduralPipelines;
185 StandardInputs _standardInputs;
186 gpu::BufferPointer _standardInputsBuffer;
189 glm::vec3 _entityDimensions;
190 glm::vec3 _entityPosition;
191 glm::mat3 _entityOrientation;
192 uint64_t _entityCreated;
195 void setupUniforms();
197 mutable uint64_t _fadeStartTime { 0 };
198 mutable bool _hasStartedFade {
false };
199 mutable bool _isFading {
false };
200 bool _doesFade {
true };
201 ProceduralProgramKey _prevKey;
203 std::function<AABox(RenderArgs*)> _boundOperator {
nullptr };
205 mutable std::mutex _mutex;
210 class ProceduralMaterial :
public NetworkMaterial {
212 ProceduralMaterial() : NetworkMaterial() { initializeProcedural(); }
213 ProceduralMaterial(
const NetworkMaterial& material) : NetworkMaterial(material) { initializeProcedural(); }
215 virtual bool isProcedural()
const override {
return true; }
216 virtual bool isEnabled()
const override {
return _procedural.isEnabled(); }
217 virtual bool isReady()
const override {
return _procedural.isReady(); }
218 virtual QString getProceduralString()
const override {
return _proceduralString; }
220 void setProceduralData(
const QString& data) {
221 _proceduralString = data;
222 _procedural.setProceduralData(ProceduralData::parse(data));
224 virtual glm::vec4 getColor(
const glm::vec4& color)
const {
return _procedural.getColor(color); }
225 virtual bool isFading()
const {
return _procedural.isFading(); }
226 void setIsFading(
bool isFading) { _procedural.setIsFading(isFading); }
227 virtual uint64_t getFadeStartTime()
const {
return _procedural.getFadeStartTime(); }
228 virtual bool hasVertexShader()
const {
return _procedural.hasVertexShader(); }
229 virtual void prepare(gpu::Batch& batch,
const glm::vec3& position,
const glm::vec3& size,
const glm::quat& orientation,
230 const uint64_t& created,
const ProceduralProgramKey key = ProceduralProgramKey()) {
231 _procedural.prepare(batch, position, size, orientation, created, key);
234 virtual void initializeProcedural();
236 void setBoundOperator(
const std::function<AABox(RenderArgs*)>& boundOperator) { _procedural.setBoundOperator(boundOperator); }
237 bool hasBoundOperator()
const {
return _procedural.hasBoundOperator(); }
238 AABox getBound(RenderArgs* args) {
return _procedural.getBound(args); }
241 QString _proceduralString;
242 Procedural _procedural;
244 typedef std::shared_ptr<ProceduralMaterial> ProceduralMaterialPointer;