CustomMesh.hpp
1 #pragma once
2 #include <Gfx/Graph/Mesh.hpp>
3 
4 #include <ossia/dataflow/geometry_port.hpp>
5 
6 #include <QtGui/private/qrhi_p.h>
7 
8 namespace score::gfx
9 {
10 
12 {
13  ossia::mesh_list geom;
14 
15  using pip = QRhiGraphicsPipeline;
16  pip::Topology topology = pip::Topology::TriangleStrip;
17  pip::CullMode cullMode = pip::CullMode::None;
18  pip::FrontFace frontFace = pip::FrontFace::CW;
19 
20  ossia::small_vector<QRhiVertexInputBinding, 2> vertexBindings;
21  ossia::small_vector<QRhiVertexInputAttribute, 2> vertexAttributes;
22 
23 public:
24  explicit CustomMesh(
25  const ossia::mesh_list& g, const ossia::geometry_filter_list_ptr& f)
26  {
27  reload(g, f);
28  }
29 
30  [[nodiscard]] MeshBuffers init(QRhi& rhi) const noexcept override
31  {
32  if(geom.meshes.empty())
33  return {};
34  if(geom.meshes[0].buffers.empty())
35  return {};
36 
37  const auto vtx_buf_size = geom.meshes[0].buffers[0].size;
38  auto mesh_buf
39  = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, vtx_buf_size);
40  mesh_buf->setName("Mesh::mesh_buf");
41  mesh_buf->create();
42 
43  QRhiBuffer* idx_buf{};
44  if(geom.meshes[0].buffers.size() > 1)
45  {
46  if(const auto idx_buf_size = geom.meshes[0].buffers[1].size; idx_buf_size > 0)
47  {
48  idx_buf
49  = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::IndexBuffer, idx_buf_size);
50  idx_buf->setName("Mesh::idx_buf");
51  idx_buf->create();
52  }
53  }
54 
55  MeshBuffers ret{mesh_buf, idx_buf};
56  return ret;
57  }
58 
59  void update(MeshBuffers& meshbuf, QRhiResourceUpdateBatch& rb) const noexcept override
60  {
61  if(geom.meshes.empty())
62  return;
63  if(geom.meshes[0].buffers.empty())
64  return;
65 
66  void* idx_buf_data = nullptr;
67  const auto vtx_buf = geom.meshes[0].buffers[0];
68  if(auto sz = vtx_buf.size; sz != meshbuf.mesh->size())
69  {
70  meshbuf.mesh->destroy();
71  meshbuf.mesh->setSize(sz);
72  meshbuf.mesh->create();
73  }
74 
75  if(meshbuf.index)
76  {
77  const auto idx_buf = geom.meshes[0].buffers[1];
78  if(geom.meshes[0].buffers.size() > 1)
79  {
80  if(const auto idx_buf_size = idx_buf.size; idx_buf_size > 0)
81  {
82  idx_buf_data = idx_buf.data.get();
83  // FIXME what if index disappears
84  if(auto sz = idx_buf.size; sz != meshbuf.index->size())
85  {
86  meshbuf.index->destroy();
87  meshbuf.index->setSize(sz);
88  meshbuf.index->create();
89  }
90  else
91  {
92  }
93  }
94  }
95  }
96  else
97  {
98  // FIXME what if index appears
99  }
100 
101  rb.updateDynamicBuffer(meshbuf.mesh, 0, meshbuf.mesh->size(), vtx_buf.data.get());
102  if(meshbuf.index)
103  {
104  rb.updateDynamicBuffer(meshbuf.index, 0, meshbuf.index->size(), idx_buf_data);
105  }
106  }
107 
108  Flags flags() const noexcept override
109  {
110  Flags f{};
111  for(auto& attr : vertexAttributes)
112  {
113  switch(attr.location())
114  {
115  case 0:
116  f |= HasPosition;
117  break;
118  case 1:
119  f |= HasTexCoord;
120  break;
121  case 2:
122  f |= HasColor;
123  break;
124  case 3:
125  f |= HasNormals;
126  break;
127  case 4:
128  f |= HasTangents;
129  break;
130  }
131  }
132  return f;
133  }
134 
135  void clear()
136  {
137  vertexBindings.clear();
138  vertexAttributes.clear();
139  }
140 
141  void preparePipeline(QRhiGraphicsPipeline& pip) const noexcept override
142  {
143  if(cullMode == QRhiGraphicsPipeline::None)
144  {
145  pip.setDepthTest(false);
146  pip.setDepthWrite(false);
147  }
148  else
149  {
150  pip.setDepthTest(true);
151  pip.setDepthWrite(true);
152  }
153 
154  pip.setTopology(this->topology);
155  pip.setCullMode(this->cullMode);
156  pip.setFrontFace(this->frontFace);
157 
158  QRhiVertexInputLayout inputLayout;
159  inputLayout.setBindings(this->vertexBindings.begin(), this->vertexBindings.end());
160  inputLayout.setAttributes(
161  this->vertexAttributes.begin(), this->vertexAttributes.end());
162  pip.setVertexInputLayout(inputLayout);
163  }
164 
165  void reload(const ossia::mesh_list& ml, const ossia::geometry_filter_list_ptr& f)
166  {
167  dirtyGeometryIndex++;
168  this->geom = ml;
169  this->filters = f;
170 
171  if(this->geom.meshes.size() == 0)
172  {
173  qDebug() << "Clearing geometry: ";
174  // clear();
175  return;
176  }
177 
178  auto& g = this->geom.meshes[0];
179 
180  vertexBindings.clear();
181  for(auto& binding : g.bindings)
182  {
183  vertexBindings.emplace_back(
184  binding.stride, (QRhiVertexInputBinding::Classification)binding.classification,
185  binding.step_rate);
186  }
187 
188  vertexAttributes.clear();
189  for(auto& attr : g.attributes)
190  {
191  vertexAttributes.emplace_back(
192  attr.binding, attr.location, (QRhiVertexInputAttribute::Format)attr.format,
193  attr.offset);
194  }
195 
196  if(g.buffers.empty())
197  {
198  qDebug() << "Error: empty buffer !";
199  clear();
200  }
201 
202  topology = (QRhiGraphicsPipeline::Topology)g.topology;
203  cullMode = (QRhiGraphicsPipeline::CullMode)g.cull_mode;
204  frontFace = (QRhiGraphicsPipeline::FrontFace)g.front_face;
205  }
206 
207  void draw(const MeshBuffers& bufs, QRhiCommandBuffer& cb) const noexcept override
208  {
209  for(auto& g : this->geom.meshes)
210  {
211  const auto sz = g.input.size();
212 
213  QVarLengthArray<QRhiCommandBuffer::VertexInput> bindings(sz);
214 
215  int i = 0;
216  for(auto& in : g.input)
217  {
218  bindings[i++] = {bufs.mesh, in.offset};
219  }
220 
221  if(g.index.buffer >= 0)
222  {
223  const auto idxFmt = g.index.format == decltype(g.index)::uint16
224  ? QRhiCommandBuffer::IndexUInt32
225  : QRhiCommandBuffer::IndexUInt32;
226  cb.setVertexInput(0, sz, bindings.data(), bufs.index, g.index.offset, idxFmt);
227  }
228  else
229  {
230  cb.setVertexInput(0, sz, bindings.data());
231  }
232 
233  if(g.index.buffer > -1)
234  {
235  cb.drawIndexed(g.indices);
236  }
237  else
238  {
239  cb.draw(g.vertices);
240  }
241  }
242  }
243 
244  const char* defaultVertexShader() const noexcept override
245  {
246  return "";
247  }
248 };
249 
250 }
Definition: CustomMesh.hpp:12
const char * defaultVertexShader() const noexcept override
A basic vertex shader that is going to work with this mesh.
Definition: CustomMesh.hpp:244
Graphics rendering pipeline for ossia score.
Definition: Filter/PreviewWidget.hpp:12
Definition: Mesh.hpp:15
Data model for meshes.
Definition: Mesh.hpp:23