d2dc58391b
build / build (push) Successful in 2m26s
- 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).
509 lines
18 KiB
C
509 lines
18 KiB
C
#include "array.h"
|
|
|
|
#include "debug.h"
|
|
#include "enum_info.h"
|
|
#include "glcase.h"
|
|
#include "light.h"
|
|
#include "state.h"
|
|
|
|
GLvoid *copy_gl_array(const GLvoid *src,
|
|
GLenum from, GLsizei width, GLsizei stride,
|
|
GLenum to, GLsizei to_width, GLsizei skip, GLsizei count, void* dst) {
|
|
if (! src || !count)
|
|
return NULL;
|
|
|
|
if (! stride)
|
|
stride = width * gl_sizeof(from);
|
|
|
|
const char *unknown_str = "LIBGL: copy_gl_array -> unknown type: %x\n";
|
|
if(!dst) {
|
|
dst = malloc((count-skip) * to_width * gl_sizeof(to));
|
|
}
|
|
GLsizei from_size = gl_sizeof(from) * width;
|
|
if (to_width < width) {
|
|
/* printf("Warning: copy_gl_array: %i < %i\n", to_width, width);
|
|
return NULL;*/
|
|
width = to_width;
|
|
}
|
|
// quick path if just copying same to same and no specific stride involved
|
|
if(stride == (to_width*gl_sizeof(to)) && width==to_width && from==to) {
|
|
memcpy(dst, (char*)src + stride*skip, (count-skip) * to_width * gl_sizeof(to));
|
|
return dst;
|
|
}
|
|
|
|
// if stride is weird, we need to be able to arbitrarily shift src
|
|
// so we leave it in a uintptr_t and cast after incrementing
|
|
uintptr_t in = (uintptr_t)src;
|
|
in += stride*skip;
|
|
if (from == to && to_width >= width) {
|
|
GL_TYPE_SWITCH(out, dst, to,
|
|
for (int i = skip; i < count; i++) {
|
|
memcpy(out, (GLvoid *)in, from_size);
|
|
for (int j = width; j < to_width; j++) {
|
|
out[j] = 0;
|
|
}
|
|
out += to_width;
|
|
in += stride;
|
|
},
|
|
default:
|
|
printf(unknown_str, from);
|
|
return NULL;
|
|
)
|
|
} else {
|
|
GL_TYPE_SWITCH(out, dst, to,
|
|
for (int i = skip; i < count; i++) {
|
|
GL_TYPE_SWITCH(input, in, from,
|
|
for (int j = 0; j < width; j++) {
|
|
out[j] = input[j];
|
|
}
|
|
for (int j = width; j < to_width; j++) {
|
|
out[j] = 0;
|
|
}
|
|
out += to_width;
|
|
in += stride;
|
|
,
|
|
default:
|
|
printf(unknown_str, from);
|
|
return NULL;
|
|
)
|
|
},
|
|
default:
|
|
printf(unknown_str, to);
|
|
return NULL;
|
|
)
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
GLvoid *copy_gl_array_texcoord(const GLvoid *src,
|
|
GLenum from, GLsizei width, GLsizei stride,
|
|
GLsizei to_width, GLsizei skip, GLsizei count, void* dst) {
|
|
if (! src || !count)
|
|
return NULL;
|
|
|
|
if (! stride)
|
|
stride = width * gl_sizeof(from);
|
|
|
|
static const char *unknown_str = "LIBGL: copy_gl_array -> unknown type: %x\n";
|
|
if(!dst)
|
|
dst = malloc((count-skip) * to_width * gl_sizeof(GL_FLOAT));
|
|
GLsizei from_size = gl_sizeof(from) * width;
|
|
GLsizei to_elem = gl_sizeof(GL_FLOAT);
|
|
uintptr_t in = (uintptr_t)src;
|
|
in += stride*skip;
|
|
GLfloat* out = (GLfloat*)dst;
|
|
if (from == GL_FLOAT && to_width >= width) {
|
|
for (int i = skip; i < count; i++) {
|
|
GLfloat* input = (GLfloat*)in;
|
|
//memcpy(out, (GLvoid *)in, from_size); // which one is faster ?
|
|
for (int j = 0; j < width; j++) {
|
|
out[j] = input[j];
|
|
}
|
|
for (int j = width; j < to_width; j++) {
|
|
if(j==3)
|
|
out[j] = 1.0f;
|
|
else
|
|
out[j] = 0.0f;
|
|
}
|
|
out += to_width;
|
|
in += stride;
|
|
}
|
|
} else {
|
|
for (int i = skip; i < count; i++) {
|
|
GL_TYPE_SWITCH(input, in, from,
|
|
for (int j = 0; j < width; j++) {
|
|
out[j] = input[j];
|
|
}
|
|
for (int j = width; j < to_width; j++) {
|
|
if(j==3)
|
|
out[j] = 1.0f;
|
|
else
|
|
out[j] = 0.0f;
|
|
}
|
|
out += to_width;
|
|
in += stride;
|
|
,
|
|
default:
|
|
printf(unknown_str, from);
|
|
return NULL;
|
|
)
|
|
}
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
GLvoid *copy_gl_array_quickconvert(const GLvoid *src,
|
|
GLenum from, GLsizei stride,
|
|
GLsizei skip, GLsizei count, void* dest) {
|
|
|
|
if (! stride)
|
|
stride = 4 * gl_sizeof(from);
|
|
const char *unknown_str = "LIBGL: copy_gl_array_quickconvert -> unknown type: %x\n";
|
|
GLvoid *dst = (dest)?dest:malloc((count-skip) * 4 * gl_sizeof(GL_FLOAT));
|
|
|
|
uintptr_t in = (uintptr_t)src;
|
|
in += stride*skip;
|
|
int j;
|
|
|
|
GLfloat *out = (GLfloat*)dst;
|
|
GL_TYPE_SWITCH2(input, in, from,
|
|
const GLfloat maxf = 1.0f/gl_max_value(from);
|
|
for (int i = skip; i < count; i++)
|
|
,
|
|
for (j = 0; j < 4; j++) {
|
|
out[j] = ((GLfloat)input[j])*maxf;
|
|
}
|
|
out += 4;
|
|
in += stride;
|
|
,
|
|
default:
|
|
printf(unknown_str, from);
|
|
return NULL;
|
|
)
|
|
return dst;
|
|
}
|
|
|
|
GLvoid *copy_gl_array_convert(const GLvoid *src,
|
|
GLenum from, GLsizei width, GLsizei stride,
|
|
GLenum to, GLsizei to_width, GLsizei skip, GLsizei count, GLvoid* filler, void* dst) {
|
|
if (! src || !count)
|
|
return NULL;
|
|
|
|
if (! stride)
|
|
stride = width * gl_sizeof(from);
|
|
GLsizei from_size = gl_sizeof(from) * width;
|
|
|
|
if(to==from && width==to_width && stride==(to_width * gl_sizeof(to))) {
|
|
if(!dst) dst = malloc((count-skip) * stride);
|
|
memcpy(dst, (char*)src+stride*skip, (count-skip)*stride);
|
|
return dst;
|
|
}
|
|
|
|
if(to==GL_FLOAT && width==to_width && width==4)
|
|
return copy_gl_array_quickconvert(src, from, stride, skip, count, dst);
|
|
if(to==GL_FLOAT && from==GL_FLOAT)
|
|
if(width<4 || *(GLfloat*)filler==1.0f) // no need to convert
|
|
return copy_gl_array_texcoord(src, from, width, stride, to_width, skip, count, dst);
|
|
else
|
|
return copy_gl_array(src, from, width, stride, to, to_width, skip, count, dst);
|
|
|
|
const char *unknown_str = "LIBGL: copy_gl_array_convert -> unknown type: %x\n";
|
|
if(!dst) dst = malloc((count-skip) * to_width * gl_sizeof(to));
|
|
if (to_width < width) {
|
|
/*printf("Warning: copy_gl_array: %i < %i\n", to_width, width);
|
|
return NULL;*/
|
|
width = to_width;
|
|
}
|
|
|
|
// if stride is weird, we need to be able to arbitrarily shift src
|
|
// so we leave it in a uintptr_t and cast after incrementing
|
|
uintptr_t in = (uintptr_t)src;
|
|
in += stride*skip;
|
|
int j;
|
|
if (from == to && to_width >= width) {
|
|
GL_TYPE_SWITCH(out, dst, to,
|
|
for (int i = skip; i < count; i++) {
|
|
memcpy(out, (GLvoid *)in, from_size);
|
|
for (j = width; j < to_width-1; j++) {
|
|
out[j]=0;
|
|
}
|
|
for (; j < to_width; j++) {
|
|
memcpy(&out[j], filler, gl_sizeof(to));
|
|
}
|
|
out += to_width;
|
|
in += stride;
|
|
},
|
|
default:
|
|
printf(unknown_str, from);
|
|
return NULL;
|
|
)
|
|
} else {
|
|
GL_TYPE_SWITCH_MAX(out, dst, to,
|
|
GL_TYPE_SWITCH2(input, in, from,
|
|
const GLuint maxf = gl_max_value(from);
|
|
for (int i = skip; i < count; i++)
|
|
,
|
|
for (j = 0; j < width; j++) {
|
|
out[j] = input[j]*maxv/maxf;
|
|
}
|
|
for (; j < to_width-1; j++) {
|
|
out[j]=0;
|
|
}
|
|
for (; j < to_width; j++) {
|
|
memcpy(&out[j], filler, gl_sizeof(to));
|
|
}
|
|
out += to_width;
|
|
in += stride;
|
|
,
|
|
default:
|
|
printf(unknown_str, from);
|
|
return NULL;
|
|
),
|
|
default:
|
|
printf(unknown_str, to);
|
|
return NULL;
|
|
)
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
GLvoid *copy_gl_pointer(vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
float filler = 0.0f;
|
|
return copy_gl_array_convert((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_FLOAT, width, skip, count, &filler, NULL);
|
|
}
|
|
GLvoid *copy_gl_pointer_color(vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
float filler = 1.0f;
|
|
return copy_gl_array_convert((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_FLOAT, width, skip, count, &filler, NULL);
|
|
}
|
|
GLvoid *copy_gl_pointer_bytecolor(vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
GLubyte filler = 255;
|
|
return copy_gl_array_convert((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_UNSIGNED_BYTE, width, skip, count, &filler, NULL);
|
|
}
|
|
|
|
GLvoid *copy_gl_pointer_raw(vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
return copy_gl_array((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_FLOAT, width, skip, count, NULL);
|
|
}
|
|
|
|
GLvoid *copy_gl_pointer_tex(vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
//float filler = 1.0f;
|
|
return copy_gl_array_texcoord((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
/*GL_FLOAT,*/ width, skip, count, /*&filler,*/ NULL);
|
|
}
|
|
|
|
void copy_gl_pointer_noalloc(void* dest, vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
float filler = 0.0f;
|
|
copy_gl_array_convert((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_FLOAT, width, skip, count, &filler, dest);
|
|
}
|
|
void copy_gl_pointer_color_noalloc(void* dest, vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
float filler = 1.0f;
|
|
copy_gl_array_convert((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_FLOAT, width, skip, count, &filler, dest);
|
|
}
|
|
void copy_gl_pointer_bytecolor_noalloc(void* dest, vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
GLubyte filler = 255;
|
|
copy_gl_array_convert((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_UNSIGNED_BYTE, width, skip, count, &filler, dest);
|
|
}
|
|
void copy_gl_pointer_raw_noalloc(void* dest, vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
copy_gl_array((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
GL_FLOAT, width, skip, count, dest);
|
|
}
|
|
void copy_gl_pointer_tex_noalloc(void* dest, vertexattrib_t *ptr, GLsizei width, GLsizei skip, GLsizei count) {
|
|
//float filler = 1.0f;
|
|
copy_gl_array_texcoord((const GLvoid*)((uintptr_t)ptr->pointer+(uintptr_t)ptr->real_pointer), ptr->type, ptr->size, ptr->stride,
|
|
/*GL_FLOAT,*/ width, skip, count, /*&filler,*/ dest);
|
|
}
|
|
|
|
GLfloat *gl_pointer_index(vertexattrib_t *p, GLint index) {
|
|
static GLfloat buf[4];
|
|
GLsizei size = gl_sizeof(p->type);
|
|
GLsizei stride = p->stride ? p->stride : (size * p->size);
|
|
uintptr_t ptr = (uintptr_t)p->pointer+(uintptr_t)p->real_pointer + (stride * index);
|
|
|
|
GL_TYPE_SWITCH(src, ptr, p->type,
|
|
for (int i = 0; i < p->size; i++) {
|
|
buf[i] = src[i];
|
|
}
|
|
// zero anything not set by the pointer
|
|
for (int i = p->size; i < 4; i++) {
|
|
buf[i] = 0;
|
|
},
|
|
default:
|
|
printf("LIBGL: unknown pointer type: 0x%x\n", p->type);
|
|
)
|
|
return buf;
|
|
}
|
|
|
|
|
|
GLfloat *copy_eval_double1(GLenum target, GLint ustride, GLint uorder,
|
|
const GLdouble *src) {
|
|
|
|
GLsizei width = get_map_width(target);
|
|
GLfloat* out;
|
|
|
|
if(!src || !width)
|
|
return NULL;
|
|
|
|
out = malloc(uorder*width*sizeof(GLfloat));
|
|
|
|
GLfloat *p = out;
|
|
|
|
for (int i=0; i<uorder; i++, src+=ustride)
|
|
for (int k=0; k<width; k++)
|
|
*p++ = src[k];
|
|
|
|
return out;
|
|
}
|
|
|
|
GLfloat *copy_eval_float1(GLenum target, GLint ustride, GLint uorder,
|
|
const GLfloat *src) {
|
|
|
|
GLsizei width = get_map_width(target);
|
|
GLfloat* out;
|
|
|
|
if(!src || !width)
|
|
return NULL;
|
|
|
|
out = malloc(uorder*width*sizeof(GLfloat));
|
|
|
|
GLfloat *p = out;
|
|
|
|
for (int i=0; i<uorder; i++, src+=ustride)
|
|
for (int k=0; k<width; k++)
|
|
*p++ = src[k];
|
|
|
|
return out;
|
|
}
|
|
|
|
GLfloat *copy_eval_double2(GLenum target, GLint ustride, GLint uorder,
|
|
GLint vstride, GLint vorder,
|
|
const GLdouble *src) {
|
|
/* Additional memory is allocated to be used by the horner and
|
|
* de Casteljau evaluation schemes.*/
|
|
GLsizei width = get_map_width(target);
|
|
GLfloat* out;
|
|
|
|
if(!src || !width)
|
|
return NULL;
|
|
|
|
int dsize = (uorder == 2 && vorder == 2)? 0 : uorder*vorder;
|
|
int hsize = (uorder > vorder ? uorder : vorder)*width;
|
|
|
|
if(hsize>dsize)
|
|
out = malloc((uorder*vorder*width+hsize)*sizeof(GLfloat));
|
|
else
|
|
out = malloc((uorder*vorder*width+dsize)*sizeof(GLfloat));
|
|
|
|
int uinc = ustride - vorder*vstride;
|
|
GLfloat* p = out;
|
|
|
|
for (int i=0; i<uorder; i++, src += uinc)
|
|
for (int j=0; j<vorder; j++, src += vstride)
|
|
for (int k=0; k<width; k++)
|
|
*p++ = src[k];
|
|
|
|
return out;
|
|
}
|
|
GLfloat *copy_eval_float2(GLenum target, GLint ustride, GLint uorder,
|
|
GLint vstride, GLint vorder,
|
|
const GLfloat *src) {
|
|
/* Additional memory is allocated to be used by the horner and
|
|
* de Casteljau evaluation schemes.*/
|
|
GLsizei width = get_map_width(target);
|
|
GLfloat* out;
|
|
|
|
if(!src || !width)
|
|
return NULL;
|
|
|
|
int dsize = (uorder == 2 && vorder == 2)? 0 : uorder*vorder;
|
|
int hsize = (uorder > vorder ? uorder : vorder)*width;
|
|
|
|
if(hsize>dsize)
|
|
out = malloc((uorder*vorder*width+hsize)*sizeof(GLfloat));
|
|
else
|
|
out = malloc((uorder*vorder*width+dsize)*sizeof(GLfloat));
|
|
|
|
int uinc = ustride - vorder*vstride;
|
|
GLfloat* p = out;
|
|
|
|
for (int i=0; i<uorder; i++, src += uinc)
|
|
for (int j=0; j<vorder; j++, src += vstride)
|
|
for (int k=0; k<width; k++)
|
|
*p++ = src[k];
|
|
|
|
return out;
|
|
}
|
|
|
|
void getminmax_indices_us(const GLushort *indices, GLsizei *max, GLsizei *min, GLsizei count) {
|
|
if (!count) return;
|
|
*max = indices[0];
|
|
*min = indices[0];
|
|
for (int i = 1; i < count; i++) {
|
|
GLsizei n = indices[i];
|
|
if( n < *min) *min = n;
|
|
if (n > *max) *max = n;
|
|
}
|
|
}
|
|
void normalize_indices_us(GLushort *indices, GLsizei *max, GLsizei *min, GLsizei count) {
|
|
getminmax_indices_us(indices, max, min, count);
|
|
for (int i = 0; i < count; i++) {
|
|
indices[i] -= *min;
|
|
}
|
|
}
|
|
|
|
void getminmax_indices_ui(const GLuint *indices, GLsizei *max, GLsizei *min, GLsizei count) {
|
|
if (!count) return;
|
|
*max = indices[0];
|
|
*min = indices[0];
|
|
for (int i = 1; i < count; i++) {
|
|
GLsizei n = indices[i];
|
|
if( n < *min) *min = n;
|
|
if (n > *max) *max = n;
|
|
}
|
|
}
|
|
void normalize_indices_ui(GLuint *indices, GLsizei *max, GLsizei *min, GLsizei count) {
|
|
getminmax_indices_ui(indices, max, min, count);
|
|
for (int i = 0; i < count; i++) {
|
|
indices[i] -= *min;
|
|
}
|
|
}
|
|
|
|
void *copy_gl_array_bgra(void* dest, const void *ptr, GLint stride, GLsizei width, GLsizei skip, GLsizei count) {
|
|
// this one only convert from BGRA (unsigned byte) to RGBA FLOAT
|
|
GLubyte* src = (GLubyte*)ptr;
|
|
|
|
if (! src || !(count-skip))
|
|
return NULL;
|
|
|
|
if (! stride)
|
|
stride = 4;
|
|
|
|
if(!dest)
|
|
dest = malloc(4*sizeof(GLfloat)*(count-skip));
|
|
GLfloat* dst = dest;
|
|
src += skip*(stride);
|
|
|
|
static const float d = 1.0f/255.0f;
|
|
for (int i=skip; i<count; i++) {
|
|
#if defined(__ARM_NEON__) && !defined(__APPLE__)
|
|
int lsrc = *(int*)src;
|
|
lsrc = (lsrc&0xff00ff00) | ((lsrc&0x00ff0000)>>16) | ((lsrc&0x000000ff)<<16);
|
|
asm volatile (
|
|
"vmov s12, %1 \n\t" // because you cannot vmovl.u8 d6, s11
|
|
"vmovl.u8 q3, d6 \n\t" // Expand to 16-bit (so unsetuped s13 is expanded in d7)
|
|
"vmovl.u16 q3, d6 \n\t" // Expand to 32-bit, ignoring expanded d7
|
|
"vcvt.f32.u32 q3, q3 \n\t" // Convert to float
|
|
"vmul.f32 q3, q3, %y2 \n\t" // Normalize
|
|
"vst1.f32 {q3}, [%0]! \n\t" // Store, next
|
|
:"+r"(dst) :"r"(lsrc), "w"(d)
|
|
: "q3", "memory"
|
|
);
|
|
#else
|
|
const GLubyte b = src[0], g = src[1], r = src[2], a = src[3];
|
|
*dst++ = r*d;
|
|
*dst++ = g*d;
|
|
*dst++ = b*d;
|
|
*dst++ = a*d;
|
|
#endif
|
|
src+=stride;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
GLvoid *copy_gl_pointer_color_bgra(const void *ptr, GLint stride, GLsizei width, GLsizei skip, GLsizei count) {
|
|
return copy_gl_array_bgra(NULL, ptr, stride, width, skip, count);
|
|
}
|
|
|
|
void copy_gl_pointer_color_bgra_noalloc(void* dest, const void *ptr, GLint stride, GLsizei width, GLsizei skip, GLsizei count)
|
|
{
|
|
copy_gl_array_bgra(dest, ptr, stride, width, skip, count);
|
|
}
|