axmol/core/2d/CCAutoPolygon.h

295 lines
11 KiB
C++

/****************************************************************************
Copyright (c) 2008-2010 Ricardo Quesada
Copyright (c) 2010-2012 cocos2d-x.org
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
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.
****************************************************************************/
#ifndef COCOS_2D_CCAUTOPOLYGON_H__
#define COCOS_2D_CCAUTOPOLYGON_H__
#include <string>
#include <vector>
#include "platform/CCImage.h"
#include "renderer/CCTrianglesCommand.h"
NS_AX_BEGIN
/**
* @addtogroup _2d
* @{
*/
/**
* PolygonInfo is an object holding the required data to display Sprites.
* It can be a simple as a triangle, or as complex as a whole 3D mesh
*/
class AX_DLL PolygonInfo
{
public:
/// @name Creators
/// @{
/**
* Creates an empty Polygon info
* @memberof PolygonInfo
* @return PolygonInfo object
*/
PolygonInfo();
/**
* Create an polygoninfo from the data of another Polygoninfo
* @param other another PolygonInfo to be copied
* @return duplicate of the other PolygonInfo
*/
PolygonInfo(const PolygonInfo& other);
// end of creators group
/// @}
/**
* Copy the member of the other PolygonInfo
* @param other another PolygonInfo to be copied
*/
PolygonInfo& operator=(const PolygonInfo& other);
~PolygonInfo();
/**
* set the data to be a pointer to a quad
* the member verts will not be released when this PolygonInfo destructs
* as the verts memory are managed by other objects
* @param quad a pointer to the V3F_C4B_T2F_Quad object
*/
void setQuad(V3F_C4B_T2F_Quad* quad);
/**
* set the data to be a pointer to a number of Quads
* the member verts will not be released when this PolygonInfo destructs
* as the verts memory are managed by other objects
* @param quad a pointer to the V3F_C4B_T2F_Quad quads
*/
void setQuads(V3F_C4B_T2F_Quad* quads, int numberOfQuads);
/**
* set the data to be a pointer to a triangles
* the member verts will not be released when this PolygonInfo destructs
* as the verts memory are managed by other objects
* @param triangles a pointer to the TrianglesCommand::Triangles object
*/
void setTriangles(const TrianglesCommand::Triangles& triangles);
/**
* get vertex count
* @return number of vertices
*/
unsigned int getVertCount() const;
/**
* get triangles count
* @return number of triangles
*/
unsigned int getTrianglesCount() const;
/**
* get sum of all triangle area size
* @return sum of all triangle area size
*/
float getArea() const;
const Rect& getRect() const { return _rect; }
void setRect(const Rect& rect) { _rect = rect; }
std::string_view getFilename() const { return _filename; }
void setFilename(std::string_view filename) { _filename = filename; }
// FIXME: this should be a property, not a public ivar
TrianglesCommand::Triangles triangles;
protected:
bool _isVertsOwner;
Rect _rect;
std::string _filename;
private:
void releaseVertsAndIndices();
};
/**
* AutoPolygon is a helper Object
* AutoPolygon's purpose is to process an image into 2d polygon mesh in runtime
* It has functions for each step in the process, from tracing all the points, to triangulation
* the result can be then passed to Sprite::create() to create a Polygon Sprite
*/
class AX_DLL AutoPolygon
{
public:
/**
* create an AutoPolygon and initialize it with an image file
* the image must be a 32bit PNG for current version 3.7
* @param filename a path to image file, e.g., "scene1/monster.png".
* @return an AutoPolygon object;
*/
AutoPolygon(std::string_view filename);
/**
* Destructor of AutoPolygon.
*/
~AutoPolygon();
/**
* trace all the points along the outline of the image,
* @warning must create AutoPolygon with filename to use this function
* @param rect a texture rect for specify an area of the image
* @param threshold the value when alpha is greater than this value will be counted as opaque, default to 0.0
* @return a vector of vec2 of all the points found in clockwise order
* @code
* auto ap = AutoPolygon("grossini.png");
* auto rect = Rect(100, 100, 200, 200);
* std::vector<Vec2> points = ap.trace(rect);//default threshold is 0.0
* @endcode
*/
std::vector<Vec2> trace(const ax::Rect& rect, float threshold = 0.0f);
/**
* reduce the amount of points so its faster for GPU to process and draw
* based on Ramer-Douglas-Peucker algorithm
* @param points a vector of Vec2 points as input
* @param rect a texture rect for specify an area of the image to avoid over reduction
* @param epsilon the perpendicular distance where points smaller than this value will be discarded
* @return a vector of Vec2 of the remaining points in clockwise order
* @code
* auto ap = AutoPolygon();
* std::vector<Vec2> reduced = ap.reduce(inputPoints, rect);//default epsilon is 2
* @endcode
*/
std::vector<Vec2> reduce(const std::vector<Vec2>& points, const Rect& rect, float epsilon = 2.0f);
/**
* expand the points along their edge, useful after you reduce the points that cuts into the sprite
* using ClipperLib
* @param points a vector of Vec2 points as input
* @param rect a texture rect for specify an area of the image, the expanded points will be clamped in this
* rect, ultimately resulting in a quad if the expansion is too great
* @param epsilon the distance which the edges will expand
* @return a vector of Vec2 as the result of the expansion
* @code
* auto ap = AutoPolygon();
* std::vector<Vec2> expanded = ap.expand(inputPoints, rect, 2.0);
* @endcode
*/
std::vector<Vec2> expand(const std::vector<Vec2>& points, const Rect& rect, float epsilon);
/**
* Triangulate the input points into triangles for rendering
* using poly2tri
* @warning points must be closed loop, cannot have 2 points sharing the same position and cannot intersect itself
* @param points a vector of vec2 points as input
* @return a Triangles object with points and indices
* @code
* auto ap = AutoPolygon();
* TrianglesCommand::Triangles myPolygons = ap.triangulate(myPoints);
* @endcode
*/
TrianglesCommand::Triangles triangulate(const std::vector<Vec2>& points);
/**
* calculate the UV coordinates for each points based on a texture rect
* @warning This method requires the AutoPolygon object to know the texture file dimension
* @param rect a texture rect to specify where to map the UV
* @param verts a pointer to the verts array, served both as input and output verts
* @param count the count for the verts array
* @code
* auto ap = AutoPolygon("grossini.png");
* TrianglesCommand::Triangles myPolygons = ap.triangulate(myPoints);
* ap.calculateUV(rect, myPolygons.verts, 20);
* @endcode
*/
void calculateUV(const Rect& rect, V3F_C4B_T2F* verts, ssize_t count);
/**
* a helper function, packing trace, reduce, expand, triangulate and calculate uv in one function
* @param rect texture rect, use Rect::ZERO for the size of the texture, default is Rect::ZERO
* @param epsilon the value used to reduce and expand, default to 2.0
* @param threshold the value where bigger than the threshold will be counted as opaque, used in trace
* @return a PolygonInfo, to use with sprite
* @code
* auto ap = AutoPolygon("grossini.png");
* PolygonInfo myInfo = ap.generateTriangles();//use all default values
* auto sp1 = Sprite::create(myInfo);
* polygonInfo myInfo2 = ap.generateTriangles(Rect::ZERO, 5.0, 0.1);//ap can be reused to generate another set of
* PolygonInfo with different settings auto sp2 = Sprite::create(myInfo2);
* @endcode
*/
PolygonInfo generateTriangles(const Rect& rect = Rect::ZERO, float epsilon = 2.0f, float threshold = 0.05f);
/**
* a helper function, packing autoPolygon creation, trace, reduce, expand, triangulate and calculate uv in one
* function
* @warning if you want to repetitively generate polygons, consider create an AutoPolygon object, and use
* generateTriangles function, as it only reads the file once
* @param filename A path to image file, e.g., "scene1/monster.png".
* @param rect texture rect, use Rect::ZERO for the size of the texture, default is Rect::ZERO
* @param epsilon the value used to reduce and expand, default to 2.0
* @param threshold the value where bigger than the threshold will be counted as opaque, used in trace
* @return a PolygonInfo, to use with sprite
* @code
* auto sp = Sprite::create(AutoPolygon::generatePolygon("grossini.png"));
* @endcode
*/
static PolygonInfo generatePolygon(std::string_view filename,
const Rect& rect = Rect::ZERO,
float epsilon = 2.0f,
float threshold = 0.05f);
protected:
Vec2 findFirstNoneTransparentPixel(const Rect& rect, float threshold);
std::vector<ax::Vec2> marchSquare(const Rect& rect, const Vec2& first, float threshold);
unsigned int getSquareValue(unsigned int x, unsigned int y, const Rect& rect, float threshold);
unsigned char getAlphaByIndex(unsigned int i);
unsigned char getAlphaByPos(const Vec2& pos);
int getIndexFromPos(unsigned int x, unsigned int y) { return y * _width + x; }
ax::Vec2 getPosFromIndex(unsigned int i)
{
return ax::Vec2(static_cast<float>(i % _width), static_cast<float>(i / _width));
}
std::vector<ax::Vec2> rdp(const std::vector<ax::Vec2>& v, float optimization);
float perpendicularDistance(const ax::Vec2& i, const ax::Vec2& start, const ax::Vec2& end);
// real rect is the size that is in scale with the texture file
Rect getRealRect(const Rect& rect);
Image* _image;
unsigned char* _data;
std::string _filename;
unsigned int _width;
unsigned int _height;
float _scaleFactor;
unsigned int _threshold;
};
NS_AX_END
#endif // #ifndef COCOS_2D_CCAUTOPOLYGON_H__