Cogs.Core
VectorFieldRenderer.cpp
1#include "VectorFieldRenderer.h"
2#include "VectorFieldSystem.h"
3
4#include "Context.h"
5#include "EntityStore.h"
6#include "ExtensionRegistry.h"
7#include "Renderer/Renderer.h"
8#include "Renderer/RenderStateUpdater.h"
9#include "Renderer/Tasks/RenderListTask.h"
10#include "Renderer/ParameterBuffers.h"
11#include "Renderer/RenderTarget.h"
12#include "Resources/Mesh.h"
13#include "Resources/Model.h"
14#include "Resources/VertexFormats.h"
15#include "Resources/DefaultMaterial.h"
16#include "Services/Time.h"
17#include "Systems/Core/TransformSystem.h"
18
19#include "Rendering/CommandGroupAnnotation.h"
20#include "Rendering/IContext.h"
21#include "Rendering/IBuffers.h"
22#include "Rendering/IGraphicsDevice.h"
23#include "Rendering/IRenderTargets.h"
24
25#include <random>
26
27namespace Cogs::Core::VectorField
28{
29
31 {
32 context = set_context;
33 device = set_device;
34 vectorFieldSystem = ExtensionRegistry::getExtensionSystem<VectorFieldSystem>(context);
35 }
36 void VectorFieldRenderer::handleEvent(uint32_t eventId, const DrawContext * renderingContext)
37 {
38 if (!renderingContext) return;
39
40 switch (eventId) {
42 for (auto & vector_field : vectorFieldSystem->pool) {
43 postRender(vector_field, renderingContext);
44 }
45 break;
46 default:
47 break;
48 }
49 }
50 enum{
51 DC_CAP,
52 DC_BASE,
53 };
54 static void vectorFieldCallback(RenderTaskContext *renderingContext, DrawContext *drawContext, const RenderItem * item, int type)
55 {
56 VectorFieldData &data = *item->getCallbackData<VectorFieldData>();
57 VectorFieldSystem *vectorFieldSystem = data.system;
58 Model *model = nullptr;
59 if(type == DC_CAP)
60 model = vectorFieldSystem->model_cap.resolve();
61 else if(type == DC_BASE)
62 model = vectorFieldSystem->model_base.resolve();
63 if(!model || !model->isLoaded()) return;
64 Mesh *mesh = model->meshes[0].resolve();
65
66 Renderer *renderer = renderingContext->renderer;
67 IGraphicsDevice *device = renderer->getDevice();
68 RenderStates &renderStates = renderer->getRenderStates();
69 RenderMesh *renderMesh = renderer->getRenderResources().getRenderMesh(model->meshes[0]);
70 IContext *deviceContext = device->getImmediateContext();
71 VectorFieldComponent &component = *data.handle.resolveComponent<VectorFieldComponent>();
72 size_t count = 0;
73 if(component.positions)
74 count = component.positions.size();
75 if(count == 0) return;
76
77 CommandGroupAnnotation commandGroup(deviceContext, "VectorFieldRenderer::generateCommands");
78
79 // PSO state
80 deviceContext->setDepthStencilState(renderStates.defaultDepthStencilStateHandle);
81 deviceContext->setBlendState(renderStates.blendStates[size_t(BlendMode::None)].handle);
82 deviceContext->setRasterizerState(renderStates.defaultRasterizerStateHandle);
83
84 applyMaterialPermutation(renderingContext, drawContext, item->binding, item->renderMaterialInstance);
85 updateEnvironmentBindings(drawContext, item->binding);
86 applyMaterialInstance(drawContext, item->binding, item->renderMaterialInstance);
87
88 // Copy Buffers
89 {
90 size_t size = count * sizeof(glm::vec3);
91 MappedBuffer<InstanceData> i_data(deviceContext, data.buffer_handle, Cogs::MapMode::WriteDiscard, size);
92 for(size_t i=0; i<count; i++){
93 glm::vec3 p = component.positions[i];
94 glm::vec3 d = component.directions[i];
95 glm::vec3 pos = p;
96 if(component.dither)
97 pos += data.dither_offset[i];
98 float t = fmod(data.time+data.time_offset[i], 1.0f);
99 if(component.animation && component.animationUseSpeed)
100 t = data.time_offset_speed[i];
101 if(!component.centerArrow)
102 pos += d*component.scale*component.length*0.5f;
103 if(component.animation){
104 float anim_scale = component.scale*component.length*component.animationScale;
105 if(component.centerArrow)
106 pos += d*anim_scale*(t-0.5f);
107 else
108 pos += d*anim_scale*t;
109 }
110 i_data[i].pos = pos;
111
112 glm::vec4 c = component.colors[i];
113 uint32_t col =
114 uint32_t(c.x*255) << 0 |
115 uint32_t(c.y*255) << 8 |
116 uint32_t(c.z*255) << 16 |
117 uint32_t(c.w*255) << 24;
118 i_data[i].color = col;
119
120 glm::vec3 u = glm::vec3(0.0, 1.0, 0.0);
121 glm::vec3 v = glm::normalize(component.directions[i]);
122 glm::vec3 w;
123 float dot = glm::dot(u, v);
124 if(fabsf(dot+1.0f) < 0.001f)
125 w = glm::vec3(1.0, 0.0, 0.0);
126 else
127 w = glm::cross(u, v);
128 glm::quat q(1.0f + dot, w);
129 i_data[i].rot = glm::normalize(q);
130 i_data[i].scale = glm::vec4(component.scale, 1.0, component.tailScale, glm::length(d)*component.length);
131 if(component.animation && component.animationFade){
132 float start = component.animationFadeTime;
133 float end = 1.0f-start;
134 float st = 1.0;
135 if(t<start) st = t/start;
136 else if(t>end) st = 1.0f-(t-end)/(1.0f-end);
137 i_data[i].scale *= glm::vec4(st, st, 1.0, 1.0);
138 }
139 }
140 }
141
142 // Vertex buffers
143 std::array<Cogs::VertexBufferHandle, MeshStreamsLayout::maxStreams> vertexBuffers;
144 std::array<uint32_t, MeshStreamsLayout::maxStreams> strides;
145
146 uint32_t n = 0;
147 for(size_t i = 0; i < renderMesh->streamsLayout.numStreams; i++){
148 vertexBuffers[n] = renderMesh->vertexBuffers[i];
149 strides[n++] = renderMesh->vertexStrides[i];
150 }
151 assert(n + 1 < MeshStreamsLayout::maxStreams);
152 vertexBuffers[n] = data.buffer_handle;
153 strides[n++] = sizeof(InstanceData);
154 deviceContext->setVertexBuffers(vertexBuffers.data(), n, strides.data(), nullptr);
155 bool indexed = renderMesh->indexBuffer != IndexBufferHandle::NoHandle;
156 if(indexed) deviceContext->setIndexBuffer(renderMesh->indexBuffer);
157
158
159 RenderItem oItem = *item;
160 oItem.worldMatrix = &data.worldMatrix;
161 applyMaterialPerObject(drawContext, item->renderMaterialInstance, oItem);
162
163 // Draw
164 auto submeshCount = mesh->submeshCount;
165 if(!submeshCount){
166 if(renderMesh->numVertexes == 0) return;
167 if(!indexed) deviceContext->drawInstanced(item->primitiveType, 0, item->numIndexes, 0, count);
168 else deviceContext->drawInstancedIndexed(item->primitiveType, 0, count, 0, renderMesh->numVertexes);
169 }
170 else{
171 auto subMeshes = mesh->mapSubMeshes(submeshCount + 1);
172 for(size_t m = 0; m < submeshCount; m++){
173 SubMesh &subMesh = subMeshes[m];
174 if(subMesh.numIndexes == 0) continue;
175 if(!indexed) deviceContext->drawInstanced(subMesh.primitiveType, subMesh.startIndex, subMesh.numIndexes, 0, count);
176 else deviceContext->drawInstancedIndexed(subMesh.primitiveType, 0, count, subMesh.startIndex, subMesh.numIndexes);
177 }
178 }
179 }
180 static void vectorFieldCallbackCap(RenderTaskContext *renderingContext, DrawContext *drawContext, const RenderItem * item)
181 {
182 vectorFieldCallback(renderingContext, drawContext, item, DC_CAP);
183 }
184 static void vectorFieldCallbackBase(RenderTaskContext *renderingContext, DrawContext *drawContext, const RenderItem * item)
185 {
186 vectorFieldCallback(renderingContext, drawContext, item, DC_BASE);
187 }
188 void VectorFieldRenderer::generateCommands(const RenderTaskContext *renderingContext, RenderList *renderList)
189 {
190 IBuffers *buffers = device->getBuffers();
191
192 for(VectorFieldComponent &component : vectorFieldSystem->pool){
193 VectorFieldData &data = vectorFieldSystem->getData(&component);
194 Model *model_cap = vectorFieldSystem->model_cap.resolve();
195 Model *model_base = vectorFieldSystem->model_base.resolve();
196 if(!model_cap || !model_cap->isLoaded()) return;
197 if(!model_base || !model_base->isLoaded()) return;
198 Mesh *mesh_cap = model_cap->meshes[0].resolve();
199 Mesh *mesh_base = model_base->meshes[0].resolve();
200 if (!mesh_cap || !mesh_cap->isLoaded()) return;
201 if (!mesh_base || !mesh_base->isLoaded()) return;
202
203 // Set up streams layout of mesh and instance streams
204 if (data.layout_cap.numStreams == 0) {
205 data.layout_cap = mesh_cap->getStreamsLayout();
206 assert(data.layout_cap.numStreams + 1 < MeshStreamsLayout::maxStreams);
207 data.layout_cap.vertexFormats[data.layout_cap.numStreams++] = data.pos_format;
208 data.layout_cap.updateHash();
209 }
210
211 if (data.layout_base.numStreams == 0) {
212 data.layout_base = mesh_cap->getStreamsLayout();
213 assert(data.layout_base.numStreams + 1 < MeshStreamsLayout::maxStreams);
214 data.layout_base.vertexFormats[data.layout_base.numStreams++] = data.pos_format;
215 data.layout_base.updateHash();
216 }
217
218 data.handle = vectorFieldSystem->getHandle(&component);
219
220 auto *transComp = component.getComponent<TransformComponent>();
221 data.worldMatrix = renderingContext->context->transformSystem->getLocalToWorld(transComp);
222
223 auto *camTransComp = renderingContext->cameraData->camera.resolve()->getComponent<TransformComponent>();
224 data.cam_pos = camTransComp->position;
225
226 // Buffer
227 size_t count = 0;
228 if(component.positions)
229 count = component.positions.size();
230 if(count > data.buffer_count){
231 if(HandleIsValid(data.buffer_handle)) buffers->releaseVertexBuffer(data.buffer_handle);
232 data.buffer_handle = buffers->loadVertexBuffer(nullptr, count, data.pos_format);
233 buffers->annotate(data.buffer_handle, "VectorField:posBuffer");
234 data.buffer_count = count;
235 }
236
237 glm::vec4 lightDir = glm::vec4(0.0, 0.0, 1.0, 0.0);
238 EntityPtr dir_light = renderingContext->context->store->getEntity("DirectionalLight", false);
239 if(dir_light){
240 LightComponent *light_comp = dir_light->getComponent<LightComponent>();
241 if (light_comp && light_comp->enabled) {
242 auto* trComp = dir_light->getComponent<TransformComponent>();
243 lightDir = context->transformSystem->getLocalToWorld(trComp) * glm::vec4(0, 0, -1, 0);
244 }
245 }
246 vectorFieldSystem->material_instance_cap->setProperty("lightDir", &lightDir, sizeof(lightDir));
247 vectorFieldSystem->material_instance_base->setProperty("lightDir", &lightDir, sizeof(lightDir));
248
249 static std::mt19937 gen(0);
250 if(data.time_offset.size() != count){
251 std::uniform_real_distribution<float> dist(0.0f, 1.0f);
252 size_t start = data.time_offset.size();
253 data.time_offset.resize(count);
254 for(size_t i=start; i < count; i++){
255 data.time_offset[i] = dist(gen);
256 }
257 }
258
259 if(data.time_offset_speed.size() != count){
260 std::uniform_real_distribution<float> dist(0.0f, 1.0f);
261 size_t start = data.time_offset_speed.size();
262 data.time_offset_speed.resize(count);
263 for(size_t i=start; i < count; i++){
264 data.time_offset_speed[i] = dist(gen);
265 }
266 }
267
268 if(data.dither_offset.size() != count || data.ditherSize != component.ditherSize){
269 std::uniform_real_distribution<float> dist(-component.ditherSize, component.ditherSize);
270 size_t start = data.dither_offset.size();
271 data.dither_offset.resize(count);
272 if(data.ditherSize != component.ditherSize)
273 start = 0;
274 for(size_t i=start; i < count; i++){
275 data.dither_offset[i] = glm::vec3(dist(gen), dist(gen), dist(gen));
276 }
277 data.ditherSize = component.ditherSize;
278 }
279
280 if(component.animation && component.animationScale >= 0.00000001f){
281 std::uniform_real_distribution<float> dist(-component.ditherSize, component.ditherSize);
282 float add = (1.0f/component.animationScale)*component.animationSpeed*(float)renderingContext->context->time->getAnimationTimeDelta();
283
284 if(component.animationUseSpeed){
285 if(component.dither){
286 for(size_t i=0; i < count; i++){
287 if(data.time_offset_speed[i]+add*component.speed[i] >= 1.0){
288 data.dither_offset[i] = glm::vec3(dist(gen), dist(gen), dist(gen));
289 }
290 }
291 }
292 for(size_t i=0; i < count; i++){
293 data.time_offset_speed[i] = fmod(data.time_offset_speed[i]+add*component.speed[i], 1.0f);
294 }
295 }
296 else if(component.dither){
297 for(size_t i=0; i < count; i++){
298 float offset = data.time_offset[i];
299 if(fmod(data.time + offset, 1.0f)+add >= 1.0){
300 data.dither_offset[i] = glm::vec3(dist(gen), dist(gen), dist(gen));
301 }
302 }
303 }
304
305 data.time += add;
306 data.time = fmod(data.time, 1.0f);
307 }
308
309 {
310 RenderItem &item = renderList->createCustom(&data.layout_cap);
311 item.layer = RenderLayers::Default;
312 item.materialInstance = vectorFieldSystem->material_instance_cap.resolve();
313 item.drawOrder = 0;
314 item.depth = 0;
315 item.blendState = (uint16_t)item.materialInstance->options.blendMode;
316 item.depthState = (uint16_t)DepthMode::Default;
317 item.setBounds(&data.bbox);
318 item.flags |= RenderItemFlags::Custom;
319 item.flags |= !mesh_cap->isCCW() ? RenderItemFlags::Clockwise : RenderItemFlags::None;
320 item.setCallbackData(&data);
321 item.callback = vectorFieldCallbackCap;
322 }
323 {
324 RenderItem &item = renderList->createCustom(&data.layout_base);
325 item.layer = RenderLayers::Default;
326 item.materialInstance = vectorFieldSystem->material_instance_base.resolve();
327 item.drawOrder = 0;
328 item.depth = 0;
329 item.blendState = (uint16_t)item.materialInstance->options.blendMode;
330 item.depthState = (uint16_t)DepthMode::Default;
331 item.setBounds(&data.bbox);
332 item.flags |= RenderItemFlags::Custom;
333 item.flags |= !mesh_base->isCCW() ? RenderItemFlags::Clockwise : RenderItemFlags::None;
334 item.setCallbackData(&data);
335 item.callback = vectorFieldCallbackBase;
336 }
337 }
338 }
339 void VectorFieldRenderer::postRender(VectorFieldComponent &component, const DrawContext *renderingContext)
340 {
341 if(component.animation){
342 renderingContext->context->engine->setDirty();
343 }
344 }
345}// namespace ...
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Core renderer system.
Definition: Renderer.h:28
RenderStates & getRenderStates() override
Get the reference to the RenderStates structure.
Definition: Renderer.h:68
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
Definition: Renderer.h:45
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual IContext * getImmediateContext()=0
Get a pointer to the immediate context used to issue commands to the graphics device.
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
Definition: EntityPtr.h:12
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ None
No blending enabled for opaque shapes, defaults to Blend for transparent shapes.
@ Default
Default, depth test & write enabled.
@ InstanceData
Per instance data.
RAII-helper for pushCommandGroupAnnotation/pushCommandGroupAnnotation.
static constexpr size_t maxStreams
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
Model resources define a template for a set of connected entities, with resources such as meshes,...
Definition: Model.h:56
RenderLayers layer
Visibility mask.
Definition: RenderList.h:170
@ PostRender
Rendering has finished for a given rendering context.
Definition: IRenderer.h:101
void initialize(Cogs::Core::Context *context, IGraphicsDevice *device) override
Initialize the extension using the given context and device.
void handleEvent(uint32_t eventId, const DrawContext *renderingContext) override
Called when rendering events occur.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
Represents a graphics device context which can receive rendering commands.
Definition: IContext.h:43
virtual void setRasterizerState(const RasterizerStateHandle handle)=0
Set the current rasterizer state.
virtual void setBlendState(const BlendStateHandle handle, const float *constant=nullptr)=0
Set the current blend state.
virtual void drawInstancedIndexed(PrimitiveType::EPrimitiveType primitiveType, const size_t startInstance, const size_t numInstances, const size_t startIndex, const size_t numIndexes)=0
Draws indexed, instanced primitives.
virtual void setIndexBuffer(IndexBufferHandle bufferHandle, uint32_t stride=4, uint32_t offset=0)=0
Sets the current index buffer.
virtual void setDepthStencilState(const DepthStencilStateHandle handle)=0
Set the current depth stencil state.
virtual void drawInstanced(PrimitiveType::EPrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes, const size_t startInstance, const size_t numInstances)=0
Draws non-indexed, instanced primitives.
virtual void setVertexBuffers(const VertexBufferHandle *vertexBufferHandles, const size_t count, const uint32_t *strides, const uint32_t *offsets)=0
Sets the current vertex buffers.
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
Provides RAII style mapping of a buffer resource.
Definition: IBuffers.h:160