Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 25 additions & 30 deletions core/2d/CCAutoPolygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Copyright (c) 2011 Zynga Inc.
Copyright (c) 2013-2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
Copyright (c) 2022 @aismann; Peter Eismann, Germany; dreifrankensoft
Copyright (c) 2022 Bytedance Inc.

https://axmolengine.github.io/

Expand Down Expand Up @@ -34,6 +35,7 @@ THE SOFTWARE.
#include "clipper2/clipper.h"
#include <algorithm>
#include <math.h>
#include "base/pod_vector.h"

USING_NS_AX;

Expand Down Expand Up @@ -579,20 +581,27 @@ TrianglesCommand::Triangles AutoPolygon::triangulate(const std::vector<Vec2>& po
log("AUTOPOLYGON: cannot triangulate %s with less than 3 points", _filename.c_str());
return TrianglesCommand::Triangles();
}


std::vector<p2t::Point> p2pointsStorage;
p2pointsStorage.reserve(points.size());
std::vector<p2t::Point*> p2points;
for (const auto& pt : points)
p2points.reserve(points.size());
for (size_t i = 0; i < points.size(); ++i)
{
p2t::Point* p = new p2t::Point(pt.x, pt.y);
p2points.emplace_back(p);
auto& pt = points[i];
p2points.emplace_back(&p2pointsStorage.emplace_back((double)pt.x, (double)pt.y));
}

p2t::CDT cdt(p2points);
cdt.Triangulate();
std::vector<p2t::Triangle*> tris = cdt.GetTriangles();

// we won't know the size of verts and indices until we process all of the triangles!
std::vector<V3F_C4B_T2F> verts;
std::vector<unsigned short> indices;

size_t indicesCount = tris.size() * 3;
ax::pod_vector<V3F_C4B_T2F> vertsBuf;
vertsBuf.reserve(indicesCount / 2);
unsigned short* indicesBuf = new unsigned short[indicesCount];

unsigned short idx = 0;
unsigned short vdx = 0;

Expand All @@ -607,7 +616,7 @@ TrianglesCommand::Triangles AutoPolygon::triangulate(const std::vector<Vec2>& po
auto length = vdx;
for (j = 0; j < length; j++)
{
if (verts[j].vertices == v3)
if (vertsBuf[j].vertices == v3)
{
found = true;
break;
Expand All @@ -616,38 +625,24 @@ TrianglesCommand::Triangles AutoPolygon::triangulate(const std::vector<Vec2>& po
if (found)
{
// if we found the same vertex, don't add to verts, but use the same vertex with indices
indices.emplace_back(j);
idx++;
indicesBuf[idx++] = j;
}
else
{
// vert does not exist yet, so we need to create a new one,
auto c4b = Color4B::WHITE;
auto t2f = Tex2F(0, 0); // don't worry about tex coords now, we calculate that later
V3F_C4B_T2F vert = {v3, c4b, t2f};
verts.emplace_back(vert);
indices.emplace_back(vdx);
idx++;
vdx++;

indicesBuf[idx++] = vdx++;

vertsBuf.emplace(V3F_C4B_T2F{v3, c4b, t2f});
}
}
}
for (auto&& j : p2points)
{
delete j;
};

// now that we know the size of verts and indices we can create the buffers
V3F_C4B_T2F* vertsBuf = new V3F_C4B_T2F[verts.size()];
memcpy(vertsBuf, verts.data(), verts.size() * sizeof(V3F_C4B_T2F));

unsigned short* indicesBuf = new unsigned short[indices.size()];
memcpy(indicesBuf, indices.data(), indices.size() * sizeof(short));

// Triangles should really use std::vector and not arrays for verts and indices.
// Then the above memcpy would not be necessary
TrianglesCommand::Triangles triangles = {vertsBuf, indicesBuf, (unsigned int)verts.size(),
(unsigned int)indices.size()};
// Good concept: the pod_vector support release internal buffer ownership
TrianglesCommand::Triangles triangles = {vertsBuf.release_pointer(), indicesBuf, (unsigned int)vdx,
(unsigned int)idx};
return triangles;
}

Expand Down
164 changes: 164 additions & 0 deletions core/base/pod_vector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/****************************************************************************
Copyright (c) 2022 Bytedance Inc.
https://axmolengine.github.io/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
The pod_vector concepts:
a. only accept pod type
b. support release memory ownership with `release_pointer`
c. support pod_allocater with C(realloc) or C++(new/delete)
b. resize operation no fill
*/
#pragma once
#include <string.h>
#include <utility>
#include <new>
#include <type_traits>

namespace ax
{

template <typename _Ty, bool /*_use_crt_alloc*/ = false>
struct pod_allocator
{
static void* reallocate(void* old_block, size_t old_count, size_t new_count)
{
if (old_count != new_count)
{
void* new_block = nullptr;
if (new_count)
{
new_block = ::operator new(new_count * sizeof(_Ty));
if (old_block)
memcpy(new_block, old_block, (std::min)(old_count, new_count) * sizeof(_Ty));
}

::operator delete(old_block);
return new_block;
}
return old_block;
}
};

template <typename _Ty>
struct pod_allocator<_Ty, true>
{
static void* reallocate(void* old_block, size_t /*old_count*/, size_t new_count)
{
return ::realloc(old_block, new_count * sizeof(_Ty));
}
};

template <typename _Ty,
typename _Alty = pod_allocator<_Ty>,
std::enable_if_t<std::is_trivially_destructible_v<_Ty>, int> = 0>
class pod_vector
{
public:
using pointer = _Ty*;
using value_type = _Ty;
pod_vector() = default;
pod_vector(pod_vector const&) = delete;
pod_vector& operator=(pod_vector const&) = delete;

pod_vector(pod_vector&& o) noexcept
{
std::swap(_Myfirst, o._Myfirst);
std::swap(_Mylast, o._Mylast);
std::swap(_Myend, o._Myend);
}
pod_vector& operator=(pod_vector&& o) noexcept
{
std::swap(_Myfirst, o._Myfirst);
std::swap(_Mylast, o._Mylast);
std::swap(_Myend, o._Myend);
return *this;
}

~pod_vector() { shrink_to_fit(0); }

template <typename... _Args>
_Ty& emplace(_Args&&... args) noexcept
{
return *new (resize(this->size() + 1)) _Ty(std::forward<_Args>(args)...);
}

void reserve(size_t new_cap)
{
if (this->capacity() < new_cap)
{
auto cur_size = this->size();
_Reallocate_exactly(new_cap);
_Mylast = _Myfirst + cur_size;
}
}

// return address of new last element
pointer resize(size_t new_size)
{
auto old_cap = this->capacity();
if (old_cap < new_size)
_Reallocate_exactly((std::max)(old_cap + old_cap / 2, new_size));
_Mylast = _Myfirst + new_size;
return _Mylast - 1;
}

_Ty& operator[](size_t idx) { return _Myfirst[idx]; }
const _Ty& operator[](size_t idx) const { return _Myfirst[idx]; }

size_t capacity() const noexcept { return _Myend - _Myfirst; }
size_t size() const noexcept { return _Mylast - _Myfirst; }
void clear() noexcept { _Mylast = _Myfirst; }

void shrink_to_fit() { shrink_to_fit(this->size()); }
void shrink_to_fit(size_t new_size)
{
if (this->capacity() != new_size)
_Reallocate_exactly(new_size);
_Mylast = _Myfirst + new_size;
}

// release memmory ownership
pointer release_pointer() noexcept
{
auto ptr = _Myfirst;
memset(this, 0, sizeof(*this));
return ptr;
}

private:
void _Reallocate_exactly(size_t new_cap)
{
auto new_block = (pointer)_Alty::reallocate(_Myfirst, _Myend - _Myfirst, new_cap);
if (new_block || 0 == new_cap)
{
_Myfirst = new_block;
_Myend = _Myfirst + new_cap;
}
else
throw std::bad_alloc{};
}

pointer _Myfirst = nullptr;
pointer _Mylast = nullptr;
pointer _Myend = nullptr;
};
} // namespace ax