Files
questshock/android/gl4es-src/src/gl/list.c
T
ml d2dc58391b
build / build (push) Successful in 2m26s
Add controller input and a laser-pointer-driven menu quad
- xr_input.c/h: an OpenXR action set (aim pose, trigger/select click, a
  menu-toggle button) plus ray/quad hit-testing, and a visible
  laser-pointer line drawn from the controller toward the hit point.
- xr_menu.c/h + MenuOverlay.java: a second composition-layer quad,
  toggled by a controller button, showing an off-screen, never-attached
  Android View tree (one "Keyboard" button so far) driven by synthetic
  touch events computed from the laser ray's hit UV.
- Migrate gl4es from a prebuilt binary baked into the Docker build-image
  to a vendored source snapshot (android/gl4es-src/) compiled from
  source at APK build time via CMake add_subdirectory(), patched through
  a new android/gl4es-patches/ (mirrors the existing engine-patches/
  pattern). This was needed to track down and fix a bug hit while
  building the menu: gl4es's fixed-pipeline emulation (fpe.c) was
  unconditionally substituting its own shader onto the menu's draw call
  (fpe_ReleventState() always sets alphafunc to a nonzero sentinel, so
  its fpe_IsEmpty() check could never see the state as empty), making
  the menu quad show the game's own rendering instead of its own
  content. Fixed by routing the menu's blit through a real
  glBlitFramebuffer() call instead of a shader-based draw, which gl4es's
  fpe.c has nothing to intercept - documented in README.md's new
  "Debugging notes" section.
- Renumber android/engine-patches/ to close the gap left by removing an
  unrelated diagnostic-only patch, and strip investigation-journal
  comments and dead diagnostic code (temporary tracing, env-var probes)
  left over from finding the bug above.
- Restructure README.md into numbered sections, document every
  engine/gl4es patch, add Android Studio dev/testing-cycle instructions,
  and generalize Quest-specific wording to any OpenXR headset. Update
  NOTICE.txt to match (gl4es is now vendored/patched source, not a
  prebuilt binary; add the OpenXR-SDK loader).
2026-08-02 06:27:49 +02:00

972 lines
33 KiB
C

#include "list.h"
#include "../glx/hardext.h"
#include "const.h"
#include "gl4es.h"
#include "glstate.h"
#include "init.h"
#include "loader.h"
#include "buffers.h"
// KH Map implementation
KHASH_MAP_IMPL_INT(material, rendermaterial_t *);
KHASH_MAP_IMPL_INT(light, renderlight_t *);
KHASH_MAP_IMPL_INT(texgen, rendertexgen_t *);
KHASH_MAP_IMPL_INT(texenv, rendertexenv_t *);
KHASH_MAP_IMPL_INT(gllisthead, renderlist_t*);
renderlist_t *alloc_renderlist() {
renderlist_t *list = (renderlist_t *)malloc(sizeof(renderlist_t));
memset(list, 0, sizeof(renderlist_t));
list->cap = DEFAULT_RENDER_LIST_CAPACITY;
list->matrix_val[0] = list->matrix_val[5] = list->matrix_val[10] =
list->matrix_val[15] = 1.0f;
list->lightmodelparam = GL_LIGHT_MODEL_AMBIENT;
list->target_texture = GL_TEXTURE_2D;
list->tmu = glstate->texture.active;
memcpy(list->lastNormal, glstate->normal, 3*sizeof(GLfloat));
memcpy(list->lastSecondaryColors, glstate->secondary, 3*sizeof(GLfloat));
memcpy(list->lastColors, glstate->color, 4*sizeof(GLfloat));
memcpy(&list->lastFogCoord, glstate->fogcoord, 1*sizeof(GLfloat));
list->instanceCount = 1;
list->open = true;
return list;
}
bool ispurerender_renderlist(renderlist_t *list) {
// return true if renderlist contains only rendering command, no state changes
if (list->calls.len)
return false;
if (list->matrix_op)
return false;
if (list->raster_op)
return false;
if (list->raster)
return false;
if (list->bitmaps)
return false;
if (list->pushattribute)
return false;
if (list->popattribute)
return false;
if (list->material || list->colormat_face || list->light || list->lightmodel || list->texgen || list->texenv)
return false;
if (list->fog_op)
return false;
if (list->instanceCount!=1)
return false;
if (list->pointparam_op)
return false;
if (list->mode_init == 0)
return false;
if (list->ind_lines || list->final_colors)
return false;
if (list->set_texture || list->set_tmu)
return false;
return true;
}
bool isempty_renderlist(renderlist_t *list) {
return (list->stage == STAGE_NONE);
}
int rendermode_dimensions(GLenum mode) {
// return 1 for points, 2 for any lines, 3 for any triangles, 4 for any Quad and 5 for polygon
switch (mode) {
case GL_POINTS:
return 1;
case GL_LINES:
case GL_LINE_LOOP:
case GL_LINE_STRIP:
return 2;
case GL_TRIANGLES:
case GL_TRIANGLE_FAN:
case GL_TRIANGLE_STRIP:
return 3;
case GL_QUADS:
case GL_QUAD_STRIP:
return 3; // It's 4, but we use only triangles...
case GL_POLYGON:
return 3; // It's 5, but we use only triangles too.
}
return 0;
}
bool islistscompatible_renderlist(renderlist_t *a, renderlist_t *b) {
if (!globals4es.mergelist || !a)
return false;
// check if 2 "pure rendering" list are compatible for merge
if (a->mode_init != b->mode_init) {
int a_mode = a->mode_dimension;
int b_mode = b->mode_dimension;
if ((a_mode == 0) || (b_mode == 0))
return false; // undetermined is not good
if (a_mode == 4) a_mode = 3; // quads are handled as triangles
if (b_mode == 4) b_mode = 3;
if (a_mode != b_mode)
return false;
}
if(a->use_vbo_array==2 || b->use_vbo_array==2)
return false;
if(a->use_vbo_indices==2 || b->use_vbo_indices==2)
return false;
if(!a->open || !b->open)
return false;
if(a->use_glstate)
return false; //TODO: Handle this case
/* if ((a->indices==NULL) != (b->indices==NULL))
return false;*/
if (a->polygon_mode != b->polygon_mode)
return false;
if ((a->vert==NULL) != (b->vert==NULL))
return false;
if ((a->normal==NULL) != (b->normal==NULL))
return false;
if ((a->color==NULL) != (b->color==NULL))
return false;
if ((a->secondary==NULL) != (b->secondary==NULL))
return false;
if ((a->fogcoord==NULL) != (b->fogcoord==NULL))
return false;
// check the textures
if(a->maxtex!=b->maxtex)
return false;
for (int i=0; i<a->maxtex; i++)
if ((a->tex[i]==NULL) != (b->tex[i]==NULL))
return false;
if ((a->set_texture==b->set_texture) && ((a->texture != b->texture) || (a->target_texture != b->target_texture)))
return false;
if (!a->set_texture && b->set_texture)
return false;
// post color is only important if b as no color pointer...
if(a->post_color && b->color==NULL)
return false;
// same for post_normal
if(a->post_normal && b->normal==NULL)
return false;
// check instanceCount (maybe it would be better to just check if both are == 1)
if(a->instanceCount != b->instanceCount)
return false;
// Check the size of a list, if it"s too big, don't merge...
if ((a->len+b->len)>60000)
return false;
if ((a->ilen+b->ilen)>60000)
return false;
return true;
}
void renderlist_createindices(int ilen, GLushort *indices, int count) {
for (int i = 0; i<ilen; i++) {
indices[i] = i+count;
}
}
#define vind(a) (((ind)?ind[(a)]:(a))+count)
void renderlist_lineloop_lines(GLushort *ind, int len, GLushort *indices, int count) {
int ilen = len*2; // new size is 2* + return
if(len>1) {
int k=0;
indices[k++] = vind(0);
indices[k++] = vind(1);
for (int i = 2; i<len; i++) {
indices[k++] = vind(i-1);
indices[k++] = vind(i);
}
// go back to initial point
indices[k++] = indices[(len-1)*2-1];
indices[k++] = indices[0];
}
}
void renderlist_linestrip_lines(GLushort *ind, int len, GLushort *indices, int count) {
int ilen = len*2-2; // new size is 2*
if (ilen<1) ilen=0;
if(len>1) {
int k=0;
indices[k++] = vind(0);
indices[k++] = vind(1);
for (int i = 2; i<len; i++) {
indices[k++] = vind(i-1);
indices[k++] = vind(i);
}
}
}
void renderlist_trianglestrip_triangles(GLushort *ind, int len, GLushort *indices, int count) {
int ilen = (len-2)*3;
if (ilen<0) ilen=0;
for (int i = 2; i<len; i++) {
indices[(i-2)*3+(i%2)] = vind(i-2);
indices[(i-2)*3+1-(i%2)] = vind(i-1);
indices[(i-2)*3+2] = vind(i);
}
}
void renderlist_trianglefan_triangles(GLushort *ind, int len, GLushort *indices, int count) {
int ilen = (len-2)*3;
if (ilen<0) ilen=0;
for (int i = 2; i<len; i++) {
indices[(i-2)*3+0] = vind(0);
indices[(i-2)*3+1] = vind(i-1);
indices[(i-2)*3+2] = vind(i);
}
}
void renderlist_quads_triangles(GLushort *ind, int len, GLushort *indices, int count) {
// len must be a multiple of 4 !
len &= ~3; // discard extra vertex...
int ilen = len*3/2;
for (int i=0, j=0; i+3<len; i+=4, j+=6) {
indices[j+0] = vind(i+0);
indices[j+1] = vind(i+1);
indices[j+2] = vind(i+2);
indices[j+3] = vind(i+0);
indices[j+4] = vind(i+2);
indices[j+5] = vind(i+3);
}
}
#undef vind
#define vind(a) ((ind)?ind[(a)]:(a))
void renderlist_quads2triangles(renderlist_t *a) {
GLushort *ind = a->indices;
int len = (ind)? a->ilen:a->len;
// len must be a multiple of 4 !
len &= ~3; // discard extra vertex...
int ilen = len*3/2;
if(a->use_glstate) {
if(ind) {//need to copy first...
ind = (GLushort*)malloc(len*sizeof(GLushort));
memcpy(ind, glstate->merger_indices, len*sizeof(GLushort));
a->shared_indices = NULL; // should not be needed
}
resize_merger_indices(ilen);
a->indices = glstate->merger_indices;
} else
a->indices = (GLushort*)malloc(ilen*sizeof(GLushort));
for (int i=0, j=0; i+3<len; i+=4, j+=6) {
a->indices[j+0] = vind(i+0);
a->indices[j+1] = vind(i+1);
a->indices[j+2] = vind(i+2);
a->indices[j+3] = vind(i+0);
a->indices[j+4] = vind(i+2);
a->indices[j+5] = vind(i+3);
}
a->ilen = ilen;
if (ind) {
if (!a->shared_indices || ((*a->shared_indices)--)==0) {
free(ind);
free(a->shared_indices);
}
a->shared_indices = NULL; // unshared list
}
a->mode = GL_TRIANGLES;
}
#undef vind
int indices_getindicesize(GLenum mode, int len) {
int ilen_a;
switch (mode) {
case GL_LINE_LOOP:
ilen_a = len*2;
if (ilen_a<0) ilen_a=1; // special borked case...
break;
case GL_LINE_STRIP:
ilen_a = (len*2)-2;
if (ilen_a<0) ilen_a=1; // special borked case...
break;
case GL_QUAD_STRIP:
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
case GL_POLYGON:
ilen_a = (len-2)*3;
if (ilen_a<0) ilen_a=1; // special borked case...
break;
case GL_QUADS:
ilen_a = ((len&~3)*3)/2;
break;
default:
ilen_a = len;
break;
}
return ilen_a;
}
int renderlist_getindicesize(renderlist_t *a) {
int ilen_a = indices_getindicesize(a->mode, ((a->indices)? a->ilen:a->len));
return ilen_a;
}
int mode_needindices(GLenum m) {
switch(m) {
case GL_LINE_LOOP:
case GL_LINE_STRIP:
case GL_TRIANGLE_FAN:
case GL_TRIANGLE_STRIP:
case GL_QUAD_STRIP:
case GL_POLYGON:
//case GL_QUADS: // not needed, but will appens anyway
return 1;
default:
return 0;
}
}
void list_add_modeinit(renderlist_t* list, GLenum mode) {
if (list->mode_init_len+1 >= list->mode_init_cap) {
list->mode_init_cap+=128;
list->mode_inits = (modeinit_t*)realloc(list->mode_inits, list->mode_init_cap*sizeof(modeinit_t));
}
list->mode_inits[list->mode_init_len].mode_init = mode;
list->mode_inits[list->mode_init_len++].ilen = list->indices?list->ilen:(list->cur_istart?list->cur_istart:list->len);
}
void unshared_renderlist(renderlist_t *a, int cap) {
if(a->shared_arrays && ((*a->shared_arrays)--)>0) {
a->cap = cap;
GLfloat *tmp;
tmp = a->vert;
if (tmp) {
a->vert = alloc_sublist(4, cap);
memcpy(a->vert, tmp, 4*a->len*sizeof(GLfloat));
}
tmp = a->normal;
if (tmp) {
a->normal = alloc_sublist(3, cap);
memcpy(a->normal, tmp, 3*a->len*sizeof(GLfloat));
}
tmp = a->color;
if (tmp) {
a->color = alloc_sublist(4, cap);
memcpy(a->color, tmp, 4*a->len*sizeof(GLfloat));
}
tmp = a->secondary;
if (tmp) {
a->secondary = alloc_sublist(4, cap);
memcpy(a->secondary, tmp, 4*a->len*sizeof(GLfloat));
}
tmp = a->fogcoord;
if (tmp) {
a->fogcoord = alloc_sublist(1, cap);
memcpy(a->fogcoord, tmp, 1*a->len*sizeof(GLfloat));
}
for (int i=0; i<a->maxtex; i++) {
tmp = a->tex[i];
if (tmp) {
a->tex[i] = alloc_sublist(4, cap);
memcpy(a->tex[i], tmp, 4*a->len*sizeof(GLfloat));
}
}
}
if(a->shared_arrays && (*a->shared_arrays)==0) {
free(a->shared_arrays);
a->shared_arrays=NULL;
}
}
void unsharedindices_renderlist(renderlist_t* a, int cap)
{
if (a->shared_indices && ((*a->shared_indices)--)>0) {
if (a->indices) {
GLushort* tmpi = a->indices;
a->indice_cap = cap;
if (a->indice_cap > 48) a->indice_cap = ((a->indice_cap+512)>>9)<<9;
a->indices = (GLushort*)malloc(a->indice_cap*sizeof(GLushort));
memcpy(a->indices, tmpi, a->ilen*sizeof(GLushort));
}
}
if(a->shared_indices && (*a->shared_indices)==0) {
free(a->shared_indices);
a->shared_indices=0;
}
}
void redim_renderlist(renderlist_t *a, int cap) {
if (a->cap < cap) {
a->cap = cap;
realloc_sublist(a->vert, 4, cap);
realloc_sublist(a->normal, 3, cap);
realloc_sublist(a->color, 4, cap);
realloc_sublist(a->secondary, 4, cap);
realloc_sublist(a->fogcoord, 1, cap);
for (int i=0; i<a->maxtex; i++)
realloc_sublist(a->tex[i], 4, cap);
}
}
void prepareadd_renderlist(renderlist_t* a, int size_to_add)
{
// alloc or realloc a->indices first...
int capindices = renderlist_getindicesize(a)+size_to_add;
if (capindices > 48) capindices = ((capindices+512)>>9)<<9;
#define alloc_a_indices \
newind=(GLushort*)malloc(capindices*sizeof(GLushort))
#define copy_a_indices \
if (a->indices) free(a->indices); \
a->indices = newind; \
a->indice_cap = capindices
// check if "a" needs to be converted
int ilen_a = renderlist_getindicesize(a);
GLushort *newind=NULL;
switch (a->mode) {
case GL_LINE_LOOP:
alloc_a_indices;
renderlist_lineloop_lines(a->indices, a->indices?a->ilen:a->len, newind, 0);
a->mode = GL_LINES;
copy_a_indices;
break;
case GL_LINE_STRIP:
alloc_a_indices;
renderlist_linestrip_lines(a->indices, a->indices?a->ilen:a->len, newind, 0);
a->mode = GL_LINES;
copy_a_indices;
break;
case GL_QUAD_STRIP:
case GL_TRIANGLE_STRIP:
alloc_a_indices;
renderlist_trianglestrip_triangles(a->indices, a->indices?a->ilen:a->len, newind, 0);
a->mode = GL_TRIANGLES;
copy_a_indices;
break;
case GL_TRIANGLE_FAN:
case GL_POLYGON:
alloc_a_indices;
renderlist_trianglefan_triangles(a->indices, a->indices?a->ilen:a->len, newind, 0);
a->mode = GL_TRIANGLES;
copy_a_indices;
break;
case GL_QUADS:
alloc_a_indices;
renderlist_quads_triangles(a->indices, a->indices?a->ilen:a->len, newind, 0);
a->mode = GL_TRIANGLES;
copy_a_indices;
break;
default:
if (!a->indices) {
// no a->indices, must alloc and fill one
alloc_a_indices;
renderlist_createindices(a->len, newind, 0);
copy_a_indices;
} else {
// a->indices already exist, just check if need to adjust its size
if (a->indice_cap < capindices) {
a->indices = (GLushort*)realloc(a->indices, capindices*sizeof(GLushort));
a->indice_cap = capindices;
}
}
break;
}
#undef copy_a_indices
#undef alloc_a_indices
a->ilen = ilen_a;
}
void doadd_renderlist(renderlist_t* a, GLenum mode, GLushort* indices, int count, int size_to_add)
{
// then append b
switch (mode) {
case GL_LINE_LOOP:
renderlist_lineloop_lines(indices, count, a->indices + a->ilen, a->len);
break;
case GL_LINE_STRIP:
renderlist_linestrip_lines(indices, count, a->indices + a->ilen, a->len);
break;
case GL_QUAD_STRIP:
case GL_TRIANGLE_STRIP:
renderlist_trianglestrip_triangles(indices, count, a->indices + a->ilen, a->len);
break;
case GL_POLYGON:
case GL_TRIANGLE_FAN:
renderlist_trianglefan_triangles(indices, count, a->indices + a->ilen, a->len);
break;
case GL_QUADS:
renderlist_quads_triangles(indices, count, a->indices + a->ilen, a->len);
break;
default:
// no transform here, just take (or create) the indice list as-is
if (!indices) {
// append a newly created indice list
renderlist_createindices(count, a->indices + a->ilen, a->len);
} else {
// append existing one
GLushort* newind = a->indices+a->ilen;
for(int i=0; i<count; i++)
newind[i] = indices[i]+a->len;
}
break;
}
a->ilen += size_to_add;
}
void append_renderlist(renderlist_t *a, renderlist_t *b) {
// append all draw elements of b in a
// check the final indice size of a and b
int ilen_a = a->ilen;
int ilen_b = b->ilen;
// lets append all the arrays
unsigned long cap = a->cap;
if (a->len + b->len >= cap) cap += b->cap + DEFAULT_RENDER_LIST_CAPACITY;
// Unshare if shared (shared array are not used for now)
unshared_renderlist(a, cap);
redim_renderlist(a, cap);
unsharedindices_renderlist(a, ((ilen_a)?ilen_a:a->len) + ((ilen_b)?ilen_b:b->len));
// append arrays
if (a->vert) memcpy(a->vert+a->len*4, b->vert, b->len*4*sizeof(GLfloat));
if (a->normal) memcpy(a->normal+a->len*3, b->normal, b->len*3*sizeof(GLfloat));
if (a->color) memcpy(a->color+a->len*4, b->color, b->len*4*sizeof(GLfloat));
if (a->secondary) memcpy(a->secondary+a->len*4, b->secondary, b->len*4*sizeof(GLfloat));
if (a->fogcoord) memcpy(a->fogcoord+a->len*1, b->fogcoord, b->len*1*sizeof(GLfloat));
for (int i=0; i<a->maxtex; i++)
if (a->tex[i]) memcpy(a->tex[i]+a->len*4, b->tex[i], b->len*4*sizeof(GLfloat));
// indices
if(!a->mode_inits) list_add_modeinit(a, a->mode_init);
if (ilen_a || ilen_b || mode_needindices(a->mode) || mode_needindices(b->mode)
|| (a->mode!=b->mode && (a->mode==GL_QUADS || b->mode==GL_QUADS)) )
{
// alloc or realloc a->indices first...
ilen_b = renderlist_getindicesize(b);
prepareadd_renderlist(a, ilen_b);
// then append b
doadd_renderlist(a, b->mode, b->indices, b->indices?b->ilen:b->len, ilen_b);
}
// lenghts
a->len += b->len;
if(a->mode_inits) list_add_modeinit(a, b->mode);
// copy the lastColors if needed
if(b->lastColorsSet) {
a->lastColorsSet = 1;
memcpy(a->lastColors, b->lastColors, 4*sizeof(GLfloat));
}
if(b->post_color) {
a->post_color = 1;
memcpy(a->post_colors, b->post_colors, 4*sizeof(GLfloat));
}
if(b->post_normal) {
a->post_normal = 1;
memcpy(a->post_normals, b->post_normals, 3*sizeof(GLfloat));
}
//all done
a->stage = STAGE_DRAW; // just in case
return;
}
void adjust_renderlist(renderlist_t *list);
renderlist_t *extend_renderlist(renderlist_t *list) {
if ((list->prev!=NULL) && ispurerender_renderlist(list) && islistscompatible_renderlist(list->prev, list)) {
// append list!
append_renderlist(list->prev, list);
renderlist_t *new = alloc_renderlist();
new->prev = list->prev;
list->prev->next = new;
// just in case
memcpy(new->lastNormal, list->lastNormal, 3*sizeof(GLfloat));
memcpy(new->lastSecondaryColors, list->lastSecondaryColors, 3*sizeof(GLfloat));
memcpy(new->lastColors, list->lastColors, 4*sizeof(GLfloat));
new->lastColorsSet = list->lastColorsSet;
// detach
list->prev = NULL;
// free list now
free_renderlist(list);
return new;
} else {
renderlist_t *new = alloc_renderlist();
list->next = new;
new->prev = list;
new->tmu = list->tmu;
// copy local state
memcpy(new->lastNormal, list->lastNormal, 3*sizeof(GLfloat));
memcpy(new->lastSecondaryColors, list->lastSecondaryColors, 3*sizeof(GLfloat));
memcpy(new->lastColors, (list->post_color)?list->post_colors:list->lastColors, 4*sizeof(GLfloat));
new->lastColorsSet = (list->post_color || list->lastColorsSet)?1:0;
return new;
}
}
renderlist_t* append_calllist(renderlist_t *list, renderlist_t *a)
{
// go to end of list
while(list->next) list = list->next;
while(a) {
if(ispurerender_renderlist(a) && islistscompatible_renderlist(list, a)) {
// append list!
append_renderlist(list, a);
} else {
// create a new appended list
renderlist_t *new = alloc_renderlist();
// prepared shared stuff...
if(a->len && !a->shared_arrays) {
a->shared_arrays = (int*)malloc(sizeof(int));
*a->shared_arrays = 0;
}
if(a->ilen && !a->shared_indices) {
a->shared_indices = (int*)malloc(sizeof(int));
*a->shared_indices = 0;
}
if(a->calls.len && !a->shared_calls) {
a->shared_calls = (int*)malloc(sizeof(int));
*a->shared_calls = 0;
}
// batch copy first
memcpy(new, a, sizeof(renderlist_t));
list->next = new;
new->prev = list;
// ok, now on new list
list = new;
// copy the many list arrays
if (list->calls.len > 0) {
++(*list->shared_calls);
/*
list->calls.calls = (packed_call_t**)malloc(sizeof(packed_call_t*)*a->calls.cap);
for (int i = 0; i < list->calls.len; i++) {
list->calls.calls[i] = glCopyPackedCall(a->calls.calls[i]);
}*/
}
if(list->len) {
++(*list->shared_arrays);
}
if(list->ilen) {
++(*list->shared_indices);
}
#define PROCESS(W, T, C) if(list->W) { \
list->W = kh_init(W); \
T *m, *m2; \
khint_t k; \
int ret; \
kh_foreach_value(a->W, m, \
k = kh_put(W, list->W, C, &ret); \
m2= kh_value(list->W, k) = malloc(sizeof(T)); \
memcpy(m2, m, sizeof(T)); \
); \
}
PROCESS(material, rendermaterial_t, m->pname);
PROCESS(light, renderlight_t, m->pname | ((m->which-GL_LIGHT0)<<16));
PROCESS(texgen, rendertexgen_t, m->pname | ((m->coord-GL_S)<<16));
PROCESS(texenv, rendertexenv_t, m->pname | ((m->target)<<16));
#undef PROCESS
if (list->lightmodel) {
list->lightmodel = (GLfloat*)malloc(4*sizeof(GLfloat));
memcpy(list->lightmodel, a->lightmodel, 4*sizeof(GLfloat));
}
if (list->raster) {
(*list->raster->shared)++;
}
if (list->bitmaps) {
(*list->bitmaps->shared)++;
}
}
a = a->next;
}
return list;
}
void free_renderlist(renderlist_t *list) {
// test if list is NULL
if (list == NULL)
return;
// we want the first list in the chain
while (list->prev)
list = list->prev;
renderlist_t *next;
do {
if(list->mode_inits)
free(list->mode_inits);
if ((list->calls.len > 0) && (!list->shared_calls || ((*list->shared_calls)--)==0)) {
if(list->shared_calls) free(list->shared_calls);
for (int i = 0; i < list->calls.len; i++) {
free(list->calls.calls[i]);
}
free(list->calls.calls);
}
int a;
if(!list->use_glstate) {
if (!list->shared_arrays || ((*list->shared_arrays)--)==0) {
if (list->shared_arrays) free(list->shared_arrays);
if (list->vert) free(list->vert);
if (list->normal) free(list->normal);
if (list->color) free(list->color);
if (list->secondary) free(list->secondary);
if (list->fogcoord) free(list->fogcoord);
for (a=0; a<list->maxtex; a++)
if (list->tex[a]) free(list->tex[a]);
}
if (!list->shared_indices || ((*list->shared_indices)--)==0) {
if (list->shared_indices) free(list->shared_indices);
if (list->indices)
free(list->indices);
}
} else
glstate->merger_used = 0;
if (list->material) {
rendermaterial_t *m;
kh_foreach_value(list->material, m,
free(m);
)
kh_destroy(material, list->material);
}
if (list->light) {
renderlight_t *m;
kh_foreach_value(list->light, m,
free(m);
)
kh_destroy(light, list->light);
}
if (list->texgen) {
rendertexgen_t *m;
kh_foreach_value(list->texgen, m,
free(m);
)
kh_destroy(texgen, list->texgen);
}
if (list->texenv) {
rendertexenv_t *m;
kh_foreach_value(list->texenv, m,
free(m);
)
kh_destroy(texenv, list->texenv);
}
if (list->lightmodel)
free(list->lightmodel);
if (list->raster && !((*list->raster->shared)--)) {
if (list->raster->texture)
gl4es_glDeleteTextures(1, &list->raster->texture);
free(list->raster->shared);
free(list->raster);
}
if(list->bitmaps && !((*list->bitmaps->shared)--)) {
for(int i=0; i<list->bitmaps->count; i++)
if(list->bitmaps->list[i].bitmap)
free(list->bitmaps->list[i].bitmap);
free(list->bitmaps->list);
free(list->bitmaps->shared);
free(list->bitmaps);
}
if(list->ind_lines)
free(list->ind_lines);
if(list->final_colors)
free(list->final_colors);
if(list->vbo_array)
deleteSingleBuffer(list->vbo_array);
if(list->vbo_indices)
deleteSingleBuffer(list->vbo_indices);
next = list->next;
free(list);
} while ((list = next));
}
void resize_renderlist(renderlist_t *list) {
if (list->use_glstate) {
if (list->len >= glstate->merger_cap) {
glstate->merger_cap += DEFAULT_RENDER_LIST_CAPACITY*8;
realloc_merger_sublist(glstate->merger_master, 4*5, glstate->merger_cap);
realloc_sublist(glstate->merger_secondary, 4, glstate->merger_cap);
for (int a=2; a<list->maxtex; a++)
realloc_sublist(glstate->merger_tex[a-2], 4, glstate->merger_cap);
if(list->vert) list->vert = glstate->merger_master;
if(list->normal) list->normal = glstate->merger_master+4+4+2*4;
if(list->color) list->color = glstate->merger_master+4;
if(list->tex[0]) list->tex[0] = glstate->merger_master+4+4;
if(list->tex[1]) list->tex[1] = glstate->merger_master+4+4+4;
if(list->fogcoord) list->fogcoord = glstate->merger_master+4+4+2*4+3;
if(list->secondary) list->secondary = glstate->merger_secondary;
for (int a=2; a<list->maxtex; a++)
if(list->tex[a]) list->tex[a] = glstate->merger_tex[a-2];
}
} else {
if (list->len >= list->cap) {
list->cap += DEFAULT_RENDER_LIST_CAPACITY*8;
realloc_sublist(list->vert, 4, list->cap);
realloc_sublist(list->normal, 3, list->cap);
realloc_sublist(list->color, 4, list->cap);
realloc_sublist(list->secondary, 4, list->cap);
realloc_sublist(list->fogcoord, 1, list->cap);
for (int a=0; a<list->maxtex; a++)
realloc_sublist(list->tex[a], 4, list->cap);
}
}
}
void resize_merger_indices(int cap) {
if(cap<glstate->merger_indice_cap)
return;
glstate->merger_indice_cap = ((glstate->merger_indice_cap+cap+512)>>9)<<9;
glstate->merger_indices = (GLushort*)realloc(glstate->merger_indices, glstate->merger_indice_cap*sizeof(GLushort));
}
void resize_indices_renderlist(renderlist_t *list, int n) {
if (!list->indices || list->shared_indices)
return;
if (list->use_glstate) {
resize_merger_indices(list->ilen+n);
list->indices = glstate->merger_indices;
} else {
if(list->ilen+n<list->indice_cap)
return;
list->indice_cap = ((list->indice_cap+n+511)>>9)<<9;
list->indices = (GLushort*)realloc(list->indices, list->indice_cap*sizeof(GLushort));
}
}
void adjust_renderlist(renderlist_t *list) {
if (! list->open)
return;
list->stage = STAGE_LAST;
list->open = false;
if(hardext.esversion==1) // no more adjustment needed for ES2
for (int a=0; a<list->maxtex; a++) {
const GLint itarget = get_target(glstate->enable.texture[a]);
gltexture_t *bound = (itarget>=0)?glstate->texture.bound[a][itarget]:NULL;
// in case of Texture bounding inside a list
if (list->set_texture && (list->tmu == a))
bound = gl4es_getTexture(list->target_texture, list->texture);
// GL_ARB_texture_rectangle
if ((list->tex[a]) && (itarget == ENABLED_TEXTURE_RECTANGLE) && (bound)) {
tex_coord_rect_arb(list->tex[a], list->tex_stride[a]>>2, list->len, bound->width, bound->height);
}
}
}
renderlist_t* end_renderlist(renderlist_t *list) {
if (!list || ! list->open)
return list;
adjust_renderlist(list);
switch (list->mode) {
case GL_QUADS:
if (((list->indices) && (list->ilen==4)) || ((list->indices==NULL) && (list->len==4))) {
list->mode = GL_TRIANGLE_FAN;
} else {
renderlist_quads2triangles(list);
}
break;
case GL_POLYGON:
list->mode = GL_TRIANGLE_FAN;
break;
case GL_QUAD_STRIP:
list->mode = GL_TRIANGLE_STRIP;
break;
}
if(list->prev && isempty_renderlist(list)) {
renderlist_t *p = list;
list = list->prev;
list->next = NULL;
p->prev = NULL;
free_renderlist(p);
}
return list;
}
renderlist_t* recycle_renderlist(renderlist_t *list, GLenum mode) {
if(isempty_renderlist(list) || (ispurerender_renderlist(list) && list->len==0)) {
list->mode_init = mode;
list->mode = mode;
list->stage=STAGE_DRAW;
if (list->post_color) {
list->post_color = 0;
rlColor4f(list, list->post_colors[0], list->post_colors[1], list->post_colors[2], list->post_colors[3]);
}
if (list->post_normal) {
list->post_normal = 0;
rlNormal3f(list, list->post_normals[0], list->post_normals[1], list->post_normals[2]);
}
return list; // recycling...
}
// check if pending color...
if (list->post_color) {
list->post_color = 0;
rlColor4f(list, list->post_colors[0], list->post_colors[1], list->post_colors[2], list->post_colors[3]);
}
if (list->post_normal) {
list->post_normal = 0;
rlNormal3f(list, list->post_normals[0], list->post_normals[1], list->post_normals[2]);
}
// check if list needs to be converted to triangles / lines...
GLushort *indices = NULL;
#define pre_expand \
if(list->use_glstate) {\
resize_merger_indices(renderlist_getindicesize(list)); indices = glstate->merger_indices;\
} else {\
list->indice_cap = renderlist_getindicesize(list);\
indices = (GLushort*)malloc(sizeof(GLushort)*list->indice_cap);\
}
#define post_expand \
list->ilen = renderlist_getindicesize(list);\
list->indices = indices
list->merger_mode = mode;
switch(list->mode) {
case GL_LINES:
if(mode!=GL_LINES && !list->indices) {
pre_expand;
renderlist_createindices(list->len, indices, 0);
post_expand;
}
break;
case GL_LINE_LOOP:
pre_expand;
renderlist_lineloop_lines(list->indices, list->indices?list->ilen:list->len, indices, 0);
post_expand;
list->mode=GL_LINES;
break;
case GL_LINE_STRIP:
pre_expand;
renderlist_linestrip_lines(list->indices, list->indices?list->ilen:list->len, indices, 0);
post_expand;
list->mode=GL_LINES;
break;
case GL_TRIANGLES:
if(mode!=GL_TRIANGLES && !list->indices) {
pre_expand;
renderlist_createindices(list->len, indices, 0);
post_expand;
}
break;
case GL_POLYGON:
case GL_TRIANGLE_FAN:
pre_expand;
renderlist_trianglefan_triangles(list->indices, list->indices?list->ilen:list->len, indices, 0);
post_expand;
list->mode=GL_TRIANGLES;
break;
case GL_QUAD_STRIP:
case GL_TRIANGLE_STRIP:
pre_expand;
renderlist_trianglestrip_triangles(list->indices, list->indices?list->ilen:list->len, indices, 0);
post_expand;
list->mode=GL_TRIANGLES;
break;
case GL_QUADS:
pre_expand;
renderlist_quads_triangles(list->indices, list->indices?list->ilen:list->len, indices, 0);
post_expand;
list->mode=GL_TRIANGLES;
break;
}
#undef pre_expand
#undef post_expand
list->cur_istart = list->len;
// All done
list->stage=STAGE_DRAW;
return list;
}