- 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).
This commit is contained in:
Executable
+169
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import jinja2
|
||||
import re
|
||||
from yaml import safe_load
|
||||
|
||||
split_re = re.compile(r'^(?P<type>.*?)\s*(?P<name>\w+)$')
|
||||
env = jinja2.Environment(
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
loader=jinja2.FileSystemLoader('template'),
|
||||
)
|
||||
|
||||
def args(args, add_type=True):
|
||||
return ', '.join(
|
||||
'{} {}'.format(arg['type'], arg['name']) if add_type else arg['name']
|
||||
for arg in args
|
||||
)
|
||||
|
||||
f = '0.2f'
|
||||
printf_lookup = {
|
||||
'GLbitfield': 'd',
|
||||
'GLboolean': 'd',
|
||||
'GLbyte': 'c',
|
||||
'GLubyte': 'c',
|
||||
'GLchar': 'c',
|
||||
'GLdouble': '0.2f',
|
||||
'GLenum': 'u',
|
||||
'GLfloat': '0.2f',
|
||||
'GLint': 'd',
|
||||
'GLintptr': 'd',
|
||||
'GLintptrARB': 'd',
|
||||
'GLshort': 'd',
|
||||
'GLsizei': 'd',
|
||||
'GLsizeiptr': 'd',
|
||||
'GLsizeiptrARB': 'd',
|
||||
'GLuint': 'u',
|
||||
'GLushort': 'u',
|
||||
'GLvoid': 'p',
|
||||
}
|
||||
|
||||
def printf(args):
|
||||
types = []
|
||||
for arg in args:
|
||||
typ = arg['type']
|
||||
if '*' in typ:
|
||||
t = 'p'
|
||||
else:
|
||||
t = printf_lookup.get(typ, 'p')
|
||||
|
||||
types.append(t)
|
||||
|
||||
return ', '.join('%' + t for t in types)
|
||||
|
||||
def unconst(s):
|
||||
split = s.split(' ')
|
||||
while 'const' in split:
|
||||
split.remove('const')
|
||||
return ' '.join(split)
|
||||
|
||||
env.filters['args'] = args
|
||||
env.filters['printf'] = printf
|
||||
env.filters['unconst'] = unconst
|
||||
|
||||
def split_arg(arg):
|
||||
match = split_re.match(arg)
|
||||
if match:
|
||||
return match.groupdict()
|
||||
else:
|
||||
return {'type': 'unknown', 'name': arg}
|
||||
|
||||
def gen(files, template, guard_name, headers,
|
||||
deep=False, cats=(), ifdef=None, ifndef=None):
|
||||
funcs = {}
|
||||
formats = []
|
||||
unique_formats = set()
|
||||
for data in files:
|
||||
if deep and not isinstance(data.values()[0], list):
|
||||
functions = []
|
||||
for cat, f in data.items():
|
||||
if not cats or cat in cats:
|
||||
functions.extend(f.items())
|
||||
else:
|
||||
functions = data.items()
|
||||
|
||||
for name, args in sorted(functions):
|
||||
props = {}
|
||||
if args:
|
||||
ret = args.pop(0)
|
||||
else:
|
||||
ret = 'void'
|
||||
|
||||
loadlib = 'LOAD_GLES'
|
||||
if name.endswith('_OES_'):
|
||||
loadlib = 'LOAD_GLES_OES'
|
||||
name = name[:-5]
|
||||
elif name.endswith('_EXT_'):
|
||||
loadlib = 'LOAD_GLES_EXT'
|
||||
name = name[:-5]
|
||||
|
||||
args = [split_arg(arg) for arg in args if not arg == 'void']
|
||||
if any(arg.get('type') == 'unknown' for arg in args):
|
||||
continue
|
||||
|
||||
if args:
|
||||
args[0]['first'] = True
|
||||
args[-1]['last'] = True
|
||||
|
||||
for i, arg in enumerate(args):
|
||||
arg['index'] = i
|
||||
|
||||
types = '_'.join(
|
||||
arg['type'].replace(' ', '_').replace('*', '__GENPT__')
|
||||
for arg in [{'type': ret}] + args)
|
||||
|
||||
props.update({
|
||||
'return': ret,
|
||||
'name': name,
|
||||
'args': args,
|
||||
'types': types,
|
||||
'void': ret == 'void',
|
||||
'loadlib': loadlib,
|
||||
})
|
||||
if not types in unique_formats:
|
||||
unique_formats.add(types)
|
||||
formats.append(props)
|
||||
|
||||
funcs[name] = props
|
||||
|
||||
context = {
|
||||
'functions': [i[1] for i in sorted(funcs.items())],
|
||||
'formats': formats,
|
||||
'headers': headers,
|
||||
'name': guard_name,
|
||||
'ifdef': ifdef,
|
||||
'ifndef': ifndef,
|
||||
}
|
||||
|
||||
t = env.get_template(template)
|
||||
return t.render(**context).rstrip('\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Generate code with yml/jinja.')
|
||||
parser.add_argument('yaml', help='spec files')
|
||||
parser.add_argument('template', help='jinja template to load')
|
||||
parser.add_argument('name', help='header guard name')
|
||||
parser.add_argument('headers', nargs='*', help='headers to include')
|
||||
parser.add_argument('--deep', help='nested definitions', action='store_true')
|
||||
parser.add_argument('--cats', help='deep category filter')
|
||||
parser.add_argument('--ifdef', help='wrap with ifdef')
|
||||
parser.add_argument('--ifndef', help='wrap with ifndef')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
files = []
|
||||
for name in args.yaml.split(','):
|
||||
with open(name) as f:
|
||||
data = safe_load(f)
|
||||
if data:
|
||||
files.append(data)
|
||||
|
||||
if args.cats:
|
||||
cats = args.cats.split(',')
|
||||
else:
|
||||
cats = None
|
||||
print(gen(files, args.template, args.name,
|
||||
args.headers, args.deep, cats,
|
||||
args.ifdef, args.ifndef))
|
||||
Reference in New Issue
Block a user