mirror of https://github.com/axmolengine/axmol.git
Add emission mask support.
This commit is contained in:
parent
6b133b68a2
commit
4d3f7ab92d
|
@ -836,6 +836,30 @@ void ParticleSystem::addParticles(int count, int animationIndex, int animationCe
|
|||
|
||||
break;
|
||||
}
|
||||
case EmissionShapeType::ALPHA_MASK:
|
||||
{
|
||||
Vec2 pos = {shape.x, shape.y};
|
||||
Vec2 size = shape.mask.size;
|
||||
Vec2 overrideSize = {shape.innerWidth, shape.innerHeight};
|
||||
Vec2 scale = {shape.outerWidth, shape.outerHeight};
|
||||
float angle = shape.coneOffset;
|
||||
|
||||
if (overrideSize.isZero())
|
||||
overrideSize = shape.mask.size;
|
||||
|
||||
Vec2 point = {0, 0};
|
||||
|
||||
{
|
||||
int rand0 = abs(RANDOM_KISS() * shape.mask.points.size());
|
||||
int index = MIN(rand0, shape.mask.points.size() - 1);
|
||||
point = shape.mask.points[index];
|
||||
}
|
||||
|
||||
_particleData.posx[i] = _sourcePosition.x + shape.x + point.x;
|
||||
_particleData.posy[i] = _sourcePosition.y + shape.y + point.y;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1141,6 +1165,32 @@ void ParticleSystem::setEmissionShape(unsigned short index, EmissionShape shape)
|
|||
iter->second = shape;
|
||||
}
|
||||
|
||||
EmissionShape ParticleSystem::createMaskShape(std::string_view maskName,
|
||||
Vec2 pos,
|
||||
Vec2 overrideSize,
|
||||
Vec2 scale,
|
||||
float angle)
|
||||
{
|
||||
EmissionShape shape{};
|
||||
|
||||
shape.type = EmissionShapeType::ALPHA_MASK;
|
||||
|
||||
shape.mask = ParticleEmissionMaskCache::getInstance()->getEmissionMask(maskName);
|
||||
|
||||
shape.x = pos.x;
|
||||
shape.y = pos.y;
|
||||
|
||||
shape.innerWidth = overrideSize.x;
|
||||
shape.innerHeight = overrideSize.y;
|
||||
|
||||
shape.outerWidth = scale.x;
|
||||
shape.outerHeight = scale.y;
|
||||
|
||||
shape.coneOffset = angle;
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
EmissionShape ParticleSystem::createPointShape(Vec2 pos)
|
||||
{
|
||||
EmissionShape shape{};
|
||||
|
@ -2232,4 +2282,87 @@ void ParticleSystem::setTimeScale(float scale)
|
|||
_timeScale = scale;
|
||||
}
|
||||
|
||||
static ParticleEmissionMaskCache* emissionMaskCache;
|
||||
|
||||
ParticleEmissionMaskCache* ParticleEmissionMaskCache::getInstance()
|
||||
{
|
||||
if (emissionMaskCache == nullptr)
|
||||
{
|
||||
emissionMaskCache = new ParticleEmissionMaskCache();
|
||||
return emissionMaskCache;
|
||||
}
|
||||
return emissionMaskCache;
|
||||
}
|
||||
|
||||
void ParticleEmissionMaskCache::bakeEmissionMask(std::string_view maskName,
|
||||
std::string_view texturePath,
|
||||
float alphaThreshold,
|
||||
bool inverted)
|
||||
{
|
||||
auto img = new Image();
|
||||
img->Image::initWithImageFile(texturePath);
|
||||
img->autorelease();
|
||||
|
||||
CCASSERT(img, "image texture was nullptr.");
|
||||
bakeEmissionMask(maskName, img, alphaThreshold, inverted);
|
||||
}
|
||||
|
||||
void ParticleEmissionMaskCache::bakeEmissionMask(std::string_view maskName,
|
||||
Image* imageTexture,
|
||||
float alphaThreshold,
|
||||
bool inverted)
|
||||
{
|
||||
auto img = imageTexture;
|
||||
CCASSERT(img, "image texture was nullptr.");
|
||||
CCASSERT(img->hasAlpha(), "image data should contain an alpha channel.");
|
||||
|
||||
vector<Vec2> points;
|
||||
|
||||
auto data = img->getData();
|
||||
auto w = img->getWidth();
|
||||
auto h = img->getHeight();
|
||||
|
||||
for (int y = 0; y < h; y++) for (int x = 0; x < w; x++)
|
||||
{
|
||||
float a = data[(y * w + x) * 4 + 3] / 255.0F;
|
||||
if (a >= alphaThreshold && !inverted)
|
||||
points.push_back({float(x), float(h - y)});
|
||||
if (a < alphaThreshold && inverted)
|
||||
points.push_back({float(x), float(h - y)});
|
||||
}
|
||||
|
||||
auto iter = this->masks.find(maskName);
|
||||
if (iter == this->masks.end())
|
||||
iter = this->masks.emplace(maskName, ParticleEmissionMaskDescriptor{}).first;
|
||||
|
||||
ParticleEmissionMaskDescriptor desc;
|
||||
desc.size = {float(w), float(h)};
|
||||
desc.points = std::move(points);
|
||||
|
||||
iter->second = desc;
|
||||
}
|
||||
|
||||
const ParticleEmissionMaskDescriptor& ParticleEmissionMaskCache::getEmissionMask(std::string_view maskName)
|
||||
{
|
||||
auto iter = this->masks.find(maskName);
|
||||
if (iter == this->masks.end())
|
||||
{
|
||||
ParticleEmissionMaskDescriptor desc;
|
||||
desc.size = {float(1), float(1)};
|
||||
desc.points = {{0, 0}};
|
||||
return desc;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void ParticleEmissionMaskCache::releaseMaskFromMemory(std::string_view maskName)
|
||||
{
|
||||
this->masks.erase(maskName);
|
||||
}
|
||||
|
||||
void ParticleEmissionMaskCache::releaseAllMasksFromMemory()
|
||||
{
|
||||
this->masks.clear();
|
||||
}
|
||||
|
||||
NS_CC_END
|
|
@ -65,7 +65,14 @@ enum class EmissionShapeType
|
|||
RECT,
|
||||
RECTTORUS,
|
||||
CIRCLE,
|
||||
TORUS
|
||||
TORUS,
|
||||
ALPHA_MASK
|
||||
};
|
||||
|
||||
struct ParticleEmissionMaskDescriptor
|
||||
{
|
||||
Vec2 size;
|
||||
std::vector<cocos2d::Vec2> points;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -90,6 +97,8 @@ struct EmissionShape
|
|||
float coneOffset;
|
||||
float coneAngle;
|
||||
float edgeElasticity;
|
||||
|
||||
ParticleEmissionMaskDescriptor mask;
|
||||
};
|
||||
|
||||
/** @struct ParticleAnimationDescriptor
|
||||
|
@ -244,6 +253,29 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CC_DLL ParticleEmissionMaskCache : public cocos2d::Ref
|
||||
{
|
||||
public:
|
||||
static ParticleEmissionMaskCache* getInstance();
|
||||
|
||||
void bakeEmissionMask(std::string_view maskName,
|
||||
std::string_view texturePath,
|
||||
float alphaThreshold = 0.5F,
|
||||
bool inverted = false);
|
||||
|
||||
void bakeEmissionMask(std::string_view maskName,
|
||||
Image* imageTexture,
|
||||
float alphaThreshold = 0.5F,
|
||||
bool inverted = false);
|
||||
|
||||
const ParticleEmissionMaskDescriptor& getEmissionMask(std::string_view maskName);
|
||||
|
||||
void releaseMaskFromMemory(std::string_view maskName);
|
||||
void releaseAllMasksFromMemory();
|
||||
|
||||
hlookup::string_map<ParticleEmissionMaskDescriptor> masks;
|
||||
};
|
||||
|
||||
// typedef void (*CC_UPDATE_PARTICLE_IMP)(id, SEL, tParticle*, Vec2);
|
||||
|
||||
class Texture2D;
|
||||
|
@ -292,7 +324,6 @@ emitter.startSpin = 0;
|
|||
@endcode
|
||||
|
||||
*/
|
||||
|
||||
class CC_DLL ParticleSystem : public Node, public TextureProtocol, public PlayableProtocol
|
||||
{
|
||||
public:
|
||||
|
@ -1164,6 +1195,17 @@ public:
|
|||
*/
|
||||
void setEmissionShape(unsigned short index, EmissionShape shape);
|
||||
|
||||
/** Adds an emission shape of type mask to the system.
|
||||
* The mask should be added using the ParticleEmissionMaskCache class.
|
||||
*
|
||||
* @param maskName Name of the emission mask.
|
||||
* @param pos Position of the emission shape in local space.
|
||||
* @param overrideSize Size of the emission mask in pixels, leave ZERO to use texture size.
|
||||
* @param scale Scale of the emission mask, the size will be multiplied by the specified scale.
|
||||
* @param angle Angle of the sampled points to be rotated in degrees.
|
||||
*/
|
||||
static EmissionShape createMaskShape(std::string_view maskName, Vec2 pos = Vec2::ZERO, Vec2 overrideSize = Vec2::ZERO, Vec2 scale = Vec2::ONE, float angle = 0.0F);
|
||||
|
||||
/** Adds an emission shape of type point to the system.
|
||||
* @param pos Position of the emission shape in local space.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue