33#include " rive/factory.hpp"
44#include " rive/layout/axis.hpp"
55#include " rive/layout/n_slicer.hpp"
6+ #include " rive/layout/n_slicer_tile_mode.hpp"
67#include " rive/math/math_types.hpp"
78#include " rive/shapes/image.hpp"
89#include " rive/shapes/slice_mesh.hpp"
@@ -180,6 +181,93 @@ std::vector<float> SliceMesh::vertexStops(const std::vector<float>& normalizedSt
180181 return result;
181182}
182183
184+ uint16_t SliceMesh::tileRepeat (std::vector<SliceMeshVertex>& vertices,
185+ std::vector<uint16_t >& indices,
186+ const std::vector<SliceMeshVertex>& box,
187+ uint16_t start)
188+ {
189+ assert (box.size () == 4 );
190+
191+ const float startX = box[0 ].vertex .x ;
192+ const float startY = box[0 ].vertex .y ;
193+ const float endX = box[2 ].vertex .x ;
194+ const float endY = box[2 ].vertex .y ;
195+
196+ const float startU = box[0 ].uv .x ;
197+ const float startV = box[0 ].uv .y ;
198+ const float endU = box[2 ].uv .x ;
199+ const float endV = box[2 ].uv .y ;
200+
201+ // The size of each repeated tile in image space
202+ Image* image = m_nslicer->image ();
203+ const float sizeX = image->width () * (endU - startU) / std::abs (image->scaleX ());
204+ const float sizeY = image->height () * (endV - startV) / std::abs (image->scaleY ());
205+
206+ float curX = startX;
207+ float curY = startY;
208+ int curV = start;
209+
210+ int escape = 1000000 ; // a million
211+ while (curY < endY && escape > 0 )
212+ {
213+ escape--;
214+ float fracY = (curY + sizeY) > endY ? (endY - curY) / sizeY : 1 ;
215+ curX = startX;
216+ while (curX < endX && escape > 0 )
217+ {
218+ escape--;
219+ int v0 = curV;
220+ float fracX = (curX + sizeX) > endX ? (endX - curX) / sizeX : 1 ;
221+
222+ std::vector<SliceMeshVertex> curTile;
223+ float endU1 = startU + (endU - startU) * fracX;
224+ float endV1 = startV + (endV - startV) * fracY;
225+ float endX1 = curX + sizeX * fracX;
226+ float endY1 = curY + sizeY * fracY;
227+
228+ // top left
229+ SliceMeshVertex v = SliceMeshVertex ();
230+ v.id = curV++;
231+ v.uv = Vec2D (startU, startV);
232+ v.vertex = Vec2D (curX, curY);
233+ curTile.emplace_back (v);
234+
235+ // top right
236+ v = SliceMeshVertex ();
237+ v.id = curV++;
238+ v.uv = Vec2D (endU1, startV);
239+ v.vertex = Vec2D (endX1, curY);
240+ curTile.emplace_back (v);
241+
242+ // bottom right
243+ v = SliceMeshVertex ();
244+ v.id = curV++;
245+ v.uv = Vec2D (endU1, endV1);
246+ v.vertex = Vec2D (endX1, endY1);
247+ curTile.emplace_back (v);
248+
249+ // bottom left
250+ v = SliceMeshVertex ();
251+ v.id = curV++;
252+ v.uv = Vec2D (startU, endV1);
253+ v.vertex = Vec2D (curX, endY1);
254+ curTile.emplace_back (v);
255+
256+ // Commit the four vertices, and the triangulation
257+ vertices.insert (vertices.end (), curTile.begin (), curTile.end ());
258+ for (uint16_t t : triangulation)
259+ {
260+ indices.emplace_back (v0 + t);
261+ }
262+
263+ curX += sizeX;
264+ }
265+ curY += sizeY;
266+ }
267+ assert (escape > 0 );
268+ return curV - start;
269+ }
270+
183271void SliceMesh::calc ()
184272{
185273 m_vertices = {};
@@ -190,13 +278,24 @@ void SliceMesh::calc()
190278 std::vector<float > vs = uvStops (AxisType::Y);
191279 std::vector<float > xs = vertexStops (us, AxisType::X);
192280 std::vector<float > ys = vertexStops (vs, AxisType::Y);
281+ const auto & tileModes = m_nslicer->tileModes ();
193282
194283 std::vector<SliceMeshVertex> vertices;
195284 uint16_t vertexIndex = 0 ;
196285 for (int patchY = 0 ; patchY < vs.size () - 1 ; patchY++)
197286 {
198287 for (int patchX = 0 ; patchX < us.size () - 1 ; patchX++)
199288 {
289+ auto tileModeIt = tileModes.find (m_nslicer->patchIndex (patchX, patchY));
290+ auto tileMode =
291+ tileModeIt == tileModes.end () ? NSlicerTileModeType::STRETCH : tileModeIt->second ;
292+
293+ // Do nothing if hidden
294+ if (tileMode == NSlicerTileModeType::HIDDEN)
295+ {
296+ continue ;
297+ }
298+
200299 const uint16_t v0 = vertexIndex;
201300 std::vector<SliceMeshVertex> patchVertices;
202301 for (const Corner& corner : patchCorners)
@@ -205,16 +304,27 @@ void SliceMesh::calc()
205304 int yIndex = patchY + corner.y ;
206305
207306 SliceMeshVertex v;
208- v.id = vertexIndex++;
307+ if (tileMode != NSlicerTileModeType::REPEAT)
308+ {
309+ v.id = vertexIndex++;
310+ }
209311 v.uv = Vec2D (us[xIndex], vs[yIndex]);
210312 v.vertex = Vec2D (xs[xIndex], ys[yIndex]);
211313
212314 patchVertices.emplace_back (v);
213315 }
214- vertices.insert (vertices.end (), patchVertices.begin (), patchVertices.end ());
215- for (uint16_t t : triangulation)
316+
317+ if (tileMode == NSlicerTileModeType::REPEAT)
318+ {
319+ vertexIndex += tileRepeat (vertices, m_indices, patchVertices, v0);
320+ }
321+ else
216322 {
217- m_indices.emplace_back (v0 + t);
323+ vertices.insert (vertices.end (), patchVertices.begin (), patchVertices.end ());
324+ for (uint16_t t : triangulation)
325+ {
326+ m_indices.emplace_back (v0 + t);
327+ }
218328 }
219329 }
220330 }
0 commit comments