d9c0a7c2dc9e9702ba3fb6074caf5964538aafbf
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / vector-based / vector-blob-atlas.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/images/texture-set-image.h>
23 #include <dali/integration-api/debug.h>
24
25 namespace
26 {
27
28 #if defined(DEBUG_ENABLED)
29   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
30 #endif
31
32 }
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Text
41 {
42
43 static void
44 EncodeBlobCoordinate( unsigned int cornerX, unsigned int cornerY,
45                       unsigned int atlasX, unsigned int atlasY,
46                       unsigned int nominalWidth, unsigned int nominalHeight,
47                       BlobCoordinate* v )
48 {
49   DALI_ASSERT_DEBUG(0 == (atlasX & ~0x7F));
50   DALI_ASSERT_DEBUG(0 == (atlasY & ~0x7F));
51   DALI_ASSERT_DEBUG(0 == (cornerX & ~1));
52   DALI_ASSERT_DEBUG(0 == (cornerY & ~1));
53   DALI_ASSERT_DEBUG(0 == (nominalWidth & ~0x3F));
54   DALI_ASSERT_DEBUG(0 == (nominalHeight & ~0x3F));
55
56   unsigned int x = (((atlasX << 6) | nominalWidth) << 1)  | cornerX;
57   unsigned int y = (((atlasY << 6) | nominalHeight) << 1) | cornerY;
58
59   unsigned int encoded = (x << 16) | y;
60
61   v->u = encoded >> 16;
62   v->v = encoded & 0xFFFF;
63 }
64
65 VectorBlobAtlas::VectorBlobAtlas( unsigned int textureWidth,
66                                   unsigned int textureHeight,
67                                   unsigned int itemWidth,
68                                   unsigned int itemHeightQuantum )
69 : mTextureWidth( textureWidth ),
70   mTextureHeight( textureHeight ),
71   mItemWidth( itemWidth ),
72   mItemHeightQuantum( itemHeightQuantum ),
73   mCursorX( 0 ),
74   mCursorY( 0 ),
75   mIsFull( false )
76 {
77   DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p size %dx%d, item width %d, height quantum %d\n", this, textureWidth, textureHeight, itemWidth, itemHeightQuantum );
78
79   mAtlasTexture = BufferImage::New( textureWidth, textureHeight, Pixel::RGBA8888 );
80
81   mTextureSet = TextureSet::New();
82   TextureSetImage( mTextureSet, 0, mAtlasTexture );
83 }
84
85 bool VectorBlobAtlas::IsFull() const
86 {
87   return mIsFull;
88 }
89
90 bool VectorBlobAtlas::FindGlyph( FontId fontId,
91                                  GlyphIndex glyphIndex,
92                                  BlobCoordinate* coords )
93 {
94   const unsigned int size( mItemLookup.size() );
95
96   for( unsigned int i=0; i<size; ++i )
97   {
98     if( mItemLookup[i].fontId     == fontId &&
99         mItemLookup[i].glyphIndex == glyphIndex )
100     {
101       const Item& item = mItemCache[ mItemLookup[i].cacheIndex ];
102
103       coords[0] = item.coords[0];
104       coords[1] = item.coords[1];
105       coords[2] = item.coords[2];
106       coords[3] = item.coords[3];
107
108       return true;
109     }
110   }
111
112   return false;
113 }
114
115 bool VectorBlobAtlas::AddGlyph( unsigned int fontId,
116                                 unsigned int glyphIndex,
117                                 VectorBlob* blob,
118                                 unsigned int length,
119                                 unsigned int nominalWidth,
120                                 unsigned int nominalHeight,
121                                 BlobCoordinate* coords )
122 {
123   if( mIsFull )
124   {
125     return false;
126   }
127
128   unsigned int w, h, x, y;
129
130   w = mItemWidth;
131   h = (length + w - 1) / w;
132
133   if( mCursorY + h > mTextureHeight )
134   {
135     // Go to next column
136     mCursorX += mItemWidth;
137     mCursorY = 0;
138   }
139
140   if( mCursorX + w <= mTextureWidth && mCursorY + h <= mTextureHeight )
141   {
142     x = mCursorX;
143     y = mCursorY;
144     mCursorY += (h + mItemHeightQuantum - 1) & ~(mItemHeightQuantum - 1);
145   }
146   else
147   {
148     DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p is now FULL\n", this );
149
150     // The atlas is now considered to be full
151     mIsFull = true;
152     return false;
153   }
154
155   if (w * h == length)
156   {
157     TexSubImage( x, y, w, h, blob );
158   }
159   else
160   {
161     TexSubImage( x, y, w, h-1, blob );
162
163     // Upload the last row separately
164     TexSubImage( x, y + h - 1, length - (w * (h - 1)), 1 , blob + w * (h - 1));
165   }
166
167   DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p capacity %d filled %d %f\%\n",
168                  this,
169                  mTextureWidth*mTextureHeight,
170                  mCursorY*mItemWidth + mCursorX*mTextureHeight,
171                  100.0f * (float)(mCursorY*mItemWidth + mCursorX*mTextureHeight) / (float)(mTextureWidth*mTextureHeight) );
172
173   Key key;
174   key.fontId = fontId;
175   key.glyphIndex = glyphIndex;
176   key.cacheIndex = mItemCache.size();
177   mItemLookup.push_back( key );
178
179   x /= mItemWidth;
180   y /= mItemHeightQuantum;
181
182   Item item;
183   EncodeBlobCoordinate( 0, 0, x, y, nominalWidth, nominalHeight, &item.coords[0] ); // BOTTOM_LEFT
184   EncodeBlobCoordinate( 0, 1, x, y, nominalWidth, nominalHeight, &item.coords[1] ); // TOP_LEFT
185   EncodeBlobCoordinate( 1, 0, x, y, nominalWidth, nominalHeight, &item.coords[2] ); // BOTTOM_RIGHT
186   EncodeBlobCoordinate( 1, 1, x, y, nominalWidth, nominalHeight, &item.coords[3] ); // TOP_RIGHT
187   mItemCache.push_back( item );
188
189   coords[0] = item.coords[0];
190   coords[1] = item.coords[1];
191   coords[2] = item.coords[2];
192   coords[3] = item.coords[3];
193
194   return true;
195 }
196
197 void VectorBlobAtlas::TexSubImage( unsigned int offsetX,
198                                    unsigned int offsetY,
199                                    unsigned int width,
200                                    unsigned int height,
201                                    VectorBlob* blob )
202 {
203   PixelBuffer* pixbuf = mAtlasTexture.GetBuffer();
204   size_t pos;
205   size_t dataIndex = 0;
206   for( size_t y= offsetY; y< height + offsetY; y++ )
207   {
208     pos = y * mTextureWidth * 4;
209     for( size_t x = offsetX; x < width + offsetX; x++ )
210     {
211       pixbuf[pos+x*4] =  0xFF & blob[dataIndex].r;
212       pixbuf[pos+x*4+1] = 0xFF & blob[dataIndex].g;
213       pixbuf[pos+x*4+2] = 0xFF & blob[dataIndex].b;
214       pixbuf[pos+x*4+3] = 0xFF & blob[dataIndex].a;
215       dataIndex++;
216     }
217   }
218
219   mAtlasTexture.Update();
220 }
221
222 } // namespace Text
223
224 } // namespace Toolkit
225
226 } // namespace Dali