Sprite2D.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. //
  2. // Copyright (c) 2008-2017 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Precompiled.h"
  23. #include "../Core/Context.h"
  24. #include "../Graphics/Texture2D.h"
  25. #include "../IO/Deserializer.h"
  26. #include "../Resource/ResourceCache.h"
  27. #include "../Atomic2D/Drawable2D.h"
  28. #include "../Atomic2D/Sprite2D.h"
  29. #include "../Atomic2D/SpriteSheet2D.h"
  30. #include "../DebugNew.h"
  31. namespace Atomic
  32. {
  33. Sprite2D::Sprite2D(Context* context) :
  34. Resource(context),
  35. hotSpot_(0.5f, 0.5f),
  36. offset_(0, 0),
  37. edgeOffset_(0.0f)
  38. {
  39. }
  40. Sprite2D::~Sprite2D()
  41. {
  42. }
  43. void Sprite2D::RegisterObject(Context* context)
  44. {
  45. context->RegisterFactory<Sprite2D>();
  46. }
  47. bool Sprite2D::BeginLoad(Deserializer& source)
  48. {
  49. if (GetName().Empty())
  50. SetName(source.GetName());
  51. // Reload
  52. if (texture_)
  53. loadTexture_ = texture_;
  54. else
  55. {
  56. loadTexture_ = new Texture2D(context_);
  57. loadTexture_->SetName(GetName());
  58. }
  59. // In case we're async loading, only call BeginLoad() for the texture (load image but do not upload to GPU)
  60. if (!loadTexture_->BeginLoad(source))
  61. {
  62. // Reload failed
  63. if (loadTexture_ == texture_)
  64. texture_.Reset();
  65. loadTexture_.Reset();
  66. return false;
  67. }
  68. return true;
  69. }
  70. bool Sprite2D::EndLoad()
  71. {
  72. // Finish loading of the texture in the main thread
  73. bool success = false;
  74. if (loadTexture_ && loadTexture_->EndLoad())
  75. {
  76. success = true;
  77. SetTexture(loadTexture_);
  78. if (texture_)
  79. SetRectangle(IntRect(0, 0, texture_->GetWidth(), texture_->GetHeight()));
  80. }
  81. else
  82. {
  83. // Reload failed
  84. if (loadTexture_ == texture_)
  85. texture_.Reset();
  86. }
  87. loadTexture_.Reset();
  88. return success;
  89. }
  90. void Sprite2D::SetTexture(Texture2D* texture)
  91. {
  92. texture_ = texture;
  93. // Ensure the texture doesn't have wrap addressing as that will cause bleeding bugs on the edges.
  94. // Could also choose border mode, but in that case a universally good border color (without alpha bugs)
  95. // would be hard to choose. Ideal is for the user to configure the texture parameters in its parameter
  96. // XML file.
  97. if (texture_->GetAddressMode(COORD_U) == ADDRESS_WRAP)
  98. {
  99. texture_->SetAddressMode(COORD_U, ADDRESS_CLAMP);
  100. texture_->SetAddressMode(COORD_V, ADDRESS_CLAMP);
  101. }
  102. }
  103. void Sprite2D::SetRectangle(const IntRect& rectangle)
  104. {
  105. rectangle_ = rectangle;
  106. }
  107. void Sprite2D::SetHotSpot(const Vector2& hotSpot)
  108. {
  109. hotSpot_ = hotSpot;
  110. }
  111. void Sprite2D::SetOffset(const IntVector2& offset)
  112. {
  113. offset_ = offset;
  114. }
  115. void Sprite2D::SetTextureEdgeOffset(float offset)
  116. {
  117. edgeOffset_ = offset;
  118. }
  119. void Sprite2D::SetSpriteSheet(SpriteSheet2D* spriteSheet)
  120. {
  121. spriteSheet_ = spriteSheet;
  122. }
  123. bool Sprite2D::GetDrawRectangle(Rect& rect, bool flipX, bool flipY) const
  124. {
  125. return GetDrawRectangle(rect, hotSpot_, flipX, flipY);
  126. }
  127. bool Sprite2D::GetDrawRectangle(Rect& rect, const Vector2& hotSpot, bool flipX, bool flipY) const
  128. {
  129. if (rectangle_.Width() == 0 || rectangle_.Height() == 0)
  130. return false;
  131. float width = (float)rectangle_.Width() * PIXEL_SIZE;
  132. float height = (float)rectangle_.Height() * PIXEL_SIZE;
  133. float hotSpotX = flipX ? (1.0f - hotSpot.x_) : hotSpot.x_;
  134. float hotSpotY = flipY ? (1.0f - hotSpot.y_) : hotSpot.y_;
  135. rect.min_.x_ = -width * hotSpotX;
  136. rect.max_.x_ = width * (1.0f - hotSpotX);
  137. rect.min_.y_ = -height * hotSpotY;
  138. rect.max_.y_ = height * (1.0f - hotSpotY);
  139. return true;
  140. }
  141. bool Sprite2D::GetTextureRectangle(Rect& rect, bool flipX, bool flipY) const
  142. {
  143. if (!texture_)
  144. return false;
  145. float invWidth = 1.0f / (float)texture_->GetWidth();
  146. float invHeight = 1.0f / (float)texture_->GetHeight();
  147. rect.min_.x_ = ((float)rectangle_.left_ + edgeOffset_) * invWidth;
  148. rect.max_.x_ = ((float)rectangle_.right_ - edgeOffset_) * invWidth;
  149. rect.min_.y_ = ((float)rectangle_.bottom_ - edgeOffset_) * invHeight;
  150. rect.max_.y_ = ((float)rectangle_.top_ + edgeOffset_) * invHeight;
  151. if (flipX)
  152. Swap(rect.min_.x_, rect.max_.x_);
  153. if (flipY)
  154. Swap(rect.min_.y_, rect.max_.y_);
  155. return true;
  156. }
  157. ResourceRef Sprite2D::SaveToResourceRef(Sprite2D* sprite)
  158. {
  159. SpriteSheet2D* spriteSheet = 0;
  160. if (sprite)
  161. spriteSheet = sprite->GetSpriteSheet();
  162. if (!spriteSheet)
  163. return GetResourceRef(sprite, Sprite2D::GetTypeStatic());
  164. // Combine sprite sheet name and sprite name as resource name.
  165. return ResourceRef(spriteSheet->GetType(), spriteSheet->GetName() + "@" + sprite->GetName());
  166. }
  167. Sprite2D* Sprite2D::LoadFromResourceRef(Object* object, const ResourceRef& value)
  168. {
  169. if (!object)
  170. return 0;
  171. ResourceCache* cache = object->GetSubsystem<ResourceCache>();
  172. if (value.type_ == Sprite2D::GetTypeStatic())
  173. return cache->GetResource<Sprite2D>(value.name_);
  174. if (value.type_ == SpriteSheet2D::GetTypeStatic())
  175. {
  176. // value.name_ include sprite sheet name and sprite name.
  177. Vector<String> names = value.name_.Split('@');
  178. if (names.Size() != 2)
  179. return 0;
  180. const String& spriteSheetName = names[0];
  181. const String& spriteName = names[1];
  182. SpriteSheet2D* spriteSheet = cache->GetResource<SpriteSheet2D>(spriteSheetName);
  183. if (!spriteSheet)
  184. return 0;
  185. return spriteSheet->GetSprite(spriteName);
  186. }
  187. return 0;
  188. }
  189. }