537 lines
15 KiB
C
537 lines
15 KiB
C
#include "evas_gl_private.h"
|
|
|
|
static void _evas_gl_common_viewport_set(Evas_GL_Context *gc);
|
|
static void _evas_gl_common_dither_set(Evas_GL_Context *gc);
|
|
static void _evas_gl_common_blend_set(Evas_GL_Context *gc);
|
|
static void _evas_gl_common_color_set(Evas_GL_Context *gc);
|
|
static void _evas_gl_common_texture_set(Evas_GL_Context *gc);
|
|
static void _evas_gl_common_clip_set(Evas_GL_Context *gc);
|
|
static void _evas_gl_common_buf_set(Evas_GL_Context *gc);
|
|
static void _evas_gl_common_other_set(Evas_GL_Context *gc);
|
|
|
|
static Evas_GL_Context *_evas_gl_common_context = NULL;
|
|
|
|
Evas_GL_Context *
|
|
evas_gl_common_context_new(void)
|
|
{
|
|
Evas_GL_Context *gc;
|
|
|
|
if (_evas_gl_common_context)
|
|
{
|
|
_evas_gl_common_context->references++;
|
|
return _evas_gl_common_context;
|
|
}
|
|
gc = calloc(1, sizeof(Evas_GL_Context));
|
|
if (!gc) return NULL;
|
|
gc->max_texture_depth = 32;
|
|
gc->max_texture_size = 2048;
|
|
gc->read_buf = GL_BACK;
|
|
gc->write_buf = GL_BACK;
|
|
gc->dither = 1;
|
|
gc->blend = 0;
|
|
gc->references = 1;
|
|
|
|
gc->change.size = 1;
|
|
gc->change.dither = 1;
|
|
gc->change.blend = 1;
|
|
gc->change.color = 1;
|
|
gc->change.texture = 1;
|
|
gc->change.clip = 1;
|
|
gc->change.buf = 1;
|
|
gc->change.other = 1;
|
|
|
|
return gc;
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_free(Evas_GL_Context *gc)
|
|
{
|
|
gc->references--;
|
|
if (gc->references > 0) return;
|
|
if (gc->yuv422p.fshad)
|
|
{
|
|
glDeleteObjectARB(gc->yuv422p.fshad);
|
|
}
|
|
if (gc->yuv422p.prog)
|
|
{
|
|
glDeleteObjectARB(gc->yuv422p.prog);
|
|
}
|
|
|
|
if (gc == _evas_gl_common_context) _evas_gl_common_context = NULL;
|
|
free(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_use(Evas_GL_Context *gc)
|
|
{
|
|
if (_evas_gl_common_context == gc) return;
|
|
if (!gc->ext.checked)
|
|
{
|
|
const GLubyte *ext;
|
|
|
|
ext = glGetString(GL_EXTENSIONS);
|
|
if (ext)
|
|
{
|
|
// if (strstr(ext, "GL_SGIS_generate_mipmap")) gc->ext.sgis_generate_mipmap = 1;
|
|
// if (strstr(ext, "GL_NV_texture_rectangle")) gc->ext.nv_texture_rectangle = 1;
|
|
// if (strstr(ext, "GL_EXT_texture_rectangle")) gc->ext.nv_texture_rectangle = 1;
|
|
if (strstr(ext, "GL_ARB_texture_non_power_of_two")) gc->ext.arb_texture_non_power_of_two = 1;
|
|
if (strstr(ext, "GL_ARB_shader_objects") && strstr(ext, "GL_ARB_vertex_shader")
|
|
&& strstr(ext, "GL_ARB_fragment_shader") && strstr(ext, "GL_ARB_shading_language"))
|
|
gc->ext.arb_program = 1;
|
|
// printf("GL EXT supported: GL_SGIS_generate_mipmap = %x\n", gc->ext.sgis_generate_mipmap);
|
|
// printf("GL EXT supported: GL_NV_texture_rectangle = %x\n", gc->ext.nv_texture_rectangle);
|
|
// printf("GL EXT supported: GL_ARB_texture_non_power_of_two = %x\n", gc->ext.arb_texture_non_power_of_two);
|
|
// this causes at least nvidia's drivers to go into pathological pain when
|
|
// changing textures a lot (doing video). so we wont do anything with this
|
|
// for now, but it does work.
|
|
// gc->ext.arb_texture_non_power_of_two = 0; printf("DISABLE GL_ARB_texture_non_power_of_two\n");
|
|
// gc->ext.nv_texture_rectangle = 0; printf("DISABLE GL_NV_texture_rectangle\n");
|
|
}
|
|
else
|
|
{
|
|
// printf("GL EXT supported: No extensions!!!!!\n");
|
|
}
|
|
|
|
if (gc->ext.arb_program)
|
|
{
|
|
gc->yuv422p.prog = glCreateProgramObjectARB();
|
|
// on an nv 6600gt this is fast - but on a 5500fx its DEAD SLOW!!!!!
|
|
// if (!gc->ext.arb_texture_non_power_of_two) return NULL;
|
|
/* BEGIN LEAK */
|
|
gc->yuv422p.fshad = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
|
|
{
|
|
const char *code =
|
|
"uniform sampler2D ytex, utex, vtex;\n"
|
|
"void main(void) {\n"
|
|
" float r, g, b, y, u, v;\n"
|
|
" y = texture2D(ytex, gl_TexCoord[0].st).r;\n"
|
|
" u = texture2D(utex, gl_TexCoord[0].st).r;\n"
|
|
" v = texture2D(vtex, gl_TexCoord[0].st).r;\n"
|
|
" y = (y - 0.0625) * 1.164;\n"
|
|
" u = u - 0.5;\n"
|
|
" v = v - 0.5;\n"
|
|
" r = y + (1.402 * v);\n"
|
|
" g = y - (0.34414 * u) - (0.71414 * v);\n"
|
|
" b = y + (1.772 * u);\n"
|
|
" gl_FragColor = vec4(r * gl_Color.r * gl_Color.a, g * gl_Color.g * gl_Color.a, b * gl_Color.b * gl_Color.a, gl_Color.a);\n"
|
|
"}\n";
|
|
glShaderSourceARB(gc->yuv422p.fshad, 1, &code, NULL);
|
|
}
|
|
glCompileShaderARB(gc->yuv422p.fshad);
|
|
glAttachObjectARB(gc->yuv422p.prog, gc->yuv422p.fshad);
|
|
/* END LEAK - something in the above leaks... beats me what. */
|
|
glLinkProgramARB(gc->yuv422p.prog);
|
|
|
|
glUseProgramObjectARB(gc->yuv422p.prog);
|
|
glUniform1iARB(glGetUniformLocationARB(gc->yuv422p.prog, "ytex"), 0);
|
|
glUniform1iARB(glGetUniformLocationARB(gc->yuv422p.prog, "utex"), 1);
|
|
glUniform1iARB(glGetUniformLocationARB(gc->yuv422p.prog, "vtex"), 2);
|
|
glUseProgramObjectARB(0);
|
|
}
|
|
|
|
gc->ext.checked = 1;
|
|
}
|
|
_evas_gl_common_context = gc;
|
|
_evas_gl_common_viewport_set(gc);
|
|
_evas_gl_common_dither_set(gc);
|
|
_evas_gl_common_blend_set(gc);
|
|
_evas_gl_common_color_set(gc);
|
|
_evas_gl_common_texture_set(gc);
|
|
_evas_gl_common_texture_set(gc);
|
|
_evas_gl_common_clip_set(gc);
|
|
_evas_gl_common_buf_set(gc);
|
|
_evas_gl_common_other_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_resize(Evas_GL_Context *gc, int w, int h)
|
|
{
|
|
//if ((gc->w == w) && (gc->h == h)) return;
|
|
gc->change.size = 1;
|
|
gc->w = w;
|
|
gc->h = h;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_viewport_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_color_set(Evas_GL_Context *gc, int r, int g, int b, int a)
|
|
{
|
|
if (r < 0) r = 0;
|
|
else if (r > 255) r = 255;
|
|
if (g < 0) g = 0;
|
|
else if (g > 255) g = 255;
|
|
if (b < 0) b = 0;
|
|
else if (b > 255) b = 255;
|
|
if (a < 0) a = 0;
|
|
else if (a > 255) a = 255;
|
|
if ((gc->r == r) && (gc->g == g) && (gc->b == b) && (gc->a == a)) return;
|
|
gc->change.color = 1;
|
|
gc->r = r;
|
|
gc->g = g;
|
|
gc->b = b;
|
|
gc->a = a;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_color_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_blend_set(Evas_GL_Context *gc, int blend)
|
|
{
|
|
if (blend == 1)
|
|
{
|
|
if (gc->blend) return;
|
|
gc->change.blend = 1;
|
|
gc->blend = 1;
|
|
gc->blend_alpha = 0;
|
|
}
|
|
else if (blend == 2)
|
|
{
|
|
if (gc->blend_alpha) return;
|
|
gc->change.blend = 1;
|
|
gc->blend = 0;
|
|
gc->blend_alpha = 1;
|
|
}
|
|
else
|
|
{
|
|
if ((!gc->blend) && (!gc->blend_alpha)) return;
|
|
gc->change.blend = 1;
|
|
gc->blend = 0;
|
|
gc->blend_alpha = 0;
|
|
}
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_blend_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_dither_set(Evas_GL_Context *gc, int dither)
|
|
{
|
|
if (((dither) && (gc->dither)) || ((!dither) && (!gc->dither))) return;
|
|
gc->change.dither = 1;
|
|
gc->dither = dither;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_dither_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_texture_set(Evas_GL_Context *gc, Evas_GL_Texture *tex, int smooth, int w, int h)
|
|
{
|
|
if (gc->font_texture > 0)
|
|
{
|
|
gc->font_texture = 0;
|
|
gc->change.texture = 1;
|
|
}
|
|
if (gc->texture != tex)
|
|
{
|
|
if (gc->texture) gc->texture->references--;
|
|
gc->texture = tex;
|
|
gc->change.texture = 1;
|
|
if (tex) tex->references++;
|
|
}
|
|
if (tex)
|
|
{
|
|
if (((smooth) && (!tex->smooth)) ||
|
|
((!smooth) && (tex->smooth)))
|
|
{
|
|
tex->smooth = smooth;
|
|
tex->changed = 1;
|
|
}
|
|
tex->uw = w;
|
|
tex->uh = h;
|
|
}
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_texture_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_font_texture_set(Evas_GL_Context *gc, Evas_GL_Font_Texture *ft)
|
|
{
|
|
if (gc->texture)
|
|
{
|
|
if (gc->texture) gc->texture->references--;
|
|
gc->texture = NULL;
|
|
gc->change.texture = 1;
|
|
}
|
|
if (gc->font_texture != ft->texture)
|
|
{
|
|
gc->font_texture = ft->texture;
|
|
gc->font_texture_rectangle = ft->pool->rectangle;
|
|
gc->change.texture = 1;
|
|
}
|
|
if (!gc->change.texture) return;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_texture_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_clip_set(Evas_GL_Context *gc, int on, int x, int y, int w, int h)
|
|
{
|
|
if (x < 0)
|
|
{
|
|
w += x;
|
|
x = 0;
|
|
}
|
|
if (y < 0)
|
|
{
|
|
h += y;
|
|
y = 0;
|
|
}
|
|
if (w < 0) w = 0;
|
|
if (h < 0) h = 0;
|
|
if (((!on) && (!gc->clip.active)) ||
|
|
((on) && (gc->clip.active) &&
|
|
(x == gc->clip.x) && (y == gc->clip.y) &&
|
|
(w == gc->clip.w) && (h == gc->clip.h)))
|
|
return;
|
|
gc->change.clip = 1;
|
|
gc->clip.active = on;
|
|
gc->clip.x = x;
|
|
gc->clip.y = y;
|
|
gc->clip.w = w;
|
|
gc->clip.h = h;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_clip_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_read_buf_set(Evas_GL_Context *gc, GLenum buf)
|
|
{
|
|
if (gc->read_buf == buf) return;
|
|
gc->change.buf = 1;
|
|
gc->read_buf = buf;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_buf_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_write_buf_set(Evas_GL_Context *gc, GLenum buf)
|
|
{
|
|
if (gc->write_buf == buf) return;
|
|
gc->change.buf = 1;
|
|
gc->write_buf = buf;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_buf_set(gc);
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_viewport_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.size) return;
|
|
glViewport(0, 0, gc->w, gc->h);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, gc->w, 0, gc->h, -1, 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glScalef(1, -1, 1);
|
|
glTranslatef(0, - gc->h, 0);
|
|
gc->change.size = 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_dither_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.dither) return;
|
|
if (gc->dither)
|
|
glEnable(GL_DITHER);
|
|
else
|
|
glDisable(GL_DITHER);
|
|
gc->change.dither = 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_blend_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.blend) return;
|
|
if (gc->blend_alpha)
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
else if (gc->blend)
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
else
|
|
glDisable(GL_BLEND);
|
|
gc->change.blend = 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_color_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.color) return;
|
|
glColor4d((double)gc->r / 255.0,
|
|
(double)gc->g / 255.0,
|
|
(double)gc->b / 255.0,
|
|
(double)gc->a / 255.0);
|
|
gc->change.color = 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_texture_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.texture) return;
|
|
if (gc->font_texture > 0)
|
|
{
|
|
glUseProgramObjectARB(0);
|
|
if (gc->texture_program)
|
|
{
|
|
glUseProgramObjectARB(0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glActiveTexture(GL_TEXTURE2);
|
|
glDisable(GL_TEXTURE_2D);
|
|
gc->texture_program = 0;
|
|
}
|
|
if (gc->font_texture_rectangle)
|
|
{
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_TEXTURE_RECTANGLE_NV);
|
|
glBindTexture(GL_TEXTURE_RECTANGLE_NV, gc->font_texture);
|
|
}
|
|
else
|
|
{
|
|
glActiveTexture(GL_TEXTURE0);
|
|
if (gc->ext.nv_texture_rectangle)
|
|
glDisable(GL_TEXTURE_RECTANGLE_NV);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, gc->font_texture);
|
|
}
|
|
}
|
|
else if (gc->texture)
|
|
{
|
|
if (gc->texture->rectangle)
|
|
{
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_TEXTURE_RECTANGLE_NV);
|
|
glBindTexture(GL_TEXTURE_RECTANGLE_NV, gc->texture->texture);
|
|
}
|
|
else
|
|
{
|
|
if (gc->ext.nv_texture_rectangle) glDisable(GL_TEXTURE_RECTANGLE_NV);
|
|
if ((gc->texture->prog) &&
|
|
(gc->texture->texture2) && (gc->texture->texture3))
|
|
{
|
|
gc->texture_program = 1;
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, gc->texture->texture);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, gc->texture->texture2);
|
|
|
|
glActiveTexture(GL_TEXTURE2);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, gc->texture->texture3);
|
|
glUseProgramObjectARB(gc->texture->prog);
|
|
}
|
|
else
|
|
{
|
|
if (gc->texture_program)
|
|
{
|
|
glUseProgramObjectARB(0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glActiveTexture(GL_TEXTURE2);
|
|
glDisable(GL_TEXTURE_2D);
|
|
gc->texture_program = 0;
|
|
}
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, gc->texture->texture);
|
|
glEnable(GL_TEXTURE_2D);
|
|
}
|
|
}
|
|
if (gc->texture->rectangle)
|
|
{
|
|
if (gc->texture->changed)
|
|
{
|
|
gc->texture->changed = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gc->texture->changed)
|
|
{
|
|
if (gc->texture->rectangle)
|
|
{
|
|
if (gc->texture->smooth)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gc->texture->smooth)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
// if (gc->texture->have_mipmaps)
|
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
// else
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
}
|
|
gc->texture->changed = 0;
|
|
}
|
|
}
|
|
}
|
|
else if (gc->font_texture == 0)
|
|
{
|
|
glDisable(GL_TEXTURE_2D);
|
|
if (gc->ext.nv_texture_rectangle) glDisable(GL_TEXTURE_RECTANGLE_NV);
|
|
}
|
|
gc->change.texture = 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_clip_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.clip) return;
|
|
/* might be faster using clip planes ??? glClipPlane() */
|
|
if (gc->clip.active)
|
|
{
|
|
glEnable(GL_SCISSOR_TEST);
|
|
glScissor(gc->clip.x,
|
|
gc->h - gc->clip.y - gc->clip.h,
|
|
gc->clip.w,
|
|
gc->clip.h);
|
|
}
|
|
else
|
|
glDisable(GL_SCISSOR_TEST);
|
|
gc->change.clip = 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_buf_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.buf) return;
|
|
glDrawBuffer(gc->write_buf);
|
|
glReadBuffer(gc->read_buf);
|
|
gc->change.buf = 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_other_set(Evas_GL_Context *gc)
|
|
{
|
|
if (!gc->change.other) return;
|
|
glShadeModel(GL_FLAT);
|
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
// glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
|
glDisable(GL_LINE_SMOOTH);
|
|
glDisable(GL_CULL_FACE);
|
|
glDepthMask(GL_FALSE);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
gc->change.other = 0;
|
|
}
|