| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- #include "CmTextSprite.h"
- #include "CmVector2.h"
- #include "CmGUIMaterialManager.h"
- namespace CamelotEngine
- {
- Sprite::Sprite()
- {
- }
- Sprite::~Sprite()
- {
- clearMesh();
- }
- UINT32 Sprite::getNumRenderElements() const
- {
- return (UINT32)mCachedRenderElements.size();
- }
- const HMaterial& Sprite::getMaterial(UINT32 renderElementIdx) const
- {
- return mCachedRenderElements.at(renderElementIdx).material;
- }
- UINT32 Sprite::getNumQuads(UINT32 renderElementIdx) const
- {
- return mCachedRenderElements.at(renderElementIdx).numQuads;
- }
- UINT32 Sprite::fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const
- {
- auto renderElem = mCachedRenderElements.at(renderElementIdx);
- UINT32 startVert = startingQuad * 4;
- UINT32 startIndex = startingQuad * 4;
- UINT32 maxVertIdx = maxNumQuads * 4;
- UINT32 maxIndexIdx = maxNumQuads * 6;
- UINT32 mNumVertices = renderElem.numQuads * 4;
- UINT32 mNumIndices = renderElem.numQuads * 6;
- assert((startVert + mNumVertices) <= maxVertIdx);
- assert((startIndex + mNumIndices) <= maxIndexIdx);
- memcpy(&vertices[startVert], renderElem.vertices, mNumVertices * sizeof(Vector2));
- memcpy(&uv[startVert], renderElem.uvs, mNumVertices * sizeof(Vector2));
- memcpy(&indices[startIndex], renderElem.indexes, mNumIndices * sizeof(UINT32));
- return renderElem.numQuads;
- }
- Point Sprite::getAnchorOffset(SpriteAnchor anchor, UINT32 width, UINT32 height) const
- {
- switch(anchor)
- {
- case SA_TopLeft:
- return -Point(0, 0);
- case SA_TopCenter:
- return -Point(width / 2, 0);
- case SA_TopRight:
- return -Point(width, 0);
- case SA_MiddleLeft:
- return -Point(0, height / 2);
- case SA_MiddleCenter:
- return -Point(width / 2, height / 2);
- case SA_MiddleRight:
- return -Point(width, height / 2);
- case SA_BottomLeft:
- return -Point(0, height);
- case SA_BottomCenter:
- return -Point(width / 2, height);
- case SA_BottomRight:
- return -Point(width, height);
- }
- return Point();
- }
- void Sprite::updateBounds() const
- {
- Vector2 min;
- Vector2 max;
- // Find starting point
- for(auto& renderElem : mCachedRenderElements)
- {
- if(renderElem.vertices != nullptr && renderElem.numQuads > 0)
- {
- min = renderElem.vertices[0];
- max = renderElem.vertices[0];
- break;
- }
- }
- // Calculate bounds
- for(auto& renderElem : mCachedRenderElements)
- {
- if(renderElem.vertices != nullptr && renderElem.numQuads > 0)
- {
- UINT32 vertexCount = renderElem.numQuads * 4;
- for(UINT32 i = 0; i < vertexCount; i++)
- {
- min = Vector2::min(min, renderElem.vertices[i]);
- max = Vector2::max(max, renderElem.vertices[i]);
- }
- }
- }
- mBounds = Rect((int)min.x, (int)min.y, (int)(max.x - min.x), (int)(max.y - min.y));
- }
- void Sprite::clearMesh() const
- {
- for(auto& renderElem : mCachedRenderElements)
- {
- UINT32 vertexCount = renderElem.numQuads * 4;
- UINT32 indexCount = renderElem.numQuads * 6;
- if(renderElem.vertices != nullptr)
- CM_DELETE_ARRAY(renderElem.vertices, Vector2, vertexCount, ScratchAlloc);
- if(renderElem.uvs != nullptr)
- CM_DELETE_ARRAY(renderElem.uvs, Vector2, vertexCount, ScratchAlloc);
- if(renderElem.indexes != nullptr)
- CM_DELETE_ARRAY(renderElem.indexes, UINT32, indexCount, ScratchAlloc);
- if(renderElem.material != nullptr)
- {
- GUIMaterialManager::instance().releaseMaterial(renderElem.material);
- }
- }
- mCachedRenderElements.clear();
- updateBounds();
- }
- // This will only properly clip an array of rectangular quads
- // Vertices in the quad must be in a specific order: top left, top right, bottom left, bottom right
- // (0, 0) represents top left of the screen
- void Sprite::clipToRect(Vector2* vertices, Vector2* uv, UINT32 numQuads, const Rect& clipRect) const
- {
- float left = (float)clipRect.x;
- float right = (float)clipRect.x + clipRect.width;
- float top = (float)clipRect.y;
- float bottom = (float)clipRect.y - clipRect.height;
- for(UINT32 i = 0; i < numQuads; i++)
- {
- UINT32 vertIdx = i * 4;
- // Attempt to skip those that are definitely not clipped
- if(vertices[vertIdx + 0].x >= left && vertices[vertIdx + 1].x <= right &&
- vertices[vertIdx + 0].y <= top && vertices[vertIdx + 2].y >= bottom)
- {
- continue;
- }
- float du = (uv[vertIdx + 1].x - uv[vertIdx + 0].x) / (vertices[vertIdx + 1].x - vertices[vertIdx + 0].x);
- float dv = (uv[vertIdx + 0].y - uv[vertIdx + 2].y) / (vertices[vertIdx + 0].y - vertices[vertIdx + 2].y);
- // Clip left
- float newLeft = Math::Clamp(vertices[vertIdx + 0].x, left, right);
- float uvLeftOffset = (newLeft - vertices[vertIdx + 0].x) * du;
- vertices[vertIdx + 0].x = newLeft;
- vertices[vertIdx + 2].x = newLeft;
- uv[vertIdx + 0].x += uvLeftOffset;
- uv[vertIdx + 2].x += uvLeftOffset;
- // Clip right
- float newRight = Math::Clamp(vertices[vertIdx + 1].x, left, right);
- float uvRightOffset = (vertices[vertIdx + 1].x - newRight) * du;
- vertices[vertIdx + 1].x = newRight;
- vertices[vertIdx + 3].x = newRight;
- uv[vertIdx + 1].x -= uvRightOffset;
- uv[vertIdx + 3].x -= uvRightOffset;
- // Clip top
- float newTop = Math::Clamp(vertices[vertIdx + 0].y, bottom, top);
- float uvTopOffset = (vertices[vertIdx + 0].y - newTop) * dv;
- vertices[vertIdx + 0].y = newTop;
- vertices[vertIdx + 1].y = newTop;
- uv[vertIdx + 0].y -= uvTopOffset;
- uv[vertIdx + 1].y -= uvTopOffset;
- // Clip bottom
- float newBottom = Math::Clamp(vertices[vertIdx + 2].y, bottom, top);
- float uvBottomOffset = (newBottom - vertices[vertIdx + 2].y) * dv;
- vertices[vertIdx + 2].y = newBottom;
- vertices[vertIdx + 3].y = newBottom;
- uv[vertIdx + 2].y += uvBottomOffset;
- uv[vertIdx + 3].y += uvBottomOffset;
- }
- }
- }
|