bgfx/examples/common/cube_atlas.h

170 lines
5.7 KiB
C
Raw Normal View History

2013-05-15 09:07:04 -04:00
/*
* Copyright 2013 Jeremie Roy. All rights reserved.
2013-04-22 16:42:11 -04:00
* License: http://www.opensource.org/licenses/BSD-2-Clause
2013-05-15 09:07:04 -04:00
*/
#ifndef CUBE_ATLAS_H_HEADER_GUARD
#define CUBE_ATLAS_H_HEADER_GUARD
2013-04-22 16:42:11 -04:00
/// Inspired from texture-atlas from freetype-gl (http://code.google.com/p/freetype-gl/)
/// by Nicolas Rougier (Nicolas.Rougier@inria.fr)
/// The actual implementation is based on the article by Jukka Jylänki : "A
/// Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional
/// Rectangle Bin Packing", February 27, 2010.
/// More precisely, this is an implementation of the Skyline Bottom-Left
/// algorithm based on C++ sources provided by Jukka Jylänki at:
/// http://clb.demon.fi/files/RectangleBinPack/
2013-05-15 09:21:23 -04:00
#include <bgfx.h>
2013-04-22 16:42:11 -04:00
struct AtlasRegion
{
enum Type
{
TYPE_GRAY = 1, // 1 component
TYPE_BGRA8 = 4 // 4 components
2013-05-15 09:21:23 -04:00
};
2013-04-22 16:42:11 -04:00
uint16_t x, y;
uint16_t width, height;
uint32_t mask; //encode the region type, the face index and the component index in case of a gray region
2013-04-23 14:36:07 -04:00
2013-05-15 09:21:23 -04:00
Type getType() const
{
return (Type) ( (mask >> 0) & 0x0000000F);
2013-05-15 09:21:23 -04:00
}
2013-05-30 02:12:05 -04:00
2013-05-15 09:21:23 -04:00
uint32_t getFaceIndex() const
{
return (mask >> 4) & 0x0000000F;
2013-05-15 09:21:23 -04:00
}
2013-05-30 02:12:05 -04:00
2013-05-15 09:21:23 -04:00
uint32_t getComponentIndex() const
{
return (mask >> 8) & 0x0000000F;
2013-05-15 09:21:23 -04:00
}
2013-05-30 02:12:05 -04:00
2013-05-15 09:21:23 -04:00
void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex)
{
mask = (_componentIndex << 8) + (_faceIndex << 4) + (uint32_t)_type;
2013-05-15 09:21:23 -04:00
}
2013-04-22 16:42:11 -04:00
};
class Atlas
{
public:
2013-05-15 22:42:39 -04:00
/// create an empty dynamic atlas (region can be updated and added)
/// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA))
/// @param maxRegionCount maximum number of region allowed in the atlas
Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount = 4096);
/// initialize a static atlas with serialized data (region can be updated but not added)
/// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA))
/// @param textureBuffer buffer of size 6*textureSize*textureSize*sizeof(uint32_t) (will be copied)
/// @param regionCount number of region in the Atlas
/// @param regionBuffer buffer containing the region (will be copied)
/// @param maxRegionCount maximum number of region allowed in the atlas
Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount = 4096);
~Atlas();
/// add a region to the atlas, and copy the content of mem to the underlying texture
uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8, uint16_t outline = 0);
/// update a preallocated region
void updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer);
/// Pack the UV coordinates of the four corners of a region to a vertex buffer using the supplied vertex format.
/// v0 -- v3
/// | | encoded in that order: v0,v1,v2,v3
/// v1 -- v2
/// @remark the UV are four signed short normalized components.
/// @remark the x,y,z components encode cube uv coordinates. The w component encode the color channel if any.
/// @param handle handle to the region we are interested in
/// @param vertexBuffer address of the first vertex we want to update. Must be valid up to vertexBuffer + offset + 3*stride + 4*sizeof(int16_t), which means the buffer must contains at least 4 vertex includind the first.
/// @param offset byte offset to the first uv coordinate of the vertex in the buffer
/// @param stride stride between tho UV coordinates, usually size of a Vertex.
2013-05-30 01:47:19 -04:00
void packUV(uint16_t _regionHandle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) const;
void packUV(const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) const;
2013-05-15 22:42:39 -04:00
/// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas
2013-05-30 01:47:19 -04:00
void packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) const;
2013-05-15 22:42:39 -04:00
/// Pack the vertex index of the region as 2 quad into an index buffer
2013-05-30 02:12:05 -04:00
static void packIndex(uint16_t* _indexBuffer, uint32_t _startIndex, uint32_t _startVertex)
2013-05-15 22:42:39 -04:00
{
2013-05-30 02:12:05 -04:00
uint16_t* indices = &_indexBuffer[_startIndex];
*indices++ = _startVertex + 0;
*indices++ = _startVertex + 1;
*indices++ = _startVertex + 2;
*indices++ = _startVertex + 0;
*indices++ = _startVertex + 2;
*indices++ = _startVertex + 3;
2013-05-15 22:42:39 -04:00
}
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
/// return the TextureHandle (cube) of the atlas
bgfx::TextureHandle getTextureHandle() const
{
return m_textureHandle;
}
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
//retrieve a region info
const AtlasRegion& getRegion(uint16_t _handle) const
{
return m_regions[_handle];
}
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
/// retrieve the size of side of a texture in pixels
2013-05-30 00:53:19 -04:00
uint16_t getTextureSize() const
2013-05-15 22:42:39 -04:00
{
return m_textureSize;
}
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
/// retrieve the usage ratio of the atlas
//float getUsageRatio() const { return 0.0f; }
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
/// retrieve the numbers of region in the atlas
uint16_t getRegionCount() const
{
return m_regionCount;
}
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
/// retrieve a pointer to the region buffer (in order to serialize it)
const AtlasRegion* getRegionBuffer() const
{
return m_regions;
}
2013-05-15 09:21:23 -04:00
2013-05-15 22:42:39 -04:00
/// retrieve the byte size of the texture
uint32_t getTextureBufferSize() const
{
return 6 * m_textureSize * m_textureSize * 4;
}
/// retrieve the mirrored texture buffer (to serialize it)
const uint8_t* getTextureBuffer() const
{
return m_textureBuffer;
}
2013-04-22 16:42:11 -04:00
private:
2013-06-04 02:58:18 -04:00
void init();
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
struct PackedLayer;
PackedLayer* m_layers;
2013-05-30 02:12:05 -04:00
AtlasRegion* m_regions;
uint8_t* m_textureBuffer;
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
uint32_t m_usedLayers;
uint32_t m_usedFaces;
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
bgfx::TextureHandle m_textureHandle;
uint16_t m_textureSize;
2013-06-04 02:16:02 -04:00
float m_texelSize;
float m_texelOffset[2];
2013-04-22 16:42:11 -04:00
2013-05-15 22:42:39 -04:00
uint16_t m_regionCount;
uint16_t m_maxRegionCount;
2013-05-15 09:01:38 -04:00
};
2013-05-15 22:42:39 -04:00
#endif // CUBE_ATLAS_H_HEADER_GUARD