move around - flatter.
[profile/ivi/evas.git] / src / modules / engines / gl_common / evas_gl_font.c
1 #include "evas_gl_private.h"
2
3 static Evas_GL_Font_Texture_Pool_Allocation *_evas_gl_font_texture_pool_request(Evas_GL_Context *gc, int w, int h);
4 static void                                  _evas_gl_font_texture_pool_relinquish(Evas_GL_Font_Texture_Pool_Allocation *fa);
5 static int                                   _evas_gl_font_texture_pool_rect_find(Evas_GL_Font_Texture_Pool *fp, int w, int h, int *x, int *y);
6
7 Evas_GL_Font_Texture *
8 evas_gl_font_texture_new(Evas_GL_Context *gc, RGBA_Font_Glyph *fg)
9 {
10    Evas_GL_Font_Texture *ft;
11    DATA8 *data;
12    int w, h, j;
13
14    int nw;
15    DATA8 *ndata;
16
17    if (fg->ext_dat) return fg->ext_dat;
18    
19    w = fg->glyph_out->bitmap.width;
20    h = fg->glyph_out->bitmap.rows;
21    
22    if ((w == 0) || (h == 0)) return NULL;
23    ft = calloc(1, sizeof(Evas_GL_Font_Texture));
24    if (!ft) return NULL;
25
26    data = fg->glyph_out->bitmap.buffer;
27    j = fg->glyph_out->bitmap.pitch;
28    if (j < w) j = w;
29
30    ft->gc = gc;
31
32    /* bug bug! glTexSubImage2D need a multiple of 4 pixels horizontally! :( */
33    nw = ((w + 3) / 4 ) * 4;
34    ndata = malloc(nw *h);
35    if (!ndata)
36      {
37         free(ft);
38         return NULL;
39      }
40    if (fg->glyph_out->bitmap.num_grays == 256)
41      {
42         int x, y;
43         DATA8 *p1, *p2;
44
45         for (y = 0; y < h; y++)
46           {
47              p1 = data + (j * y);
48              p2 = ndata + (nw * y);
49              for (x = 0; x < w; x++)
50                {
51                   *p2 = *p1;
52                   p1++;
53                   p2++;
54                }
55           }
56      }
57    else if (fg->glyph_out->bitmap.num_grays == 0)
58      {
59         DATA8 *tmpbuf = NULL, *dp, *tp, bits;
60         int bi, bj, end;
61         const DATA8 bitrepl[2] = {0x0, 0xff};
62         
63         tmpbuf = malloc(w);
64         if (tmpbuf)
65           {
66              int x, y;
67              DATA8 *p1, *p2;
68              
69              for (y = 0; y < h; y++)
70                {
71                   p1 = tmpbuf;
72                   p2 = ndata + (nw * y);
73                   tp = tmpbuf;
74                   dp = data + (y * fg->glyph_out->bitmap.pitch);
75                   for (bi = 0; bi < w; bi += 8)
76                     {
77                        bits = *dp;
78                        if ((w - bi) < 8) end = w - bi;
79                        else end = 8;
80                        for (bj = 0; bj < end; bj++)
81                          {
82                             *tp = bitrepl[(bits >> (7 - bj)) & 0x1];
83                             tp++;
84                          }
85                        dp++;
86                     }
87                   for (x = 0; x < w; x++)
88                     {
89                        *p2 = *p1;
90                        p1++;
91                        p2++;
92                     }
93                }
94              free(tmpbuf);
95           }
96      }
97    
98    /* where in pool texture does this live */
99    ft->w = w;
100    ft->h = h;
101    ft->aw = nw;
102    ft->ah = h;
103
104    ft->alloc = _evas_gl_font_texture_pool_request(gc, ft->aw, ft->ah);
105    if (!ft->alloc)
106      {
107         free(ndata);
108         free(ft);
109         return NULL;
110      }
111    ft->x = ft->alloc->x;
112    ft->y = ft->alloc->y;
113    ft->pool = ft->alloc->pool;
114    ft->texture =  ft->pool->texture;
115    if (ft->pool->rectangle)
116      {
117         glEnable(GL_TEXTURE_RECTANGLE_NV);
118         glBindTexture(GL_TEXTURE_RECTANGLE_NV, ft->texture);
119         glTexSubImage2D(GL_TEXTURE_RECTANGLE_NV, 0,
120                         ft->x, ft->y, nw, ft->h,
121                         GL_ALPHA, GL_UNSIGNED_BYTE, ndata);
122      }
123    else
124      {
125         glBindTexture(GL_TEXTURE_2D, ft->texture);
126         glTexSubImage2D(GL_TEXTURE_2D, 0,
127                         ft->x, ft->y, nw, ft->h,
128                         GL_ALPHA, GL_UNSIGNED_BYTE, ndata);
129      }
130    if (ndata) free(ndata);
131    if (gc->texture)
132      {
133         if (gc->texture) gc->texture->references--;
134         gc->texture = NULL;
135      }
136    gc->font_texture = ft->texture;
137    gc->font_texture_rectangle = ft->pool->rectangle;
138    gc->change.texture = 1;
139    if (ft->pool->rectangle)
140      {
141         ft->tx1 = ft->x;
142         ft->ty1 = ft->y;
143         ft->tx2 = ft->x + ft->w;
144         ft->ty2 = ft->y + ft->h;
145      }
146    else
147      {
148         ft->tx1 = (double)(ft->x        ) / (double)(ft->pool->w);
149         ft->ty1 = (double)(ft->y        ) / (double)(ft->pool->h);
150         ft->tx2 = (double)(ft->x + ft->w) / (double)(ft->pool->w);
151         ft->ty2 = (double)(ft->y + ft->h) / (double)(ft->pool->h);
152      }
153
154    return ft;
155 }
156
157 void
158 evas_gl_font_texture_free(Evas_GL_Font_Texture *ft)
159 {
160    if (!ft) return;
161    if (ft->gc->font_texture == ft->texture)
162      {
163         ft->gc->font_texture = 0;
164         ft->gc->change.texture = 1;
165      }
166    _evas_gl_font_texture_pool_relinquish(ft->alloc);
167    free(ft);
168 }
169
170 void
171 evas_gl_font_texture_draw(Evas_GL_Context *gc, void *surface, RGBA_Draw_Context *dc, RGBA_Font_Glyph *fg, int x, int y)
172 {
173    Evas_GL_Font_Texture *ft;
174
175    if (dc != gc->dc)
176         return;
177
178    /* 35 */
179    ft = fg->ext_dat;
180    if (!ft) return;
181 //   if (surface == 0)
182      {
183         int r, g, b, a;
184
185         a = (dc->col.col >> 24) & 0xff;
186         if (a == 0) return;
187         r = (dc->col.col >> 16) & 0xff;
188         g = (dc->col.col >> 8 ) & 0xff;
189         b = (dc->col.col      ) & 0xff;
190         /* have to un-premul the color - as we are using blend mode 2 (non-premul blend) */
191         r = (r * 255) / a;
192         g = (g * 255) / a;
193         b = (b * 255) / a;
194         evas_gl_common_context_color_set(gc, r, g, b, a);
195         if (dc->clip.use)
196           evas_gl_common_context_clip_set(gc, 1,
197                                           dc->clip.x, dc->clip.y,
198                                           dc->clip.w, dc->clip.h);
199         else
200           evas_gl_common_context_clip_set(gc, 0,
201                                           0, 0, 0, 0);
202         evas_gl_common_context_blend_set(gc, 2);
203         evas_gl_common_context_read_buf_set(gc, GL_BACK);
204         evas_gl_common_context_write_buf_set(gc, GL_BACK);
205      }
206    /* 32 */
207    evas_gl_common_context_font_texture_set(gc, ft);
208    /* 32 */
209    glBegin(GL_QUADS);
210    glTexCoord2d(ft->tx1, ft->ty1); glVertex2i(x        , y        );
211    glTexCoord2d(ft->tx2, ft->ty1); glVertex2i(x + ft->w, y        );
212    glTexCoord2d(ft->tx2, ft->ty2); glVertex2i(x + ft->w, y + ft->h);
213    glTexCoord2d(ft->tx1, ft->ty2); glVertex2i(x        , y + ft->h);
214    glEnd();
215    /* 28 */
216 }
217
218 static Evas_GL_Font_Texture_Pool_Allocation *
219 _evas_gl_font_texture_pool_request(Evas_GL_Context *gc, int w, int h)
220 {
221    Evas_List *l;
222    Evas_GL_Font_Texture_Pool_Allocation *fa;
223    Evas_GL_Font_Texture_Pool *fp;
224    int minw = 256;
225    int minh = 256;
226    int shift;
227
228    for (l = gc->tex_pool; l; l = l->next)
229      {
230         int x, y;
231
232         fp = l->data;
233         if (_evas_gl_font_texture_pool_rect_find(fp, w, h, &x, &y))
234           {
235              fa = calloc(1, sizeof(Evas_GL_Font_Texture_Pool_Allocation));
236              if (!fa) return NULL;
237              fa->pool = fp;
238              fa->x = x;
239              fa->y = y;
240              fa->w = w;
241              fa->h = h;
242              fp->allocations = evas_list_prepend(fp->allocations, fa);
243              if (evas_list_alloc_error())
244                {
245                   free(fa);
246                   return NULL;
247                }
248              fp->references++;
249              return fa;
250           }
251      }
252    /* need new font texture pool entry */
253    /* minimum size either minw x minh OR the size of glyph up to power 2 */
254    if (w > minw)
255      {
256         minw = w;
257         shift = 1; while (minw > shift) shift = shift << 1; minw = shift;
258      }
259    if (h > minh)
260      {
261         minh = h;
262         shift = 1; while (minh > shift) shift = shift << 1; minh = shift;
263      }
264
265    fp = calloc(1, sizeof(Evas_GL_Font_Texture_Pool));
266    if (!fp) return NULL;
267    gc->tex_pool = evas_list_append(gc->tex_pool, fp);
268    if (evas_list_alloc_error())
269      {
270         free(fp);
271         return NULL;
272      }
273    fp->gc = gc;
274    fp->w = minw;
275    fp->h = minh;
276    if (gc->ext.nv_texture_rectangle) fp->rectangle = 1;
277
278    /* we dont want this mipmapped if sgis_generate_mipmap will mipmap it */
279    if (gc->ext.sgis_generate_mipmap)
280      glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
281 //   glEnable(GL_TEXTURE_2D);
282    if (fp->rectangle)
283      {
284         glEnable(GL_TEXTURE_RECTANGLE_NV);
285         glGenTextures(1, &(fp->texture));
286         /* FIXME check gl error */
287
288         glBindTexture(GL_TEXTURE_RECTANGLE_NV, fp->texture);
289         glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_REPEAT);
290         glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_REPEAT);
291         glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
292         glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
293         glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0,
294                      GL_ALPHA4, fp->w, fp->h, 0,
295                      GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
296         /* FIXME check gl error */
297      }
298    else
299      {
300         glEnable(GL_TEXTURE_2D);
301         glGenTextures(1, &(fp->texture));
302         /* FIXME check gl error */
303
304         glBindTexture(GL_TEXTURE_2D, fp->texture);
305         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
306         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
307         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
308         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
309         glTexImage2D(GL_TEXTURE_2D, 0,
310                      GL_ALPHA4, fp->w, fp->h, 0,
311                      GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
312         /* FIXME check gl error */
313      }
314
315    /* new allocation entirely */
316    fa = calloc(1, sizeof(Evas_GL_Font_Texture_Pool_Allocation));
317    if (!fa)
318      {
319         gc->tex_pool = evas_list_remove(gc->tex_pool, fp);
320         glDeleteTextures(1, &(fp->texture));
321         free(fp);
322         return NULL;
323      }
324    fa->pool = fp;
325    fa->x = 0;
326    fa->y = 0;
327    fa->w = w;
328    fa->h = h;
329    fp->allocations = evas_list_prepend(fp->allocations, fa);
330    if (evas_list_alloc_error())
331      {
332         printf("alloc prob\n");
333         gc->tex_pool = evas_list_remove(gc->tex_pool, fp);
334         glDeleteTextures(1, &(fp->texture));
335         free(fa);
336         free(fp);
337         return NULL;
338      }
339    fp->references++;
340    return fa;
341 }
342
343 static void
344 _evas_gl_font_texture_pool_relinquish(Evas_GL_Font_Texture_Pool_Allocation *fa)
345 {
346    fa->pool->allocations = evas_list_remove(fa->pool->allocations, fa);
347    fa->pool->references--;
348    if (fa->pool->references <= 0)
349      {
350         fa->pool->gc->tex_pool =
351           evas_list_remove(fa->pool->gc->tex_pool, fa->pool);
352         glDeleteTextures(1, &(fa->pool->texture));
353         free(fa->pool);
354      }
355    free(fa);
356 }
357
358 static int
359 _evas_gl_font_texture_pool_rect_find(Evas_GL_Font_Texture_Pool *fp,
360                                      int w, int h,
361                                      int *x, int *y)
362 {
363    Evas_List *l;
364
365    if ((w > fp->w) || (h > fp->h)) return 0;
366    for (l = fp->allocations; l; l = l->next)
367      {
368         Evas_GL_Font_Texture_Pool_Allocation *fa;
369         Evas_List *l2;
370         int tx, ty, tw, th;
371         int t1, t2;
372         int intersects;
373
374         fa = l->data;
375         t1 = t2 = 1;
376         if ((fa->x + fa->w + w) > fp->w) t1 = 0;
377         if ((fa->y + h) > fp->h) t1 = 0;
378         if ((fa->y + fa->h + h) > fp->h) t2 = 0;
379         if ((fa->x + w) > fp->w) t2 = 0;
380         intersects = 0;
381         if (t1)
382           {
383              /* 1. try here:
384               * +----++--+
385               * |AAAA||??|
386               * |AAAA|+--+
387               * |AAAA|
388               * +----+
389               */
390              tx = fa->x + fa->w;
391              ty = fa->y;
392              tw = w;
393              th = h;
394              for (l2 = fp->allocations; l2; l2 = l2->next)
395                {
396                   Evas_GL_Font_Texture_Pool_Allocation *fa2;
397                   int rx, ry, rw, rh;
398
399                   /* dont do the rect we are just using as our offset */
400                   if (l2 == l) continue;
401                   fa2 = l2->data;
402                   rx = fa2->x;
403                   ry = fa2->y;
404                   rw = fa2->w;
405                   rh = fa2->h;
406                   if (RECTS_INTERSECT(tx, ty, tw, th, rx, ry, rw, rh))
407                     {
408                        intersects = 1;
409                        break;
410                     }
411                }
412              if (!intersects)
413                {
414                   *x = tx;
415                   *y = ty;
416                   return 1;
417                }
418           }
419         intersects = 0;
420         if (t2)
421           {
422              /* 2. try here:
423               * +----+
424               * |AAAA|
425               * |AAAA|
426               * |AAAA|
427               * +----+
428               * +--+
429               * |??|
430               * +--+
431               */
432              tx = fa->x;
433              ty = fa->y + fa->h;
434              tw = w;
435              th = h;
436              for (l2 = fp->allocations; l2; l2 = l2->next)
437                {
438                   Evas_GL_Font_Texture_Pool_Allocation *fa2;
439                   int rx, ry, rw, rh;
440
441                   /* dont do the rect we are just using as our offset */
442                   if (l2 == l) continue;
443                   /* hmmm crash here on mga... l2->data seems broken */
444                   /* so far it looks like memory corruption, but i can't */
445                   /* use valgrind to inspect any further due to the dri */
446                   /* hardware stuff :( */
447                   fa2 = l2->data;
448
449                   rx = fa2->x;
450                   ry = fa2->y;
451                   rw = fa2->w;
452                   rh = fa2->h;
453                   if (RECTS_INTERSECT(tx, ty, tw, th, rx, ry, rw, rh))
454                     {
455                        intersects = 1;
456                        break;
457                     }
458                }
459              if (!intersects)
460                {
461                   *x = tx;
462                   *y = ty;
463                   return 1;
464                }
465           }
466      }
467    return 0;
468 }