summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/examples/common/cube_atlas.h
blob: c35b0a1ef2f4ad26dab7bd92bb8008f0aba53959 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * Copyright 2013 Jeremie Roy. All rights reserved.
 * License: http://www.opensource.org/licenses/BSD-2-Clause
 */

#ifndef CUBE_ATLAS_H_HEADER_GUARD
#define CUBE_ATLAS_H_HEADER_GUARD

/// 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/

#include <bgfx.h>

struct AtlasRegion
{
	enum Type
	{
		TYPE_GRAY = 1, // 1 component
		TYPE_BGRA8 = 4  // 4 components
	};

	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

	Type getType() const
	{
		return (Type) ( (mask >> 0) & 0x0000000F);
	}

	uint32_t getFaceIndex() const
	{
		return (mask >> 4) & 0x0000000F;
	}

	uint32_t getComponentIndex() const
	{
		return (mask >> 8) & 0x0000000F;
	}

	void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex)
	{
		mask = (_componentIndex << 8) + (_faceIndex << 4) + (uint32_t)_type;
	}
};

class Atlas
{
public:
	/// 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.
	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;

	/// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas
	void packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) const;

	/// return the TextureHandle (cube) of the atlas
	bgfx::TextureHandle getTextureHandle() const
	{
		return m_textureHandle;
	}

	//retrieve a region info
	const AtlasRegion& getRegion(uint16_t _handle) const
	{
		return m_regions[_handle];
	}

	/// retrieve the size of side of a texture in pixels
	uint16_t getTextureSize() const
	{
		return m_textureSize;
	}

	/// retrieve the usage ratio of the atlas
	//float getUsageRatio() const { return 0.0f; }

	/// retrieve the numbers of region in the atlas
	uint16_t getRegionCount() const
	{
		return m_regionCount;
	}

	/// retrieve a pointer to the region buffer (in order to serialize it)
	const AtlasRegion* getRegionBuffer() const
	{
		return m_regions;
	}

	/// 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;
	}

private:
	void init();

	struct PackedLayer;
	PackedLayer* m_layers;
	AtlasRegion* m_regions;
	uint8_t* m_textureBuffer;

	uint32_t m_usedLayers;
	uint32_t m_usedFaces;

	bgfx::TextureHandle m_textureHandle;
	uint16_t m_textureSize;
	float m_texelSize;
	float m_texelOffset[2];

	uint16_t m_regionCount;
	uint16_t m_maxRegionCount;
};

#endif // CUBE_ATLAS_H_HEADER_GUARD