| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767 |
- #include "Base.h"
- #include "Sprite.h"
- #include "Scene.h"
- namespace gameplay
- {
- Sprite::Sprite() : Drawable(),
- _width(0), _height(0), _offset(OFFSET_BOTTOM_LEFT), _anchor(Vector2(0.5f, 0.5f)), _flipFlags(FLIP_NONE),
- _frames(NULL), _frameCount(1), _frameStride(0), _framePadding(1), _frameIndex(0),
- _opacity(1.0f), _color(Vector4::one()), _blendMode(BLEND_ALPHA), _batch(NULL)
- {
- }
- Sprite::~Sprite()
- {
- SAFE_DELETE_ARRAY(_frames);
- SAFE_DELETE(_batch);
- }
- Sprite& Sprite::operator=(const Sprite& sprite)
- {
- return *this;
- }
-
- Sprite* Sprite::create(const char* imagePath, float width, float height, Effect* effect)
- {
- return Sprite::create(imagePath, width, height, Rectangle(0, 0, -1, -1), 1, effect);
- }
-
- Sprite* Sprite::create(const char* imagePath, float width, float height,
- const Rectangle& source, unsigned int frameCount, Effect* effect)
- {
- GP_ASSERT(imagePath != NULL);
- GP_ASSERT(width >= -1 && height >= -1);
- GP_ASSERT(source.width >= -1 && source.height >= -1);
- GP_ASSERT(frameCount > 0);
-
- SpriteBatch* batch = SpriteBatch::create(imagePath, effect);
- batch->getSampler()->setWrapMode(Texture::CLAMP, Texture::CLAMP);
- batch->getSampler()->setFilterMode(Texture::Filter::LINEAR, Texture::Filter::LINEAR);
- batch->getStateBlock()->setDepthWrite(false);
- batch->getStateBlock()->setDepthTest(true);
-
- unsigned int imageWidth = batch->getSampler()->getTexture()->getWidth();
- unsigned int imageHeight = batch->getSampler()->getTexture()->getHeight();
- if (width == -1)
- width = imageWidth;
- if (height == -1)
- height = imageHeight;
-
- Sprite* sprite = new Sprite();
- sprite->_width = width;
- sprite->_height = height;
- sprite->_batch = batch;
- sprite->_frameCount = frameCount;
- sprite->_frames = new Rectangle[frameCount];
- sprite->_frames[0] = source;
- if (sprite->_frames[0].width == -1.0f)
- sprite->_frames[0].width = imageWidth;
- if (sprite->_frames[0].height == -1.0f)
- sprite->_frames[0].height = imageHeight;
- return sprite;
- }
- static bool parseBlendMode(const char* str, Sprite::BlendMode* blend)
- {
- GP_ASSERT(blend);
- if (!str)
- {
- *blend = Sprite::BLEND_NONE;
- return false;
- }
- if (strcmp(str, "BLEND_ALPHA") == 0)
- {
- *blend = Sprite::BLEND_ALPHA;
- }
- else if (strcmp(str, "BLEND_ADDITIVE") == 0)
- {
- *blend = Sprite::BLEND_ADDITIVE;
- }
- else if (strcmp(str, "BLEND_MULTIPLIED") == 0)
- {
- *blend = Sprite::BLEND_MULTIPLIED;
- }
- else if (strcmp(str, "BLEND_NONE") != 0)
- {
- GP_ERROR("Failed to get corresponding sprite blend mode for unsupported value '%s'.", str);
- *blend = Sprite::BLEND_NONE;
- return false;
- }
- else
- {
- *blend = Sprite::BLEND_NONE;
- }
- return true;
- }
- static bool parseFlipFlags(const char* str, Sprite::FlipFlags* flip)
- {
- GP_ASSERT(flip);
- if (!str)
- {
- *flip = Sprite::FLIP_NONE;
- return false;
- }
- if (strcmp(str, "FLIP_VERTICAL") == 0)
- {
- *flip = Sprite::FLIP_VERTICAL;
- }
- else if (strcmp(str, "FLIP_HORIZONTAL") == 0)
- {
- *flip = Sprite::FLIP_HORIZONTAL;
- }
- else if (strcmp(str, "FLIP_VERTICAL_HORIZONTAL") == 0)
- {
- *flip = (Sprite::FlipFlags)(Sprite::FLIP_VERTICAL | Sprite::FLIP_HORIZONTAL);
- }
- else if (strcmp(str, "FLIP_NONE") != 0)
- {
- GP_ERROR("Failed to get corresponding sprite flip flag for unsupported value '%s'.", str);
- *flip = Sprite::FLIP_NONE;
- return false;
- }
- else
- {
- *flip = Sprite::FLIP_NONE;
- }
- return true;
- }
- static bool parseOffset(const char* str, Sprite::Offset* offset)
- {
- GP_ASSERT(offset);
- if (!str)
- {
- *offset = Sprite::OFFSET_LEFT;
- return false;
- }
- if (strcmp(str, "OFFSET_LEFT") == 0)
- {
- *offset = Sprite::OFFSET_LEFT;
- }
- else if (strcmp(str, "OFFSET_HCENTER") == 0)
- {
- *offset = Sprite::OFFSET_HCENTER;
- }
- else if (strcmp(str, "OFFSET_RIGHT") == 0)
- {
- *offset = Sprite::OFFSET_RIGHT;
- }
- else if (strcmp(str, "OFFSET_TOP") == 0)
- {
- *offset = Sprite::OFFSET_TOP;
- }
- else if (strcmp(str, "OFFSET_VCENTER") == 0)
- {
- *offset = Sprite::OFFSET_VCENTER;
- }
- else if (strcmp(str, "OFFSET_BOTTOM") == 0)
- {
- *offset = Sprite::OFFSET_BOTTOM;
- }
- else if (strcmp(str, "OFFSET_ANCHOR") == 0)
- {
- *offset = Sprite::OFFSET_ANCHOR;
- }
- else if (strcmp(str, "OFFSET_TOP_LEFT") == 0)
- {
- *offset = Sprite::OFFSET_TOP_LEFT;
- }
- else if (strcmp(str, "OFFSET_VCENTER_LEFT") == 0)
- {
- *offset = Sprite::OFFSET_VCENTER_LEFT;
- }
- else if (strcmp(str, "OFFSET_BOTTOM_LEFT") == 0)
- {
- *offset = Sprite::OFFSET_BOTTOM_LEFT;
- }
- else if (strcmp(str, "OFFSET_TOP_HCENTER") == 0)
- {
- *offset = Sprite::OFFSET_TOP_HCENTER;
- }
- else if (strcmp(str, "OFFSET_VCENTER_HCENTER") == 0)
- {
- *offset = Sprite::OFFSET_VCENTER_HCENTER;
- }
- else if (strcmp(str, "OFFSET_BOTTOM_HCENTER") == 0)
- {
- *offset = Sprite::OFFSET_BOTTOM_HCENTER;
- }
- else if (strcmp(str, "OFFSET_TOP_RIGHT") == 0)
- {
- *offset = Sprite::OFFSET_TOP_RIGHT;
- }
- else if (strcmp(str, "OFFSET_VCENTER_RIGHT") == 0)
- {
- *offset = Sprite::OFFSET_VCENTER_RIGHT;
- }
- else if (strcmp(str, "OFFSET_BOTTOM_RIGHT") != 0)
- {
- GP_ERROR("Failed to get corresponding sprite offset for unsupported value '%s'.", str);
- *offset = Sprite::OFFSET_LEFT;
- return false;
- }
- else
- {
- *offset = Sprite::OFFSET_BOTTOM_RIGHT;
- }
- return true;
- }
- Sprite* Sprite::create(Properties* properties)
- {
- // Check if the Properties is valid and has a valid namespace.
- if (!properties || strcmp(properties->getNamespace(), "sprite") != 0)
- {
- GP_ERROR("Properties object must be non-null and have namespace equal to 'sprite'.");
- return NULL;
- }
- // Get image path.
- const char* imagePath = properties->getString("path");
- if (imagePath == NULL || strlen(imagePath) == 0)
- {
- GP_ERROR("Sprite is missing required image file path.");
- return NULL;
- }
- // Don't support loading custom effects
- Effect* effect = NULL;
- // Get width and height
- float width = -1.0f;
- float height = -1.0f;
- float widthPercentage = 0.0f;
- float heightPercentage = 0.0f;
- if (properties->exists("width"))
- {
- if (properties->getType("width") == Properties::NUMBER) //TODO: Verify that this works for "100" but fails for "100%"
- {
- width = properties->getFloat("width");
- }
- else
- {
- widthPercentage = properties->getFloat("width") / 100.0f;
- }
- }
- if (properties->exists("height"))
- {
- if (properties->getType("height") == Properties::NUMBER)
- {
- height = properties->getFloat("height");
- }
- else
- {
- heightPercentage = properties->getFloat("height") / 100.0f;
- }
- }
- Sprite* sprite;
- if (properties->exists("source"))
- {
- // Get source frame
- Rectangle source;
- properties->getVector4("source", (Vector4*)&source);
- // Get frame count
- int frameCount = properties->getInt("frameCount");
- if (frameCount < 0)
- {
- GP_WARN("Sprites require at least one frame. Defaulting to frame count 1.");
- }
- if (frameCount < 1)
- {
- frameCount = 1;
- }
- // Load sprite
- sprite = Sprite::create(imagePath, width, height, source, frameCount, effect);
- }
- else
- {
- // Load sprite
- sprite = Sprite::create(imagePath, width, height, effect);
- }
- // Edit scaling of sprites if needed
- if (widthPercentage != 0.0f || heightPercentage != 0.0f)
- {
- if (widthPercentage != 0.0f)
- {
- sprite->_width *= widthPercentage;
- sprite->_frames[0].width *= widthPercentage;
- }
- if (heightPercentage != 0.0f)
- {
- sprite->_height *= heightPercentage;
- sprite->_frames[0].height *= heightPercentage;
- }
- }
- // Get anchor
- Vector4 vect;
- if (properties->getVector2("anchor", (Vector2*)&vect))
- {
- sprite->setAnchor(*((Vector2*)&vect));
- }
- // Get color
- if (properties->exists("color"))
- {
- switch (properties->getType("color"))
- {
- case Properties::VECTOR3:
- vect.w = 1.0f;
- properties->getVector3("color", (Vector3*)&vect);
- break;
- case Properties::VECTOR4:
- properties->getVector4("color", &vect);
- break;
- case Properties::STRING:
- default:
- properties->getColor("color", &vect);
- break;
- }
- sprite->setColor(vect);
- }
- // Get opacity
- if (properties->exists("opacity"))
- {
- sprite->setOpacity(properties->getFloat("opacity"));
- }
- // Get blend mode
- BlendMode mode;
- if (parseBlendMode(properties->getString("blendMode"), &mode))
- {
- sprite->setBlendMode(mode);
- }
- // Get flip flags
- FlipFlags flags;
- if (parseFlipFlags(properties->getString("flip"), &flags))
- {
- sprite->setFlip(flags);
- }
- // Get sprite offset
- Offset offset;
- if (parseOffset(properties->getString("offset"), &offset))
- {
- sprite->setOffset(offset);
- }
- return sprite;
- }
-
- float Sprite::getWidth() const
- {
- return _width;
- }
- float Sprite::getHeight() const
- {
- return _height;
- }
-
- void Sprite::setOffset(Sprite::Offset offset)
- {
- _offset = offset;
- }
- Sprite::Offset Sprite::getOffset() const
- {
- return _offset;
- }
-
- void Sprite::setAnchor(const Vector2& anchor)
- {
- _anchor = anchor;
- }
- const Vector2& Sprite::getAnchor() const
- {
- return _anchor;
- }
-
- void Sprite::setFlip(int flipFlags)
- {
- _flipFlags = flipFlags;
- }
- int Sprite::getFlip() const
- {
- return _flipFlags;
- }
- void Sprite::setFrameSource(unsigned int frameIndex, const Rectangle& source)
- {
- GP_ASSERT(frameIndex < _frameCount);
-
- _frames[frameIndex] = source;
- }
- const Rectangle& Sprite::getFrameSource(unsigned int frameIndex) const
- {
- GP_ASSERT(frameIndex < _frameCount);
-
- return _frames[frameIndex];
- }
- void Sprite::computeFrames(unsigned int frameStride, unsigned int framePadding)
- {
- _frameStride = frameStride;
- _framePadding = framePadding;
-
- if (_frameCount < 2)
- return;
- unsigned int imageWidth = _batch->getSampler()->getTexture()->getWidth();
- unsigned int imageHeight = _batch->getSampler()->getTexture()->getHeight();
- float textureWidthRatio = 1.0f / imageWidth;
- float textureHeightRatio = 1.0f / imageHeight;
-
- // If we have a stride then compute the wrap width
- float strideWidth;
- if (_frameStride > 0)
- strideWidth = _frameStride * _frames[0].width;
- else
- strideWidth = imageWidth;
-
- // Mark the start as reference
- float x = _frames[0].x;
- float y = _frames[0].y;
- float width = _frames[0].width;
- float height = _frames[0].height;
-
- // Compute frames 1+
- for (unsigned int frameIndex = 1; frameIndex < _frameCount; frameIndex++)
- {
- _frames[frameIndex].x = x;
- _frames[frameIndex].y = y;
- _frames[frameIndex].width = _width;
- _frames[frameIndex].height = _height;
-
- x += _frames[frameIndex].width + (float)_framePadding;
- if (x >= imageWidth)
- {
- y += _frames[frameIndex].height + (float)_framePadding;
- if (y >= imageHeight)
- {
- y = 0.0f;
- }
- x = 0.0f;
- }
- }
- }
- unsigned int Sprite::getFrameCount() const
- {
- return _frameCount;
- }
- unsigned int Sprite::getFramePadding() const
- {
- return _framePadding;
- }
- unsigned int Sprite::getFrameStride() const
- {
- return _frameStride;
- }
- void Sprite::setFrameIndex(unsigned int index)
- {
- _frameIndex = index;
- }
- unsigned int Sprite::getFrameIndex() const
- {
- return _frameIndex;
- }
- void Sprite::setOpacity(float opacity)
- {
- _opacity = opacity;
- }
- float Sprite::getOpacity() const
- {
- return _opacity;
- }
- void Sprite::setColor(const Vector4& color)
- {
- _color = color;
- }
- const Vector4& Sprite::getColor() const
- {
- return _color;
- }
-
- Sprite::BlendMode Sprite::getBlendMode() const
- {
- return _blendMode;
- }
-
- void Sprite::setBlendMode(BlendMode mode)
- {
- switch (mode)
- {
- case BLEND_NONE:
- _batch->getStateBlock()->setBlend(false);
- break;
- case BLEND_ALPHA:
- _batch->getStateBlock()->setBlend(true);
- _batch->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
- _batch->getStateBlock()->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
- break;
- case BLEND_ADDITIVE:
- _batch->getStateBlock()->setBlend(true);
- _batch->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
- _batch->getStateBlock()->setBlendDst(RenderState::BLEND_ONE);
- break;
- case BLEND_MULTIPLIED:
- _batch->getStateBlock()->setBlend(true);
- _batch->getStateBlock()->setBlendSrc(RenderState::BLEND_ZERO);
- _batch->getStateBlock()->setBlendDst(RenderState::BLEND_SRC_COLOR);
- break;
- default:
- GP_ERROR("Unsupported blend mode (%d).", mode);
- break;
- }
- }
- Texture::Sampler* Sprite::getSampler() const
- {
- return _batch->getSampler();
- }
- RenderState::StateBlock* Sprite::getStateBlock() const
- {
- return _batch->getStateBlock();
- }
- Material* Sprite::getMaterial() const
- {
- return _batch->getMaterial();
- }
- unsigned int Sprite::draw(bool wireframe)
- {
- // Apply scene camera projection and translation offsets
- Vector3 position = Vector3::zero();
- if (_node && _node->getScene())
- {
- Camera* activeCamera = _node->getScene()->getActiveCamera();
- if (activeCamera)
- {
- Node* cameraNode = _node->getScene()->getActiveCamera()->getNode();
- if (cameraNode)
- {
- // Scene projection
- Matrix projectionMatrix;
- projectionMatrix = _node->getProjectionMatrix();
- _batch->setProjectionMatrix(projectionMatrix);
-
- // Camera translation offsets
- position.x -= cameraNode->getTranslationWorld().x;
- position.y -= cameraNode->getTranslationWorld().y;
-
- }
- }
-
- // Apply node translation offsets
- Vector3 translation = _node->getTranslationWorld();
- position.x += translation.x;
- position.y += translation.y;
- position.z += translation.z;
- }
-
- // Apply local offset translation offsets
- if ((_offset & OFFSET_HCENTER) == OFFSET_HCENTER)
- position.x -= _width * 0.5;
- if ((_offset & OFFSET_RIGHT) == OFFSET_RIGHT)
- position.x -= _width;
- if ((_offset & OFFSET_VCENTER) == OFFSET_VCENTER)
- position.y -= _height * 0.5f;
- if ((_offset & OFFSET_TOP) == OFFSET_TOP)
- position.y -= _height;
- if ((_offset & OFFSET_ANCHOR) == OFFSET_ANCHOR)
- {
- position.x -= _width * _anchor.x;
- position.y -= _height * _anchor.y;
- }
-
- // Apply node scale and rotation
- float rotationAngle = 0.0f;
- Vector2 scale = Vector2(_width, _height);
- if (_node)
- {
- // Apply node rotation
- const Quaternion& rot = _node->getRotation();
- if (rot.x != 0.0f || rot.y != 0.0f || rot.z != 0.0f)
- rotationAngle = rot.toAxisAngle(NULL);
-
- // Apply node scale
- if (_node->getScaleX() != 1.0f)
- scale.x *= _node->getScaleX();
- if (_node->getScaleY() != 1.0f)
- scale.y *= _node->getScaleY();
- }
-
- // Apply flip flags
- if ((_flipFlags & FLIP_HORIZONTAL) == FLIP_HORIZONTAL)
- {
- position.x += scale.x;
- scale.x = -scale.x;
- }
- if ((_flipFlags & FLIP_VERTICAL) == FLIP_VERTICAL)
- {
- position.y += scale.y;
- scale.y = -scale.y;
- }
-
- // TODO: Proper batching from cache based on batching rules (image, layers, etc)
- _batch->start();
- _batch->draw(position, _frames[_frameIndex], scale, Vector4(_color.x, _color.y, _color.z, _color.w * _opacity),
- _anchor, rotationAngle);
- _batch->finish();
-
- return 1;
- }
-
- Drawable* Sprite::clone(NodeCloneContext& context)
- {
- Sprite* spriteClone = new Sprite();
- // Clone animations
- AnimationTarget::cloneInto(static_cast<AnimationTarget*>(spriteClone), context);
- // Get copied node if it exists
- if (Node* node = getNode())
- {
- Node* clonedNode = context.findClonedNode(node);
- if (clonedNode)
- {
- spriteClone->setNode(clonedNode);
- }
- }
- // Clone properties
- spriteClone->_width = _width;
- spriteClone->_height = _height;
- spriteClone->_offset = _offset;
- spriteClone->_anchor = _anchor;
- spriteClone->_flipFlags = _flipFlags;
- spriteClone->_opacity = _opacity;
- spriteClone->_color = _color;
- spriteClone->_blendMode = _blendMode;
- spriteClone->_frames = new Rectangle[_frameCount];
- memcpy(spriteClone->_frames, _frames, sizeof(Rectangle) * _frameCount);
- spriteClone->_frameCount = _frameCount;
- spriteClone->_frameStride = _frameStride;
- spriteClone->_framePadding = _framePadding;
- spriteClone->_frameIndex = _frameIndex;
- spriteClone->_batch = _batch;
- return spriteClone;
- }
- int Sprite::getPropertyId(TargetType type, const char* propertyIdStr)
- {
- GP_ASSERT(propertyIdStr);
- if (type == AnimationTarget::TRANSFORM)
- {
- if (strcmp(propertyIdStr, "ANIMATE_OPACITY") == 0)
- {
- return Sprite::ANIMATE_OPACITY;
- }
- else if (strcmp(propertyIdStr, "ANIMATE_COLOR") == 0)
- {
- return Sprite::ANIMATE_COLOR;
- }
- else if (strcmp(propertyIdStr, "ANIMATE_KEYFRAME") == 0)
- {
- return Sprite::ANIMATE_KEYFRAME;
- }
- }
- return AnimationTarget::getPropertyId(type, propertyIdStr);
- }
- unsigned int Sprite::getAnimationPropertyComponentCount(int propertyId) const
- {
- switch (propertyId)
- {
- case ANIMATE_OPACITY:
- return 1;
- case ANIMATE_COLOR:
- return 4;
- case ANIMATE_KEYFRAME:
- return 1;
- default:
- return -1;
- }
- }
- void Sprite::getAnimationPropertyValue(int propertyId, AnimationValue* value)
- {
- GP_ASSERT(value);
-
- switch (propertyId)
- {
- case ANIMATE_OPACITY:
- value->setFloat(0, _opacity);
- break;
- case ANIMATE_COLOR:
- value->setFloat(0, _color.x);
- value->setFloat(1, _color.y);
- value->setFloat(2, _color.z);
- value->setFloat(3, _color.w);
- break;
- case ANIMATE_KEYFRAME:
- value->setFloat(0, (float)_frameIndex);
- break;
- default:
- break;
- }
- }
- void Sprite::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
- {
- GP_ASSERT(value);
-
- switch(propertyId)
- {
- case ANIMATE_OPACITY:
- setOpacity(Curve::lerp(blendWeight, _opacity, value->getFloat(0)));
- break;
- case ANIMATE_COLOR:
- setColor(Vector4(Curve::lerp(blendWeight, _color.x, value->getFloat(0)),
- Curve::lerp(blendWeight, _color.x, value->getFloat(1)),
- Curve::lerp(blendWeight, _color.x, value->getFloat(2)),
- Curve::lerp(blendWeight, _color.x, value->getFloat(3))));
- break;
- case ANIMATE_KEYFRAME:
- _frameIndex = (unsigned int)value->getFloat(0);
- break;
- default:
- break;
- }
- }
- }
|