Files
commandergenius/project/jni/gl4es/src/gl/gl.c
2016-11-06 22:07:01 +02:00

1503 lines
54 KiB
C
Executable File

#include "gl.h"
#include "debug.h"
#include "../glx/hardext.h"
#include "init.h"
glstate_t *glstate = NULL;
glstate_t *default_glstate = NULL;
void init_matrix(glstate_t* glstate);
void* NewGLState(void* shared_glstate) {
if(shared_glstate) {
glstate_t* glstate = (glstate_t*)shared_glstate;
glstate->shared_cnt++;
return (void*)glstate;
}
glstate_t *glstate = (glstate_t*)malloc(sizeof(glstate_t));
GLfloat white[] = {1.0f, 1.0f, 1.0f, 1.0f};
memset(glstate, 0, sizeof(glstate_t));
memcpy(glstate->color, white, sizeof(GLfloat)*4);
glstate->last_error = GL_NO_ERROR;
glstate->normal[3] = 1.0f; // default normal is 0/0/1
glstate->matrix_mode = GL_MODELVIEW;
// add default VBO
{
khint_t k;
int ret;
khash_t(buff) *list = glstate->buffers = kh_init(buff);
k = kh_put(buff, list, 0, &ret);
glbuffer_t *buff = kh_value(list, k) = malloc(sizeof(glbuffer_t));
buff->buffer = 0;
buff->type = 0;
buff->data = NULL;
buff->usage = GL_STATIC_DRAW;
buff->size = 0;
buff->access = GL_READ_WRITE;
buff->mapped = 0;
glstate->defaultvbo = buff;
}
// add default VAO
{
khint_t k;
int ret;
khash_t(glvao) *list = glstate->vaos = kh_init(glvao);
k = kh_put(glvao, list, 0, &ret);
glvao_t *glvao = kh_value(list, k) = malloc(sizeof(glvao_t));
// new vao is binded to default vbo
memset(glvao, 0, sizeof(glvao_t));
// just put is number
glvao->array = 0;
glstate->defaultvao = glvao;
}
// Bind defaults...
glstate->vao = glstate->defaultvao;
glstate->shared_cnt = 0;
glstate->gl_batch = globals4es.batch;
//raster & viewport
glstate->raster.raster_zoomx=1.0f;
glstate->raster.raster_zoomy=1.0f;
// init the matrix tracking
init_matrix(glstate);
for(int i=0; i<4; i++)
glstate->raster.raster_scale[i] = 1.0f;
LOAD_GLES(glGetFloatv);
gles_glGetFloatv(GL_VIEWPORT, (GLfloat*)&glstate->raster.viewport);
return (void*)glstate;
}
void DeleteGLState(void* oldstate) {
glstate_t* state = (glstate_t*)state;
if(!state) return;
if(state->shared_cnt) {
--state->shared_cnt;
return;
}
if(glstate == state)
glstate = NULL;
#define free_hashmap(T, N, K) \
{ \
T *m; \
kh_foreach_value(state->N, m, \
free(m); \
) \
kh_destroy(K, state->N); \
}
free_hashmap(glvao_t, vaos, glvao);
free_hashmap(glbuffer_t, buffers, buff);
free_hashmap(glquery_t, queries, queries);
free_hashmap(gltexture_t, texture.list, tex);
#undef free_hashmap
// free eval maps
#define freemap(dims, name) \
{ map_statef_t *m = (map_statef_t *)state->map##dims.name; \
if (m) { \
if (m->free) \
free((void *)m->points); \
free(m); \
} }
freemap(1, vertex3); freemap(1, vertex4); freemap(1, index); freemap(1, color4); freemap(1, normal);
freemap(1, texture1); freemap(1, texture2); freemap(1, texture3); freemap(1, texture4);
freemap(2, vertex3); freemap(2, vertex4); freemap(2, index); freemap(2, color4); freemap(2, normal);
freemap(2, texture1); freemap(2, texture2); freemap(2, texture3); freemap(2, texture4);
#undef freemap
// free lists
if(state->lists) {
for (int i=0; i<state->list.count; i++)
free_renderlist(state->lists[i]);
free(state->lists);
}
if(state->list.active) free_renderlist(state->list.active);
// free matrix stack
#define free_matrix(A) \
if (state->A) { \
free(state->A->stack); \
free(state->A); \
}
free_matrix(projection_matrix);
free_matrix(modelview_matrix);
for (int i=0; i<MAX_TEX; i++)
free_matrix(texture_matrix[i]);
free(glstate->texture_matrix);
#undef free_matrix
// probably missing some things to free here!
// all done
free(state);
return;
}
void ActivateGLState(void* new_glstate) {
if(glstate == (glstate_t*)new_glstate) return; // same state, nothing to do
if (glstate && glstate->gl_batch) flush();
glstate = (new_glstate)?(glstate_t*)new_glstate:default_glstate;
// check if viewport is correct
if(glstate->raster.viewport.width==0.0f || glstate->raster.viewport.height==0.0f) {
LOAD_GLES(glGetFloatv);
gles_glGetFloatv(GL_VIEWPORT, (GLfloat*)&glstate->raster.viewport);
}
if (globals4es.batch && glstate->init_batch==0) init_batch();
}
void gl_init() {
default_glstate = (glstate_t*)NewGLState(NULL);
ActivateGLState(default_glstate);
}
#ifndef GL_TEXTURE_STREAM_IMG
#define GL_TEXTURE_STREAM_IMG 0x8C0D
#endif
static void proxy_glEnable(GLenum cap, bool enable, void (*next)(GLenum)) {
#define proxy_enable(constant, name) \
case constant: glstate->enable.name = enable; next(cap); break
#define enable(constant, name) \
case constant: glstate->enable.name = enable; break;
#define proxy_clientenable(constant, name) \
case constant: glstate->vao->name = enable; next(cap); break
#define clientenable(constant, name) \
case constant: glstate->vao->name = enable; break;
// TODO: maybe could be weird behavior if someone tried to:
// 1. enable GL_TEXTURE_1D
// 2. enable GL_TEXTURE_2D
// 3. disable GL_TEXTURE_1D
// 4. render. GL_TEXTURE_2D would be disabled.
// cap = map_tex_target(cap);
// Alpha Hack
if (globals4es.alphahack && (cap==GL_ALPHA_TEST) && enable) {
if (glstate->texture.bound[glstate->texture.active])
if (!glstate->texture.bound[glstate->texture.active]->alpha)
enable = false;
}
noerrorShim();
#ifdef TEXSTREAM
if (cap==GL_TEXTURE_STREAM_IMG)
glstate->enable.texture_2d[glstate->texture.active] = enable;
#endif
switch (cap) {
enable(GL_AUTO_NORMAL, auto_normal);
proxy_enable(GL_BLEND, blend);
proxy_enable(GL_TEXTURE_2D, texture_2d[glstate->texture.active]);
enable(GL_TEXTURE_GEN_S, texgen_s[glstate->texture.active]);
enable(GL_TEXTURE_GEN_T, texgen_t[glstate->texture.active]);
enable(GL_TEXTURE_GEN_R, texgen_r[glstate->texture.active]);
enable(GL_TEXTURE_GEN_Q, texgen_q[glstate->texture.active]);
enable(GL_LINE_STIPPLE, line_stipple);
// point sprite
proxy_enable(GL_POINT_SPRITE, pointsprite);
// Secondary color
enable(GL_COLOR_SUM, color_sum);
clientenable(GL_SECONDARY_COLOR_ARRAY, secondary_array);
// for glDrawArrays
clientenable(GL_VERTEX_ARRAY, vertex_array);
clientenable(GL_NORMAL_ARRAY, normal_array);
clientenable(GL_COLOR_ARRAY, color_array);
clientenable(GL_TEXTURE_COORD_ARRAY, tex_coord_array[glstate->texture.client]);
// Texture 1D and 3D
enable(GL_TEXTURE_1D, texture_1d[glstate->texture.active]);
enable(GL_TEXTURE_3D, texture_3d[glstate->texture.active]);
default: errorGL(); next(cap); break;
}
#undef proxy_enable
#undef enable
#undef proxy_clientenable
#undef clientenable
}
int Cap2BatchState(GLenum cap) {
switch (cap) {
case GL_ALPHA_TEST: return ENABLED_ALPHA;
case GL_BLEND: return ENABLED_BLEND;
case GL_CULL_FACE: return ENABLED_CULL;
case GL_DEPTH_TEST: return ENABLED_DEPTH;
case GL_TEXTURE_2D: return ENABLED_TEX2D_TEX0
+(glstate->statebatch.active_tex_changed?glstate->statebatch.active_tex-GL_TEXTURE0:glstate->texture.active);
}
return ENABLED_LAST;
}
void gl4es_glEnable(GLenum cap) {
if (glstate->list.active && (glstate->gl_batch && !glstate->list.compiling)) {
int which_cap = Cap2BatchState(cap);
if (which_cap!=ENABLED_LAST) {
if ((glstate->statebatch.enabled[which_cap] == 1))
return; // nothing to do...
if (glstate->statebatch.enabled[which_cap])
flush();
glstate->statebatch.enabled[which_cap] = 1;
}
}
PUSH_IF_COMPILING(glEnable)
if (globals4es.texstream && (cap==GL_TEXTURE_2D)) {
if (glstate->texture.bound[glstate->texture.active])
if (glstate->texture.bound[glstate->texture.active]->streamed)
cap = GL_TEXTURE_STREAM_IMG;
}
LOAD_GLES(glEnable);
proxy_glEnable(cap, true, gles_glEnable);
}
void glEnable(GLenum cap) AliasExport("gl4es_glEnable");
void gl4es_glDisable(GLenum cap) {
if (glstate->list.active && (glstate->gl_batch && !glstate->list.compiling)) {
int which_cap = Cap2BatchState(cap);
if (which_cap!=ENABLED_LAST) {
if ((glstate->statebatch.enabled[which_cap] == 2))
return; // nothing to do...
if (glstate->statebatch.enabled[which_cap])
flush();
glstate->statebatch.enabled[which_cap] = 2;
}
}
PUSH_IF_COMPILING(glDisable)
if (globals4es.texstream && (cap==GL_TEXTURE_2D)) {
if (glstate->texture.bound[glstate->texture.active])
if (glstate->texture.bound[glstate->texture.active]->streamed)
cap = GL_TEXTURE_STREAM_IMG;
}
LOAD_GLES(glDisable);
proxy_glEnable(cap, false, gles_glDisable);
}
void glDisable(GLenum cap) AliasExport("gl4es_glDisable");
void gl4es_glEnableClientState(GLenum cap) {
// should flush for now... to be optimized later!
if (glstate->list.active && (glstate->gl_batch && !glstate->list.compiling))
flush();
LOAD_GLES(glEnableClientState);
proxy_glEnable(cap, true, gles_glEnableClientState);
}
void glEnableClientState(GLenum cap) AliasExport("gl4es_glEnableClientState");
void gl4es_glDisableClientState(GLenum cap) {
// should flush for now... to be optimized later!
if (glstate->list.active && (glstate->gl_batch && !glstate->list.compiling))
flush();
LOAD_GLES(glDisableClientState);
proxy_glEnable(cap, false, gles_glDisableClientState);
}
void glDisableClientState(GLenum cap) AliasExport("gl4es_glDisableClientState");
#define isenabled(what, where) \
case what: return glstate->enable.where
#define clientisenabled(what, where) \
case what: return glstate->vao->where
GLboolean gl4es_glIsEnabled(GLenum cap) {
// should flush for now... to be optimized later!
if (glstate->list.active && (glstate->gl_batch && !glstate->list.compiling))
flush();
LOAD_GLES(glIsEnabled);
noerrorShim();
switch (cap) {
isenabled(GL_AUTO_NORMAL, auto_normal);
isenabled(GL_LINE_STIPPLE, line_stipple);
isenabled(GL_TEXTURE_GEN_S, texgen_s[glstate->texture.active]);
isenabled(GL_TEXTURE_GEN_T, texgen_t[glstate->texture.active]);
isenabled(GL_TEXTURE_GEN_R, texgen_r[glstate->texture.active]);
isenabled(GL_TEXTURE_GEN_Q, texgen_q[glstate->texture.active]);
isenabled(GL_COLOR_SUM, color_sum);
isenabled(GL_POINT_SPRITE, pointsprite);
clientisenabled(GL_SECONDARY_COLOR_ARRAY, secondary_array);
isenabled(GL_TEXTURE_1D, texture_1d[glstate->texture.active]);
isenabled(GL_TEXTURE_3D, texture_3d[glstate->texture.active]);
clientisenabled(GL_VERTEX_ARRAY, vertex_array);
clientisenabled(GL_NORMAL_ARRAY, normal_array);
clientisenabled(GL_COLOR_ARRAY, color_array);
clientisenabled(GL_TEXTURE_COORD_ARRAY, tex_coord_array[glstate->texture.client]);
default:
errorGL();
return gles_glIsEnabled(cap);
}
}
#undef isenabled
#undef clientisenabled
GLboolean glIsEnabled(GLenum cap) AliasExport("gl4es_glIsEnabled");
static renderlist_t *arrays_to_renderlist(renderlist_t *list, GLenum mode,
GLsizei skip, GLsizei count) {
if (! list)
list = alloc_renderlist();
//if (glstate->list.compiling) LOGD("arrary_to_renderlist while compiling list, skip=%d, count=%d\n", skip, count);
list->mode = mode;
list->mode_init = mode;
list->len = count-skip;
list->cap = count-skip;
if (glstate->vao->vertex_array) {
list->vert = copy_gl_pointer_tex(&glstate->vao->pointers.vertex, 4, skip, count);
}
if (glstate->vao->color_array) {
list->color = copy_gl_pointer_color(&glstate->vao->pointers.color, 4, skip, count);
}
if (glstate->vao->secondary_array/* && glstate->enable.color_array*/) {
list->secondary = copy_gl_pointer(&glstate->vao->pointers.secondary, 4, skip, count); // alpha chanel is always 0 for secondary...
}
if (glstate->vao->normal_array) {
list->normal = copy_gl_pointer_raw(&glstate->vao->pointers.normal, 3, skip, count);
}
for (int i=0; i<hardext.maxtex; i++) {
if (glstate->vao->tex_coord_array[i]) {
list->tex[i] = copy_gl_pointer_tex(&glstate->vao->pointers.tex_coord[i], 4, skip, count);
}
}
return list;
}
static inline bool should_intercept_render(GLenum mode) {
// check bounded tex that will be used if one need some transformations
for (int aa=0; aa<hardext.maxtex; aa++) {
if (glstate->enable.texture_2d[aa] || glstate->enable.texture_1d[aa] || glstate->enable.texture_3d[aa]) {
if ((glstate->enable.texgen_s[aa] || glstate->enable.texgen_t[aa] || glstate->enable.texgen_r[aa] || glstate->enable.texgen_q[aa]))
return true;
}
}
if(glstate->polygon_mode == GL_LINE && mode>=GL_TRIANGLES)
return true;
if ((glstate->vao->secondary_array) && (glstate->vao->color_array))
return true;
if (glstate->vao->color_array && (glstate->vao->pointers.color.size != 4))
return true;
return (
(glstate->vao->vertex_array && ! valid_vertex_type(glstate->vao->pointers.vertex.type)) ||
(mode == GL_LINES && glstate->enable.line_stipple) ||
(mode == GL_QUADS) || (glstate->list.active && (glstate->list.compiling || glstate->gl_batch))
);
}
void gl4es_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
//printf("glDrawElements(%s, %d, %s, %p), vtx=%p map=%p\n", PrintEnum(mode), count, PrintEnum(type), indices, (glstate->vao->vertex)?glstate->vao->vertex->data:NULL, (glstate->vao->elements)?glstate->vao->elements->data:NULL);
// TODO: split for count > 65535?
// special check for QUADS and TRIANGLES that need multiple of 4 or 3 vertex...
if (mode == GL_QUADS) while(count%4) count--;
else if (mode == GL_TRIANGLES) while(count%3) count--;
if (count<0) {
errorShim(GL_INVALID_VALUE);
return;
}
if (count==0) {
noerrorShim();
return;
}
noerrorShim();
GLushort *sindices;
bool need_free = (type!=GL_UNSIGNED_SHORT);
if(need_free)
sindices = copy_gl_array((glstate->vao->elements)?glstate->vao->elements->data + (uintptr_t)indices:indices,
type, 1, 0, GL_UNSIGNED_SHORT, 1, 0, count);
else
sindices = (glstate->vao->elements)?(glstate->vao->elements->data + (uintptr_t)indices):(GLvoid*)indices;
bool compiling = (glstate->list.active && (glstate->list.compiling || glstate->gl_batch));
if (compiling) {
renderlist_t *list = NULL;
GLsizei min, max;
NewStage(glstate->list.active, STAGE_DRAW);
list = glstate->list.active;
if(need_free) {
normalize_indices(sindices, &max, &min, count);
list = arrays_to_renderlist(list, mode, min, max + 1);
list->indices = sindices;
} else {
getminmax_indices(sindices, &max, &min, count);
list = arrays_to_renderlist(list, mode, min, max + 1);
list->indices = copy_gl_array(sindices, type, 1, 0, GL_UNSIGNED_SHORT, 1, 0, count);
if(min) normalize_indices(list->indices, &max, &min, count);
}
list->ilen = count;
list->indice_cap = count;
//end_renderlist(list);
glstate->list.active = extend_renderlist(list);
return;
}
if (should_intercept_render(mode)) {
renderlist_t *list = NULL;
GLsizei min, max;
if(need_free) {
normalize_indices(sindices, &max, &min, count);
list = arrays_to_renderlist(list, mode, min, max + 1);
list->indices = sindices;
} else {
getminmax_indices(sindices, &max, &min, count);
list = arrays_to_renderlist(list, mode, min, max + 1);
list->indices = copy_gl_array(sindices, type, 1, 0, GL_UNSIGNED_SHORT, 1, 0, count);
if(min) normalize_indices(list->indices, &max, &min, count);
}
list->ilen = count;
list->indice_cap = count;
list = end_renderlist(list);
draw_renderlist(list);
free_renderlist(list);
return;
} else {
LOAD_GLES(glDrawElements);
LOAD_GLES(glNormalPointer);
LOAD_GLES(glVertexPointer);
LOAD_GLES(glColorPointer);
LOAD_GLES(glTexCoordPointer);
LOAD_GLES(glEnable);
LOAD_GLES(glDisable);
LOAD_GLES(glEnableClientState);
LOAD_GLES(glDisableClientState);
GLuint len = 0;
for (int i=0; i<count; i++)
if (len<sindices[i]) len = sindices[i]; // get the len of the arrays
len++; // lenght is max(indices) + 1 !
#define client_state(A, B, C) \
if(glstate->vao->A != glstate->clientstate.A) { \
C \
if((glstate->clientstate.A = glstate->vao->A)==true) \
gles_glEnableClientState(B); \
else \
gles_glDisableClientState(B); \
}
GLenum mode_init = mode;
/*if (glstate->polygon_mode == GL_LINE && mode>=GL_TRIANGLES)
mode = GL_LINE_LOOP;*/
if (glstate->polygon_mode == GL_POINT && mode>=GL_TRIANGLES)
mode = GL_POINTS;
if (mode == GL_QUAD_STRIP)
mode = GL_TRIANGLE_STRIP;
if (mode == GL_POLYGON)
mode = GL_TRIANGLE_FAN;
if (glstate->render_mode == GL_SELECT) {
select_glDrawElements(&glstate->vao->pointers.vertex, mode, count, GL_UNSIGNED_SHORT, sindices);
} else {
// secondry color and color sizef != 4 are "intercepted" and draw using a list
client_state(color_array, GL_COLOR_ARRAY, );
if (glstate->vao->color_array)
gles_glColorPointer(glstate->vao->pointers.color.size, glstate->vao->pointers.color.type, glstate->vao->pointers.color.stride, glstate->vao->pointers.color.pointer);
client_state(normal_array, GL_NORMAL_ARRAY, );
if (glstate->vao->normal_array)
gles_glNormalPointer(glstate->vao->pointers.normal.type, glstate->vao->pointers.normal.stride, glstate->vao->pointers.normal.pointer);
client_state(vertex_array, GL_VERTEX_ARRAY, );
if (glstate->vao->vertex_array)
gles_glVertexPointer(glstate->vao->pointers.vertex.size, glstate->vao->pointers.vertex.type, glstate->vao->pointers.vertex.stride, glstate->vao->pointers.vertex.pointer);
GLuint old_tex = glstate->texture.client;
#define TEXTURE(A) gl4es_glClientActiveTexture(A+GL_TEXTURE0);
for (int aa=0; aa<MAX_TEX; aa++) {
client_state(tex_coord_array[aa], GL_TEXTURE_COORD_ARRAY, TEXTURE(aa););
if (!glstate->enable.texture_2d[aa] && (glstate->enable.texture_1d[aa] || glstate->enable.texture_3d[aa])) {
TEXTURE(aa);
gles_glEnable(GL_TEXTURE_2D);
}
if (glstate->vao->tex_coord_array[aa]) {
TEXTURE(aa);
tex_setup_texcoord(len);
}
}
if (glstate->texture.client!=old_tex)
TEXTURE(old_tex);
// POLYGON mode as LINE is "intercepted" and drawn using list
gles_glDrawElements(mode, count, GL_UNSIGNED_SHORT, sindices);
for (int aa=0; aa<MAX_TEX; aa++) {
if (!glstate->enable.texture_2d[aa] && (glstate->enable.texture_1d[aa] || glstate->enable.texture_3d[aa])) {
TEXTURE(aa);
gles_glDisable(GL_TEXTURE_2D);
}
}
if (glstate->texture.client!=old_tex)
TEXTURE(old_tex);
#undef TEXTURE
}
if(need_free)
free(sindices);
}
}
void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) AliasExport("gl4es_glDrawElements");
void gl4es_glDrawArrays(GLenum mode, GLint first, GLsizei count) {
// special check for QUADS and TRIANGLES that need multiple of 4 or 3 vertex...
if (mode == GL_QUADS) while(count%4) count--;
else if (mode == GL_TRIANGLES) while(count%3) count--;
if (count<0) {
errorShim(GL_INVALID_VALUE);
return;
}
if (count==0) {
noerrorShim();
return;
}
// special case for (very) large GL_QUADS array
if ((mode==GL_QUADS) && (count>4*8000)) {
// split the array in manageable slice
int cnt = 4*8000;
for (int i=0; i<count; i+=4*8000) {
if (i+cnt>count) cnt = count-i;
gl4es_glDrawArrays(mode, i, cnt);
}
return;
}
noerrorShim();
LOAD_GLES(glNormalPointer);
LOAD_GLES(glVertexPointer);
LOAD_GLES(glColorPointer);
LOAD_GLES(glTexCoordPointer);
LOAD_GLES(glEnable);
LOAD_GLES(glDisable);
LOAD_GLES(glEnableClientState);
LOAD_GLES(glDisableClientState);
if (glstate->list.active && (glstate->list.compiling || glstate->gl_batch)) {
NewStage(glstate->list.active, STAGE_DRAW);
glstate->list.active = arrays_to_renderlist(glstate->list.active, mode, first, count+first);
glstate->list.active = extend_renderlist(glstate->list.active);
return;
}
/*if (glstate->polygon_mode == GL_LINE && mode>=GL_TRIANGLES)
mode = GL_LINE_LOOP;*/
if (glstate->polygon_mode == GL_POINT && mode>=GL_TRIANGLES)
mode = GL_POINTS;
if (should_intercept_render(mode)) {
renderlist_t *list;
list = arrays_to_renderlist(NULL, mode, first, count+first);
list = end_renderlist(list);
draw_renderlist(list);
free_renderlist(list);
} else {
LOAD_GLES(glDrawArrays);
GLenum mode_init = mode;
if (mode == GL_QUAD_STRIP)
mode = GL_TRIANGLE_STRIP;
if (mode == GL_POLYGON)
mode = GL_TRIANGLE_FAN;
if (glstate->render_mode == GL_SELECT) {
select_glDrawArrays(&glstate->vao->pointers.vertex, mode, first, count);
} else {
// setup the Array Pointers
client_state(color_array, GL_COLOR_ARRAY, );
if (glstate->vao->color_array)
gles_glColorPointer(glstate->vao->pointers.color.size, glstate->vao->pointers.color.type, glstate->vao->pointers.color.stride, glstate->vao->pointers.color.pointer);
client_state(normal_array, GL_NORMAL_ARRAY, );
if (glstate->vao->normal_array)
gles_glNormalPointer(glstate->vao->pointers.normal.type, glstate->vao->pointers.normal.stride, glstate->vao->pointers.normal.pointer);
client_state(vertex_array, GL_VERTEX_ARRAY, );
if (glstate->vao->vertex_array)
gles_glVertexPointer(glstate->vao->pointers.vertex.size, glstate->vao->pointers.vertex.type, glstate->vao->pointers.vertex.stride, glstate->vao->pointers.vertex.pointer);
GLuint old_tex = glstate->texture.client;
#define TEXTURE(A) gl4es_glClientActiveTexture(A+GL_TEXTURE0);
for (int aa=0; aa<MAX_TEX; aa++) {
client_state(tex_coord_array[aa], GL_TEXTURE_COORD_ARRAY, TEXTURE(aa););
if (!glstate->enable.texture_2d[aa] && (glstate->enable.texture_1d[aa] || glstate->enable.texture_3d[aa])) {
TEXTURE(aa);
gles_glEnable(GL_TEXTURE_2D);
}
if (glstate->vao->tex_coord_array[aa]) {
TEXTURE(aa);
tex_setup_texcoord(count+first);
/*glClientActiveTexture(aa+GL_TEXTURE0);
gles_glTexCoordPointer(glstate->pointers.tex_coord[aa].size, glstate->pointers.tex_coord[aa].type, glstate->pointers.tex_coord[aa].stride, glstate->pointers.tex_coord[aa].pointer);*/
}
}
if (glstate->texture.client!=old_tex)
TEXTURE(old_tex);
gles_glDrawArrays(mode, first, count);
for (int aa=0; aa<MAX_TEX; aa++) {
if (!glstate->enable.texture_2d[aa] && (glstate->enable.texture_1d[aa] || glstate->enable.texture_3d[aa])) {
TEXTURE(aa);
gles_glDisable(GL_TEXTURE_2D);
}
}
if (glstate->texture.client!=old_tex)
TEXTURE(old_tex);
#undef TEXTURE
}
}
}
#undef client_state
void glDrawArrays(GLenum mode, GLint first, GLsizei count) AliasExport("gl4es_glDrawArrays");
#ifndef USE_ES2
#define clone_gl_pointer(t, s)\
t.size = s; t.type = type; t.stride = stride; t.pointer = pointer + (uintptr_t)((glstate->vao->vertex)?glstate->vao->vertex->data:0)
void gl4es_glVertexPointer(GLint size, GLenum type,
GLsizei stride, const GLvoid *pointer) {
noerrorShim();
clone_gl_pointer(glstate->vao->pointers.vertex, size);
}
void gl4es_glColorPointer(GLint size, GLenum type,
GLsizei stride, const GLvoid *pointer) {
noerrorShim();
clone_gl_pointer(glstate->vao->pointers.color, size);
}
void gl4es_glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) {
noerrorShim();
clone_gl_pointer(glstate->vao->pointers.normal, 3);
}
void gl4es_glTexCoordPointer(GLint size, GLenum type,
GLsizei stride, const GLvoid *pointer) {
noerrorShim();
clone_gl_pointer(glstate->vao->pointers.tex_coord[glstate->texture.client], size);
}
void gl4es_glSecondaryColorPointer(GLint size, GLenum type,
GLsizei stride, const GLvoid *pointer) {
if (size!=3)
return; // Size must be 3...
clone_gl_pointer(glstate->vao->pointers.secondary, size);
noerrorShim();
}
#undef clone_gl_pointer
#endif
void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) AliasExport("gl4es_glVertexPointer");
void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) AliasExport("gl4es_glColorPointer");
void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) AliasExport("gl4es_glNormalPointer");
void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) AliasExport("gl4es_glTexCoordPointer");
void glSecondaryColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) AliasExport("gl4es_glSecondaryColorPointer");
void gl4es_glInterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer) {
uintptr_t ptr = (uintptr_t)pointer;
// element lengths
GLsizei tex=0, color=0, normal=0, vert=0;
// element formats
GLenum tf, cf, nf, vf;
tf = cf = nf = vf = GL_FLOAT;
noerrorShim();
switch (format) {
case GL_V2F: vert = 2; break;
case GL_V3F: vert = 3; break;
case GL_C4UB_V2F:
color = 4; cf = GL_UNSIGNED_BYTE;
vert = 2;
break;
case GL_C4UB_V3F:
color = 4; cf = GL_UNSIGNED_BYTE;
vert = 3;
break;
case GL_C3F_V3F:
color = 3;
vert = 4;
break;
case GL_N3F_V3F:
normal = 3;
vert = 3;
break;
case GL_C4F_N3F_V3F:
color = 4;
normal = 3;
vert = 3;
break;
case GL_T2F_V3F:
tex = 2;
vert = 3;
break;
case GL_T4F_V4F:
tex = 4;
vert = 4;
break;
case GL_T2F_C4UB_V3F:
tex = 2;
color = 4; cf = GL_UNSIGNED_BYTE;
vert = 3;
break;
case GL_T2F_C3F_V3F:
tex = 2;
color = 3;
vert = 3;
break;
case GL_T2F_N3F_V3F:
tex = 2;
normal = 3;
vert = 3;
break;
case GL_T2F_C4F_N3F_V3F:
tex = 2;
color = 4;
normal = 3;
vert = 3;
break;
case GL_T4F_C4F_N3F_V4F:
tex = 4;
color = 4;
normal = 3;
vert = 4;
break;
default:
errorShim(GL_INVALID_ENUM);
return;
}
if (!stride)
stride = tex * gl_sizeof(tf) +
color * gl_sizeof(cf) +
normal * gl_sizeof(nf) +
vert * gl_sizeof(vf);
if (tex) {
gl4es_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
gl4es_glTexCoordPointer(tex, tf, stride, (GLvoid *)ptr);
ptr += tex * gl_sizeof(tf);
}
if (color) {
gl4es_glEnableClientState(GL_COLOR_ARRAY);
gl4es_glColorPointer(color, cf, stride, (GLvoid *)ptr);
ptr += color * gl_sizeof(cf);
}
if (normal) {
gl4es_glEnableClientState(GL_NORMAL_ARRAY);
gl4es_glNormalPointer(nf, stride, (GLvoid *)ptr);
ptr += normal * gl_sizeof(nf);
}
if (vert) {
gl4es_glEnableClientState(GL_VERTEX_ARRAY);
gl4es_glVertexPointer(vert, vf, stride, (GLvoid *)ptr);
}
}
void glInterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer) AliasExport("gl4es_glInterleavedArrays");
// immediate mode functions
void gl4es_glBegin(GLenum mode) {
if (!glstate->list.active)
glstate->list.active = alloc_renderlist();
NewStage(glstate->list.active, STAGE_DRAW);
glstate->list.active->mode = mode;
glstate->list.active->mode_init = mode;
noerrorShim(); // TODO, check Enum validity
}
void glBegin(GLenum mode) AliasExport("gl4es_glBegin");
void gl4es_glEnd() {
if (!glstate->list.active) return;
// check if TEXTUREx is activate and no TexCoord (or texgen), in that case, create a dummy one base on glstate->..
for (int a=0; a<MAX_TEX; a++)
if (glstate->enable.texture_2d[a] && ((glstate->list.active->tex[a]==0) && !(glstate->enable.texgen_s[a] || glstate->texture.pscoordreplace[a])))
rlMultiTexCoord4f(glstate->list.active, GL_TEXTURE0+a, glstate->texcoord[a][0], glstate->texcoord[a][1], glstate->texcoord[a][2], glstate->texcoord[a][3]);
// render if we're not in a display list
if (!(glstate->list.compiling || glstate->gl_batch)) {
renderlist_t *mylist = glstate->list.active;
glstate->list.active = NULL;
mylist = end_renderlist(mylist);
draw_renderlist(mylist);
free_renderlist(mylist);
} else {
glstate->list.active = extend_renderlist(glstate->list.active);
}
noerrorShim();
}
void glEnd() AliasExport("gl4es_glEnd");
void gl4es_glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) {
if (glstate->list.active) {
if (glstate->list.active->stage != STAGE_DRAW) {
if (glstate->list.active->stage != STAGE_DRAW) {
if ((glstate->list.compiling || glstate->gl_batch) && glstate->list.active) {
glstate->list.active->lastNormal[0] = nx; glstate->list.active->lastNormal[1] = ny; glstate->list.active->lastNormal[2] = nz;
}
PUSH_IF_COMPILING(glNormal3f);
}
} else {
rlNormal3f(glstate->list.active, nx, ny, nz);
glstate->list.active->lastNormal[0] = nx; glstate->list.active->lastNormal[1] = ny; glstate->list.active->lastNormal[2] = nz;
noerrorShim();
}
}
#ifndef USE_ES2
else {
LOAD_GLES(glNormal3f);
gles_glNormal3f(nx, ny, nz);
errorGL();
}
#endif
glstate->normal[0] = nx; glstate->normal[1] = ny; glstate->normal[2] = nz;
}
void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) AliasExport("gl4es_glNormal3f");
void gl4es_glVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
if (glstate->list.active) {
rlVertex4f(glstate->list.active, x, y, z, w);
noerrorShim();
}
}
void glVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) AliasExport("gl4es_glVertex4f");
void gl4es_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
if (glstate->list.active) {
if (glstate->list.active->stage != STAGE_DRAW) {
glstate->list.active->lastColors[0] = red; glstate->list.active->lastColors[1] = green;
glstate->list.active->lastColors[2] = blue; glstate->list.active->lastColors[3] = alpha;
glstate->list.active->lastColorsSet = 1;
PUSH_IF_COMPILING(glColor4f);
}
rlColor4f(glstate->list.active, red, green, blue, alpha);
noerrorShim();
}
#ifndef USE_ES2
else {
LOAD_GLES(glColor4f);
gles_glColor4f(red, green, blue, alpha);
errorGL();
}
#endif
// change the state last thing
glstate->color[0] = red; glstate->color[1] = green;
glstate->color[2] = blue; glstate->color[3] = alpha;
}
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) AliasExport("gl4es_glColor4f");
void gl4es_glSecondaryColor3f(GLfloat r, GLfloat g, GLfloat b) {
if (glstate->list.active) {
rlSecondary3f(glstate->list.active, r, g, b);
glstate->list.active->lastSecondaryColors[0] = r; glstate->list.active->lastSecondaryColors[1] = g;
glstate->list.active->lastSecondaryColors[2] = b;
noerrorShim();
} else {
noerrorShim();
}
// change the state last thing
glstate->secondary[0] = r; glstate->secondary[1] = g;
glstate->secondary[2] = b;
}
void glSecondaryColor3f(GLfloat r, GLfloat g, GLfloat b) AliasExport("gl4es_glSecondaryColor3f");
#ifndef USE_ES2
void gl4es_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) {
LOAD_GLES(glMaterialfv);
if ((glstate->list.compiling || glstate->gl_batch) && glstate->list.active) {
//TODO: Materialfv can be done per vertex, how to handle that ?!
//NewStage(glstate->list.active, STAGE_MATERIAL);
rlMaterialfv(glstate->list.active, face, pname, params);
noerrorShim();
} else {
if (face!=GL_FRONT_AND_BACK) {
face=GL_FRONT_AND_BACK;
}
gles_glMaterialfv(face, pname, params);
errorGL();
}
}
void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) AliasExport("gl4es_glMaterialfv");
void gl4es_glMaterialf(GLenum face, GLenum pname, const GLfloat param) {
LOAD_GLES(glMaterialf);
if ((glstate->list.compiling || glstate->gl_batch) && glstate->list.active) {
GLfloat params[4];
memset(params, 0, 4*sizeof(GLfloat));
params[0] = param;
NewStage(glstate->list.active, STAGE_MATERIAL);
rlMaterialfv(glstate->list.active, face, pname, params);
noerrorShim();
} else {
if (face!=GL_FRONT_AND_BACK) {
face=GL_FRONT_AND_BACK;
}
gles_glMaterialf(face, pname, param);
errorGL();
}
}
void glMaterialf(GLenum face, GLenum pname, const GLfloat param) AliasExport("gl4es_glMaterialf");
#endif
void gl4es_glTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
if (glstate->list.active) {
rlTexCoord4f(glstate->list.active, s, t, r, q);
}
noerrorShim();
glstate->texcoord[0][0] = s; glstate->texcoord[0][1] = t;
glstate->texcoord[0][2] = r; glstate->texcoord[0][3] = q;
}
void glTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) AliasExport("gl4es_glTexCoord4f");
void gl4es_glMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) {
// TODO, error if target is unsuported texture....
if (glstate->list.active) {
rlMultiTexCoord4f(glstate->list.active, target, s, t, r, q);
}
noerrorShim();
glstate->texcoord[target-GL_TEXTURE0][0] = s; glstate->texcoord[target-GL_TEXTURE0][1] = t;
glstate->texcoord[target-GL_TEXTURE0][2] = r; glstate->texcoord[target-GL_TEXTURE0][3] = q;
}
void glMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) AliasExport("gl4es_glMultiTexCoord4f");
void glMultiTexCoord4fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) AliasExport("gl4es_glMultiTexCoord4f");
void gl4es_glArrayElement(GLint i) {
GLfloat *v;
pointer_state_t *p;
p = &glstate->vao->pointers.color;
if (glstate->vao->color_array) {
v = gl_pointer_index(p, i);
GLfloat scale = 1.0f/gl_max_value(p->type);
// color[3] defaults to 1.0f
if (p->size < 4)
v[3] = 1.0f;
// scale color coordinates to a 0 - 1.0 range
for (int i = 0; i < p->size; i++) {
v[i] *= scale;
}
gl4es_glColor4fv(v);
}
p = &glstate->vao->pointers.secondary;
if (glstate->vao->secondary_array) {
v = gl_pointer_index(p, i);
GLfloat scale = 1.0f/gl_max_value(p->type);
// scale color coordinates to a 0 - 1.0 range
for (int i = 0; i < p->size; i++) {
v[i] *= scale;
}
gl4es_glSecondaryColor3fv(v);
}
p = &glstate->vao->pointers.normal;
if (glstate->vao->normal_array) {
v = gl_pointer_index(p, i);
gl4es_glNormal3fv(v);
}
p = &glstate->vao->pointers.tex_coord[0];
if (glstate->vao->tex_coord_array[0]) {
v = gl_pointer_index(p, i);
if (p->size<4)
gl4es_glTexCoord2fv(v);
else
gl4es_glTexCoord4fv(v);
}
int a;
for (a=1; a<MAX_TEX; a++) {
p = &glstate->vao->pointers.tex_coord[a];
if (glstate->vao->tex_coord_array[a]) {
v = gl_pointer_index(p, i);
if (p->size<4)
gl4es_glMultiTexCoord2fv(GL_TEXTURE0+a, v);
else
gl4es_glMultiTexCoord4fv(GL_TEXTURE0+a, v);
}
}
p = &glstate->vao->pointers.vertex;
if (glstate->vao->vertex_array) {
v = gl_pointer_index(p, i);
if (p->size == 4) {
gl4es_glVertex4fv(v);
} else if (p->size == 3) {
gl4es_glVertex3fv(v);
} else {
gl4es_glVertex2fv(v);
}
}
}
void glArrayElement(GLint i) AliasExport("gl4es_glArrayElement");
// TODO: between a lock and unlock, I can assume the array pointers are unchanged
// so I can build a renderlist_t on the first call and hold onto it
// maybe I need a way to call a renderlist_t with (first, count)
void gl4es_glLockArrays(GLint first, GLsizei count) {
glstate->list.locked = true;
noerrorShim();
}
void glLockArraysEXT(GLint first, GLsizei count) AliasExport("gl4es_glLockArrays");
void gl4es_glUnlockArrays() {
glstate->list.locked = false;
noerrorShim();
}
void glUnlockArraysEXT() AliasExport("gl4es_glUnlockArrays");
// display lists
static renderlist_t *gl4es_glGetList(GLuint list) {
if (glIsList(list))
return glstate->lists[list - 1];
return NULL;
}
GLuint gl4es_glGenLists(GLsizei range) {
if (range<0) {
errorShim(GL_INVALID_VALUE);
return 0;
}
noerrorShim();
int start = glstate->list.count;
if (glstate->lists == NULL) {
glstate->list.cap += range + 100;
glstate->lists = malloc(glstate->list.cap * sizeof(uintptr_t));
} else if (glstate->list.count + range > glstate->list.cap) {
glstate->list.cap += range + 100;
glstate->lists = realloc(glstate->lists, glstate->list.cap * sizeof(uintptr_t));
}
glstate->list.count += range;
for (int i = 0; i < range; i++) {
glstate->lists[start+i] = NULL;
}
return start + 1;
}
GLuint glGenLists(GLsizei range) AliasExport("gl4es_glGenLists");
void gl4es_glNewList(GLuint list, GLenum mode) {
errorShim(GL_INVALID_VALUE);
if (list==0)
return;
if (! glIsList(list))
return;
noerrorShim();
if (glstate->gl_batch) {
glstate->gl_batch = 0;
flush();
}
glstate->list.name = list;
glstate->list.mode = mode;
// TODO: if glstate->list.active is already defined, we probably need to clean up here
glstate->list.active = alloc_renderlist();
glstate->list.compiling = true;
}
void glNewList(GLuint list, GLenum mode) AliasExport("gl4es_glNewList");
void gl4es_glEndList() {
noerrorShim();
GLuint list = glstate->list.name;
if (glstate->list.compiling) {
// Free the previous list if it exist...
free_renderlist(glstate->lists[list - 1]);
glstate->lists[list - 1] = GetFirst(glstate->list.active);
glstate->list.compiling = false;
end_renderlist(glstate->list.active);
glstate->list.active = NULL;
if (globals4es.batch==1) {
init_batch();
}
if (glstate->list.mode == GL_COMPILE_AND_EXECUTE) {
glCallList(list);
}
}
}
void glEndList() AliasExport("gl4es_glEndList");
renderlist_t* append_calllist(renderlist_t *list, renderlist_t *a);
void gl4es_glCallList(GLuint list) {
noerrorShim();
if ((glstate->list.compiling || glstate->gl_batch) && glstate->list.active) {
glstate->list.active = append_calllist(glstate->list.active, gl4es_glGetList(list));
return;
}
// TODO: the output of this call can be compiled into another display list
renderlist_t *l = gl4es_glGetList(list);
if (l)
draw_renderlist(l);
}
void glCallList(GLuint list) AliasExport("gl4es_glCallList");
void glPushCall(void *call) {
if ((glstate->list.compiling || glstate->gl_batch) && glstate->list.active) {
NewStage(glstate->list.active, STAGE_GLCALL);
rlPushCall(glstate->list.active, call);
}
}
void gl4es_glCallLists(GLsizei n, GLenum type, const GLvoid *lists) {
#define call(name, type) \
case name: glCallList(((type *)lists)[i] + glstate->list.base); break
// seriously wtf
#define call_bytes(name, stride) \
case name: \
l = (GLubyte *)lists; \
list = 0; \
for (j = 0; j < stride; j++) { \
list += *(l + (i * stride + j)) << (stride - j); \
} \
gl4es_glCallList(list + glstate->list.base); \
break
unsigned int i, j;
GLuint list;
GLubyte *l;
for (i = 0; i < n; i++) {
switch (type) {
call(GL_BYTE, GLbyte);
call(GL_UNSIGNED_BYTE, GLubyte);
call(GL_SHORT, GLshort);
call(GL_UNSIGNED_SHORT, GLushort);
call(GL_INT, GLint);
call(GL_UNSIGNED_INT, GLuint);
call(GL_FLOAT, GLfloat);
call_bytes(GL_2_BYTES, 2);
call_bytes(GL_3_BYTES, 3);
call_bytes(GL_4_BYTES, 4);
}
}
#undef call
#undef call_bytes
}
void glCallLists(GLsizei n, GLenum type, const GLvoid *lists) AliasExport("gl4es_glCallLists");
void gl4es_glDeleteList(GLuint list) {
if(glstate->gl_batch) {
flush();
}
renderlist_t *l = gl4es_glGetList(list);
if (l) {
free_renderlist(l);
glstate->lists[list-1] = NULL;
}
// lists just grow upwards, maybe use a better storage mechanism?
}
void gl4es_glDeleteLists(GLuint list, GLsizei range) {
noerrorShim();
for (int i = 0; i < range; i++) {
gl4es_glDeleteList(list+i);
}
}
void glDeleteLists(GLuint list, GLsizei range) AliasExport("gl4es_glDeleteLists");
void gl4es_glListBase(GLuint base) {
noerrorShim();
glstate->list.base = base;
}
void glListBase(GLuint base) AliasExport("gl4es_glListBase");
GLboolean gl4es_glIsList(GLuint list) {
noerrorShim();
if (list - 1 < glstate->list.count) {
return true;
}
return false;
}
GLboolean glIsList(GLuint list) AliasExport("gl4es_glIsList");
void gl4es_glPolygonMode(GLenum face, GLenum mode) {
noerrorShim();
if (face != GL_FRONT_AND_BACK)
errorShim(GL_INVALID_ENUM);
if (face == GL_BACK)
return; //TODO, handle face enum for polygon mode != GL_FILL
if ((glstate->list.compiling || glstate->gl_batch) && (glstate->list.active)) {
NewStage(glstate->list.active, STAGE_POLYGON);
glstate->list.active->polygon_mode = mode;
return;
}
switch(mode) {
case GL_LINE:
case GL_POINT:
glstate->polygon_mode = mode;
break;
case GL_FILL:
glstate->polygon_mode = 0;
break;
default:
glstate->polygon_mode = 0;
}
}
void glPolygonMode(GLenum face, GLenum mode) AliasExport("gl4es_glPolygonMode");
void gl4es_glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
PUSH_IF_COMPILING(glBlendColor);
LOAD_GLES_OES(glBlendColor);
if (gles_glBlendColor)
gles_glBlendColor(red, green, blue, alpha);
else {
static int test = 1;
if (test) {
LOGD("stub glBlendColor(%f, %f, %f, %f)\n", red, green, blue, alpha);
test = 0;
}
}
}
void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) AliasExport("gl4es_glBlendColor");
void glBlendColorEXT(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) AliasExport("gl4es_glBlendColor");
void glBlendColorARB(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) AliasExport("gl4es_glBlendColor");
void gl4es_glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)
{
PUSH_IF_COMPILING(glBlendFuncSeparate);
LOAD_GLES_OES(glBlendFuncSeparate);
#ifdef ODROID
if(gles_glBlendFuncSeparate)
#endif
gles_glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
}
void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) AliasExport("gl4es_glBlendFuncSeparate");
void glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) AliasExport("gl4es_glBlendFuncSeparate");
void gl4es_glBlendEquationSeparate(GLenum modeRGB, GLenum modeA) {
PUSH_IF_COMPILING(glBlendEquationSeparate);
LOAD_GLES_OES(glBlendEquationSeparate);
#ifdef ODROID
if(gles_glBlendEquationSeparate)
#endif
gles_glBlendEquationSeparate(modeRGB, modeA);
}
void glBlendEquationSeparate(GLenum modeRGB, GLenum modeA) AliasExport("gl4es_glBlendEquationSeparate");
void glBlendEquationSeparateEXT(GLenum modeRGB, GLenum modeA) AliasExport("gl4es_glBlendEquationSeparate");
void gl4es_glBlendFunc(GLenum sfactor, GLenum dfactor) {
if (glstate->list.active && (glstate->gl_batch && !glstate->list.compiling)) {
if ((glstate->statebatch.blendfunc_s == sfactor) && (glstate->statebatch.blendfunc_d == dfactor))
return; // nothing to do...
if (!glstate->statebatch.blendfunc_s) {
glstate->statebatch.blendfunc_s = sfactor;
glstate->statebatch.blendfunc_d = dfactor;
} else {
flush();
}
}
PUSH_IF_COMPILING(glBlendFunc);
LOAD_GLES(glBlendFunc);
LOAD_GLES_OES(glBlendFuncSeparate);
errorGL();
// There are some limitations in GLES1.1 Blend functions
switch(sfactor) {
case GL_SRC_COLOR:
if (gles_glBlendFuncSeparate) {
gles_glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
return;
}
sfactor = GL_ONE; // approx...
break;
case GL_ONE_MINUS_SRC_COLOR:
if (gles_glBlendFuncSeparate) {
gles_glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
return;
}
sfactor = GL_ONE; // not sure it make sense...
break;
// here, we need support for glBlendColor...
case GL_CONSTANT_COLOR:
case GL_CONSTANT_ALPHA:
sfactor = GL_ONE;
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
case GL_ONE_MINUS_CONSTANT_ALPHA:
sfactor = GL_ZERO;
break;
default:
break;
}
switch(dfactor) {
case GL_DST_COLOR:
sfactor = GL_ONE; // approx...
break;
case GL_ONE_MINUS_DST_COLOR:
sfactor = GL_ZERO; // not sure it make sense...
break;
// here, we need support for glBlendColor...
case GL_CONSTANT_COLOR:
case GL_CONSTANT_ALPHA:
sfactor = GL_ONE;
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
case GL_ONE_MINUS_CONSTANT_ALPHA:
sfactor = GL_ZERO;
break;
default:
break;
}
if ((globals4es.blendhack) && (sfactor==GL_SRC_ALPHA) && (dfactor==GL_ONE)) {
// special case, as seen in Xash3D, but it breaks torus_trooper, so behind a parameter
sfactor = GL_ONE;
}
#ifdef ODROID
if(gles_glBlendFunc)
#endif
gles_glBlendFunc(sfactor, dfactor);
}
void glBlendFunc(GLenum sfactor, GLenum dfactor) AliasExport("gl4es_glBlendFunc");
void gl4es_glStencilMaskSeparate(GLenum face, GLuint mask) {
// fake function..., call it only for front or front_and_back, just ignore back (crappy, I know)
if ((face==GL_FRONT) || (face==GL_FRONT_AND_BACK))
gl4es_glStencilMask(mask);
}
void glStencilMaskSeparate(GLenum face, GLuint mask) AliasExport("gl4es_glStencilMaskSeparate");
void init_statebatch() {
memset(&glstate->statebatch, 0, sizeof(statebatch_t));
}
void flush() {
// flush internal list
renderlist_t *mylist = glstate->list.active;
if (mylist) {
GLuint old = glstate->gl_batch;
glstate->list.active = NULL;
glstate->gl_batch = 0;
mylist = end_renderlist(mylist);
draw_renderlist(mylist);
free_renderlist(mylist);
glstate->gl_batch = old;
}
init_statebatch();
glstate->list.active = (glstate->gl_batch)?alloc_renderlist():NULL;
}
void init_batch() {
glstate->list.active = alloc_renderlist();
init_statebatch();
glstate->gl_batch = 1;
glstate->init_batch = 1;
}
#ifndef ANDROID
extern void BlitEmulatedPixmap();
#endif
void gl4es_glFlush() {
LOAD_GLES(glFlush);
if (glstate->list.active && !glstate->gl_batch) {
errorShim(GL_INVALID_OPERATION);
return;
}
if (glstate->gl_batch) flush();
gles_glFlush();
errorGL();
#ifndef ANDROID
if(glstate->emulatedPixmap && !glstate->emulatedWin)
BlitEmulatedPixmap();
#endif
}
void glFlush() AliasExport("gl4es_glFlush");
void gl4es_glFinish() {
LOAD_GLES(glFinish);
if (glstate->list.active && !glstate->gl_batch) {
errorShim(GL_INVALID_OPERATION);
return;
}
if (glstate->gl_batch) flush();
gles_glFinish();
errorGL();
}
void glFinish() AliasExport("gl4es_glFinish");
void gl4es_glFogfv(GLenum pname, const GLfloat* params) {
LOAD_GLES(glFogfv);
if ((glstate->list.compiling || glstate->gl_batch) && glstate->list.active) {
if (pname == GL_FOG_COLOR) {
NewStage(glstate->list.active, STAGE_FOG);
rlFogOp(glstate->list.active, 1, params);
return;
}
}
PUSH_IF_COMPILING(glFogfv);
gles_glFogfv(pname, params);
}
void glFogfv(GLenum pname, const GLfloat* params) AliasExport("gl4es_glFogfv");
void gl4es_glIndexPointer(GLenum type, GLsizei stride, const GLvoid * pointer) {
static bool warning = false;
if(!warning) {
LOGD("Warning, stubbed glIndexPointer\n");
warning = true;
}
}
void glIndexPointer(GLenum type, GLsizei stride, const GLvoid * pointer) AliasExport("gl4es_glIndexPointer");
void gl4es_glEdgeFlagPointer(GLsizei stride, const GLvoid * pointer) {
static bool warning = false;
if(!warning) {
LOGD("Warning, stubbed glEdgeFlagPointer\n");
warning = true;
}
}
void glEdgeFlagPointer(GLsizei stride, const GLvoid * pointer) AliasExport("gl4es_glEdgeFlagPointer");
void gl4es_glPointParameteri(GLenum pname, GLint param)
{
gl4es_glPointParameterf(pname, param);
}
void glPointParameteri(GLenum pname, GLint param) AliasExport("gl4es_glPointParameteri");
void gl4es_glPointParameteriv(GLenum pname, const GLint * params)
{
GLfloat tmp[3];
int v=(pname==GL_POINT_DISTANCE_ATTENUATION)?3:1;
for (int i=0; i<v; i++) tmp[i] = params[i];
gl4es_glPointParameterfv(pname, tmp);
}
void glPointParameteriv(GLenum pname, const GLint * params) AliasExport("gl4es_glPointParameteriv");
void gl4es_glMultiDrawArrays(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount)
{
LOAD_GLES_EXT(glMultiDrawArrays);
if((!gles_glMultiDrawArrays) || should_intercept_render(mode) || (glstate->list.active && (glstate->list.compiling || glstate->gl_batch))
|| (glstate->render_mode == GL_SELECT) || ((glstate->polygon_mode == GL_LINE) || (glstate->polygon_mode == GL_POINT)) )
{
// divide the call
// TODO optimize with forcing Batch mode
for (int i=0; i<primcount; i++)
gl4es_glDrawArrays(mode, first[i], count[i]);
}
else
{
if(mode==GL_QUAD_STRIP) mode=GL_TRIANGLE_STRIP;
else if(mode==GL_POLYGON) mode=GL_TRIANGLE_FAN;
gles_glMultiDrawArrays(mode, first, count, primcount);
errorGL();
}
}
void glMultiDrawArrays(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) AliasExport("gl4es_glMultiDrawArrays");
void gl4es_glMultiDrawElements( GLenum mode, GLsizei *count, GLenum type, const void * const *indices, GLsizei primcount)
{
LOAD_GLES_EXT(glMultiDrawElements);
if((!gles_glMultiDrawElements) || should_intercept_render(mode) || (glstate->list.active && (glstate->list.compiling || glstate->gl_batch))
|| (glstate->render_mode == GL_SELECT) || ((glstate->polygon_mode == GL_LINE) || (glstate->polygon_mode == GL_POINT)) || (type != GL_UNSIGNED_SHORT) )
{
// divide the call
// TODO optimize with forcing Batch mode
for (int i=0; i<primcount; i++)
gl4es_glDrawElements(mode, count[i], type, indices[i]);
}
else
{
if(mode==GL_QUAD_STRIP) mode=GL_TRIANGLE_STRIP;
else if(mode==GL_POLYGON) mode=GL_TRIANGLE_FAN;
gles_glMultiDrawElements(mode, count, type, indices, primcount);
errorGL();
}
}
void glMultiDrawElements( GLenum mode, GLsizei *count, GLenum type, const void * const *indices, GLsizei primcount) AliasExport("gl4es_glMultiDrawElements");