1#include "VectorFieldRenderer.h"
2#include "VectorFieldSystem.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"
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"
27namespace Cogs::Core::VectorField
32 context = set_context;
34 vectorFieldSystem = ExtensionRegistry::getExtensionSystem<VectorFieldSystem>(context);
38 if (!renderingContext)
return;
42 for (
auto & vector_field : vectorFieldSystem->
pool) {
43 postRender(vector_field, renderingContext);
56 VectorFieldData &data = *item->getCallbackData<VectorFieldData>();
57 VectorFieldSystem *vectorFieldSystem = data.system;
58 Model *model =
nullptr;
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();
66 Renderer *renderer = renderingContext->renderer;
69 RenderMesh *renderMesh = renderer->getRenderResources().getRenderMesh(model->meshes[0]);
71 VectorFieldComponent &component = *data.handle.resolveComponent<VectorFieldComponent>();
73 if(component.positions)
74 count = component.positions.size();
75 if(count == 0)
return;
84 applyMaterialPermutation(renderingContext, drawContext, item->binding, item->renderMaterialInstance);
85 updateEnvironmentBindings(drawContext, item->binding);
86 applyMaterialInstance(drawContext, item->binding, item->renderMaterialInstance);
90 size_t size = count *
sizeof(glm::vec3);
92 for(
size_t i=0; i<count; i++){
93 glm::vec3 p = component.positions[i];
94 glm::vec3 d = component.directions[i];
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);
108 pos += d*anim_scale*t;
112 glm::vec4 c = component.colors[i];
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;
120 glm::vec3 u = glm::vec3(0.0, 1.0, 0.0);
121 glm::vec3 v = glm::normalize(component.directions[i]);
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);
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;
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);
143 std::array<Cogs::VertexBufferHandle, MeshStreamsLayout::maxStreams> vertexBuffers;
144 std::array<uint32_t, MeshStreamsLayout::maxStreams> strides;
147 for(
size_t i = 0; i < renderMesh->streamsLayout.
numStreams; i++){
148 vertexBuffers[n] = renderMesh->vertexBuffers[i];
149 strides[n++] = renderMesh->vertexStrides[i];
152 vertexBuffers[n] = data.buffer_handle;
154 deviceContext->
setVertexBuffers(vertexBuffers.data(), n, strides.data(),
nullptr);
156 if(indexed) deviceContext->
setIndexBuffer(renderMesh->indexBuffer);
159 RenderItem oItem = *item;
160 oItem.worldMatrix = &data.worldMatrix;
161 applyMaterialPerObject(drawContext, item->renderMaterialInstance, oItem);
164 auto submeshCount = mesh->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);
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);
180 static void vectorFieldCallbackCap(RenderTaskContext *renderingContext, DrawContext *drawContext,
const RenderItem * item)
182 vectorFieldCallback(renderingContext, drawContext, item, DC_CAP);
184 static void vectorFieldCallbackBase(RenderTaskContext *renderingContext, DrawContext *drawContext,
const RenderItem * item)
186 vectorFieldCallback(renderingContext, drawContext, item, DC_BASE);
188 void VectorFieldRenderer::generateCommands(
const RenderTaskContext *renderingContext, RenderList *renderList)
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;
204 if (data.layout_cap.numStreams == 0) {
205 data.layout_cap = mesh_cap->getStreamsLayout();
207 data.layout_cap.vertexFormats[data.layout_cap.numStreams++] = data.pos_format;
208 data.layout_cap.updateHash();
211 if (data.layout_base.numStreams == 0) {
212 data.layout_base = mesh_cap->getStreamsLayout();
214 data.layout_base.vertexFormats[data.layout_base.numStreams++] = data.pos_format;
215 data.layout_base.updateHash();
218 data.handle = vectorFieldSystem->getHandle(&component);
220 auto *transComp = component.getComponent<TransformComponent>();
221 data.worldMatrix = renderingContext->context->transformSystem->getLocalToWorld(transComp);
223 auto *camTransComp = renderingContext->cameraData->camera.resolve()->getComponent<TransformComponent>();
224 data.cam_pos = camTransComp->position;
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;
237 glm::vec4 lightDir = glm::vec4(0.0, 0.0, 1.0, 0.0);
238 EntityPtr dir_light = renderingContext->context->store->getEntity(
"DirectionalLight",
false);
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);
246 vectorFieldSystem->material_instance_cap->setProperty(
"lightDir", &lightDir,
sizeof(lightDir));
247 vectorFieldSystem->material_instance_base->setProperty(
"lightDir", &lightDir,
sizeof(lightDir));
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);
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);
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)
274 for(
size_t i=start; i < count; i++){
275 data.dither_offset[i] = glm::vec3(dist(gen), dist(gen), dist(gen));
277 data.ditherSize = component.ditherSize;
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();
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));
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);
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));
306 data.time = fmod(data.time, 1.0f);
310 RenderItem &item = renderList->createCustom(&data.layout_cap);
311 item.
layer = RenderLayers::Default;
312 item.materialInstance = vectorFieldSystem->material_instance_cap.resolve();
315 item.blendState = (uint16_t)item.materialInstance->options.blendMode;
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;
324 RenderItem &item = renderList->createCustom(&data.layout_base);
325 item.layer = RenderLayers::Default;
326 item.materialInstance = vectorFieldSystem->material_instance_base.resolve();
329 item.blendState = (uint16_t)item.materialInstance->options.blendMode;
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;
339 void VectorFieldRenderer::postRender(VectorFieldComponent &component,
const DrawContext *renderingContext)
341 if(component.animation){
342 renderingContext->context->engine->setDirty();
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.
RenderStates & getRenderStates() override
Get the reference to the RenderStates structure.
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
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.
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...
Model resources define a template for a set of connected entities, with resources such as meshes,...
RenderLayers layer
Visibility mask.
@ PostRender
Rendering has finished for a given rendering context.
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.
Represents a graphics device context which can receive rendering commands.
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.
Provides RAII style mapping of a buffer resource.