efl/legacy/evas/src/evas_gl_routines.c

3076 lines
77 KiB
C

#include "evas_gl_routines.h"
#include "evas_fileless_image.h"
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <assert.h>
/* uncomment this is partial buffer swaps slow - problem with glcopypixels? */
#define GLSWB 1
/* uncomment if your GL implimentation is CRAP at clipping */
/* #define GLNOCLIP 1 */
/* uncomment this if your gl doesn thandle rendering all the update rects */
/* well - i knwo nvidias performance blows if u render mroe than 1 rect */
#define GLBOUNDING 1
#define INTERSECTS(x, y, w, h, xx, yy, ww, hh) \
((x < (xx + ww)) && \
(y < (yy + hh)) && \
((x + w) > xx) && \
((y + h) > yy))
#define CLIP_TO(_x, _y, _w, _h, _cx, _cy, _cw, _ch) \
{ \
if (INTERSECTS(_x, _y, _w, _h, _cx, _cy, _cw, _ch)) \
{ \
if (_x < _cx) \
{ \
_w += _x - _cx; \
_x = _cx; \
if (_w < 0) _w = 0; \
} \
if ((_x + _w) > (_cx + _cw)) \
_w = _cx + _cw - _x; \
if (_y < _cy) \
{ \
_h += _y - _cy; \
_y = _cy; \
if (_h < 0) _h = 0; \
} \
if ((_y + _h) > (_cy + _ch)) \
_h = _cy + _ch - _y; \
} \
else \
{ \
_w = 0; _h = 0; \
} \
}
#define TT_VALID( handle ) ( ( handle ).z != NULL )
#ifdef HAVE_GL
static int __evas_gl_configuration[] =
{
GLX_DOUBLEBUFFER,
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
None
};
static Evas_GL_Window *__evas_current = NULL;
static Evas_List __evas_windows = NULL;
static Evas_List __evas_contexts = NULL;
static Evas_List __evas_images = NULL;
static Evas_List __evas_fonts = NULL;
static int __evas_image_cache = 0;
static int __evas_image_cache_max = 512 * 1024;
static char **__evas_fpath = NULL;
static int __evas_fpath_num = 0;
static int __evas_font_cache = 0;
static int __evas_font_cache_max = 512 * 1024;
static int __evas_rend_lut[9] = { 0, 64, 128, 192, 255, 255, 255, 255, 255};
static int __evas_have_tt_engine = 0;
static TT_Engine __evas_tt_engine;
/* smooth (linear interp / supersample/mipmap scaling or "nearest" sampling */
static int __evas_smooth = 1;
/* the current clip region and color */
static int __evas_clip = 0;
static int __evas_clip_x = 0;
static int __evas_clip_y = 0;
static int __evas_clip_w = 0;
static int __evas_clip_h = 0;
static int __evas_clip_r = 0;
static int __evas_clip_g = 0;
static int __evas_clip_b = 0;
static int __evas_clip_a = 0;
static Evas_GL_Context *
__evas_gl_context_new(Display *disp, int screen)
{
Evas_GL_Context *c;
XSetWindowAttributes att;
int eb, evb;
if (!glXQueryExtension(disp, &eb, &evb)) return NULL;
c = malloc(sizeof(Evas_GL_Context));
c->disp = disp;
c->screen = screen;
c->visualinfo = glXChooseVisual(c->disp, c->screen, __evas_gl_configuration);
c->visual = c->visualinfo->visual;
c->context = glXCreateContext(c->disp, c->visualinfo, NULL, GL_TRUE);
c->root = RootWindow(c->disp, c->screen);
c->colormap = XCreateColormap(c->disp, c->root, c->visual, 0);
att.colormap = c->colormap;
att.border_pixel = 0;
att.event_mask = 0;
c->win = XCreateWindow(c->disp, c->root, 0, 0, 1, 1, 0,
c->visualinfo->depth, InputOutput,
c->visual, CWColormap | CWBorderPixel | CWEventMask,
&att);
glXMakeCurrent(c->disp, c->win, c->context);
glShadeModel(GL_FLAT);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
c->texture = 0;
glDisable(GL_TEXTURE_2D);
c->dither = 0;
glDisable(GL_DITHER);
c->blend = 1;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
c->color = 0xffffffff;
glColor4f(1.0, 1.0, 1.0, 1.0);
c->clip.active = 0;
c->clip.x = 0;
c->clip.y = 0;
c->clip.w = 0;
c->clip.h = 0;
glDisable(GL_SCISSOR_TEST);
c->read_buf = GL_BACK;
glReadBuffer(GL_BACK);
c->write_buf = GL_FRONT;
glDrawBuffer(GL_BACK);
c->bound_texture = NULL;
/* FIXME: need to determine these */
c->max_texture_depth = 32;
c->max_texture_size = 256;
return c;
}
static Evas_GL_Context *
__evas_gl_context_lookup(Display *disp, int screen)
{
Evas_List l;
Evas_GL_Context *c;
for (l = __evas_contexts; l; l = l->next)
{
c = l->data;
if ((c->disp == disp) && (c->screen == screen))
{
if (l != __evas_contexts)
{
__evas_contexts = evas_list_remove(__evas_contexts, c);
__evas_contexts = evas_list_prepend(__evas_contexts, c);
}
return c;
}
}
c = __evas_gl_context_new(disp, screen);
if (!c) return NULL;
__evas_contexts = evas_list_prepend(__evas_contexts, c);
return c;
}
static Evas_GL_Window *
__evas_gl_window_new(Display *disp, Window win)
{
Evas_GL_Context *c;
Evas_GL_Window *w;
Window root;
int screen, i;
XWindowAttributes att;
XGetWindowAttributes(disp, win, &att);
root = att.root;
screen = 0;
for (i = 0; i < ScreenCount(disp); i++)
{
if (RootWindow(disp, i) == root)
{
screen = i;
break;
}
}
c = __evas_gl_context_lookup(disp, screen);
if (!c) return NULL;
w = malloc(sizeof(Evas_GL_Window));
w->disp = disp;
w->win = win;
w->context = c;
w->root = root;
w->screen = screen;
w->updates = NULL;
w->w = 0;
w->h = 0;
return w;
}
static Evas_GL_Window *
__evas_gl_window_lookup(Display *disp, Window win)
{
Evas_List l;
Evas_GL_Window *w;
for (l = __evas_windows; l; l = l->next)
{
w = l->data;
if ((w->win == win) && (w->disp == disp))
{
if (l != __evas_windows)
{
__evas_windows = evas_list_remove(__evas_windows, w);
__evas_windows = evas_list_prepend(__evas_windows, w);
}
return w;
}
}
w = __evas_gl_window_new(disp, win);
if (!w) return NULL;
__evas_windows = evas_list_prepend(__evas_windows, w);
return w;
}
static Evas_GL_Window *
__evas_gl_window_current(Display *disp, Window win, int w, int h)
{
Evas_GL_Window *glw;
glw = __evas_gl_window_lookup(disp, win);
if (!glw) return NULL;
if (glw != __evas_current)
{
__evas_current = glw;
glXMakeCurrent(glw->disp, glw->win, glw->context->context);
glShadeModel(GL_FLAT);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
if (glw->context->dither) glEnable(GL_DITHER);
else glDisable(GL_DITHER);
if (glw->context->blend)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else glDisable(GL_BLEND);
if (glw->context->texture) glEnable(GL_TEXTURE_2D);
else glDisable(GL_TEXTURE_2D);
glColor4d((double)((glw->context->color >> 24) & 0xff) / 255.0,
(double)((glw->context->color >> 16) & 0xff) / 255.0,
(double)((glw->context->color >> 8) & 0xff) / 255.0,
(double)((glw->context->color ) & 0xff) / 255.0);
if (glw->context->clip.active)
{
glEnable(GL_SCISSOR_TEST);
glScissor(glw->context->clip.x,
glw->h - glw->context->clip.y - glw->context->clip.h,
glw->context->clip.w,
glw->context->clip.h);
}
else
glDisable(GL_SCISSOR_TEST);
if (glw->context->bound_texture)
glBindTexture(GL_TEXTURE_2D, glw->context->bound_texture->texture);
}
if ((glw->w != w) || (glw->h != h))
{
double dr, dg, db, da;
glw->w = w;
glw->h = h;
glViewport(0, 0, glw->w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, glw->w, 0, glw->h, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1, -1, 1);
glTranslatef(0, - glw->h, 0);
}
return glw;
}
static void
__evas_gl_window_dither(Evas_GL_Window *w, int onoff)
{
if (!w) return;
if (w->context->dither == onoff) return;
w->context->dither = onoff;
if (w->context->dither) glEnable(GL_DITHER);
else glDisable(GL_DITHER);
}
static void
__evas_gl_window_blend(Evas_GL_Window *w, int onoff)
{
if (!w) return;
if (w->context->blend == onoff) return;
w->context->blend = onoff;
if (w->context->blend)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else glDisable(GL_BLEND);
}
static void
__evas_gl_window_texture(Evas_GL_Window *w, int onoff)
{
if (!w) return;
if (w->context->texture == onoff) return;
w->context->texture = onoff;
if (w->context->texture) glEnable(GL_TEXTURE_2D);
else glDisable(GL_TEXTURE_2D);
}
static void
__evas_gl_window_color(Evas_GL_Window *w, int r, int g, int b, int a)
{
DATA32 col;
if (!w) return;
col = (r << 24) | (g << 16) | (b << 8) | (a);
if (w->context->color == col) return;
w->context->color = col;
glColor4d((double)r / 255.0,
(double)g / 255.0,
(double)b / 255.0,
(double)a / 255.0);
}
static void
__evas_gl_window_clip(Evas_GL_Window *w, int c, int cx, int cy, int cw, int ch)
{
if (!w) return;
if (w->context->clip.active == c)
{
if ((c) &&
(w->context->clip.x == cx) && (w->context->clip.y == cy) &&
(w->context->clip.w == cw) && (w->context->clip.h == ch))
return;
}
w->context->clip.active = c;
w->context->clip.x = cx;
w->context->clip.y = cy;
w->context->clip.w = cw;
w->context->clip.h = ch;
if (w->context->clip.active)
{
glEnable(GL_SCISSOR_TEST);
glScissor(w->context->clip.x,
w->h - w->context->clip.y - w->context->clip.h,
w->context->clip.w,
w->context->clip.h);
}
else
glDisable(GL_SCISSOR_TEST);
}
static void
__evas_gl_window_write_buf(Evas_GL_Window *w, GLenum buf)
{
if (!w) return;
if (w->context->write_buf != buf)
{
w->context->write_buf = buf;
glDrawBuffer(buf);
}
}
static void
__evas_gl_window_read_buf(Evas_GL_Window *w, GLenum buf)
{
if (!w) return;
if (w->context->read_buf != buf)
{
w->context->read_buf = buf;
glReadBuffer(buf);
}
}
static void
__evas_gl_window_swap_rect(Evas_GL_Window *w, int rx, int ry, int rw, int rh)
{
if (!w) return;
__evas_gl_window_read_buf(w, GL_BACK);
__evas_gl_window_write_buf(w, GL_FRONT);
__evas_gl_window_blend(w, 0);
__evas_gl_window_clip(w, 0, 0, 0, 0, 0);
__evas_gl_window_dither(w, 0);
ry = w->h - ry - rh;
glRasterPos2i(rx, w->h - ry);
glCopyPixels(rx, ry, rw, rh, GL_COLOR);
}
static void
__evas_gl_window_use_texture(Evas_GL_Window *w, Evas_GL_Texture *tex, int smooth)
{
if (!w) return;
if (w->context->bound_texture != tex)
{
glBindTexture(GL_TEXTURE_2D, tex->texture);
w->context->bound_texture = tex;
}
if (smooth != tex->smooth)
{
#ifdef HAVE_GLU
if (smooth)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
#else
if (smooth)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
else
#endif
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
tex->smooth = smooth;
}
}
static Evas_GL_Texture *
__evas_gl_texture_new(Evas_GL_Window *w, Imlib_Image im, int ix, int iy, int iw, int ih)
{
Evas_GL_Texture *tex;
int tx, ty, tw, th, im_w, im_h;
DATA32 *data, *p1, *p2, *im_data;
int shift;
Imlib_Image prev_im;
if (!w) return NULL;
tex = malloc(sizeof(Evas_GL_Texture));
shift = 1; while (iw > shift) shift = shift << 1; tw = shift;
shift = 1; while (ih > shift) shift = shift << 1; th = shift;
tex->w = tw;
tex->h = th;
glGenTextures(1, &(tex->texture));
glBindTexture(GL_TEXTURE_2D, tex->texture);
w->context->bound_texture = tex;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
tex->smooth = 0;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
prev_im = imlib_context_get_image();
imlib_context_set_image(im);
im_data = imlib_image_get_data_for_reading_only();
if (!im_data) return tex;
data = malloc(tw * th * 4);
im_w = imlib_image_get_width();
im_h = imlib_image_get_height();
for (ty = 0; ty < ih; ty++)
{
p1 = im_data + ((iy + ty) * im_w) + ix;
p2 = data + (ty * tw);
for (tx = 0; tx < iw; tx++)
{
#ifndef WORDS_BIGENDIAN
*p2 =
((*p1 & 0xff000000)) |
((*p1 & 0x00ff0000) >> 16) |
((*p1 & 0x0000ff00)) |
((*p1 & 0x000000ff) << 16);
#else
*p2 =
((*p1 & 0xff000000) >> 24) |
((*p1 & 0x00ff0000) << 8) |
((*p1 & 0x0000ff00) << 8) |
((*p1 & 0x000000ff) << 8);
#endif
p2++; p1++;
}
if (tx < tw)
{
for (; tx < tw; tx++) *p2 = p2[-1];
}
}
if (ty < th)
{
for (; ty < th; ty++)
{
p1 = data + ((ty - 1) * tw);
p2 = data + (ty * tw);
for (tx = 0; tx < tw; tx++)
{
*p2 = *p1; p2++; p1++;
}
}
}
#ifdef HAVE_GLU
/* FIXME: GLU mipmap generation is BLOODY SLOW */
if (0) /* if libGLU is fucking slow piece of shit - do it ourselves */
{
if (imlib_image_has_alpha())
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA8, tw, th, GL_RGBA,
GL_UNSIGNED_BYTE, data);
else
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, tw, th, GL_RGBA,
GL_UNSIGNED_BYTE, data);
}
#else
if (0)
{
if (imlib_image_has_alpha())
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tw, th, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, tw, th, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data);
}
#endif
else
{
int mw, mh;
int level;
Imlib_Image im1 = NULL, im2 = NULL;
int alpha = 0;
mw = tw;
mh = th;
level = 0;
alpha = imlib_image_has_alpha();
im1 = imlib_create_image_using_data(tw, th, data);
imlib_context_set_image(im1);
imlib_image_set_has_alpha(1);
for (;;)
{
int pw, ph;
DATA32 *idat;
imlib_context_set_image(im1);
idat = imlib_image_get_data_for_reading_only();
if (alpha)
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mw, mh, 0,
GL_RGBA, GL_UNSIGNED_BYTE, idat);
else
glTexImage2D(GL_TEXTURE_2D, level, GL_RGB8, mw, mh, 0,
GL_RGBA, GL_UNSIGNED_BYTE, idat);
imlib_image_put_back_data(idat);
if ((mw == 1) && (mh == 1)) break;
level++;
pw = mw; ph = mh;
mw >>= 1; if (mw < 1) mw = 1;
mh >>= 1; if (mh < 1) mh = 1;
im2 = imlib_create_cropped_scaled_image(0, 0, pw, ph, mw, mh);
imlib_free_image();
im1 = im2; im2 = NULL;
imlib_context_set_image(im1);
imlib_image_set_has_alpha(1);
}
if (im1)
{
imlib_context_set_image(im1);
imlib_free_image();
im1 = NULL;
}
}
free(data);
imlib_context_set_image(im);
imlib_image_put_back_data(im_data);
imlib_context_set_image(prev_im);
return tex;
}
static void
__evas_gl_texture_free(Evas_GL_Window *w, Evas_GL_Texture *tex)
{
if (!w) return;
glDeleteTextures(1, &tex->texture);
if (w->context->bound_texture == tex) w->context->bound_texture = NULL;
free(tex);
}
static Evas_GL_Texmesh *
__evas_gl_make_image_textures(Evas_GL_Window *w, Evas_GL_Image *image)
{
Evas_List l;
Evas_GL_Texmesh *tm;
int tx, ty, ex, ey, tw, th, ix, iy, iw, ih;
int i, shift;
Imlib_Image prev_im;
for (l = image->textures; l; l = l->next)
{
tm = l->data;
if (tm->context == w->context) return tm;
}
tm = malloc(sizeof(Evas_GL_Texmesh));
tm->window = w;
tm->context = w->context;
image->textures = evas_list_prepend(image->textures, tm);
if ((!image->im) && (image->file))
image->im = _evas_find_fileless_image(image->file);
if ((!image->im) && (image->file))
{
image->im = imlib_load_image(image->file);
imlib_context_set_image(image->im);
imlib_image_set_changes_on_disk();
}
tx = (image->w - 2) / (w->context->max_texture_size - 2);
ex = (image->w - 1) - (tx * (w->context->max_texture_size - 2));
if (tx == 0) ex = image->w;
tm->tiles.x_left = ex;
shift = 1; while (ex > shift) shift = shift << 1; ex = shift;
ty = (image->h - 2) / (w->context->max_texture_size - 2);
ey = (image->h - 1) - (ty * (w->context->max_texture_size - 2));
if (ty == 0) ey = image->h;
tm->tiles.y_left = ey;
shift = 1; while (ey > shift) shift = shift << 1; ey = shift;
tm->tiles.x = tx;
tm->tiles.y = ty;
tm->tiles.x_edge = ex;
tm->tiles.y_edge = ey;
tm->textures = malloc(sizeof(Evas_GL_Texmesh *) * (tm->tiles.x + 1) * (tm->tiles.y + 1));
i = 0;
for (ty = 0; ty <= tm->tiles.y; ty++)
{
/* figure out image y,h */
/* texture is only an edge size */
if ((ty == 0) && (tm->tiles.y == 0))
{
iy = 0;
ih = image->h;
}
/* start edge */
else if (ty == 0)
{
iy = 0;
ih = w->context->max_texture_size;
}
/* end edge */
else if (ty == tm->tiles.y)
{
iy = (w->context->max_texture_size - 1) - 1 +
((ty - 1) * (w->context->max_texture_size - 2));
ih = image->h - iy;
}
/* middle tex */
else
{
iy = (w->context->max_texture_size - 1) - 1 +
((ty - 1) * (w->context->max_texture_size - 2));
ih = w->context->max_texture_size;
}
for (tx = 0; tx <= tm->tiles.x; tx++)
{
/* figure out image x,w */
/* texture is only an edge size */
if ((tx == 0) && (tm->tiles.x == 0))
{
ix = 0;
iw = image->w;
}
/* start edge */
else if (tx == 0)
{
ix = 0;
iw = w->context->max_texture_size;
}
/* end edge */
else if (tx == tm->tiles.x)
{
ix = (w->context->max_texture_size - 1) - 1 +
((tx - 1) * (w->context->max_texture_size - 2));
iw = image->w - ix;
}
/* middle tex */
else
{
ix = (w->context->max_texture_size - 1) - 1 +
((tx - 1) * (w->context->max_texture_size - 2));
iw = w->context->max_texture_size;
}
if (image->im)
tm->textures[i] = __evas_gl_texture_new(w, image->im,
ix, iy, iw, ih);
i++;
}
}
if ((image->file) && (image->im))
{
prev_im = imlib_context_get_image();
imlib_context_set_image(image->im);
imlib_free_image_and_decache();
image->im = NULL;
imlib_context_set_image(prev_im);
}
return tm;
}
static void
__evas_gl_free_image_textures(Evas_GL_Image *image)
{
Evas_List l;
if (image->textures)
{
for (l = image->textures; l; l = l->next)
{
Evas_GL_Texmesh *tm;
Evas_GL_Window *w;
int i;
tm = l->data;
w = __evas_gl_window_current(tm->window->disp, tm->window->win,
tm->window->w, tm->window->h);
for (i = 0; i < (tm->tiles.x + 1) * (tm->tiles.y + 1); i++)
__evas_gl_texture_free(w, tm->textures[i]);
free(tm->textures);
tm->tiles.x = 0;
tm->tiles.y = 0;
tm->tiles.x_edge = 0;
tm->tiles.y_edge = 0;
free(tm);
}
evas_list_free(image->textures);
}
image->textures = NULL;
}
static Evas_GL_Image *
__evas_gl_image_alloc(char *file)
{
Evas_GL_Image *image;
Imlib_Image im, prev_im;
im = _evas_find_fileless_image(file);
if (!im)
im = imlib_load_image(file);
if (!im) return NULL;
imlib_context_set_image(im);
imlib_image_set_changes_on_disk();
image = malloc(sizeof(Evas_GL_Image));
image->file = malloc(strlen(file) + 1);
strcpy(image->file, file);
image->im = im;
prev_im = imlib_context_get_image();
imlib_context_set_image(im);
image->w = imlib_image_get_width();
image->h = imlib_image_get_height();
image->has_alpha = imlib_image_has_alpha();
image->border.l = 0;
image->border.r = 0;
image->border.t = 0;
image->border.b = 0;
image->references = 1;
image->textures = NULL;
imlib_context_set_image(prev_im);
return image;
}
static void
__evas_gl_image_dealloc(Evas_GL_Image *image)
{
Imlib_Image prev_im;
if (image->file) free(image->file);
if (image->im)
{
prev_im = imlib_context_get_image();
imlib_context_set_image(image->im);
imlib_free_image();
imlib_context_set_image(prev_im);
}
if (image->textures)
__evas_gl_free_image_textures(image);
free(image);
}
static void
__evas_gl_image_cache_flush(void)
{
while (__evas_image_cache > __evas_image_cache_max)
{
Evas_GL_Image *im, *im_last;
Evas_List l;
im_last = NULL;
for (l = __evas_images; l; l = l->next)
{
im = l->data;
if (im->references == 0) im_last = im;
}
if (im_last)
{
__evas_image_cache -= im_last->w * im_last->h * 4;
__evas_images = evas_list_remove(__evas_images, im_last);
__evas_gl_image_dealloc(im_last);
}
}
}
static Evas_GL_Graident_Texture *
__evas_gl_gradient_texture_new(Evas_GL_Window *w, Evas_GL_Graident *gr)
{
Evas_List l;
Evas_GL_Graident_Texture *tg;
for (l = gr->textures; l; l = l->next)
{
tg = l->data;
if (tg->context == w->context) return tg;
}
tg = malloc(sizeof(Evas_GL_Graident_Texture));
tg->window = w;
tg->context = w->context;
tg->texture = NULL;
gr->textures = evas_list_prepend(gr->textures, tg);
return tg;
}
static void
__evas_gl_gradient_texture_free(Evas_GL_Graident_Texture *tg)
{
if (tg->texture)
__evas_gl_texture_free(tg->window, tg->texture);
free(tg);
}
static Evas_GL_Texture *
__evas_gl_texture_alpha_new(Evas_GL_Window *w)
{
Evas_GL_Texture *tex;
DATA8 *data;
if (!w) return NULL;
tex = malloc(sizeof(Evas_GL_Texture));
tex->w = w->context->max_texture_size;
tex->h = w->context->max_texture_size;
glGenTextures(1, &(tex->texture));
glBindTexture(GL_TEXTURE_2D, tex->texture);
w->context->bound_texture = tex;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
tex->smooth = 0;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
data = malloc(w->context->max_texture_size * w->context->max_texture_size);
memset(data, 0, w->context->max_texture_size * w->context->max_texture_size);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA4,
w->context->max_texture_size, w->context->max_texture_size, 0,
GL_ALPHA, GL_UNSIGNED_BYTE, data);
free(data);
return tex;
}
static void
__evas_gl_texture_paste_data(Evas_GL_Window *w, Evas_GL_Texture *tex, int x, int y, DATA8 *data, int iw, int ih)
{
__evas_gl_window_use_texture(w, tex, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, iw, ih,
GL_ALPHA, GL_UNSIGNED_BYTE, data);
}
static Evas_GL_Glyph *
__evas_gl_text_font_get_glyph(Evas_GL_Font *fn, int glyph)
{
Evas_GL_Glyph *g;
Evas_List l;
int hash;
int code;
hash = glyph & 0xff;
for (l = fn->glyphs[hash]; l; l = l->next)
{
g = l->data;
if (g->glyph_id == glyph)
{
if (l != fn->glyphs[hash])
{
fn->glyphs[hash] = evas_list_remove(fn->glyphs[hash], g);
fn->glyphs[hash] = evas_list_prepend(fn->glyphs[hash], g);
}
return g;
}
}
g = malloc(sizeof(Evas_GL_Glyph));
g->glyph_id = glyph;
TT_New_Glyph(fn->face, &(g->glyph));
code = TT_Char_Index(fn->char_map, glyph);
TT_Load_Glyph(fn->instance, g->glyph, code, TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
TT_Get_Glyph_Metrics(g->glyph, &(g->metrics));
g->texture = NULL;
g->textures = NULL;
g->tex.x1 = 0.0;
g->tex.x2 = 0.0;
g->tex.y1 = 0.0;
g->tex.y2 = 0.0;
fn->glyphs[hash] = evas_list_prepend(fn->glyphs[hash], g);
return g;
}
static TT_Raster_Map *
__evas_gl_text_font_raster_new(int width, int height)
{
TT_Raster_Map *rmap;
rmap = malloc(sizeof(TT_Raster_Map));
if (!rmap) return NULL;
rmap->width = (width + 3) & -4;
rmap->rows = height;
rmap->flow = TT_Flow_Up;
rmap->cols = rmap->width;
rmap->size = rmap->rows * rmap->width;
if (rmap->size <= 0)
{
free(rmap);
return NULL;
}
rmap->bitmap = malloc(rmap->size);
if (!rmap->bitmap)
{
free(rmap);
return NULL;
}
memset(rmap->bitmap, 0, rmap->size);
return rmap;
}
static void
__evas_gl_text_font_raster_free(TT_Raster_Map * rmap)
{
if (rmap->bitmap) free(rmap->bitmap);
free(rmap);
}
static void
__evas_gl_text_font_render_glyph(Evas_GL_Window *glw, Evas_GL_Font *fn, Evas_GL_Glyph *g)
{
Evas_List l;
Evas_GL_Font_Texture *ft;
Evas_GL_Glyph_Texture *gt;
Evas_GL_Texture *tex;
int tx, ty, tw, th, xmin, ymin, xmax, ymax;
TT_Raster_Map *rmap;
if ((g->texture) && (g->texture->context == glw->context)) return;
for (l = g->textures; l; l = l->next)
{
gt = l->data;
if (gt->context == glw->context)
{
g->texture = gt;
g->tex.x1 = gt->tex.x1;
g->tex.x2 = gt->tex.x2;
g->tex.y1 = gt->tex.y1;
g->tex.y2 = gt->tex.y2;
return;
}
}
xmin = g->metrics.bbox.xMin & -64;
ymin = g->metrics.bbox.yMin & -64;
xmax = (g->metrics.bbox.xMax + 63) & -64;
ymax = (g->metrics.bbox.yMax + 63) & -64;
tw = ((xmax - xmin) / 64) + 1;
th = ((ymax - ymin) / 64) + 1;
/* could never fit glyph into max texture size tile */
if ((tw > glw->context->max_texture_size) ||
(th > glw->context->max_texture_size))
{
g->texture = NULL;
return;
}
/* find a new texture with space */
ft = NULL;
tex = NULL;
tx = 0;
ty = 0;
for (l = fn->textures; l; l = l->next)
{
ft = l->data;
if (ft->context == glw->context)
{
tex = ft->texture;
if ((tex->h - ft->cursor.y) >= th)
{
if ((tex->w - ft->cursor.x) >= tw)
{
if (ft->cursor.row_h < th) ft->cursor.row_h = th;
tx = ft->cursor.x;
ty = ft->cursor.y;
ft->cursor.x += tw;
goto done;
}
else
{
ty = ft->cursor.y + ft->cursor.row_h;
if ((tex->h - ty) >= th)
{
ft->cursor.y += ft->cursor.row_h;
ft->cursor.row_h = th;
ft->cursor.x = tw;
tx = 0;
ty = ft->cursor.y;
goto done;
}
}
}
}
ft = NULL;
}
done:
if (!ft)
{
/* make a new texture with space */
tex = __evas_gl_texture_alpha_new(glw);
ft = malloc(sizeof(Evas_GL_Font_Texture));
ft->cursor.x = tw;
ft->cursor.y = 0;
ft->cursor.row_h = th;
ft->window = glw;
ft->context = glw->context;
ft->texture = tex;
fn->textures = evas_list_prepend(fn->textures, ft);
tx = 0;
ty = 0;
}
/* paste glyph in free spot in texture */
gt = malloc(sizeof(Evas_GL_Glyph_Texture));
rmap = __evas_gl_text_font_raster_new(tw, th);
if (rmap)
{
int x, y;
DATA8 *data;
TT_Get_Glyph_Pixmap(g->glyph, rmap, -xmin, -ymin);
data = malloc(tw * th * sizeof(DATA8));
for (y = 0; y < th; y++)
{
for (x = 0; x < tw; x++)
{
int rval;
rval = (int)(((unsigned char *)(rmap->bitmap))[((rmap->rows - y - 1) * rmap->cols) + x]);
data[(y * tw) + x] = __evas_rend_lut[rval];
}
}
__evas_gl_texture_paste_data(glw, tex, tx, ty, data, tw, th);
free(data);
__evas_gl_text_font_raster_free(rmap);
}
gt->texture = tex;
gt->window = glw;
gt->context = glw->context;
gt->tex.x1 = (double)tx / (double)glw->context->max_texture_size;
gt->tex.x2 = (double)(tx + tw) / (double)glw->context->max_texture_size;
gt->tex.y1 = (double)ty / (double)glw->context->max_texture_size;
gt->tex.y2 = (double)(ty + th) / (double)glw->context->max_texture_size;
g->textures = evas_list_prepend(g->textures, gt);
g->texture = gt;
g->tex.x1 = gt->tex.x1;
g->tex.x2 = gt->tex.x2;
g->tex.y1 = gt->tex.y1;
g->tex.y2 = gt->tex.y2;
}
static int
__evas_gl_is_file(char *file)
{
struct stat st;
if (stat(file, &st) < 0)
return 0;
return 1;
}
static char *
__evas_gl_font_find(char *font)
{
char buf[4096];
char *ext[] = {".ttf", ".TTF", ""};
int i, j;
for (i = 0; i < 3; i++)
{
sprintf(buf, "%s%s", font, ext[i]);
if (__evas_gl_is_file(buf))
{
char *f;
f = malloc(strlen(buf) + 1);
strcpy(f, buf);
return f;
}
}
for (j = 0; j < __evas_fpath_num; j++)
{
for (i = 0; i < 3; i++)
{
sprintf(buf, "%s/%s%s", __evas_fpath[j], font, ext[i]);
if (__evas_gl_is_file(buf))
{
char *f;
f = malloc(strlen(buf) + 1);
strcpy(f, buf);
return f;
}
}
}
return NULL;
}
static Evas_GL_Font *
__evas_gl_font_load(char *font, int size)
{
Evas_GL_Font *fn;
char *file;
TT_Error error;
int i, num_cmap, upm;
const int dpi = 96;
file = __evas_gl_font_find(font);
if (!file) return NULL;
if (!__evas_have_tt_engine)
{
error = TT_Init_FreeType(&__evas_tt_engine);
if (error) return NULL;
__evas_have_tt_engine = 1;
}
fn = malloc(sizeof(Evas_GL_Font));
fn->font = malloc(strlen(font) + 1);
strcpy(fn->font, font);
fn->size = size;
fn->engine = __evas_tt_engine;
error = TT_Open_Face(fn->engine, file, &fn->face);
if (error)
{
free(fn->font);
free(fn);
free(file);
return NULL;
}
free(file);
error = TT_Get_Face_Properties(fn->face, &fn->properties);
if (error)
{
TT_Close_Face(fn->face);
free(fn->font);
free(fn);
return NULL;
}
error = TT_New_Instance(fn->face, &fn->instance);
if (error)
{
TT_Close_Face(fn->face);
free(fn->font);
free(fn);
return NULL;
}
TT_Set_Instance_Resolutions(fn->instance, dpi, dpi);
TT_Set_Instance_CharSize(fn->instance, size * 64);
TT_Get_Instance_Metrics(fn->instance, &fn->metrics);
upm = fn->properties.header->Units_Per_EM;
fn->ascent = (fn->properties.horizontal->Ascender * fn->metrics.y_ppem) / upm;
fn->descent = (fn->properties.horizontal->Descender * fn->metrics.y_ppem) / upm;
if (fn->descent < 0) fn->descent = -fn->descent;
num_cmap = fn->properties.num_CharMaps;
for (i = 0; i < num_cmap; i++)
{
unsigned short platform, encoding;
TT_Get_CharMap_ID(fn->face, i, &platform, &encoding);
if ((platform == 3 && encoding == 1) ||
(platform == 0 && encoding == 0))
{
TT_Get_CharMap(fn->face, i, &fn->char_map);
break;
}
}
if (i == num_cmap)
TT_Get_CharMap(fn->face, 0, &fn->char_map);
fn->max_descent = 0;
fn->max_ascent = 0;
memset(fn->glyphs, 0, sizeof(Evas_List) * 256);
fn->textures = NULL;
fn->references = 1;
/* go thru the first 256 glyps to calculate max ascent/descent */
{
Evas_GL_Glyph *g;
for (i = 0; i < 256; i++)
{
g = __evas_gl_text_font_get_glyph(fn, i);
if (!g) continue;
if (!TT_VALID(g->glyph)) continue;
if ((g->metrics.bbox.yMin & -64) < fn->max_descent)
fn->max_descent = (g->metrics.bbox.yMin & -64);
if (((g->metrics.bbox.yMax + 63) & -64) > fn->max_ascent)
fn->max_ascent = ((g->metrics.bbox.yMax + 63) & -64);
}
}
if (((fn->ascent == 0) && (fn->descent == 0)) || (fn->ascent == 0))
{
fn->ascent = fn->max_ascent / 64;
fn->descent = -fn->max_descent / 64;
}
TT_Flush_Face(fn->face);
return fn;
}
static void
__evas_gl_text_font_cache_flush(void)
{
Evas_List l;
Evas_GL_Font *fn_last;
Evas_GL_Font *fn;
while (__evas_font_cache > __evas_font_cache_max)
{
fn_last = NULL;
for (l = __evas_fonts; l; l = l->next)
{
fn = l->data;
if (fn->references == 0) fn_last = fn;
}
if (fn_last)
{
int i;
for (l = fn_last->textures; l; l = l->next)
{
Evas_GL_Font_Texture *ft;
ft = l->data;
__evas_font_cache -= ft->texture->w * ft->texture->h;
}
TT_Done_Instance(fn_last->instance);
TT_Close_Face(fn_last->face);
if (fn_last->font) free(fn_last->font);
for (i = 0; i < 256; i++)
{
if (fn_last->glyphs[i])
{
for (l = fn_last->glyphs[i]; l; l = l->next)
{
Evas_GL_Glyph *g;
Evas_List ll;
g = l->data;
if (g->textures)
{
for (ll = g->textures; ll; ll = ll->next)
{
Evas_GL_Glyph_Texture *gt;
gt = ll->data;
free(gt);
}
evas_list_free(g->textures);
}
free(g);
}
evas_list_free(fn_last->glyphs[i]);
}
}
if (fn_last->textures)
{
for (l = fn_last->textures; l; l = l->next)
{
Evas_GL_Font_Texture *ft;
ft = l->data;
__evas_gl_texture_free(ft->window, ft->texture);
free(ft);
}
evas_list_free(fn_last->textures);
}
__evas_fonts = evas_list_remove(__evas_fonts, fn_last);
free(fn_last);
}
}
}
void
__evas_gl_image_intern_draw(Evas_GL_Image *im,
Evas_GL_Window *glw,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h,
int allow_smooth)
{
Evas_List l;
Evas_GL_Texmesh *tm;
double scx, scy;
double x0, y0, w0, h0;
int go;
if (src_w < 1) src_w = 1;
if (src_h < 1) src_h = 1;
if (dst_w < 1) return;
if (dst_h < 1) return;
tm = __evas_gl_make_image_textures(glw, im);
scx = (double)dst_w / (double)src_w;
scy = (double)dst_h / (double)src_h;
x0 = (double)dst_x - ((double)src_x * scx);
y0 = (double)dst_y - ((double)src_y * scy);
w0 = (double)im->w * scx;
h0 = (double)im->h * scy;
#ifndef GLNOCLIP
for (l = glw->updates; l; l = l->next)
{
Evas_GL_Rect *rect;
go = 1;
rect = l->data;
{
int rx, ry, rw, rh;
rx = dst_x;
ry = dst_y;
rw = dst_w;
rh = dst_h;
CLIP_TO(rx, ry, rw, rh, rect->x, rect->y, rect->w, rect->h);
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
}
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
#else
go = 1;
{
int rx, ry, rw, rh;
rx = dst_x;
ry = dst_y;
rw = dst_w;
rh = dst_h;
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
else
{
if (!((src_x != 0) || (src_w != im->w) ||
(src_y != 0) || (src_h != im->h)))
__evas_gl_window_clip(glw, 0, 0, 0, 0, 0);
}
}
#endif
/* render image here */
if (go)
{
int tx, ty, t;
double ty1, ty2, tx1, tx2;
double x1, x2, y1, y2;
int smooth = 0;
if ((__evas_smooth) && (allow_smooth))
{
if ((dst_w == src_w) && (dst_h == src_h))
smooth = 0;
else smooth = __evas_smooth;
}
else
smooth = 0;
t = 0;
for (ty = 0; ty <= tm->tiles.y; ty++)
{
if ((ty == 0) && (ty < tm->tiles.y))
{
y1 = y0;
y2 = y1 + ((double)(glw->context->max_texture_size - 1) * scy);
ty1 = 0.0;
ty2 = (double)(glw->context->max_texture_size - 2) / (double)(glw->context->max_texture_size - 1);
}
else if (ty < tm->tiles.y)
{
y1 = y0 + (((double)(glw->context->max_texture_size - 1) + ((double)(ty - 1) * (double)(glw->context->max_texture_size - 2))) * scy);
y2 = y1 + ((double)(glw->context->max_texture_size - 2) * scy);
ty1 = 1.0 / (double)(glw->context->max_texture_size - 1);
ty2 = (double)(glw->context->max_texture_size - 2) / (double)(glw->context->max_texture_size - 1);
}
else
{
if (ty == 0) y1 = y0;
else
y1 = y0 + h0 - ((double)tm->tiles.y_left * scy);
y2 = y0 + h0;
if (ty == 0)
{
ty1 = 0.0;
ty2 = (double)(tm->tiles.y_left - 1) / (double)(tm->tiles.y_edge - 1);
}
else
{
ty1 = 1.0 / (double)(tm->tiles.y_edge - 1);
ty2 = (double)(1 + tm->tiles.y_left - 1) / (double)(tm->tiles.y_edge - 1);
}
}
for (tx = 0; tx <= tm->tiles.x; tx++)
{
if ((tx == 0) && (tx < tm->tiles.x))
{
x1 = x0;
x2 = x1 + (255 * scx);
tx1 = 0.0;
tx2 = (double)(glw->context->max_texture_size - 2) / (double)(glw->context->max_texture_size - 1);
}
else if (tx < tm->tiles.x)
{
x1 = x0 + (((double)(glw->context->max_texture_size - 1) + ((double)(tx - 1) * (double)(glw->context->max_texture_size - 2))) * scx);
x2 = x1 + ((double)(glw->context->max_texture_size - 2) * scx);
tx1 = 1.0 / (double)(glw->context->max_texture_size - 1);
tx2 = (double)(glw->context->max_texture_size - 2) / (double)(glw->context->max_texture_size - 1);
}
else
{
if (tx == 0) x1 = x0;
else
x1 = x0 + w0 - ((double)tm->tiles.x_left * scx);
x2 = x0 + w0;
if (tx == 0)
{
tx1 = 0.0;
tx2 = (double)(tm->tiles.x_left - 1) / (double)(tm->tiles.x_edge - 1);
}
else
{
tx1 = 1.0 / (double)(tm->tiles.x_edge - 1);
tx2 = (double)(1 + tm->tiles.x_left - 1) / (double)(tm->tiles.x_edge - 1);
}
}
__evas_gl_window_use_texture(glw, tm->textures[t++], smooth);
glBegin(GL_QUADS);
glTexCoord2d(tx1, ty1); glVertex2d(x1, y1);
glTexCoord2d(tx2, ty1); glVertex2d(x2, y1);
glTexCoord2d(tx2, ty2); glVertex2d(x2, y2);
glTexCoord2d(tx1, ty2); glVertex2d(x1, y2);
glEnd();
}
}
}
#ifndef GLNOCLIP
}
#endif
}
/*****************************************************************************/
/* image externals ***********************************************************/
/*****************************************************************************/
void
__evas_gl_image_draw(Evas_GL_Image *im,
Display *disp, Imlib_Image dstim,
Window w, int win_w, int win_h,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h,
int cr, int cg, int cb, int ca)
{
Evas_GL_Window *glw;
if (__evas_clip)
{
cr = (cr * __evas_clip_r) / 255;
cg = (cg * __evas_clip_g) / 255;
cb = (cb * __evas_clip_b) / 255;
ca = (ca * __evas_clip_a) / 255;
}
if (ca <= 0) return;
if (src_w < 1) src_w = 1;
if (src_h < 1) src_h = 1;
if (dst_w < 1) return;
if (dst_h < 1) return;
glw = __evas_gl_window_current(disp, w, win_w, win_h);
if (!glw) return;
__evas_gl_window_texture(glw, 1);
if (ca == 255) __evas_gl_window_blend(glw, im->has_alpha);
else __evas_gl_window_blend(glw, 1);
__evas_gl_window_write_buf(glw, GL_BACK);
__evas_gl_window_read_buf(glw, GL_BACK);
__evas_gl_window_color(glw, cr, cg, cb, ca);
__evas_gl_window_dither(glw, 1);
if ((im->border.l == 0) && (im->border.r == 0) &&
(im->border.t == 0) && (im->border.b == 0))
__evas_gl_image_intern_draw(im, glw, src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h,
1);
else
{
double scx, scy;
double x0, y0, w0, h0;
int ecx, ecy, ecw, ech, ec;
int x, y, w, h, dx, dy, dw, dh;
int smooth;
scx = (double)dst_w / (double)src_w;
scy = (double)dst_h / (double)src_h;
x0 = (double)dst_x - ((double)src_x * scx);
y0 = (double)dst_y - ((double)src_y * scy);
w0 = (double)im->w * scx;
h0 = (double)im->h * scy;
ec = __evas_clip;
ecx = __evas_clip_x;
ecy = __evas_clip_y;
ecw = __evas_clip_w;
ech = __evas_clip_h;
if (__evas_clip)
{
CLIP_TO(dst_x, dst_y, dst_w, dst_h,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
}
__evas_clip = 1;
__evas_clip_x = dst_x;
__evas_clip_y = dst_y;
__evas_clip_w = dst_w;
__evas_clip_h = dst_h;
dst_x = x0;
dst_y = y0;
dst_w = w0;
dst_h = h0;
x = 0; y = 0;
w = im->border.l; h = im->border.t;
dx = dst_x; dy = dst_y;
dw = w; dh = h;
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, 0);
smooth = 0; if (scx > 1.0) smooth = 1;
x = im->border.l; y = 0;
w = im->w - (im->border.l + im->border.r); h = im->border.t;
dx = dst_x + im->border.l; dy = dst_y;
dw = dst_w - (im->border.l + im->border.r); dh = h;
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, smooth);
x = im->w - im->border.r; y = 0;
w = im->border.r; h = im->border.t;
dx = dst_x + dst_w - im->border.r;
dy = dst_y; dw = w; dh = h;
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, 0);
smooth = 0; if (scy > 1.0) smooth = 1;
x = 0; y = im->border.t;
w = im->border.l; h = im->h - (im->border.t + im->border.b);
dx = dst_x; dy = dst_y + im->border.t; dw = w;
dh = dst_h - (im->border.t + im->border.b);
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, smooth);
smooth = 0; if ((scx > 1.0) && (scy > 1.0)) smooth = 1;
x = im->border.l; y = im->border.t;
w = im->w - (im->border.l + im->border.r); h = im->h - (im->border.t + im->border.b);
dx = dst_x + im->border.l; dy = dst_y + im->border.t;
dw = dst_w - (im->border.l + im->border.r); dh = dst_h - (im->border.t + im->border.b);
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, smooth);
smooth = 0; if (scy > 1.0) smooth = 1;
x = im->w - im->border.r; y = im->border.t;
w = im->border.r; h = im->h - (im->border.t + im->border.b);
dx = dst_x + dst_w - im->border.r; dy = dst_y + im->border.t;
dw = w; dh = dst_h - (im->border.t + im->border.b);
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, smooth);
x = 0; y = im->h - im->border.b;
w = im->border.l; h = im->border.b;
dx = dst_x; dy = dst_y + dst_h - im->border.b;
dw = w; dh = h;
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, 0);
smooth = 0; if (scx > 1.0) smooth = 1;
x = im->border.l; y = im->h - im->border.b;
w = im->w - (im->border.l + im->border.r); h = im->border.b;
dx = dst_x + im->border.l; dy = dst_y + dst_h - im->border.b;
dw = dst_w - (im->border.l + im->border.r); dh = h;
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, smooth);
x = im->w - im->border.r; y = im->h - im->border.b;
w = im->border.r; h = im->border.b;
dx = dst_x + dst_w - im->border.r; dy = dst_y + dst_h - im->border.b;
dw = w; dh = h;
__evas_gl_image_intern_draw(im, glw, x, y, w, h, dx, dy, dw, dh, 0);
__evas_clip = ec;
__evas_clip_x = ecx;
__evas_clip_y = ecy;
__evas_clip_w = ecw;
__evas_clip_h = ech;
}
}
Evas_GL_Image *
__evas_gl_image_new_from_file(Display *disp, char *file)
{
Evas_List l;
Evas_GL_Image *image;
for (l = __evas_images; l; l = l->next)
{
image = l->data;
if ((image->file) && (!strcmp(image->file, file)))
{
if (image->references == 0)
{
__evas_image_cache -= image->w * image->h * 4;
}
image->references++;
if (l != __evas_images)
{
__evas_images = evas_list_remove(__evas_images, image);
__evas_images = evas_list_prepend(__evas_images, image);
}
return image;
}
}
image = __evas_gl_image_alloc(file);
if (image) __evas_images = evas_list_prepend(__evas_images, image);
return image;
}
void
__evas_gl_image_free(Evas_GL_Image *im)
{
if (im->references > 0)
im->references--;
if (im->references == 0)
{
__evas_image_cache += im->w * im->h * 4;
__evas_gl_image_cache_flush();
}
}
void
__evas_gl_image_cache_empty(Display *disp)
{
int prev_cache;
prev_cache = __evas_image_cache_max;
__evas_image_cache_max = 0;
__evas_gl_image_cache_flush();
__evas_image_cache_max = prev_cache;
}
void
__evas_gl_image_cache_set_size(Display *disp, int size)
{
__evas_image_cache_max = size;
__evas_gl_image_cache_flush();
}
int
__evas_gl_image_cache_get_size(Display *disp)
{
return __evas_image_cache_max;
}
int
__evas_gl_image_get_width(Evas_GL_Image *im)
{
return im->w;
}
int
__evas_gl_image_get_height(Evas_GL_Image *im)
{
return im->h;
}
void
__evas_gl_image_set_borders(Evas_GL_Image *im, int left, int right,
int top, int bottom)
{
im->border.l = left;
im->border.r = right;
im->border.t = top;
im->border.b = bottom;
}
void
__evas_gl_image_set_smooth_scaling(int on)
{
__evas_smooth = on;
}
/*****************************************************************************/
/* font externals ************************************************************/
/*****************************************************************************/
Evas_GL_Font *
__evas_gl_text_font_new(Display *disp, char *font, int size)
{
Evas_List l;
Evas_GL_Font *fn;
if (!font) return NULL;
for (l = __evas_fonts; l; l = l->next)
{
Evas_GL_Font *fn;
fn = l->data;
if (!strcmp(fn->font, font) && (size == fn->size))
{
if (l != __evas_fonts)
{
__evas_fonts = evas_list_remove(__evas_fonts, fn);
__evas_fonts = evas_list_prepend(__evas_fonts, fn);
}
if (fn->references == 0)
{
for (l = fn->textures; l; l = l->next)
{
Evas_GL_Font_Texture *ft;
ft = l->data;
__evas_font_cache -= ft->texture->w * ft->texture->h;
}
}
fn->references++;
return fn;
}
}
fn = __evas_gl_font_load(font, size);
if (!fn) return NULL;
__evas_fonts = evas_list_prepend(__evas_fonts, fn);
return fn;
}
void
__evas_gl_text_font_free(Evas_GL_Font *fn)
{
if (!fn) return;
if (fn->references >= 0)
{
fn->references--;
if (fn->references == 0)
{
Evas_List l;
for (l = fn->textures; l; l = l->next)
{
Evas_GL_Font_Texture *ft;
ft = l->data;
__evas_font_cache += ft->texture->w * ft->texture->h;
}
}
}
__evas_gl_text_font_cache_flush();
}
int
__evas_gl_text_font_get_ascent(Evas_GL_Font *fn)
{
if (!fn) return 0;
return fn->ascent / 64;
}
int
__evas_gl_text_font_get_descent(Evas_GL_Font *fn)
{
if (!fn) return 0;
return fn->descent / 64;
}
int
__evas_gl_text_font_get_max_ascent(Evas_GL_Font *fn)
{
if (!fn) return 0;
return fn->max_ascent / 64;
}
int
__evas_gl_text_font_get_max_descent(Evas_GL_Font *fn)
{
if (!fn) return 0;
return fn->max_descent / 64;
}
void
__evas_gl_text_font_get_advances(Evas_GL_Font *fn, char *text,
int *advance_horiz,
int *advance_vert)
{
int i, ascent, descent, pw, ph;
if (advance_horiz) *advance_horiz = 0;
if (advance_horiz) *advance_vert = 0;
if (!fn) return;
if (!text) return;
if (text[0] == 0) return;
ascent = fn->ascent;
descent = fn->descent;
pw = 0;
ph = ascent + descent;
for (i = 0; text[i]; i++)
{
Evas_GL_Glyph *g;
int glyph;
glyph = ((unsigned char *)text)[i];
g = __evas_gl_text_font_get_glyph(fn, glyph);
if (!g) continue;
if (!TT_VALID(g->glyph)) continue;
if (i == 0)
pw += ((-g->metrics.bearingX) / 64);
pw += g->metrics.advance / 64;
}
*advance_horiz = pw;
*advance_vert = ph;
}
int
__evas_gl_text_font_get_first_inset(Evas_GL_Font *fn, char *text)
{
int i;
if (!fn) return 0;
if (!text) return 0;
if (text[0] == 0) return 0;
for (i = 0; text[i]; i++)
{
Evas_GL_Glyph *g;
int glyph;
glyph = ((unsigned char *)text)[i];
g = __evas_gl_text_font_get_glyph(fn, glyph);
if (!g) continue;
if (!TT_VALID(g->glyph)) continue;
return ((-g->metrics.bearingX) / 64);
}
return 0;
}
void
__evas_gl_text_font_add_path(char *path)
{
int i;
for (i = 0; i < __evas_fpath_num; i++)
{
if (!strcmp(path, __evas_fpath[i])) return;
}
__evas_fpath_num++;
if (!__evas_fpath) __evas_fpath = malloc(sizeof(char *));
else __evas_fpath = realloc(__evas_fpath,
(__evas_fpath_num * sizeof(char *)));
__evas_fpath[__evas_fpath_num - 1] = malloc(strlen(path) + 1);
strcpy(__evas_fpath[__evas_fpath_num - 1], path);
}
void
__evas_gl_text_font_del_path(char *path)
{
int i, j;
for (i = 0; i < __evas_fpath_num; i++)
{
if (!strcmp(path, __evas_fpath[i]))
{
__evas_fpath_num--;
for (j = i; j < __evas_fpath_num; j++)
__evas_fpath[j] = __evas_fpath[j + 1];
if (__evas_fpath_num > 0)
__evas_fpath = realloc(__evas_fpath,
__evas_fpath_num * sizeof(char *));
else
{
free(__evas_fpath);
__evas_fpath = NULL;
}
}
}
}
char **
__evas_gl_text_font_list_paths(int *count)
{
*count = __evas_fpath_num;
return __evas_fpath;
}
void
__evas_gl_text_cache_empty(Display *disp)
{
int prev_cache;
prev_cache = __evas_font_cache_max;
__evas_font_cache_max = 0;
__evas_gl_text_font_cache_flush();
__evas_font_cache_max = prev_cache;
}
void
__evas_gl_text_cache_set_size(Display *disp, int size)
{
__evas_font_cache_max = size;
__evas_gl_text_font_cache_flush();
}
int
__evas_gl_text_cache_get_size(Display *disp)
{
return __evas_font_cache_max;
}
void
__evas_gl_text_draw(Evas_GL_Font *fn, Display *disp, Imlib_Image dstim, Window win,
int win_w, int win_h, int x, int y, char *text,
int cr, int cg, int cb, int ca)
{
Evas_GL_Window *glw;
Evas_List l;
int go;
if (__evas_clip)
{
cr = (cr * __evas_clip_r) / 255;
cg = (cg * __evas_clip_g) / 255;
cb = (cb * __evas_clip_b) / 255;
ca = (ca * __evas_clip_a) / 255;
}
if (ca <= 0) return;
glw = __evas_gl_window_current(disp, win, win_w, win_h);
if (!glw) return;
__evas_gl_window_texture(glw, 1);
__evas_gl_window_blend(glw, 1);
__evas_gl_window_write_buf(glw, GL_BACK);
__evas_gl_window_read_buf(glw, GL_BACK);
__evas_gl_window_color(glw, cr, cg, cb, ca);
__evas_gl_window_dither(glw, 1);
#ifndef GLNOCLIP
for (l = glw->updates; l; l = l->next)
{
Evas_GL_Rect *rect;
go = 1;
rect = l->data;
{
int rx, ry, rw, rh;
rx = 0;
ry = 0;
rw = win_w;
rh = win_h;
CLIP_TO(rx, ry, rw, rh, rect->x, rect->y, rect->w, rect->h);
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
}
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
#else
go = 1;
{
int rx, ry, rw, rh;
rx = 0;
ry = 0;
rw = win_w;
rh = win_h;
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
else
__evas_gl_window_clip(glw, 0, 0, 0, 0, 0);
}
#endif
/* render string here */
if (go)
{
int i;
int x_offset, y_offset;
int glyph, rows;
Evas_GL_Glyph *g;
if (text[0] == 0) return;
glyph = ((unsigned char *)text)[0];
g = __evas_gl_text_font_get_glyph(fn, glyph);
if (!TT_VALID(g->glyph))
#ifndef GLNOCLIP
continue;
#else
return;
#endif
x_offset = 0;
if (g) x_offset = - (g->metrics.bearingX / 64);
y_offset = -(fn->max_descent / 64);
__evas_gl_text_get_size(fn, text, NULL, &rows);
for (i = 0; text[i]; i++)
{
int xmin, ymin, xmax, ymax, off, adj;
/* for internationalization this here wouldnt just use */
/* the char value of the text[i] but translate form utf-8 */
/* or whetever and incriment i appropriately and set g to */
/* the glyph index */
glyph = ((unsigned char *)text)[i];
g = __evas_gl_text_font_get_glyph(fn, glyph);
__evas_gl_text_font_render_glyph(glw, fn, g);
if (!g) continue;
if (!TT_VALID(g->glyph)) continue;
xmin = g->metrics.bbox.xMin & -64;
ymin = g->metrics.bbox.yMin & -64;
xmax = (g->metrics.bbox.xMax + 63) & -64;
ymax = (g->metrics.bbox.yMax + 63) & -64;
xmin = (xmin >> 6) + x_offset;
ymin = (ymin >> 6) + y_offset;
xmax = (xmax >> 6) + x_offset;
ymax = (ymax >> 6) + y_offset;
if (ymin < 0) off = 0;
else off = rows - ymin - 1;
adj = (rows - ymax) -
((fn->max_ascent - fn->max_descent) >> 6);
if ((g->texture) && (g->texture->texture))
{
__evas_gl_window_texture(glw, 1);
__evas_gl_window_use_texture(glw,
g->texture->texture,
0);
}
else
__evas_gl_window_texture(glw, 0);
glBegin(GL_QUADS);
glTexCoord2d(g->tex.x1, g->tex.y1);
glVertex2i(x + xmin, y + ymin + off + adj);
glTexCoord2d(g->tex.x2, g->tex.y1);
glVertex2i(x + xmax + 1, y + ymin + off + adj);
glTexCoord2d(g->tex.x2, g->tex.y2);
glVertex2i(x + xmax + 1, y + ymax + off + adj + 1);
glTexCoord2d(g->tex.x1, g->tex.y2);
glVertex2i(x + xmin, y + ymax + off + adj + 1);
glEnd();
x_offset += g->metrics.advance / 64;
}
}
#ifndef GLNOCLIP
}
#endif
}
void
__evas_gl_text_get_size(Evas_GL_Font *fn, char *text, int *w, int *h)
{
int i, pw, ph;
Evas_GL_Glyph *g;
int glyph;
if (!fn) return;
if (!text) return;
if (text[0] == 0) return;
pw = 0;
ph = (fn->max_ascent - fn->max_descent) / 64;
for (i = 0; text[i]; i++)
{
/* for internationalization this here wouldnt just use */
/* the char value of the text[i] but translate form utf-8 */
/* or whetever and incriment i appropriately and set g to */
/* the glyph index */
glyph = ((unsigned char *)text)[i];
g = __evas_gl_text_font_get_glyph(fn, glyph);
if (!g) continue;
if (!TT_VALID(g->glyph)) continue;
if (i == 0)
pw += ((-g->metrics.bearingX) / 64);
if (text[i + 1] == 0) /* last char - ineternationalization issue */
{
if ((g->metrics.bbox.xMax / 64) == 0)
pw += (g->metrics.advance / 64);
else
pw += (g->metrics.bbox.xMax / 64);
}
else
pw += g->metrics.advance / 64;
}
if (w) *w = pw;
if (h) *h = ph;
}
int
__evas_gl_text_get_character_at_pos(Evas_GL_Font *fn, char *text, int x, int y, int *cx, int *cy, int *cw, int *ch)
{
int i, px, ppx;
if (cx) *cx = 0;
if (cy) *cy = 0;
if (cw) *cw = 0;
if (ch) *ch = 0;
if (!fn) return -1;
if (!text) return -1;
if (text[0] == 0) return -1;
if ((y < 0) || (y > (fn->ascent + fn->descent))) return -1;
if (cy) *cy = 0;
if (ch) *ch = fn->ascent + fn->descent;
ppx = 0;
px = 0;
for (i = 0; text[i]; i++)
{
Evas_GL_Glyph *g;
int glyph;
glyph = ((unsigned char *)text)[i];
g = __evas_gl_text_font_get_glyph(fn, glyph);
if (!g) continue;
if (!TT_VALID(g->glyph)) continue;
if (i == 0)
px += ((-g->metrics.bearingX) / 64);
if (text[i + 1] == 0)
px += (g->metrics.bbox.xMax / 64);
else
px += g->metrics.advance / 64;
if ((x >= ppx) && (x < px))
{
if (cx)
*cx = ppx;
if (cw)
*cw = px - ppx;
return i;
}
}
return -1;
}
void
__evas_gl_text_get_character_number(Evas_GL_Font *fn, char *text, int num, int *cx, int *cy, int *cw, int *ch)
{
int i, px, ppx;
if (cx) *cx = 0;
if (cy) *cy = 0;
if (cw) *cw = 0;
if (ch) *ch = 0;
if (!fn) return;
if (!text) return;
if (text[0] == 0) return;
if (cy) *cy = 0;
if (ch) *ch = fn->ascent + fn->descent;
ppx = 0;
px = 0;
for (i = 0; text[i]; i++)
{
Evas_GL_Glyph *g;
int glyph;
glyph = ((unsigned char *)text)[i];
g = __evas_gl_text_font_get_glyph(fn, glyph);
if (!g) continue;
if (!TT_VALID(g->glyph)) continue;
ppx = px;
if (i == 0)
px += ((-g->metrics.bearingX) / 64);
if (text[i + 1] == 0)
px += (g->metrics.bbox.xMax / 64);
else
px += g->metrics.advance / 64;
if (i == num)
{
if (cx) *cx = ppx;
if (cw) *cw = px - ppx;
return;
}
}
}
/*****************************************************************************/
/* rectangle externals *******************************************************/
/*****************************************************************************/
void __evas_gl_rectangle_draw(Display *disp, Imlib_Image dstim, Window win,
int win_w, int win_h,
int x, int y, int w, int h,
int cr, int cg, int cb, int ca)
{
Evas_GL_Window *glw;
Evas_List l;
int go;
if (__evas_clip)
{
cr = (cr * __evas_clip_r) / 255;
cg = (cg * __evas_clip_g) / 255;
cb = (cb * __evas_clip_b) / 255;
ca = (ca * __evas_clip_a) / 255;
}
if (ca <= 0) return;
if (w < 1) return;
if (h < 1) return;
glw = __evas_gl_window_current(disp, win, win_w, win_h);
if (!glw) return;
__evas_gl_window_texture(glw, 0);
if (ca < 255) __evas_gl_window_blend(glw, 1);
else __evas_gl_window_blend(glw, 0);
__evas_gl_window_write_buf(glw, GL_BACK);
__evas_gl_window_read_buf(glw, GL_BACK);
__evas_gl_window_color(glw, cr, cg, cb, ca);
__evas_gl_window_dither(glw, 1);
#ifndef GLNOCLIP
for (l = glw->updates; l; l = l->next)
{
Evas_GL_Rect *rect;
go = 1;
rect = l->data;
{
int rx, ry, rw, rh;
rx = x;
ry = y;
rw = w;
rh = h;
CLIP_TO(rx, ry, rw, rh, rect->x, rect->y, rect->w, rect->h);
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
}
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
#else
go = 1;
{
int rx, ry, rw, rh;
rx = x;
ry = y;
rw = w;
rh = h;
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
else
__evas_gl_window_clip(glw, 0, 0, 0, 0, 0);
}
#endif
/* render rect here */
if (go)
{
double x1, x2, y1, y2;
x1 = (double)x;
y1 = (double)y;
x2 = (double)(x + w);
y2 = (double)(y + h);
glBegin(GL_QUADS);
glVertex2d(x1, y1);
glVertex2d(x2, y1);
glVertex2d(x2, y2);
glVertex2d(x1, y2);
glEnd();
}
#ifndef GLNOCLIP
}
#endif
}
/*****************************************************************************/
/* line externals ************************************************************/
/*****************************************************************************/
void __evas_gl_line_draw(Display *disp, Imlib_Image dstim, Window win,
int win_w, int win_h,
int x1, int y1, int x2, int y2,
int cr, int cg, int cb, int ca)
{
Evas_GL_Window *glw;
Evas_List l;
int go;
if (__evas_clip)
{
cr = (cr * __evas_clip_r) / 255;
cg = (cg * __evas_clip_g) / 255;
cb = (cb * __evas_clip_b) / 255;
ca = (ca * __evas_clip_a) / 255;
}
if (ca <= 0) return;
glw = __evas_gl_window_current(disp, win, win_w, win_h);
if (!glw) return;
__evas_gl_window_texture(glw, 0);
if (ca < 255) __evas_gl_window_blend(glw, 1);
else __evas_gl_window_blend(glw, 0);
__evas_gl_window_write_buf(glw, GL_BACK);
__evas_gl_window_read_buf(glw, GL_BACK);
__evas_gl_window_color(glw, cr, cg, cb, ca);
__evas_gl_window_dither(glw, 1);
#ifndef GLNOCLIP
for (l = glw->updates; l; l = l->next)
{
Evas_GL_Rect *rect;
go = 1;
rect = l->data;
{
int rx, ry, rw, rh;
rx = 0;
ry = 0;
rw = win_w;
rh = win_h;
CLIP_TO(rx, ry, rw, rh, rect->x, rect->y, rect->w, rect->h);
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
}
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
#else
go = 1;
{
int rx, ry, rw, rh;
rx = 0;
ry = 0;
rw = win_w;
rh = win_h;
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
else
__evas_gl_window_clip(glw, 0, 0, 0, 0, 0);
}
#endif
/* render rect here */
if (go)
{
glBegin(GL_LINES);
glVertex2d((double)x1 + 0.5, (double)y1 + 0.5);
glVertex2d((double)x2 + 0.5, (double)y2 + 0.5);
glEnd();
}
#ifndef GLNOCLIP
}
#endif
}
/*****************************************************************************/
/* gradient externals ********************************************************/
/*****************************************************************************/
Evas_GL_Graident *
__evas_gl_gradient_new(Display *disp)
{
Evas_GL_Graident *gr;
gr = malloc(sizeof(Evas_GL_Graident));
gr->col_range = NULL;
gr->textures = NULL;
}
void
__evas_gl_gradient_free(Evas_GL_Graident *gr)
{
if (gr->col_range)
{
imlib_context_set_color_range(gr->col_range);
imlib_free_color_range();
}
if (gr->textures);
{
Evas_List l;
for (l = gr->textures; l; l = l->next)
{
Evas_GL_Graident_Texture *tg;
tg = l->data;
__evas_gl_gradient_texture_free(tg);
}
evas_list_free(gr->textures);
}
free(gr);
}
void
__evas_gl_gradient_color_add(Evas_GL_Graident *gr, int r, int g, int b,
int a, int dist)
{
if (!gr->col_range) gr->col_range = imlib_create_color_range();
imlib_context_set_color_range(gr->col_range);
imlib_context_set_color(r, g, b, a);
imlib_add_color_to_color_range(dist);
}
void
__evas_gl_gradient_draw(Evas_GL_Graident *gr,
Display *disp, Imlib_Image dstim, Window win, int win_w, int win_h,
int x, int y, int w, int h, double angle)
{
Evas_GL_Window *glw;
Evas_List l;
int go;
int cr, cg, cb, ca;
Evas_GL_Graident_Texture *tg;
if (__evas_clip)
{
cr = __evas_clip_r;
cg = __evas_clip_g;
cb = __evas_clip_b;
ca = __evas_clip_a;
}
else
{
cr = 255;
cg = 255;
cb = 255;
ca = 255;
}
if (ca <= 0) return;
if (w < 1) return;
if (h < 1) return;
glw = __evas_gl_window_current(disp, win, win_w, win_h);
if (!glw) return;
__evas_gl_window_texture(glw, 1);
__evas_gl_window_blend(glw, 1);
__evas_gl_window_write_buf(glw, GL_BACK);
__evas_gl_window_read_buf(glw, GL_BACK);
__evas_gl_window_color(glw, cr, cg, cb, ca);
__evas_gl_window_dither(glw, 1);
#ifndef GLNOCLIP
for (l = glw->updates; l; l = l->next)
{
Evas_GL_Rect *rect;
go = 1;
rect = l->data;
{
int rx, ry, rw, rh;
rx = x;
ry = y;
rw = w;
rh = h;
CLIP_TO(rx, ry, rw, rh, rect->x, rect->y, rect->w, rect->h);
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
}
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
#else
go = 1;
{
int rx, ry, rw, rh;
rx = x;
ry = y;
rw = w;
rh = h;
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
else
__evas_gl_window_clip(glw, 0, 0, 0, 0, 0);
}
#endif
/* render gradient here */
if (go)
{
double x1, x2, y1, y2;
double max, t[8];
int i;
tg = __evas_gl_gradient_texture_new(glw, gr);
if (!tg->texture)
{
Imlib_Image prev_im, im;
DATA32 *data;
int tw, th;
tw = glw->context->max_texture_size;
th = 4;
im = imlib_create_image(tw, th);
prev_im = imlib_context_get_image();
imlib_context_set_image(im);
imlib_image_set_has_alpha(1);
data = imlib_image_get_data();
memset(data, 0, tw * th * sizeof(DATA32));
imlib_image_put_back_data(data);
imlib_context_set_color_range(gr->col_range);
imlib_image_fill_color_range_rectangle(1, 1, tw - 2, th - 2,
270.0);
data = imlib_image_get_data();
memcpy(&(data[(1) + (0 * tw)]), &(data[(1) + (1 * tw)]),
(tw - 2) * sizeof(DATA32));
memcpy(&(data[(1) + (3 * tw)]), &(data[(1) + (2 * tw)]),
(tw - 2) * sizeof(DATA32));
data[(0) + (0 * tw)] = data[(1) + (0 * tw)];
data[(0) + (1 * tw)] = data[(1) + (1 * tw)];
data[(0) + (2 * tw)] = data[(1) + (2 * tw)];
data[(0) + (3 * tw)] = data[(1) + (3 * tw)];
data[(tw - 1) + (0 * tw)] = data[(tw - 2) + (0 * tw)];
data[(tw - 1) + (1 * tw)] = data[(tw - 2) + (1 * tw)];
data[(tw - 1) + (2 * tw)] = data[(tw - 2) + (2 * tw)];
data[(tw - 1) + (3 * tw)] = data[(tw - 2) + (3 * tw)];
imlib_image_put_back_data(data);
tg->texture = __evas_gl_texture_new(glw, im, 0, 0, tw, th);
imlib_free_image();
}
__evas_gl_window_use_texture(glw, tg->texture, 1);
t[0] = cos(((-angle + 45 + 90) * 2 * 3.141592654) / 360);
t[1] = sin(((-angle + 45 + 90) * 2 * 3.141592654) / 360);
t[2] = cos(((-angle + 45 + 180) * 2 * 3.141592654) / 360);
t[3] = sin(((-angle + 45 + 180) * 2 * 3.141592654) / 360);
t[4] = cos(((-angle + 45 + 270) * 2 * 3.141592654) / 360);
t[5] = sin(((-angle + 45 + 270) * 2 * 3.141592654) / 360);
t[6] = cos(((-angle + 45 + 0) * 2 * 3.141592654) / 360);
t[7] = sin(((-angle + 45 + 0) * 2 * 3.141592654) / 360);
max = 0;
for (i = 0; i < 8; i++)
{
if ((t[i] < 0) && (-t[i] > max)) max = -t[i];
else if ((t[i] > max)) max = t[i];
}
if (max > 0)
{
for (i = 0; i < 8; i++) t[i] *= 1 / max;
}
for (i = 0; i < 8; i+=2)
{
t[i] = (1.0 +
((((0.5) + (t[i] / 2.0)) *
((double)glw->context->max_texture_size - 2.0)))) /
(double)glw->context->max_texture_size;
t[i + 1] = (1.0 + ((((0.5) - (t[i + 1] / 2.0))) * 2.0)) / 4.0;
}
x1 = (double)x;
y1 = (double)y;
x2 = (double)(x + w);
y2 = (double)(y + h);
glBegin(GL_QUADS);
glTexCoord2d(t[0], t[1]); glVertex2d(x1, y1);
glTexCoord2d(t[2], t[3]); glVertex2d(x2, y1);
glTexCoord2d(t[4], t[5]); glVertex2d(x2, y2);
glTexCoord2d(t[6], t[7]); glVertex2d(x1, y2);
glEnd();
}
#ifndef GLNOCLIP
}
#endif
}
/* something is wrong here - GL experts? the polys dont get tesselated */
/* correctly */
#ifdef HAVE_GLU
static void
__evas_gl_tess_begin_cb(GLenum which)
{
glBegin(which);
}
static void
__evas_gl_tess_end_cb(void)
{
glEnd();
}
static void
__evas_gl_tess_error_cb(GLenum errorcode)
{
}
static void
__evas_gl_tess_vertex_cb(GLvoid *vertex)
{
GLdouble *v;
v = vertex;
glVertex2d(v[0], v[1]);
}
static void
__evas_gl_tess_combine_cb(GLdouble coords[3],
GLdouble *vertex_data[4],
GLfloat weight[4], GLdouble **data_out)
{
GLdouble *vertex;
vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
vertex[0] = coords[0];
vertex[1] = coords[1];
*data_out = vertex;
}
#endif
/************/
/* polygons */
/************/
void
__evas_gl_poly_draw (Display *disp, Imlib_Image dstim, Window win,
int win_w, int win_h,
Evas_List points,
int cr, int cg, int cb, int ca)
{
Evas_GL_Window *glw;
Evas_List l;
int go;
if (__evas_clip)
{
cr = (cr * __evas_clip_r) / 255;
cg = (cg * __evas_clip_g) / 255;
cb = (cb * __evas_clip_b) / 255;
ca = (ca * __evas_clip_a) / 255;
}
if (ca <= 0) return;
glw = __evas_gl_window_current(disp, win, win_w, win_h);
if (!glw) return;
__evas_gl_window_texture(glw, 0);
if (ca < 255) __evas_gl_window_blend(glw, 1);
else __evas_gl_window_blend(glw, 0);
__evas_gl_window_write_buf(glw, GL_BACK);
__evas_gl_window_read_buf(glw, GL_BACK);
__evas_gl_window_color(glw, cr, cg, cb, ca);
__evas_gl_window_dither(glw, 1);
#ifndef GLNOCLIP
for (l = glw->updates; l; l = l->next)
{
Evas_GL_Rect *rect;
go = 1;
rect = l->data;
{
int rx, ry, rw, rh;
rx = 0;
ry = 0;
rw = win_w;
rh = win_h;
CLIP_TO(rx, ry, rw, rh, rect->x, rect->y, rect->w, rect->h);
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
}
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
#else
go = 1;
{
int rx, ry, rw, rh;
rx = 0;
ry = 0;
rw = win_w;
rh = win_h;
if (__evas_clip)
{
CLIP_TO(rx, ry, rw, rh,
__evas_clip_x, __evas_clip_y,
__evas_clip_w, __evas_clip_h);
if ((rw > 0) && (rh > 0))
__evas_gl_window_clip(glw, 1, rx, ry, rw, rh);
else go = 0;
}
else
__evas_gl_window_clip(glw, 0, 0, 0, 0, 0);
}
#endif
/* render poly here */
if (go)
{
Evas_List l2;
#ifdef HAVE_GLU
{
static void *tess = NULL;
GLdouble *glp = NULL;
int i, num;
if (!tess)
{
tess = gluNewTess();
gluTessCallback(tess, GLU_TESS_BEGIN, __evas_gl_tess_begin_cb);
gluTessCallback(tess, GLU_TESS_END, __evas_gl_tess_end_cb);
gluTessCallback(tess, GLU_TESS_ERROR, __evas_gl_tess_error_cb);
gluTessCallback(tess, GLU_TESS_VERTEX, __evas_gl_tess_vertex_cb);
gluTessCallback(tess, GLU_TESS_COMBINE, __evas_gl_tess_combine_cb);
}
num = 0;
for (l2 = points; l2; l2 = l2->next) num++;
i = 0;
glp = malloc(num * 6 * sizeof(GLdouble));
gluTessNormal(tess, 0, 0, 1);
gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
gluTessBeginPolygon(tess, NULL);
gluTessBeginContour(tess);
for (l2 = points; l2; l2 = l2->next)
{
Evas_Point p;
p = l2->data;
glp[i++] = p->x;
glp[i++] = p->y;
glp[i++] = 0;
gluTessVertex(tess, &(glp[i - 3]), &(glp[i - 3]));
i += 3;
}
gluTessEndContour(tess);
gluTessEndPolygon(tess);
free(glp);
}
#else
glBegin(GL_POLYGON);
for (l2 = points; l2; l2 = l2->next)
{
Evas_Point p;
p = l2->data;
glVertex2d(p->x, p->y);
}
glEnd();
#endif
}
#ifndef GLNOCLIP
}
#endif
}
/*****************************************************************************/
/* general externals *********************************************************/
/*****************************************************************************/
void
__evas_gl_set_clip_rect(int on, int x, int y, int w, int h, int r, int g, int b, int a)
{
__evas_clip = on;
__evas_clip_x = x;
__evas_clip_y = y;
__evas_clip_w = w;
__evas_clip_h = h;
__evas_clip_r = r;
__evas_clip_g = g;
__evas_clip_b = b;
__evas_clip_a = a;
}
void
__evas_gl_sync(Display *disp)
{
glFlush();
glXWaitGL();
XSync(disp, False);
}
void
__evas_gl_flush_draw(Display *disp, Imlib_Image dstim, Window win)
{
Evas_GL_Window *glw;
Evas_List l;
glw = __evas_gl_window_lookup(disp, win);
if (!glw) return;
if (glw->updates)
{
for (l = glw->updates; l; l = l->next)
{
Evas_GL_Rect *rect;
rect = l->data;
#ifndef GLSWB
__evas_gl_window_swap_rect(glw, rect->x, rect->y, rect->w, rect->h);
#endif
free(rect);
}
evas_list_free(glw->updates);
glw->updates = NULL;
}
#ifdef GLSWB
glXSwapBuffers(disp, win);
#endif
}
void
__evas_gl_set_vis_cmap(Visual *vis, Colormap cmap)
{
}
int
__evas_gl_capable(Display *disp)
{
int eb, evb;
Evas_List l;
static Evas_List capables = NULL;
for (l = capables; l; l = l->next)
{
if (l->data == disp) return 1;
}
if (glXQueryExtension(disp, &eb, &evb))
{
capables = evas_list_prepend(capables, disp);
return 1;
}
return 0;
}
static XVisualInfo *__evas_vi = NULL;
Visual *
__evas_gl_get_visual(Display *disp, int screen)
{
static Display *d = NULL;
if (d != disp)
{
d = disp;
__evas_vi = glXChooseVisual(disp, screen, __evas_gl_configuration);
}
return __evas_vi->visual;
}
XVisualInfo *
__evas_gl_get_visual_info(Display *disp, int screen)
{
__evas_gl_get_visual(disp, screen);
return __evas_vi;
}
Colormap
__evas_gl_get_colormap(Display *disp, int screen)
{
static Display *d = NULL;
static Colormap cmap = 0;
if (!__evas_vi) __evas_gl_get_visual(disp, screen);
if (d != disp)
{
d = disp;
cmap = XCreateColormap(disp, RootWindow(disp, screen), __evas_vi->visual, 0);
}
return cmap;
}
void
__evas_gl_init(Display *disp, int screen, int colors)
{
}
void
__evas_gl_draw_add_rect(Display *disp, Imlib_Image dstim, Window win,
int x, int y, int w, int h)
{
Evas_GL_Window *glw;
Evas_GL_Rect *rect;
glw = __evas_gl_window_lookup(disp, win);
if (!glw) return;
#ifdef GLBOUNDING
if (glw->updates)
{
rect = glw->updates->data;
if (x < rect->x)
{
rect->w += (rect->x - x);
rect->x = x;
}
if ((x + w) > (rect->x + rect->w))
{
rect->w = (x + w) - rect->x;
}
if (y < rect->y)
{
rect->h += (rect->y - y);
rect->y = y;
}
if ((y + h) > (rect->y + rect->h))
{
rect->h = (y + h) - rect->y;
}
return;
}
#endif
rect = malloc(sizeof(Evas_GL_Rect));
rect->x = x;
rect->y = y;
rect->w = w;
rect->h = h;
glw->updates = evas_list_append(glw->updates, rect);
}
#else
/***************/
/* image stuff */
/***************/
Evas_GL_Image *__evas_gl_image_new_from_file(Display *disp, char *file){return NULL;}
void __evas_gl_image_free(Evas_GL_Image *im){}
void __evas_gl_image_cache_empty(Display *disp){}
void __evas_gl_image_cache_set_size(Display *disp, int size){}
int __evas_gl_image_cache_get_size(Display *disp){return 0;}
int __evas_gl_image_get_width(Evas_GL_Image *im){return 0;}
int __evas_gl_image_get_height(Evas_GL_Image *im){return 0;}
void __evas_gl_image_set_borders(Evas_GL_Image *im, int left, int right, int top, int bottom){}
void __evas_gl_image_set_smooth_scaling(int on){}
void __evas_gl_image_draw(Evas_GL_Image *im, Display *disp, Imlib_Image dstim, Window w, int win_w, int win_h, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int cr, int cg, int cb, int ca){}
/********/
/* text */
/********/
Evas_GL_Font *__evas_gl_text_font_new(Display *disp, char *font, int size){return NULL;}
void __evas_gl_text_font_free(Evas_GL_Font *fn){}
void __evas_gl_text_font_add_path(char *path){}
int __evas_gl_text_font_get_ascent(Evas_GL_Font *fn){return 0;}
int __evas_gl_text_font_get_descent(Evas_GL_Font *fn){return 0;}
int __evas_gl_text_font_get_max_ascent(Evas_GL_Font *fn){return 0;}
int __evas_gl_text_font_get_max_descent(Evas_GL_Font *fn){return 0;}
void __evas_gl_text_font_get_advances(Evas_GL_Font *fn, char *text, int *advance_horiz, int *advance_vert){}
int __evas_gl_text_font_get_first_inset(Evas_GL_Font *fn, char *text){return 0;}
void __evas_gl_text_font_del_path(char *path){}
char **__evas_gl_text_font_list_paths(int *count){return NULL;}
void __evas_gl_text_cache_empty(Display *disp){}
void __evas_gl_text_cache_set_size(Display *disp, int size){}
int __evas_gl_text_cache_get_size(Display *disp){return 0;}
void __evas_gl_text_get_size(Evas_GL_Font *fn, char *text, int *w, int *h){}
int __evas_gl_text_get_character_at_pos(Evas_GL_Font *fn, char *text, int x, int y, int *cx, int *cy, int *cw, int *ch){return 0;}
void __evas_gl_text_get_character_number(Evas_GL_Font *fn, char *text, int num, int *cx, int *cy, int *cw, int *ch){}
void __evas_gl_text_draw(Evas_GL_Font *fn, Display *disp, Imlib_Image dstim, Window win, int win_w, int win_h, int x, int y, char *text, int r, int g, int b, int a){}
/**************/
/* rectangles */
/**************/
void __evas_gl_rectangle_draw(Display *disp, Imlib_Image dstim, Window win, int win_w, int win_h, int x, int y, int w, int h, int r, int g, int b, int a){}
/*********/
/* lines */
/*********/
void __evas_gl_line_draw(Display *disp, Imlib_Image dstim, Window win, int win_w, int win_h, int x1, int y1, int x2, int y2, int r, int g, int b, int a){}
/*************/
/* gradients */
/*************/
Evas_GL_Graident *__evas_gl_gradient_new(Display *disp){return NULL;}
void __evas_gl_gradient_free(Evas_GL_Graident *gr){}
void __evas_gl_gradient_color_add(Evas_GL_Graident *gr, int r, int g, int b, int a, int dist){}
void __evas_gl_gradient_draw(Evas_GL_Graident *gr, Display *disp, Imlib_Image dstim, Window win, int win_w, int win_h, int x, int y, int w, int h, double angle){}
/************/
/* polygons */
/************/
void __evas_gl_poly_draw (Display *disp, Imlib_Image dstim, Window win, int win_w, int win_h, Evas_List points, int r, int g, int b, int a) {}
/***********/
/* drawing */
/***********/
void __evas_gl_init(Display *disp, int screen, int colors){}
int __evas_gl_capable(Display *disp){return 0;}
void __evas_gl_flush_draw(Display *disp, Imlib_Image dstim, Window win){}
void __evas_gl_sync(Display *disp){}
Visual *__evas_gl_get_visual(Display *disp, int screen){return NULL;}
XVisualInfo *__evas_gl_get_visual_info(Display *disp, int screen){return NULL;}
Colormap __evas_gl_get_colormap(Display *disp, int screen){return 0;}
void __evas_gl_draw_add_rect(Display *disp, Imlib_Image dstim, Window win, int x, int y, int w, int h){}
#endif