26 Commits

Author SHA1 Message Date
ml 5d7564c3b5 Update the docs and add AGENTS.md
build / build (push) Successful in 2m18s
2026-09-20 15:25:33 +02:00
ml 70c43240bc Add a Cheats menu tab with engine cheat buttons and unlimited-resource switches
build / build (push) Successful in 3m42s
The new Cheats tab exposes the engine's own cheat handlers as buttons:
give all items and weapons, toggle physics, next level and previous
level. Physics shows its state through the button highlight. The buttons
need a running game and show a message otherwise.

It also has four independent session-only switches for unlimited health,
energy, ammo and items (grenades and drugs). While a switch is on, its
resource is topped up every frame by qs_cheat_refill() from the new
engine patch 26. The switches are not saved to the config.
2026-09-20 14:59:33 +02:00
ml d8324d409e Add free view and a separate cyberspace action set
build / build (push) Successful in 3m24s
- Free view: hold a mapped input (default: left grip) and that thumbstick
  drives the engine's mouse look, with the stick's normal bindings suspended
  while held. Also available for the right stick, unbound by default.
- Cyberspace actions: eleven thrust/climb/dive/bank/roll actions with their
  own bindings, active only in cyberspace. The normal movement actions are
  inactive there, and capture exclusivity only compares actions that can be
  active together, so one input can be bound in both sets.
- Cyberspace pitch and bank scale with thumbstick deflection instead of
  running at full strength.
- Remove the toggle_freelook action; bind the automap view to the right
  stick click by default.
- Engine patches: 24 exposes whether the player is in cyberspace, 25 lets
  the controller code scale cyberspace pitch and bank.
2026-09-20 07:24:44 +02:00
ml c24b7f15cb Add remappable controller controls with a Controller Options tab
build / build (push) Successful in 2m14s
Add a player_controls config group that maps game actions to controller
inputs, and a Controller Options menu tab to rebind them in-headset.

- 45 actions: movement, click/double-click, jump, fire, and the engine's own
  keyboard hotkeys (posture, save/load, weapon/MFD select, etc.), sent to the
  engine as synthetic key events. Cheat and dead hotkeys are not exposed.
- Press-to-capture rebinding with per-input exclusivity, Reset to Defaults
  (built-in defaults, then questshock.config.default.json), and new defaults:
  left stick moves/strafes, right stick turns.
- Controller profiles for Touch, Vive and generic OpenXR
  (res/controller_profiles/), matched to the active interaction profile at
  runtime, with a fatal dialog if a profile's bindings are rejected at
  startup.
- The menu's thumbstick locomotion is disabled while the Controller Options
  tab is open or a capture is active. A scrollable list with a tap-to-jump
  scroll bar handles the long action list.
- Opening the menu pauses a running game and resumes it on close.
- Reset Position now keeps the player's facing instead of turning the screen
  to the current gaze.
- Play the intro video in the game's language (engine patch 23), falling back
  to English.
- Watchdog and shared-key handling for stuck movement keys, plus key-edge
  logging.
2026-09-20 06:08:50 +02:00
ml e1e6a006d4 Add configurable game/initial screen width and distance, with a bundled first-run config
build / build (push) Successful in 2m41s
- Video Options tab offers width and distance presets independently for
  the Initial Screen (splash/intro/menu) and Game Screen (gameplay)
  profiles, with their preset step/offset configurable via
  questshock.config.json.
- Ships res/questshock.config.default.json as the initial config on
  first run (or whenever questshock.config.json doesn't exist yet),
  refreshed from the APK on every launch without touching a user's own
  saved config.
2026-09-06 09:08:54 +02:00
ml 5fe4cdf7f8 Bump AGP to 8.5.2 and Gradle to 8.7 for 16 KB page-size support
build / build (push) Successful in 2m21s
Every .so this project builds was already ELF-segment-aligned for 16 KB
pages (build-image/Dockerfile's ANDROID_16KB_LDFLAGS, app/build.gradle's
own CMAKE_SHARED_LINKER_FLAGS), but AGP 8.1.1 doesn't align native
libraries' zip entries within the APK itself - that only became automatic
in AGP 8.5.1, which is what Android Studio's "not compatible with 16 KB
devices" warning was actually flagging. No build-image changes needed:
Gradle/AGP are resolved over the network at build time, not baked into
the image.
2026-09-05 16:18:29 +02:00
ml 369555efc7 Making the menu slightly larger 2026-09-05 15:53:15 +02:00
ml 360a1f7e3d Add VR locomotion: move/turn with thumbsticks while the menu is open
build / build (push) Successful in 2m25s
- Left thumbstick snap-turns, right thumbstick smooth-moves, letting the
  player line themselves up with the fixed game quad ("virtual screen")
  without needing physical room-scale space to do it in. Implemented via
  a second OpenXR reference space (a "play space") derived from the real
  LOCAL space by the inverse of the player's transform, so every existing
  quad/hit-testing/rendering call site just needed g_local_space swapped
  for it - no manual coordinate-transform math required elsewhere
- Generalized the ray/quad hit-testing in xr_input.c to a proper
  oriented-plane intersection (needed once quads can rotate); verified it
  degenerates to the old axis-aligned formula when unrotated, so the
  keyboard and non-recentered menu are unaffected
- The menu launcher now re-centers in front of the player, correctly
  oriented to face them, each time it's freshly reopened
- "Reset Position" (Main Menu tab) recenters using the player's current
  real head pose - not a plain reset-to-origin, which only undid
  thumbstick movement and ignored physical drift since the session
  started. The same recenter runs once automatically at startup too, as a
  fallback for when there's no complete saved position to use instead
- Position/orientation persists in questshock.config.json's new
  player_position group (independent of savegames), including new
  numeric-value support in the config file's hand-rolled JSON parser
  (previously string-enums only)
2026-09-05 15:47:54 +02:00
ml c0619a55ab Add a language option to the VR menu, and fix a crash switching to it
build / build (push) Successful in 2m22s
- New "Language" row on the Main Menu tab (English/French/German),
  backed by a new "general" group in questshock.config.json
- Fixes a device-reproduced crash: switching language used to call
  language_dealfunc(), whose render_run()/opanel_redraw() repaint
  assumes the game's own in-game options panel is on screen - crashes
  (SIGSEGV) when triggered from our independent VR overlay instead.
  Now calls language_change() directly, which is all that's actually
  needed to reload resources and refresh the inventory/MFD/side-icon UI
- Fixes a second crash: this data set ships frnstrng.res/gerstrng.res
  but not mfdfrn.res/mfdger.res, and language_change() closes the
  current resource files before discovering the new ones don't exist -
  leaving no valid resource file open and crashing on the next lookup.
  Now checks both files exist before ever switching, refusing the
  change (with an in-headset popup) instead of corrupting resource state
- extract_assets.sh can now also pull mfdfrn.res/mfdger.res out of a
  System Shock: Classic installer (which includes them, unlike Enhanced
  Edition) if one is present in res/assets/ - entirely optional
- Documented all of the above in README.md/CONFIG.md
2026-09-05 08:09:12 +02:00
ml 09280dd410 Overhaul the VR menu UI: header, tabs, live video options, hover/click feedback, i18n, and dragging
build / build (push) Successful in 2m25s
- Header with title, git-tag-derived version, and a live FPS/frame-time/
  CPU/GPU-utilization/free-memory stats ribbon below the tab bar (FPS via
  a new per-frame tracker in xr_session.c; CPU/GPU via the OpenXR
  XR_META_performance_metrics extension, gracefully unavailable on
  runtimes that don't support it)
- Bottom tab bar with a live-editable Video Options tab (renderer/
  resolution), applying changes immediately via qs_config.c
- Hover and press feedback on every menu/keyboard button via a
  StateListDrawable (Android's default ripple never animates on this
  permanently unattached view tree), with a lighter default button color
  for visibility
- i18n for all menu/keyboard chrome text, following the game's own
  language setting (Strings.java)
- The main menu is now draggable via its header, matching the keyboard;
  xr_input.c's drag handling is generalized to per-overlay state instead
  of being keyboard-only
- The keyboard's title bar now matches the menu header's style
2026-09-05 07:02:30 +02:00
ml c4fd4eb3dd Adding support for a configuration file 2026-09-05 05:30:00 +02:00
ml e0a2e1f4bf Fix persistent GL_INVALID_OPERATION spam and resolution-change bugs on Android
build / build (push) Successful in 2m44s
- opengl_end_frame() bound framebuffer 0 on Android, which has no valid
  target there (real presentation goes through the OpenXR swapchain's own
  FBOs) - gl4es reported this every frame. Skip it there.
- render_hack_cameras() re-entered opengl_start_frame()/opengl_end_frame()
  for camera-monitor renders that never touch the GL screen; excluded them
  to match use_opengl()'s existing behavior. Also drains a stray error left
  by xrPollEvent().
- ChangeScreenSize() never called opengl_resize() on Android, freezing the
  3D render target at launch size after an in-game resolution change; and
  xr_get_game_resolution() used the swapchain's fixed size instead of the
  current screen resolution, misplacing the laser-pointer cursor after such
  a change.
- Removes all temporary bisection diagnostics added while tracking down the
  GL_INVALID_OPERATION source.
2026-09-04 16:34:52 +02:00
ml 504ed3e1cb Fix SFX and MIDI music not playing on Android
snd_start_digital() opened two separate SDL audio devices - a raw one
for cutscene/audiolog audio and a second via Mix_OpenAudio() for
SFX/MIDI - but Android's audio backends only ever allow one open
non-capture device, so the second open always failed silently.

- Consolidate onto a single Mix_OpenAudio() device; cutscene/audiolog
  PCM is now mixed into its output via Mix_SetPostMix() instead of a
  dedicated device (16-android-audio-single-device.patch)
- Add SDL_GetError() to the failure log so a future open failure is
  actually diagnosable (15-android-audio-error-detail.patch)
- Make NativeMidiInit() report failure on platforms with no real
  implementation (Android included), instead of silently claiming
  success without opening anything (17-android-native-midi-unsupported.patch)
- Strengthen the OpenSL ES driver hint to SDL_HINT_OVERRIDE and log the
  active audio driver as a standing diagnostic (05-android-audio-driver.patch)
2026-08-30 07:09:16 +02:00
ml d6e438a541 Fix 3D texture corruption and stuck/dead-key input bugs
build / build (push) Successful in 2m13s
Stale GL_UNPACK state in gl4es and a missing pre-release GPU sync
caused diagonal-banded corruption in the 3D view. Synthetic key
press/release must track the real controller button or touch down/up
edges, not fire together in one call - fixes a typed movement key
sticking forever, then a follow-up that had silently broken A-button
jump and on-screen keyboard arrow keys. Also adds force-rebuild.sh for
the known stageEngine stale-cache issue.
2026-08-29 19:26:53 +02:00
matthias a2fb95e57b Add Windows cross-compilation via MinGW, and fix Docker build permission
build / build (push) Successful in 3m5s
issues on vboxsf-mounted checkouts

New `make dist-win`/`package-win` targets (folded into `dist`/`package`
alongside the renamed `dist-linux`/`package-linux`) cross-compile
systemshock.exe via MinGW, using prebuilt SDL2/SDL2_mixer/GLEW/
fluidsynth-lite baked into the build-image - no Windows machine or Wine
needed to build it, confirmed working and playable on a real Windows
machine. dist-win/ ships DLLs flat alongside the exe plus a new
res/run.bat launcher, packaged into a .zip the same way dist/ becomes a
.tar.gz.

Also fixes three build-image bugs hit while testing on a VirtualBox
vboxsf-mounted checkout: build-engine.sh/docker-entrypoint.sh losing
their execute bit (chmod +x on restrictive source perms), the container
user missing access to /workspace's supplementary vboxsf group, and
cp -a failing on symlink/hard-link creation (vboxsf doesn't support
either) - now falls back to dereferencing copies when detected. Also
adds Docker/zip/etc. prerequisites to the README for both the desktop
and Quest builds.
2026-08-16 06:27:31 +02:00
ml 581af95e7b Drive the engine's mouse cursor from the VR aim ray on the game quad
build / build (push) Successful in 1m44s
The game quad's laser beam was purely visual - aiming at the game's own
UI (inventory, menus, dialogs) had no way to interact with it. Add a
real mouse pointer: absolute cursor position plus a single left click,
mirroring a plain point-and-click mouse (no mouselook, no right-click,
no drag).

New xr_mouse.c/h bridges the aim-ray hit-test to the vendored engine's
own public mouse API - mouse_put_xy() for position, a synthetic
SDL_MOUSEBUTTONDOWN/UP (SDL_BUTTON_LEFT) via SDL_PushEvent for clicks,
the same technique nativeSendPrintableChar() already uses for
synthetic keyboard input. No engine patch needed. Deliberately bypasses
SDLActivity.onNativeMouse()/SDL_MOUSEMOTION/SetMouseXY(), whose
physical-window-size scaling is unreliable in this headless immersive
build.

xr_input_try_game_quad() now reports the hit u,v; a new
g_game_touch_active[] tracks a held click on the game quad so it
survives the ray straying onto the keyboard/menu before release,
gating those overlays' claims the same way pending overlay touches
already do.
2026-08-14 08:36:09 +02:00
ml 824b4a2506 Give the game quad the same laser-beam pointer as the overlays
Aiming looked and behaved differently depending on whether the
keyboard/menu was open: xr_input_try_overlay() claimed a hand's ray for
its overlay whenever the overlay was merely visible, regardless of
whether the ray was actually pointed at it - so with the keyboard open,
aiming at the main game screen still showed a beam terminating at the
keyboard's fixed depth, while closing the keyboard swapped in the old
flat cross-shaped reticle at whatever the ray was really pointing at.

Only claim an overlay when the ray is actually relevant this frame - a
real hit, or a touch/drag begun on a previous frame still pending
release - so a visible-but-unaimed-at overlay now falls through to the
next-priority target. Give the game quad its own hit-test
(xr_input_try_game_quad()) and the same billboarded laser-beam
treatment as the overlays instead of the old flat reticle, so aiming
looks and behaves identically everywhere - overlay open or not. The
old reticle GL program/shaders are now fully dead and removed. No
click/touch dispatch is added to the game quad itself; that's future
work.
2026-08-14 07:59:09 +02:00
ml 920842a465 Show a laser-beam pointer while aiming at the menu/keyboard
build / build (push) Successful in 1m40s
The flat cross-shaped reticle used while aiming at the game quad is
drawn directly into the game quad's own texture, so it only ever made
sense there - while the menu launcher or keyboard was open, there was
no visual feedback at all until the ray was precisely on target,
making both panels hard to aim at.

Add a second, thin XrCompositionLayerQuad per hand: a billboarded
"laser beam" ribbon from the controller to wherever that hand's ray
currently crosses the plane of whichever overlay (keyboard, then menu)
claims it that frame, oriented via a view-space head pose so it reads
as a line from the viewer's eye regardless of angle, colored per hand
(cyan left, amber right) and clamped to 2m so grazing angles don't
produce an absurdly long beam. Built from data xr_input.c's existing
per-hand hit-testing already computes; the game-quad reticle itself is
untouched.
2026-08-14 07:30:13 +02:00
ml 3be310ade6 Split the keyboard onto its own translucent OpenXR quad
build / build (push) Successful in 1m52s
Expand the on-screen keyboard to a full US layout (letters, digits,
punctuation, Shift layer, Tab, arrows, F1-F12, one-shot Ctrl/Alt
modifiers), make it a persistent, movable, closeable panel via a
title-bar drag handle, and lower its opacity.

Previously the keyboard was just a second panel swapped into the same
quad as the menu launcher, which made the launcher translucent too and
made the keyboard and menu mutually exclusive. Extract the shared
swapchain/JNI/touch-dispatch plumbing into two generic, reusable
modules - xr_swapchain.c (swapchain + per-image FBO setup) and
xr_overlay.c (an off-screen Android View rendered into its own OpenXR
quad, hit-tested via a laser pointer) - and make the menu launcher and
keyboard two independent XrOverlay instances instead of one. The
controller's menu button now only opens/closes the launcher; the
launcher's "Keyboard" button only opens the keyboard - so the keyboard
can stay up while picking something from the menu, and only the
keyboard's own Close button hides it.

xr_menu.c/.h are gone, fully absorbed into xr_overlay.c. On the Java
side, OverlayPanel.java carries the shared off-screen-render/touch/
cursor plumbing that MenuOverlay and the new KeyboardOverlay both
subclass.
2026-08-14 06:43:44 +02:00
ml 2d8fb49bf5 Add hand-built on-screen keyboard to the OpenXR menu quad
build / build (push) Successful in 1m45s
MenuOverlay's key grid forwards every press to the game as real input:
non-printable keys (Esc/Enter/Backspace) as an SDLActivity.onNativeKeyDown()/
onNativeKeyUp() pair, and printable keys (letters, Space) as a synthesized
SDL_TEXTINPUT event pushed directly from native code, since the engine's
pump_events() only picks up printable ASCII from that event type, not from
SDL_KEYDOWN. Confirmed on-device, including that Space now correctly skips
the intro cutscene alongside Esc/Enter.
2026-08-05 08:11:16 +02:00
ml 1be0bebda2 Split the menu quad back onto its own independent OpenXR swapchain
build / build (push) Successful in 1m43s
Replaces the single shared, side-by-side swapchain (game + menu content
packed into one image, needing viewport/scissor juggling to keep the
menu's own glClear from bleeding into the game's region) with two fully
independent XrSwapchainState instances, each sized to exactly its own
content and acquired/released on its own within the same
xrBeginFrame/xrEndFrame pair - an ordinary multi-layer OpenXR setup.

The shared-swapchain design was originally adopted to work around what
looked like a Horizon OS compositor limitation with independent
swapchains, but that was diagnosed before the real root cause of the
"menu shows the game's content" bug was found (gl4es's fpe.c
unconditionally substituting its own shader onto the menu's draw call -
see README's Debugging notes). Since the actual fix routes the menu's
blit through a real, non-gl4es glBlitFramebuffer() call - orthogonal to
how many swapchains exist - splitting back onto two swapchains works
fine and removes the GL_SCISSOR_TEST workaround and sub-rectangle
offset math entirely. Confirmed on-device: both quads render correctly,
hit-testing and 90 FPS unaffected.

Also adds a visible cursor to the menu quad itself: xr_input.c now
tracks whichever hand's aim ray hits the menu each frame and forwards it
to a new MenuOverlay.nativeUpdateCursor(), which draws a small dot at
that position (composited through the same Bitmap the menu's own
content already goes through) - previously there was no visual feedback
at all showing where you were pointing before pulling the trigger.
2026-08-02 08:01:14 +02:00
ml 2b52b818e8 Added a make android-studio target that wraps ./run-image.sh bash build-image/prepare-android-project.sh --host-paths, and updated the README (Layout's Makefile-target list, "5.2. Building natively in Android Studio", and "5.3. Testing cycles") to reference it — including a note that it must be re-run after make clean specifically, since that's what just bit you. Run make android-studio now to fix the build.
build / build (push) Successful in 1m42s
2026-08-02 06:46:07 +02:00
ml d2dc58391b Add controller input and a laser-pointer-driven menu quad
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).
2026-08-02 06:27:49 +02:00
ml 2300d081c3 Add OpenXR bring-up: render the game as a floating quad in an immersive Quest session
build / build (push) Successful in 2m12s
- New android/app/src/main/cpp/xr_session.c (+.h): owns the OpenXR
  instance/session/local-space/swapchain and the per-frame
  xrWaitFrame/xrBeginFrame/xrEndFrame loop, submitting the game's
  existing flat render as a single head-tracked XrCompositionLayerQuad.
  No stereo rendering or controller input yet - that's steps B/C/D of
  the plan.
- 11-android-openxr-cmake.patch: links the OpenXR loader as a build
  dependency, staged into jniLibs the same way as gl4es/SDL2.
  build-image/Dockerfile and prepare-android-project.sh build and stage
  it.
- 12-android-openxr-present.patch: redirects OpenGL.cc's final present
  step (opengl_swap_and_restore / SDLDraw's software path) into the XR
  swapchain FBO instead of the window, on Android only. Two real gl4es
  bugs had to be worked around to get pixels on screen at all:
    - gl4es's own glBindFramebuffer errors on an FBO id it didn't create
      itself, even though the real driver-level bind succeeds - fixed by
      creating the swapchain FBO container via gl4es's own
      glGenFramebuffers/glBindFramebuffer, and only using the real
      (dlsym'd) driver call for attaching OpenXR's foreign swapchain
      texture, which gl4es's own attach can't handle.
    - gl4es's glBegin/glVertexAttrib/glVertex3f immediate-mode emulation
      only captures a fresh per-vertex value for attribute 0 (position,
      driven directly by glVertex3f) - custom attributes like this
      shader's texcoords/light are GLES2's *constant*-attribute API and
      applied once for the whole draw, not per vertex, silently
      collapsing the UI-overlay quad to a single sampled texel. Fixed by
      switching that one draw call to real vertex arrays
      (glVertexAttribPointer/glDrawArrays).
  Also flips the V texcoord to match SDL's top-down row order against
  GL's texture convention, and reuses a persistent texture object
  instead of a fresh gen/upload/delete every frame.
- AndroidManifest.xml: declares the immersive-HMD intent category and
  focus-aware metadata, drops the 2D-panel layout hint.
- README: documents the new OpenXR immersive mode.
2026-07-25 07:25:27 +02:00
ml 0f59898bb6 - AndroidManifest.xml: add android:screenOrientation="landscape" and a
build / build (push) Successful in 2m15s
<layout> defaultWidth/defaultHeight/minWidth/minHeight/gravity hint -
  Quest's Home shell otherwise defaults a freshly-launched 2D panel to a
  portrait shape, cropping the game's 4:3 640x480 content down to a
  sliver.
- The actual root cause of the remaining crop (game rendering into one
  corner of an otherwise correctly-sized panel), found via on-device
  logcat and the new diagnostics below rather than guesswork:
  ChangeScreenSize() (engine/src/MacSrc/ShockBitmap.c) calls
  SDL_SetWindowSize() whenever the game sets its video mode. That's a
  desktop-only operation in effect - Android has no SetWindowSize driver
  hook, so SDL's generic layer instead overwrites its own cached window
  size to the game's internal resolution (640x480) and synthesizes a
  resize event from that, desyncing SDL's notion of the window size from
  the real, unchanged Android surface (e.g. 1600x1200). Both SDL's own
  renderer viewport and the engine's custom GL viewport then scale
  against that corrupted cached size. 10-android-no-window-resize.patch
  skips the desktop-only SDL_SetWindowFullscreen/SetWindowSize/
  SetWindowPosition calls on Android, keeping the legitimate
  SDL_RenderSetLogicalSize/offscreen-bitmap setup.
- 06-android-resize-event.patch: also react to SDL_WINDOWEVENT_RESIZED
  in the engine's event loop, not just SIZE_CHANGED - Android's SDL video
  backend never sends SIZE_CHANGED for surface-driven resizes, only
  RESIZED, an independent gap worth closing regardless of the bug above.
- 08/09-android-logcat-*.patch: route the engine's existing log.c output
  (previously plain fprintf(stderr,...), never actually captured by
  logcat on this build) through __android_log_vprint instead, so every
  existing INFO/DEBUG/WARN/ERROR call site becomes visible for on-device
  debugging. This is what made the diagnostic below (and everything
  since) observable at all.
- 07-android-size-diagnostics.patch: one-time startup log comparing
  SDL_GetWindowSize/SDL_GL_GetDrawableSize/SDL_GetRendererOutputSize -
  the evidence that actually pinned down the SDL_SetWindowSize bug above.
- QuestShockActivity.java: add a diagnostic onSizeChanged() log on
  GameSurface, used to rule out a later Android-side panel relayout as
  the cause before finding the real one.
2026-07-24 06:31:18 +02:00
ml 4e47e0a989 Fix missing-assets detection race, 16 KB page alignment, and Android audio backend
build / build (push) Successful in 2m11s
- QuestShockActivity now actually blocks the native engine from starting
  when game data is missing, closing three gaps found via on-device
  testing: super.onCreate() must run unconditionally first (Android
  throws SuperNotCalledException otherwise); SDLActivity.mBrokenLibraries
  is now set provisionally before the storage-permission check, since
  onWindowFocusChanged() closing the permission dialog could otherwise
  start the engine before the async onRequestPermissionsResult() callback
  ran; and a new GameSurface (SDLSurface subclass) closes the actual gap
  that let the init_popups NULL-deref crash through even with
  mBrokenLibraries set - SDLSurface.surfaceChanged() starts the native
  thread directly without ever checking that flag.
- Force Android to use SDL2's openslES audio backend instead of AAudio
  (android/engine-patches/05-android-audio-driver.patch): AAudio only
  allows one open playback device at a time, but the engine opens two
  (cutscene audio via SDL_OpenAudioDevice, SFX/MIDI via Mix_OpenAudio),
  hitting an assertion failure on real hardware.
- Add 16 KB ELF page-size alignment (-Wl,-z,max-page-size=16384) to every
  Android shared library - the four prebuilts (SDL2, SDL2_mixer,
  fluidsynth-lite, gl4es, in build-image/Dockerfile) and the engine's own
  libmain.so (build.gradle) - matching Google's Play Store requirement
  for Android 15+ and clearing Android Studio's compatibility warning.
- Add a stageEngine Gradle task that automatically re-stages the patched
  engine/ copy and prebuilt libraries before any Android Studio build
  (hooked into preBuild, with proper up-to-date checking), so source/
  patch changes can't silently go stale in the build/android-engine
  scratch copy - previously a manual, easy-to-forget step. Skips
  automatically inside the build-image container so make apk/CI are
  unaffected.
2026-07-23 19:20:22 +02:00
374 changed files with 153654 additions and 203 deletions
+2
View File
@@ -0,0 +1,2 @@
* text=auto
*.sh text eol=lf
+24 -11
View File
@@ -1,14 +1,16 @@
name: build
# Builds a versioned Linux release tarball (see `make package`) on every
# push/PR, plus on-demand via the Gitea "Run workflow" button. Runs
# Builds versioned Linux and Windows release packages (see `make
# package`, which builds both - a .tar.gz and a .zip) on every push/PR,
# plus on-demand via the Gitea "Run workflow" button. Runs
# inside the build-image (see ../../build-image/Dockerfile, built/pushed
# via ../../build-image.sh and ../../upload-image.sh), which bundles
# every dependency engine/ needs to compile - no network access needed
# at job runtime. Since the job's container already *is* the build-image
# (QUESTSHOCK_BUILD_IMAGE=1), `make package`'s `engine` prerequisite
# compiles directly instead of trying to docker-run it again, which
# wouldn't work here (no nested docker).
# every dependency engine/ needs to compile (for both platforms,
# including the Windows cross-toolchain) - no network access needed at
# job runtime. Since the job's container already *is* the build-image
# (QUESTSHOCK_BUILD_IMAGE=1), `make package`'s `engine`/`engine-win`
# prerequisites compile directly instead of trying to docker-run it
# again, which wouldn't work here (no nested docker).
on:
push:
pull_request:
@@ -45,18 +47,27 @@ jobs:
command -v cmake >/dev/null 2>&1 || { echo "PREFLIGHT FAIL: cmake not in PATH" >&2; exit 1; }
[ -n "${QUESTSHOCK_BUILD_IMAGE:-}" ] || { echo "PREFLIGHT FAIL: QUESTSHOCK_BUILD_IMAGE not set - not running inside the questshock build-image?" >&2; exit 1; }
[ -d /opt/prebuilt/built_sdl ] || { echo "PREFLIGHT FAIL: /opt/prebuilt/built_sdl missing" >&2; exit 1; }
[ -d /opt/prebuilt/android/gl4es ] || { echo "PREFLIGHT FAIL: /opt/prebuilt/android/gl4es missing - runner is using a build-image older than the Android/Quest layer" >&2; exit 1; }
# gl4es itself is no longer prebuilt here (compiled from source at
# APK-build time instead - see build-image/Dockerfile's gl4es
# comment) - openxr was added to this image in the same
# Android/Quest layer, so it's an equally good marker of that.
[ -d /opt/prebuilt/android/openxr ] || { echo "PREFLIGHT FAIL: /opt/prebuilt/android/openxr missing - runner is using a build-image older than the Android/Quest layer" >&2; exit 1; }
[ -d /opt/prebuilt/win/sdl2 ] || { echo "PREFLIGHT FAIL: /opt/prebuilt/win/sdl2 missing - runner is using a build-image older than the Windows cross-build layer" >&2; exit 1; }
command -v x86_64-w64-mingw32-gcc >/dev/null 2>&1 || { echo "PREFLIGHT FAIL: x86_64-w64-mingw32-gcc not in PATH" >&2; exit 1; }
command -v zip >/dev/null 2>&1 || { echo "PREFLIGHT FAIL: zip not in PATH (needed by make package-win)" >&2; exit 1; }
- name: Build package
run: make package
- name: Upload build artifact
- name: Upload build artifacts
# v4 uses the newer @actions/artifact backend, which this Gitea
# instance's artifact storage doesn't support (GHESNotSupportedError) - v3 works.
uses: actions/upload-artifact@v3
with:
name: shockolate
path: dist/shockolate-*-linux-*.tar.gz
path: |
dist/shockolate-*-linux-*.tar.gz
dist/shockolate-*-windows-*.zip
- name: Build Quest APK
# QUESTSHOCK_BUILD_IMAGE is already set (see Preflight above), so
@@ -74,13 +85,14 @@ jobs:
path: dist/questshock-*-android-*.apk
- name: Publish to dl.ladkau.de
# Uploads the tarball and APK over SFTP instead of using
# Uploads the tarball, zip, and APK over SFTP instead of using
# actions/upload-artifact (whose zip wrapping can't be disabled).
# Only runs on push so PR builds don't publish.
if: gitea.event_name == 'push'
run: |
set -euo pipefail
TARBALL="$(ls dist/shockolate-*-linux-*.tar.gz)"
ZIP="$(ls dist/shockolate-*-windows-*.zip)"
APK="$(ls dist/questshock-*-android-*.apk)"
mkdir -p ~/.ssh
echo "${{ secrets.DL_SFTP_KEY }}" > ~/.ssh/dl_sftp_key
@@ -90,5 +102,6 @@ jobs:
uploader@dl.ladkau.de <<EOF
-mkdir files/questshock
put $TARBALL files/questshock/$(basename "$TARBALL")
put $ZIP files/questshock/$(basename "$ZIP")
put $APK files/questshock/$(basename "$APK")
EOF
+7 -1
View File
@@ -3,16 +3,22 @@
# Game assets are not included in the repo
/res/assets/setup_system_shock_enhanced*
/res/assets/setup_system_shock_classic*
/res/assets/*.zip
/res/assets/ss_ee/
# Build output
/dist/
/dist-win/
/build/
# Engine build artifacts (engine/ is committed as a source snapshot; these
# are generated by run-image.sh / build-image/build-engine.sh)
# are generated by run-image.sh / build-image/build-engine.sh /
# build-image/build-engine-win.sh - the Windows cross-build's own scratch
# copy of engine/ lives under /build/win-engine/, already covered above)
/engine/build_ext/
/engine/.build-output/
/engine/.build-output-win/
/engine/CMakeCache.txt
/engine/CMakeFiles/
/engine/cmake_install.cmake
+373
View File
@@ -0,0 +1,373 @@
# AGENTS.md
Guidance for AI coding agents (and new contributors) working on Questshock.
README.md is the user-facing build/usage guide and CONFIG.md documents the
configuration file; this file covers how the code is organised and the rules to
follow when changing it.
## 1. What this project is
Questshock plays the 1994 game System Shock on a standalone VR headset (Meta
Quest 2 is the tested device). It wraps [Shockolate](https://github.com/Interrupt/systemshock),
a cross-platform port of the original engine, in an Android app that:
- runs the unmodified 2D engine (software or OpenGL renderer) and shows its
frame on a head-tracked virtual screen (an OpenXR quad layer);
- shows a menu and an on-screen keyboard as separate OpenXR quads, operated by
a laser pointer from either controller;
- maps controller inputs to game actions through a configurable binding layer;
- persists settings in `/sdcard/questshock/questshock.config.json`.
A desktop (Linux/Windows) build of the same engine exists for development
without a headset; it has none of the Android/OpenXR code.
## 2. Hard rules
These come from the maintainer. Follow them without being asked again.
1. **Never commit.** Do not run `git commit` (or amend, rebase, push), even if
asked to commit. Draft the commit message and show it; the maintainer runs
the commit. Mention any new untracked file that has to be `git add`ed
(typically a new patch under `android/engine-patches/`).
2. **Do not build.** Do not run `make apk`, `./gradlew`, or `make android-studio`
to check that a change compiles. The maintainer deploys from Android Studio.
`make apk` and `make android-studio` overwrite `android/engine.properties`
with container-only paths and break an open Android Studio project. What you
can do is dry-run patches (section 6) and run static consistency checks
(section 12). Say plainly in your report that the change was not built or
tested.
3. **`engine/` and `android/gl4es-src/` are never edited.** They are vendored
snapshots. Every change to them is a numbered patch under
`android/engine-patches/` or `android/gl4es-patches/`, applied to a scratch
copy at build time. (`engine/` is GPLv3, see README section 6.)
4. **Patch numbers stay contiguous** (`01`, `02`, ... with no gap). When you
insert or delete a patch, renumber the rest and update every reference to
the numbers (README patch reference, code comments).
5. **Comments and documentation describe the current state and why it has to be
that way.** No history or narrative: no "used to", "originally", "no
longer", "now", "this was fixed", "confirmed on device", incident stories or
dropped alternatives. History belongs in commit messages. A comment that
would read oddly to someone who never saw an earlier version should be
rewritten or cut. Default to one or two lines. (README section 5.5, the
debugging notes, is the one deliberate exception.)
6. **Standalone headset only, OpenXR first.** No feature may need a host PC
(no PCVR, tethering or streaming). Prefer OpenXR APIs over vendor-specific
ones (Meta's Oculus Mobile SDK and the like) so the port can run on other
Android OpenXR headsets. Flag a request that would break either rule
instead of quietly doing it.
7. **Do not bump `build-image/VERSION`** just because `build-image/Dockerfile`
changed. Bump it only once a build with the current number has succeeded
end to end (for example a CI run). Ask if unsure.
8. **Keep docs in sync with behaviour.** A user-visible change updates
README.md and/or CONFIG.md in the same change; a new or renumbered engine
patch updates the README patch reference (section 5.4).
## 3. Repository layout
| Path | What it is |
|---|---|
| `engine/` | Vendored Shockolate source. Read-only for us. |
| `android/engine-patches/` | Numbered `patch -p1` files applied to a scratch copy of `engine/`. |
| `android/gl4es-src/`, `android/gl4es-patches/` | Vendored GL4ES (desktop GL to GLES) and its patches. |
| `android/app/src/main/cpp/` | First-party native code (section 4). |
| `android/app/src/main/java/de/ladkau/questshock/` | First-party Java (section 4). `org/libsdl/app/` is vendored SDL2 glue (zlib). |
| `android/app/build.gradle` | Gradle project; the `stageEngine` task stages the patched engine. |
| `android/force-rebuild.sh` | Stops Gradle daemons and wipes staged/build output for a fully fresh native build. |
| `build-image/` | Docker build environment (`Dockerfile`, `VERSION`, `prepare-android-project.sh`, `build-apk.sh`, engine build scripts). |
| `res/` | Bundled resources: `questshock.config.default.json`, `controller_profiles/` (JSON + PNG per controller), `assets/` (where the user's own game data goes, git-ignored), `run.sh`/`run.bat`. |
| `Makefile` | `engine`, `dist`, `package`, `apk`, `android-studio`, `clean`, ... (see README section 2). |
| `README.md`, `CONFIG.md`, `NOTICE.txt` | User docs, config reference, license notice. |
`build/`, `dist/`, `dist-win/` and `res/assets/ss_ee/` are generated or
proprietary and git-ignored. `registry.env` holds local registry settings; do
not print it or commit it.
## 4. Android app architecture
### 4.1 Native modules (`android/app/src/main/cpp/`)
| File | Role |
|---|---|
| `xr_session.c/.h` | OpenXR instance and session lifecycle, frame loop, composition layers (game quad, menu, keyboard, laser beams). |
| `xr_swapchain.c/.h` | Swapchain creation, acquire and release, per-image FBOs. |
| `xr_overlay.c/.h` | Generic "off-screen Android `View` rendered into an OpenXR quad" module, hit-tested by a laser pointer. The menu and the keyboard are two instances. |
| `xr_input.c/.h` | Controller input: OpenXR actions, raw-input layer, action bindings, capture-mode rebinding, key injection into the engine, free view, cyberspace scaling, snap-turn/smooth-move of the player's position, pointer rays. The largest file. |
| `xr_mouse.c/.h` | Injects mouse motion and clicks into the engine. |
| `qs_config.c/.h` | Configuration: JSON parse, apply, write; screen profiles; menu-driven requests; cheats; menu-triggered pause. |
| `questshock_native.c` | JNI exports and small native helpers (`nativeChdir`, `nativeSendPrintableChar`, ...). |
### 4.2 Java classes
| Class | Role |
|---|---|
| `QuestShockActivity` | `SDLActivity` subclass. Creates `/sdcard/questshock/`, extracts bundled files, blocks engine start until the game data exists. |
| `OverlayPanel` | Base for the off-screen panels: builds the view tree, renders it to a texture, turns ray hits into touch events. |
| `MenuOverlay` | The menu: Main Menu, Video Options, Controller Options and Cheats tabs. Singleton. |
| `KeyboardOverlay` | The on-screen keyboard. |
| `Strings` | All menu and keyboard text in English, French and German. |
### 4.3 How the pieces fit
- The engine's present path is redirected (engine patch 11) so that
`SDLDraw()` submits into the OpenXR game-quad swapchain. The per-frame
entry point of `xr_input.c` is `xr_input_sync_and_draw()`, called from the
frame path in `xr_session.c` on the engine's own thread.
- The engine's own log output goes to logcat (patch 08); Java and native
first-party code log under the tag `QuestShock`.
- Bindings, config and menu state are owned natively. Java only displays and
requests.
### 4.4 Threads and cross-thread requests
- Engine state (player struct, game loop, cheats, config apply) must only be
touched on the engine thread.
- Menu code calls native functions through JNI. Anything that changes engine
state must be enqueued, not executed inline: the JNI export calls a
`qs_config_request_*()` function, which pushes an SDL custom event
(`SDL_RegisterEvents`); `qs_config_handle_event()` handles it on the engine
thread (it is called from `pump_events()`, engine patch 21). To add a new
request, add an event type, the `qs_config_request_*()` enqueue function and
a branch in `qs_config_handle_event()`.
- Getters that Java calls (`qs_config_cheat_unlimited_mask()`, binding-name
getters, ...) must be plain scalar or string reads that are safe from any
thread.
- Per-frame work that must run on the engine thread (such as
`qs_config_frame_tick()`) is called from `xr_input.c`.
- JNI symbol names must match the Java `native` declarations exactly
(`Java_de_ladkau_questshock_<Class>_<method>`). A mismatch only fails at
runtime, so check it (section 12).
### 4.5 Off-screen views (`OverlayPanel`, `MenuOverlay`, `KeyboardOverlay`)
The view tree is built and drawn from native code and is never attached to a
window. Consequences that shape the UI code:
- Only `ACTION_DOWN`/`ACTION_UP` touches arrive (the laser trigger). There is no
drag, fling or multi-touch. Scrolling is done by a self-drawn scroll bar
(`ScrollBarView` in `MenuOverlay`), not by the framework.
- `View.post()` never runs, so anything that defers work through it does not
work. `ProgressBar` and `SeekBar` are unusable for the same reason.
- Hover and hit-testing use `OverlayPanel.absoluteBounds()`, which subtracts
ancestor scroll offsets.
- Toggling a child's visibility needs an explicit re-measure and re-layout
(see `relayoutAndRedraw()`).
- All user-visible text goes through `Strings.get(key, language)` with an
English, French and German entry, and is re-applied in `applyTranslations()`
when the language changes. "OpenGL" is a brand name and is not translated.
## 5. Configuration system
- `qs_config.c` holds one parsed struct per group (`video_options`, `general`,
`player_position`, `player_controls`), a parse function, an apply function,
and the writer `qs_config_write_file()`. Groups are tagged live-appliable or
restart-required (`QS_*_REQUIRES_RESTART`).
- Load order at startup: `questshock.config.json`, else
`questshock.config.default.json` (bundled, refreshed on every launch), else
the engine's own `prefs.txt` behaviour. Save is only ever an explicit menu
action.
- Invalid values are logged and skipped individually; unknown keys are ignored.
**Adding an option:** parsed-struct field, parse, apply (with validation and a
`WARN` on invalid input), write in `qs_config_write_file()`, restart flag,
`CONFIG.md`, and (if it should have a shipped default) `res/questshock.config.default.json`.
The virtual screen has two profiles, "initial" (splash, cutscenes, main menu)
and "game", switched by `qs_screen_profile_notify_loop_mode()` from engine
patch 22. `s_screen_profile_is_game` in `qs_config.c` doubles as "a game is
running" and gates the cheats and the menu pause.
## 6. Engine patches
Rules:
- Guard every engine change with `#ifdef __ANDROID__` so the desktop build is
unaffected, and keep hunks minimal.
- Patches are applied in filename order with `patch -p1` from the engine root
(paths look like `a/src/GameSrc/hkeyfunc.c`). Patch N is generated against
the tree with patches `01..N-1` applied.
- Some engine files use CRLF line endings (for example `mouselook.c`). Edits
and generated patches must preserve them byte for byte; check with `file`
or `cat -A`. An editor or script that rewrites line endings produces a
whole-file diff.
- Do not hand-edit hunk headers. Regenerate the patch from a scratch copy.
Creating or changing a patch:
1. Make a scratch copy of `engine/` (for example under the session scratch
directory) and apply patches `01..N-1` to it (`patch -p1 -d <scratch> < ...`).
2. Copy the target file(s) to a second location, edit them in the scratch copy.
3. Produce the patch with `diff -u` using `a/` and `b/` path prefixes relative
to the engine root, and save it as `android/engine-patches/NN-android-<topic>.patch`.
4. Dry-run the whole series on a fresh copy of `engine/`
(`patch -p1 --dry-run`, or apply for real on the copy) and confirm every
patch applies cleanly, with the patched file byte-identical to what you
edited.
5. Keep numbering contiguous, and update the README patch reference (5.4) and
any code comments that cite patch numbers.
Gradle's `stageEngine` task re-stages and re-patches on build, but it can wrongly
report `UP-TO-DATE` when a **new** patch file appears. If a native change does
not show up on the device, tell the maintainer to run `./gradlew --stop`, or
`android/force-rebuild.sh`, or delete `build/android-engine`, before assuming
the change is wrong.
Engine symbols used from first-party code (for example `game_paused`,
`pause_game_func`, `toggle_giveall_func`, `qs_cheat_refill`,
`qs_in_cyberspace`) are declared `extern` next to their use in `qs_config.c` or
`xr_input.c`, with a comment naming the engine file and patch.
## 7. Controller mapping (`xr_input.c`)
Structure:
- Physical controls are OpenXR actions, suggested once against three
interaction profiles: Meta Touch, HTC Vive wand and the core
`khr/simple_controller`. A single wrong path makes the whole
`xrSuggestInteractionProfileBindings` call fail, so each profile lists only
components it really has. A failure calls
`qs_config_report_fatal_input_error()` and aborts input init.
- The **raw-input layer** (`QsRawInput`) digitizes every physical control
(buttons, triggers, squeezes, thumbstick clicks, and eight thumbstick
directions with hysteresis) each frame. `QS_RAW_NONE` means unbound.
- **Actions** (`QsControlAction`) are bound to raw inputs through `s_binding[]`.
The default bindings are `kDefaults[]`.
- Contexts: `ALWAYS`, `NORMAL` (move, strafe, turn, jump, stand, crouch, prone)
and `CYBER` (the eleven `cyber_*` actions). The active set is chosen with
`qs_in_cyberspace()` (patch 24). Two actions conflict only if their contexts
can be active together (`xr_input_contexts_overlap()`).
- Capture mode (`xr_input_process_capture()`): the next fresh raw down-edge is
assigned to the chosen action. Any other action in an overlapping context that
held that input (or its symmetric alias) is set to `none`. The reset and the
timeout (8 s) paths never leave a half-assigned state.
- The menu button is not a raw input and can never be bound, so the menu can
always be reached to press **Reset to Defaults**.
- While the menu is open, `mouse_click` is always the trigger (the controller
used to operate the menu); after it closes, the bound `mouse_click` drives
both the keyboard and the game quad.
- While the Controller Options tab is open, the menu's own thumbstick
snap-turn and smooth-move are disabled
(`g_controller_options_tab_open`, set through
`nativeSetControllerOptionsTabOpen`).
- Free view: holding a `free_*_thumbstick_view` binding turns that stick into
the engine's mouse look (cursor forced hidden, stick direction bindings
suspended). It uses `SDL_ShowCursor(SDL_DISABLE)` because the engine zeroes
mouse-look velocity while the cursor is visible.
- Cyberspace pitch and bank scale with stick deflection through the globals
from patch 25 (`qs_cyber_pitch_scale`, `qs_cyber_bank_scale`).
### Adding or changing a bindable action (checklist)
All of these lists share one order and must stay identical:
1. `QsControlAction` enum in `xr_input.c` (and append before `QS_ACTION_COUNT`).
2. `kActionNames[]` in `xr_input.c`.
3. `s_binding[]` initial values and `kDefaults[]` in `xr_input.c`.
4. If it injects a key: a `kKeyActions[]` entry (keycode, modifiers, whether it
needs `SDL_TEXTINPUT`); add the key to the stuck-key watchdog list
(`kWatchedKeys`) if it is held continuously.
5. `ACTION_KEYS` in `MenuOverlay.java`, and `FIRST_ROW_ACTIONS` if it should be
listed first.
6. `Strings.java`: `action_<key>` in EN/FR/DE.
7. `QS_MAX_PLAYER_CONTROL_ACTIONS` in `qs_config.c` if the count outgrows it.
8. `CONFIG.md`: the action tables and the count in the Player Controls intro;
README default-controls table if it has a default binding.
9. Check that no two actions that can be active together share a default input.
### Injecting keys into the engine
- Plain printable keys (letters, digits, Space, punctuation) need an
`SDL_TEXTINPUT` event plus `SDL_KEYDOWN`/`SDL_KEYUP`. Modifier, control-range,
F and keypad keys use `SDL_KEYDOWN`/`SDL_KEYUP` with the right `mod`.
- **Send the release on the real up edge, never in the same call as the
press.** The engine polls movement keys once per frame before it drains
events, so a press and release drained together are never seen and the key
silently does nothing. Tie the release to the physical button's up edge (or
the touch's `ACTION_UP`/`ACTION_CANCEL`).
- Held keys are tracked in the engine's `sshockKeyStates[]`; `xr_input.c`
keeps a watchdog that clears a watched key the engine still thinks is down
after its binding is released.
- Actions that share an engine key (for example the several ways to fire, or
the movement keys) are handled with sibling logic in the dispatch loop
(`wantDown[]`); do not press or release the shared key independently.
## 8. Cheats tab
- Buttons and switches live in `MenuOverlay.buildCheatsTab()`; ids are
`QS_CHEAT_*` in `qs_config.c` and `CHEAT_*` in `MenuOverlay.java` (keep them
identical).
- The engine's own cheat handlers (`toggle_giveall_func`, `toggle_physics_func`,
`toggle_up_level_func`, `toggle_down_level_func`) are called on the engine
thread through `qs_apply_cheat()`, and only while a game is running.
- The four unlimited switches are a bitmask in `qs_config.c`
(`QS_CHEAT_MASK_*`: health 1, energy 2, ammo 4, items 8). Every frame
`qs_config_frame_tick()` calls `qs_cheat_refill(mask)` (patch 26). The mask
values must match the patch. The switches are not persisted.
- The four `cheat_*` hotkeys are deliberately not bindable in
`player_controls`. New cheats go on the Cheats tab.
## 9. Menu pause
Opening the menu pauses a running game (`qs_apply_menu_pause()` through the
menu-visibility event); closing it resumes only if the menu did the pausing and
the game is still paused. Do not toggle pause blindly, since the pause function
toggles.
## 10. Bundled files on the device
`QuestShockActivity` extracts these into `/sdcard/questshock/`:
- shaders, the default soundfont and `GET_ASSETS_QUEST.txt` (once);
- `questshock.config.default.json` and `controller_profiles/` (every launch,
overwriting only the bundled filenames so user-added profiles survive).
`res/controller_profiles/` and the default config are staged into APK assets by
`build-image/prepare-android-project.sh`; new staged directories must also be
declared as `inputs.dir(...)` of `stageEngine` in `android/app/build.gradle`.
The proprietary game data (`res/data/`, `res/sound/`) is never bundled or
committed. The app refuses to start the engine until it is present.
## 11. Code and documentation style
- Match the surrounding code: naming, comment density, idiom. C is plain C with
`static` helpers and `//` comments; Java targets Android API 34 and uses only the SDK plus
`androidx.core`.
- Keep functions and file-level constants near their use. Put magic numbers in
named constants (see `QS_FREE_VIEW_*`, `QS_CYBER_ROTATION_*`).
- Keep the `xr_input.h` and `qs_config.h` declarations documented with a short
comment saying which thread may call them.
- Comments: what and why, current state only (rule 5 in section 2).
- Docs: README.md is organised by numbered sections that other text cites
("5.5.3"); do not renumber existing sections. Add new material as a new
subsection instead.
- English, French and German strings live in `Strings.java`; keep the three
entries of each key on the same `put(...)`.
## 12. Verifying a change without building
Because you may not build (rule 2), check statically and say so in the report:
- **Patches:** apply the whole series to a fresh copy of `engine/` and confirm
no rejects. Confirm the edited file matches the patched result byte for byte.
- **JNI:** every `native` method in the Java classes has a
`Java_de_ladkau_questshock_<Class>_<method>` export with a matching signature,
and no export is left without a Java declaration.
- **Ordered lists:** `QsControlAction`, `kActionNames[]`, `s_binding[]`,
`kDefaults[]` and `ACTION_KEYS` have the same length and order.
- **Strings:** every `Strings.get("...")` key exists in `Strings.java`.
- **Balance:** braces and parentheses balance. `qs_config.c` reports a
brace-count offset of +5 from character literals containing `'{'`; that is
not a bug.
- **Docs:** README and CONFIG.md agree with the code (action counts, default
bindings, patch list).
Then report what was checked, what was not (build, on-device behaviour), and
any device check the maintainer should do (for example a new patch that may
need `android/force-rebuild.sh`).
## 13. Commit messages
Draft only (rule 1). Use a short imperative subject (about 70 characters), a
blank line, then a body that explains what the change does and why: the
user-visible behaviour, the mechanism, and any constraint worth remembering.
Mention new files that need `git add`.
+458
View File
@@ -0,0 +1,458 @@
# Persistent configuration (`questshock.config.json`)
QuestShock can load a persistent, human-editable configuration file at
startup, in addition to (and independent of) the engine's own `prefs.txt`.
- **Location**: `/sdcard/questshock/questshock.config.json` - the same
folder you already copy `res/data`/`res/sound` into (see README.md
section 5.1).
- **Format**: plain JSON, grouped by concern. Each top-level key is a
*group*; each key inside a group is one *option*.
- **Loading**: read automatically at app startup, before the splash screen,
if the file exists. If it doesn't, `questshock.config.default.json` (same
folder) is used instead - a copy bundled with the app, refreshed on every
launch, never overwriting your own saved `questshock.config.json`. If
neither file exists, the engine behaves as it did before this file
existed (driven by `prefs.txt` as usual).
- **Saving**: never automatic. In-headset, open the menu (controller menu
button) and press **Save Configuration** to write the file from your
current live settings, overwriting it if present. Press **Load
Configuration** to re-read the file and apply it without restarting the
app.
- **Live vs. restart-required**: every option below is tagged as either
*live-appliable* (applying it while already playing takes effect
immediately) or *restart-required*. Pressing **Load Configuration**
applies every live-appliable change straight away; if the file also
changes something restart-required, a dialog lists exactly which
option(s) need it and offers:
- **Dismiss** - keep playing with the live-appliable changes already
applied; the restart-required option(s) stay as they were.
- **Restart Now** - relaunches the app, which re-runs this same startup
load and so applies every group in the file, including the
restart-required ones.
(Every option currently documented below is live-appliable, so this
dialog won't actually appear yet - it's built in for options added in a
future version that do need a restart.)
- Unrecognized groups/keys are ignored (harmless if you're editing the file
in advance for a future version). An invalid value for a *specific*
option (see each option's possible values below) is logged and that one
option is skipped - every other valid option in the file still applies.
A file that isn't valid JSON at all is ignored entirely, with nothing
applied.
- `questshock.config.json` and `prefs.txt` are fully independent - loading
or saving one never reads or writes the other.
## Example
```json
{
"video_options": {
"renderer": "opengl",
"resolution": "1024x768",
"initial_screen_width_m": 1.6,
"initial_screen_distance_m": 2.0,
"game_screen_width_m": 2.8,
"game_screen_distance_m": 2.0,
"screen_width_offset_m": 1.0,
"screen_width_step_m": 0.6,
"screen_distance_offset_m": 1.0,
"screen_distance_step_m": 0.5
},
"general": {
"language": "english"
},
"player_position": {
"x": 0.0,
"z": 0.0,
"yaw_degrees": 0.0
},
"player_controls": {
"move_forward": "left_thumbstick_up",
"move_back": "left_thumbstick_down",
"strafe_left": "left_thumbstick_left",
"strafe_right": "left_thumbstick_right",
"turn_left": "right_thumbstick_left",
"turn_right": "right_thumbstick_right",
"jump": "left_thumbstick_click",
"mouse_click": "right_a",
"mouse_double_click": "right_b",
"stand": "right_thumbstick_up",
"prone": "right_thumbstick_down",
"map_view": "right_thumbstick_click",
"fire_weapon": "right_trigger"
}
}
```
## Video Options (`video_options`)
### `renderer`
Which renderer the game uses to draw the 3D view.
- **Type**: enum
- **Possible values**: `"software"`, `"opengl"`
- **Restart required?**: No (live-appliable)
### `resolution`
The game's internal rendering resolution.
- **Type**: enum
- **Possible values**: `"320x200"`, `"320x400"`, `"640x400"`, `"640x480"`, `"1024x768"`
- **Restart required?**: No (live-appliable)
### `initial_screen_width_m`, `initial_screen_distance_m`, `game_screen_width_m`, `game_screen_distance_m`
The virtual screen's physical width and distance from the player (both in
meters) - the game shows two independently configurable screen
"profiles", switched automatically based on what's currently on screen:
- **Initial Screen** (`initial_screen_*`) - the splash screen, intro
cutscenes, and the game's own main menu.
- **Game Screen** (`game_screen_*`) - actual gameplay (the 3D view,
automap, cyberspace, etc.).
Switching happens automatically - no player action needed - the instant
the game itself transitions between these (e.g. starting/loading a game,
or returning to the menu).
- **Type**: number (meters)
- **Possible values**: the in-headset Video Options tab offers 5 presets
each - widths `1.0`, `1.6` (the original, pre-this-feature default),
`2.2`, `2.8`, `3.4`; distances `1.0`, `1.5`, `2.0` (the original,
pre-this-feature default), `2.5`, `3.0` - but a hand-edited value
doesn't need to match a preset exactly (it's clamped to a sane range -
width `[0.2, 10.0]`, distance `[0.5, 10.0]` - rather than snapped or
rejected; the Video Options tab just shows no button selected for an
in-between value).
- **Restart required?**: No (live-appliable)
- **Note**: the screen is always flat - there's no curve option.
### `screen_width_offset_m`, `screen_width_step_m`, `screen_distance_offset_m`, `screen_distance_step_m`
Reshapes the 5 preset buttons the Video Options tab offers for width and
distance (above) - config-file-only, there's no in-headset control for
these. Shared by both **Initial Screen** and **Game Screen** (both
columns' buttons show the same 5 values per row) - this only changes
what the buttons offer, not either profile's current value.
Preset button `index` (0-4) shows `offset + step * index`. For example,
a distance offset of `0` and step of `2` shows buttons `0`, `2`, `4`,
`6`, `8`; the defaults below reproduce this feature's original launch
presets exactly.
- **Type**: number (meters)
- **Default values**: width offset `1.0`, step `0.6` (buttons `1.0`,
`1.6`, `2.2`, `2.8`, `3.4`); distance offset `1.0`, step `0.5` (buttons
`1.0`, `1.5`, `2.0`, `2.5`, `3.0`).
- **Restart required?**: No (live-appliable)
- **Note**: not clamped - an unusual offset/step (e.g. negative step) is
accepted as-is. A resulting preset value outside the current value's
own clamp range (see above) still clamps normally when that preset
button is actually pressed.
## General (`general`)
### `language`
The game's UI/text language - both the game's own resource strings and this
project's own menu/keyboard chrome text (title bar, buttons, etc.).
- **Type**: enum
- **Possible values**: `"english"`, `"french"`, `"german"`
- **Restart required?**: No (live-appliable) - applies the same way the
game's own in-game options menu applies a language change (reloads the
language-specific resource files and refreshes the inventory/MFD/side-icon
UI immediately).
- **Note**: French and German both need their own full resource pack
(`frnstrng.res`/`mfdfrn.res`, `gerstrng.res`/`mfdger.res` under
`res/data/`) - if any of those files aren't present, the switch is
refused (logged, `questshock.config.json` and the current language are
left unchanged) rather than leaving the game with no valid resource file
open. See README.md section 3 ("Game assets") for where `mfdfrn.res`/
`mfdger.res` come from - the GOG Enhanced Edition installer alone doesn't
include them.
- The intro cutscene is also played in the selected language when its
voice-over file (`svfrintr.res`/`svgeintr.res` under `res/data/`) is
present; otherwise the English intro plays.
## Player Position (`player_position`)
Where the player is virtually standing/facing, independent of - and not
reset by - starting a new game or loading a save (same independence from
`prefs.txt`/savegames as every other group here). Set by moving around
in-headset (menu open, left thumbstick snap-turns, right thumbstick smooth-
moves) to line yourself up with the game quad ("virtual screen"). Height is
never included here - it always comes from your real tracked headset
height, not this file.
**Startup fallback**: only applied at startup if all three fields (`x`,
`z`, `yaw_degrees`) are present - a config file with none of them (or none
at all), or a partial/hand-edited one missing any of the three, falls back
to an automatic recenter instead (see **Reset Position** below), using
your real head pose at that moment. A complete saved position is applied
as-is, with no such recenter.
**Reset Position** (Main Menu tab) is a live-only action, not a config
value: it moves you to the centre in front of the game quad, based on where
your head actually is right now. It resets only your *position*, not which
way you're facing, so the screen does not rotate to follow your gaze - press
it while looking off to one side and the screen stays off to the other side.
The automatic recenter at startup (when there's no saved position) does
face the screen towards where you're looking. Reset Position never reads or
writes `questshock.config.json`.
### `x`, `z`
Horizontal position, in meters, on the play space's floor plane.
- **Type**: number
- **Restart required?**: No (live-appliable)
### `yaw_degrees`
Which way the player is virtually facing, in degrees.
- **Type**: number
- **Restart required?**: No (live-appliable)
## Player Controls (`player_controls`)
Maps each of 57 in-game actions to a physical controller input: 9
movement/click actions, 2 free-view actions, 11 cyberspace actions, and 35
for the engine's own keyboard hotkeys and firing (posture, save/load, weapon
select, MFD panels, etc. - see the hotkey table below). Some actions are bound by default (see the default-input
columns); the rest are unbound and can be bound on demand. Assign them in the
**Controller Options** menu tab: tap an action's binding button, then press
the button or stick direction to use ("Press a button…"); tap it again, or
wait 8 seconds, to cancel without changing it.
- **Type**: one enum-string field per action (below)
- **Restart required?**: No (live-appliable) - a rebind takes effect
immediately, and persists across restarts once saved (**Save
Configuration**, same as every other group here).
- **Menu movement**: while the Controller Options tab is open, the menu's own
thumbstick snap-turn and smooth-move (see `player_position`) are disabled, so
pressing inputs to assign them doesn't move you away from the screen.
- **Not included here**: opening/closing the VR menu itself is a fixed,
non-remappable button (see "Menu button" below) - there's no
`menu_toggle` field, and the Controller Options tab never lets you
reassign it. This guarantees you can always reach this tab and press
**Reset to Defaults** to recover from any bad rebind, no matter what else
you've reassigned.
- **Reset to Defaults**: restores the "Default input" column below for
every action not overridden by a `player_controls` group in
`questshock.config.default.json` - if that file defines one (it doesn't,
out of the box), the values it specifies are applied on top of the table
below instead, so you can customize what "reset" means without a rebuild.
This is independent of your own `questshock.config.json` - resetting
doesn't read or write that file, just the live bindings (**Save
Configuration** afterward to persist them).
### Actions
| Action key | Default input | Effect |
|---|---|---|
| `move_forward` | `left_thumbstick_up` | Walk forward |
| `move_back` | `left_thumbstick_down` | Walk backward |
| `strafe_left` | `left_thumbstick_left` | Step sideways, left |
| `strafe_right` | `left_thumbstick_right` | Step sideways, right |
| `turn_left` | `right_thumbstick_left` | Turn left |
| `turn_right` | `right_thumbstick_right` | Turn right |
| `jump` | `left_thumbstick_click` | Jump |
| `mouse_click` | `right_a` | Click - operates the keyboard/game quad's cursor, whichever the pointing hand's ray is over |
| `mouse_double_click` | `right_b` | Double-click - game quad only (e.g. using an inventory item); has no effect over the menu or keyboard |
| `free_left_thumbstick_view` | `left_squeeze` | Hold to look around with the left thumbstick (see below) |
| `free_right_thumbstick_view` | `none` | Hold to look around with the right thumbstick (see below) |
Movement actions bound to a thumbstick direction are suppressed while the
VR menu is open, since the same physical stick already snap-turns/smooth-
moves the player in that state (see `player_position` above) - this is the
one case where a binding's effect depends on whether the menu is open, and
it only ever affects the 8 thumbstick-direction inputs below.
**Free view** (`free_left_thumbstick_view`, `free_right_thumbstick_view`) is
the engine's mouse look driven by a thumbstick. While the bound input is held,
that stick looks around instead of doing its normal job: left/right turns the
view, up/down looks up and down, in proportion to how far the stick is pushed.
The stick's own direction bindings (move, strafe, turn, stand/prone) are
suspended while it is held, and the cursor stays centred in the view. Release
the input to return to normal. It has no effect while the VR menu is open.
### Cyberspace actions
Cyberspace has its own set of movement actions, active only while the player
is in cyberspace. While in cyberspace the normal movement actions
(`move_*`, `strafe_*`, `turn_*`, `jump`, `stand`, `crouch`, `prone`) are
inactive, and the cyberspace actions are inactive everywhere else. Each set
has its own bindings, so one input can be bound in both (for example the left
stick up is `move_forward` on foot and `cyber_climb` in cyberspace);
the Controller Options tab only reports a conflict between actions that can
be active at the same time. Free view, clicking and firing work in both.
Pitch and bank (`cyber_climb`, `cyber_dive`, `cyber_bank_*` and the four
diagonals) are proportional when bound to a thumbstick direction: pushing the
stick further turns faster, from 20% of full speed just past the trigger point
to 60% at full deflection. Bound to a button they run at full speed. Thrust and
roll are always full speed.
| Action key | Default input | Keyboard equivalent | Effect |
|---|---|---|---|
| `cyber_thrust` | `right_thumbstick_up` | `s` | Thrust forward |
| `cyber_climb` | `left_thumbstick_up` | `w` | Pitch up |
| `cyber_dive` | `left_thumbstick_down` | `x` | Pitch down |
| `cyber_bank_left` | `left_thumbstick_left` | `a` | Bank left |
| `cyber_bank_right` | `left_thumbstick_right` | `d` | Bank right |
| `cyber_roll_left` | `right_thumbstick_left` | `e` | Roll left |
| `cyber_roll_right` | `right_thumbstick_right` | `q` | Roll right |
| `cyber_climb_left` | `none` | Keypad 7 | Pitch up and bank left |
| `cyber_climb_right` | `none` | Keypad 9 | Pitch up and bank right |
| `cyber_dive_left` | `none` | Keypad 1 | Pitch down and bank left |
| `cyber_dive_right` | `none` | Keypad 3 | Pitch down and bank right |
`mouse_click` additionally behaves differently depending on the menu:
while the VR menu is open, its "click" is always whichever hand's trigger
is used to interact with the menu (so you can never lock yourself out of
this settings screen by rebinding `mouse_click` elsewhere); once the menu
is closed, both the on-screen keyboard (if it's still open) and the game
quad use your actual `mouse_click` binding. The default (`right_a`) is a
specific button on the right controller, so only the right hand's ray clicks;
bind the `trigger` identifier (see below) for either hand to click.
### Hotkey actions
The engine's own keyboard hotkeys (`HotKeyLookup[]` in `Prefs.c`) plus
firing, as 35 bindable actions. `stand` (`right_thumbstick_up`), `prone`
(`right_thumbstick_down`), `map_view` (`right_thumbstick_click`) and
`fire_weapon` (`right_trigger`) are bound by default; the rest are unbound
(`none`). Each fires once per press, like pressing the key on a real
keyboard (there is no hold behavior).
| Action key | Keyboard equivalent | Effect |
|---|---|---|
| `stand` | `t` | Stand up |
| `crouch` | `g` | Crouch |
| `prone` | `b` | Go prone |
| `pause` | `p` | Pause the game |
| `full_view` | Ctrl+F | Switch to the fullscreen view loop |
| `normal_view` | Ctrl+D | Switch to the normal gameplay view |
| `map_view` | Ctrl+A | Switch to the automap view |
| `save_game` | Ctrl+S | Save the game |
| `load_game` | Ctrl+L | Load the game |
| `select_grenade` | Ctrl+' | Select the next grenade type |
| `arm_grenade` | Alt+' | Arm the selected grenade |
| `select_drug` | Ctrl+; | Select the next drug/patch |
| `use_drug` | Alt+; | Use the selected drug/patch |
| `toggle_online_help` | Ctrl+H | Toggle the online help overlay |
| `show_help` | Alt+O | Show the help screen |
| `toggle_music` | Ctrl+M | Toggle music |
| `quit` | Ctrl+Q | Quit the game - opt-in only; nothing binds this by default |
| `cycle_weapon_next` | Tab | Ready the next weapon |
| `cycle_weapon_prev` | Shift+Tab | Ready the previous weapon |
| `cycle_detail` | Ctrl+1 | Cycle the graphics detail level |
| `reload_weapon_primary` | Ctrl+Backspace | Reload the current weapon's primary ammo |
| `reload_weapon_secondary` | Alt+Backspace | Reload the current weapon's secondary ammo |
| `hud_color` | Alt+H | Cycle the HUD color scheme |
| `clear_fullscreen` | Backspace | Close a fullscreen view (e.g. a datapad or email) |
| `mfd_left_1`-`mfd_left_5` | F1-F5 | Set the left MFD panel to Weapon/Item/Map/Target/Info |
| `mfd_right_1`-`mfd_right_5` | F6-F10 | Set the right MFD panel to Weapon/Item/Map/Target/Info |
| `fire_weapon` | Enter | Fire the readied weapon at the cursor (the engine's default fire key). Clicking in the 3D view with `mouse_click` also fires; this is a separate button for it |
**Not exposed** (other `HotKeyLookup[]` entries):
- `keypad 0`-`keypad 9`: a controller button per digit is not useful; use the
on-screen keyboard.
- `toggle_freelook` (F): the free-view actions cover mouse look.
- The 4 `cheat_*` entries: debug cheats. They are on the menu's Cheats tab
instead, along with four switches for unlimited health, energy, ammo and
items. Those are not saved to the config.
- `mac_help` (disabled) and `audiolog_cancel` (its build flag is not
defined): they are not real hotkeys in this build.
- `toggle_opengl` (Ctrl+G): the Video Options tab's Renderer buttons already
toggle the same setting.
- The 10 numeric hardware-item hotkeys (bio scan, fullscreen, 360 view,
lantern, shield, infrared, nav unit, data reader, booster, jumpjets): their
registered keys never match a real keypress in the engine.
### Raw input identifiers
Every raw physical input available to bind an action to, with its generic
OpenXR interaction-profile component name and its Meta Quest Touch control
name. Two symmetric identifiers (`trigger`, `squeeze`) are also accepted, but
only for `mouse_click`/`mouse_double_click`: they mean "either hand's own
trigger/grip, whichever hand is pointing". Every other identifier below
refers to one specific control.
| Identifier | OpenXR component (Touch) | Meta Quest control |
|---|---|---|
| `left_trigger` | `/user/hand/left/input/trigger/value` | Left Trigger |
| `right_trigger` | `/user/hand/right/input/trigger/value` | Right Trigger |
| `left_squeeze` | `/user/hand/left/input/squeeze/value` | Left Grip |
| `right_squeeze` | `/user/hand/right/input/squeeze/value` | Right Grip |
| `left_x` | `/user/hand/left/input/x/click` | X Button |
| `left_y` | `/user/hand/left/input/y/click` | Y Button |
| `right_a` | `/user/hand/right/input/a/click` | A Button |
| `right_b` | `/user/hand/right/input/b/click` | B Button |
| `left_thumbstick_click` | `/user/hand/left/input/thumbstick/click` | Left Thumbstick Click |
| `right_thumbstick_click` | `/user/hand/right/input/thumbstick/click` | Right Thumbstick Click |
| `left_thumbstick_up/down/left/right` | `/user/hand/left/input/thumbstick` (digitized) | Left Thumbstick, tilted |
| `right_thumbstick_up/down/left/right` | `/user/hand/right/input/thumbstick` (digitized) | Right Thumbstick, tilted |
| `trigger` | either hand's trigger | Either Trigger (`mouse_click`/`mouse_double_click` only) |
| `squeeze` | either hand's grip | Either Grip (`mouse_click`/`mouse_double_click` only) |
| `none` | - | Unbound - the action never fires |
**Menu button** (left controller, Touch/Vive/generic alike) is not in this
list - it always opens/closes the VR menu and can never be reassigned.
**Other supported controllers**: HTC Vive wands have no A/B/X/Y and no
analog grip - `left_x`/`left_y`/`right_a`/`right_b` simply never fire on
that profile, and `left/right_squeeze` are a plain click rather than
analog. Their trackpad stands in for the thumbstick identifiers above
(same digitization, just a trackpad instead of a stick). A bare-minimum
OpenXR controller (`khr/simple_controller`, used as a fallback when
neither Touch nor Vive bindings are suggested) only has `left_trigger`/
`right_trigger` (via its `select/click` component) and the menu button -
every other identifier above simply never fires on it, which is why the
Controller Options tab shows a note and hides irrelevant rows when this
profile is active.
### Controller profile files (`controller_profiles/`)
The Controller Options tab shows a labeled illustration of whichever
controller is actually active, driven by `res/controller_profiles/*.json`
(bundled with the app, copied to `/sdcard/questshock/controller_profiles/`
on every launch, refreshing the known bundled files without touching any
extra ones you add there yourself). Each file:
```json
{
"name": "Meta Quest Touch",
"interaction_profile": "/interaction_profiles/oculus/touch_controller",
"image": "touch.png",
"controls": [
{"id": "right_b", "label": "B", "anchor_x": 0.76, "anchor_y": 0.22}
]
}
```
- `interaction_profile` - the OpenXR interaction profile path this file
describes; matched against whichever one is actually bound at runtime.
Falls back to `generic.json` if nothing matches.
- `image` - filename (same folder) of the controller illustration.
- `controls` - one entry per labeled point on that illustration: `id` is a
raw input identifier from the table above (thumbstick directions share
one `left_thumbstick`/`right_thumbstick` entry, since they're the same
physical stick); `anchor_x`/`anchor_y` are 0-1 fractions of the image for
positioning that label's pointer line.
This is presentation data only - adding real support for a new controller
still needs matching bindings in the app itself; a profile file with no
corresponding code-level support just never gets matched.
### Fatal startup error
If the OpenXR runtime rejects any of the three supported controller
profiles' bindings at launch (an app bug, not something you did), a
non-cancelable dialog explains this and exits - this should never happen
in a normal build.
+99 -15
View File
@@ -1,20 +1,28 @@
# Assembles dist/ - a self-contained, runnable copy of System Shock -
# from the compiled engine (built via Docker, see build-image.sh/
# run-image.sh) and the game assets extracted from a purchased copy (see
# Assembles dist/ (Linux) and dist-win/ (Windows, cross-compiled via
# MinGW) - self-contained, runnable copies of System Shock - from the
# compiled engine (built via Docker, see build-image.sh/run-image.sh) and
# the game assets extracted from a purchased copy (see
# res/assets/extract_assets.sh). Building the engine needs the build-image
# (./build-image.sh, once); everything else here is plain file copying.
# `dist-linux`/`dist-win` build just one platform; plain `dist` builds
# both.
#
# `make package` instead builds a redistributable tarball that omits the
# proprietary game assets entirely (see res/assets/GET_ASSETS.txt, which
# it ships in their place) - this is what CI publishes.
# `make package` instead builds redistributable archives (a .tar.gz for
# Linux, a .zip for Windows) that omit the proprietary game assets
# entirely (see res/assets/GET_ASSETS.txt, which they ship in their
# place) - this is what CI publishes. Same dist-linux/dist-win/(both)
# split via package-linux/package-win/package.
DIST_DIR := dist
ENGINE_OUT := engine/.build-output
ASSETS_DIR := res/assets/ss_ee
BUILD_DIR := build
ARCH := $(shell uname -m)
DIST_DIR := dist
DIST_WIN_DIR := dist-win
ENGINE_OUT := engine/.build-output
ENGINE_OUT_WIN := engine/.build-output-win
ASSETS_DIR := res/assets/ss_ee
BUILD_DIR := build
ARCH := $(shell uname -m)
.PHONY: all dist build-image engine assets package apk clean
.PHONY: all dist dist-linux dist-win build-image engine engine-win assets \
package package-linux package-win apk android-studio clean
all: dist
@@ -40,6 +48,16 @@ engine:
./run-image.sh; \
fi
# Cross-compiles engine/ for Windows via MinGW - see build-engine-win.sh
# for why this can't share build-engine.sh's engine/build_ext/ (a scratch
# copy is used instead). Same QUESTSHOCK_BUILD_IMAGE detection as `engine`.
engine-win:
@if [ -n "$$QUESTSHOCK_BUILD_IMAGE" ]; then \
bash build-image/build-engine-win.sh; \
else \
./run-image.sh bash build-image/build-engine-win.sh; \
fi
# Fails with a pointer to extract_assets.sh if the purchased game assets
# haven't been extracted yet.
assets:
@@ -49,7 +67,10 @@ assets:
exit 1; \
fi
dist: engine assets
# Builds both platforms. `dist-linux`/`dist-win` build just one.
dist: dist-linux dist-win
dist-linux: engine assets
@echo "== Assembling $(DIST_DIR) =="
rm -rf "$(DIST_DIR)/systemshock" "$(DIST_DIR)/lib" "$(DIST_DIR)/res" \
"$(DIST_DIR)/shaders" "$(DIST_DIR)/run.sh"
@@ -64,6 +85,27 @@ dist: engine assets
chmod +x "$(DIST_DIR)/run.sh"
@echo "== Done - run $(DIST_DIR)/run.sh to play =="
# Windows counterpart of dist-linux. Unlike dist/, the DLLs sit flat
# alongside systemshock.exe instead of in a lib/ subdirectory - Windows'
# default DLL search order already checks the executable's own directory
# first, so (unlike run.sh's LD_LIBRARY_PATH) run.bat needs no extra
# wiring for that.
dist-win: engine-win assets
@echo "== Assembling $(DIST_WIN_DIR) =="
rm -rf "$(DIST_WIN_DIR)"
mkdir -p "$(DIST_WIN_DIR)/res/data" "$(DIST_WIN_DIR)/res/sound"
cp "$(ENGINE_OUT_WIN)/systemshock.exe" "$(ENGINE_OUT_WIN)"/*.dll "$(DIST_WIN_DIR)/"
cp "$(ENGINE_OUT_WIN)/soundfont.sf2" "$(DIST_WIN_DIR)/res/"
cp -a engine/shaders "$(DIST_WIN_DIR)/shaders"
cp -a "$(ASSETS_DIR)/data/." "$(DIST_WIN_DIR)/res/data/"
cp -a "$(ASSETS_DIR)/sound/." "$(DIST_WIN_DIR)/res/sound/"
cp res/run.bat "$(DIST_WIN_DIR)/run.bat"
@echo "== Done - run $(DIST_WIN_DIR)/run.bat (or systemshock.exe) to play =="
# Builds both platforms' redistributable archives. `package-linux`/
# `package-win` build just one.
package: package-linux package-win
# Builds a versioned, redistributable Linux release tarball at
# dist/shockolate-<version>-linux-<arch>.tar.gz - everything needed to
# run except the proprietary game assets (res/GET_ASSETS.txt explains how
@@ -72,7 +114,7 @@ dist: engine assets
# tag to drive a release. Override with `make package VERSION=1.2.3`, or
# just run it untagged for a local dev build (gets a 0.0.0-dev+<sha>
# placeholder version, with a warning).
package: engine
package-linux: engine
@git config --global --add safe.directory "$$(pwd)" 2>/dev/null || true
@V="$$(VERSION="$(VERSION)" ./build-image/version.sh)"; \
PKG_NAME="shockolate-$$V-linux-$(ARCH)"; \
@@ -95,6 +137,33 @@ package: engine
rm -rf "$(BUILD_DIR)/package"; \
echo "Wrote $(DIST_DIR)/$$PKG_NAME.tar.gz"
# Windows counterpart of package-linux: dist/shockolate-<version>-windows-
# x86_64.zip. Same versioning (build-image/version.sh) and VERSION=
# override. Needs `zip` on whatever host runs `make package-win` itself
# (unlike engine-win's own build, packaging isn't run inside the
# build-image) - see README's Desktop build prerequisites.
package-win: engine-win
@git config --global --add safe.directory "$$(pwd)" 2>/dev/null || true
@command -v zip >/dev/null 2>&1 || { echo "PREFLIGHT FAIL: zip not found in PATH" >&2; exit 1; }
@V="$$(VERSION="$(VERSION)" ./build-image/version.sh)"; \
PKG_NAME="shockolate-$$V-windows-x86_64"; \
PKG_STAGE="$(BUILD_DIR)/package/$$PKG_NAME"; \
echo "Packaging $$PKG_NAME"; \
rm -rf "$$PKG_STAGE"; \
mkdir -p "$$PKG_STAGE/res"; \
cp "$(ENGINE_OUT_WIN)/systemshock.exe" "$(ENGINE_OUT_WIN)"/*.dll "$$PKG_STAGE/"; \
cp -a engine/shaders "$$PKG_STAGE/shaders"; \
cp "$(ENGINE_OUT_WIN)/soundfont.sf2" "$$PKG_STAGE/res/"; \
cp res/assets/GET_ASSETS.txt "$$PKG_STAGE/res/GET_ASSETS.txt"; \
cp res/run.bat "$$PKG_STAGE/run.bat"; \
cp LICENSE "$$PKG_STAGE/LICENSE"; \
cp engine/LICENSE "$$PKG_STAGE/LICENSE.Shockolate"; \
cp NOTICE.txt "$$PKG_STAGE/NOTICE.txt"; \
mkdir -p "$(DIST_DIR)"; \
(cd "$(BUILD_DIR)/package" && zip -rq "$(CURDIR)/$(DIST_DIR)/$$PKG_NAME.zip" "$$PKG_NAME"); \
rm -rf "$(BUILD_DIR)/package"; \
echo "Wrote $(DIST_DIR)/$$PKG_NAME.zip"
# Builds the Quest APK (see build-image/build-apk.sh and
# android/engine-patches/ - engine/ itself is never modified; a patch is
# applied to a scratch copy at build time instead). Same
@@ -108,8 +177,23 @@ apk:
./run-image.sh bash build-image/build-apk.sh; \
fi
# Stages a scratch, patched copy of engine/ and android/gl4es-src/, plus
# the Android SDL2/SDL2_mixer/fluidsynth-lite/openxr prebuilts, with
# host-resolvable paths (writes android/engine.properties) so Android
# Studio can compile and deploy android/ natively - see README's "5.2.
# Building natively in Android Studio". `make apk` doesn't need this; it
# stages the same things itself inside the build-image. Re-run after
# `make clean` (which deletes android/engine.properties) or after
# changing engine/, android/engine-patches/, android/gl4es-src/,
# android/gl4es-patches/, or the prebuilt-library versions in
# build-image/Dockerfile - Android Studio's own Gradle build already
# does this automatically via its stageEngine task, so this is mainly
# useful for first-time setup or confirming staging succeeded on its own.
android-studio:
./run-image.sh bash build-image/prepare-android-project.sh --host-paths
clean:
rm -rf "$(DIST_DIR)" "$(BUILD_DIR)" "$(ENGINE_OUT)" \
rm -rf "$(DIST_DIR)" "$(DIST_WIN_DIR)" "$(BUILD_DIR)" "$(ENGINE_OUT)" "$(ENGINE_OUT_WIN)" \
engine/build_ext engine/CMakeCache.txt engine/CMakeFiles \
engine/cmake_install.cmake engine/Makefile engine/systemshock \
engine/src/Libraries/CMakeFiles \
+24 -2
View File
@@ -8,5 +8,27 @@ and is not relicensed by this project's MIT license.
Game assets are not included - see res/GET_ASSETS.txt.
The Quest build bundles GL4ES (https://github.com/ptitSeb/gl4es),
prebuilt unmodified as lib/arm64-v8a/libGL.so, which is MIT-licensed.
The Android build additionally bundles:
- GL4ES (https://github.com/ptitSeb/gl4es), vendored and patched (see
android/gl4es-patches/) and compiled from source at APK build time as
lib/arm64-v8a/libGL.so. It is MIT-licensed.
- The Khronos Group's OpenXR-SDK loader
(https://github.com/KhronosGroup/OpenXR-SDK), prebuilt unmodified as
lib/arm64-v8a/libopenxr_loader.so. It is Apache 2.0-licensed.
The Windows build (cross-compiled via MinGW - see README's "4.2. Windows
cross-build") additionally bundles:
- GLEW (http://glew.sourceforge.net/), unmodified, as glew32.dll - used
for OpenGL extension loading, which Windows' own opengl32.dll doesn't
provide past OpenGL 1.1 (Linux instead gets this straight from Mesa's
headers, needing no separate loader library - see
engine/src/MacSrc/OpenGL.cc). It is licensed under a combination of the
Modified BSD License, the MIT License, and the Khronos License, all
permissive.
- The MinGW-w64 runtime's winpthreads library, as libwinpthread-1.dll. It
is MIT-licensed. (GCC's own runtime, libgcc/libstdc++, is linked
statically into systemshock.exe instead of shipped as a DLL, under the
GCC Runtime Library Exception - this doesn't subject the rest of the
binary to the GPL.)
+873 -68
View File
File diff suppressed because it is too large Load Diff
+144 -12
View File
@@ -4,29 +4,125 @@ apply plugin: 'com.android.application'
// build-apk.sh, or standalone with --host-paths to prep for a native
// build in Android Studio - see README) since they're only known at
// prep/build time, not something a checked-in build.gradle can hardcode.
// engineDir is the scratch, patched copy of engine/; prebuiltDir is the
// Android SDL2/SDL2_mixer/fluidsynth-lite/gl4es prebuilts - both point
// into this container's own paths for build-apk.sh's own gradlew call,
// or host-resolvable paths (plus a host-side export of prebuiltDir, since
// /opt/prebuilt/android only exists in the image) when prepared with
// --host-paths for Android Studio.
// engineDir is the scratch, patched copy of engine/; gl4esDir is the
// scratch, patched copy of android/gl4es-src/ (built from source as a
// CMake subdirectory of engine/'s own native build below, not prebuilt);
// prebuiltDir is the Android SDL2/SDL2_mixer/fluidsynth-lite/openxr
// prebuilts - all point into this container's own paths for
// build-apk.sh's own gradlew call, or host-resolvable paths (plus a
// host-side export of prebuiltDir, since /opt/prebuilt/android only
// exists in the image) when prepared with --host-paths for Android
// Studio.
def engineProps = new Properties()
file("${projectDir}/../engine.properties").withInputStream { engineProps.load(it) }
def engineDir = engineProps.getProperty('engineDir')
if (engineDir == null) {
throw new GradleException("android/engine.properties is missing 'engineDir' - run via build-apk.sh or prepare-android-project.sh, not gradlew directly")
}
def gl4esDir = engineProps.getProperty('gl4esDir')
if (gl4esDir == null) {
throw new GradleException("android/engine.properties is missing 'gl4esDir' - run via build-apk.sh or prepare-android-project.sh, not gradlew directly")
}
def prebuiltDir = engineProps.getProperty('prebuiltDir')
if (prebuiltDir == null) {
throw new GradleException("android/engine.properties is missing 'prebuiltDir' - run via build-apk.sh or prepare-android-project.sh, not gradlew directly")
}
// Set by build-apk.sh (see build-image/version.sh, shared with the
// desktop tarball's versioning) via -PquestshockVersionName/Code. Default
// here only covers a direct, unsupported `gradlew` invocation.
def questshockVersionName = project.hasProperty('questshockVersionName') ? project.property('questshockVersionName') : '0.0.0-dev'
// desktop tarball's versioning) via -PquestshockVersionName/Code. Building
// directly from Android Studio (the normal day-to-day workflow - see
// README) never passes that property, so the default below has to carry
// its own weight rather than just being a fallback for some rare, other,
// unsupported path: it runs `git describe` itself, the same way
// engine/CMakeLists.txt's own PROJECT_REVERSION_STRING does for the
// engine's *own* separate version string - "vX.Y.Z" on a clean tagged
// commit, or "vX.Y.Z-N-gHASH[-dirty]" otherwise, so a build between
// releases is still identifiable from the in-headset menu (see
// MenuOverlay.java's header, which reads BuildConfig.VERSION_NAME).
def gitDescribeVersionName = {
try {
def proc = ["git", "-C", projectDir.toString(), "describe", "--tags", "--always", "--dirty"].execute()
proc.waitFor()
if (proc.exitValue() == 0) {
def out = proc.text.trim()
if (out) {
return out
}
}
} catch (Exception ignored) {
// git not on PATH, or this isn't a git checkout at all (e.g. a
// source tarball) - fall through to the placeholder below.
}
return "0.0.0-dev"
}
def questshockVersionName = project.hasProperty('questshockVersionName') ? project.property('questshockVersionName') : gitDescribeVersionName()
def questshockVersionCode = project.hasProperty('questshockVersionCode') ? project.property('questshockVersionCode').toInteger() : 1
// Auto-refreshes the staged, patched engine/ and gl4es-src/ copies and
// prebuilt libraries (see build-image/prepare-android-project.sh
// --host-paths, and the engineDir/gl4esDir/prebuiltDir properties read
// above) so a plain Android Studio build/run can never silently compile
// against a stale scratch copy after engine/, android/engine-patches/,
// android/gl4es-src/, or android/gl4es-patches/ change - previously a
// manual, easy to forget re-run. inputs/outputs are declared so Gradle
// skips the (Docker-invoking, not free) step entirely when nothing
// relevant actually changed, keeping pure-Java edit/run cycles fast.
//
// This step only re-stages whatever is already baked into the build-image
// (it re-runs prepare-android-project.sh inside the existing image, which
// is fast - no compilation happens here) - engine/ and gl4es-src/ are both
// then compiled from these scratch copies by the externalNativeBuild CMake
// configure below (see android/engine-patches/02-android-opengl-es.patch's
// add_subdirectory of gl4esDir), so Gradle's own incremental CMake/Ninja
// build only recompiles what actually changed, same as any other native
// source edit. This task does NOT rebuild the image itself: if you changed
// build-image/Dockerfile (a real toolchain/dependency change, not
// engine-patches/ or gl4es-patches/, which this task re-stages on its own),
// you still need to run ./build-image.sh yourself first (a slow, deliberate
// step - see the memory on build-image versioning) so the image actually
// contains your changes before this task re-stages them.
def repoRoot = file("${projectDir}/../..")
def stageEngineTask = tasks.register("stageEngine", Exec) {
group = "build setup"
description = "Refreshes the patched engine/ scratch copy and prebuilt libraries for a native Android Studio build (build-image/prepare-android-project.sh --host-paths)."
workingDir repoRoot
commandLine "./run-image.sh", "bash", "build-image/prepare-android-project.sh", "--host-paths"
// /opt/prebuilt/android only ever exists inside the build-image
// container itself (baked in at image-build time, never on the host -
// see build-image/Dockerfile). Its presence means this build is
// build-apk.sh's own gradlew call, running INSIDE that container, which
// already staged everything itself in container mode before invoking
// gradlew - re-running this task there would try to `docker run` from
// inside a container with no docker socket, breaking make apk/CI. Only
// a genuine host-side Android Studio build (where this path is absent)
// needs this task.
onlyIf { !file('/opt/prebuilt/android').isDirectory() }
inputs.dir("${repoRoot}/engine")
inputs.dir("${projectDir}/../engine-patches")
inputs.dir("${projectDir}/../gl4es-src")
inputs.dir("${projectDir}/../gl4es-patches")
inputs.file("${repoRoot}/build-image/Dockerfile")
// Staged into assets/ by prepare-android-project.sh.
inputs.file("${repoRoot}/res/questshock.config.default.json")
inputs.dir("${repoRoot}/res/controller_profiles")
outputs.dir("${repoRoot}/build/android-engine")
outputs.dir("${repoRoot}/build/android-gl4es")
outputs.dir("${repoRoot}/build/android-prebuilt")
outputs.file("${projectDir}/../engine.properties")
outputs.dir("${projectDir}/src/main/assets")
}
// preBuild is what every variant's compile/native-build tasks already
// transitively depend on, regardless of AGP version's exact CMake task
// naming - the simplest reliable hook to run before any of them.
afterEvaluate {
tasks.named("preBuild").configure {
dependsOn stageEngineTask
}
}
android {
namespace "de.ladkau.questshock"
// compileSdk/buildToolsVersion/ndkVersion must all match what
@@ -59,22 +155,51 @@ android {
// SDL2_mixer and FluidSynth via the same build_ext/ BUNDLED
// convention the desktop build already uses (populated in the
// scratch engine copy by prepare-android-project.sh from
// prebuiltDir). ANDROID_PREBUILT_DIR is also read directly by
// android/engine-patches/02-android-opengl-es.patch, for gl4es.
// prebuiltDir). ANDROID_GL4ES_DIR is read by
// android/engine-patches/02-android-opengl-es.patch, which
// add_subdirectory()'s it to compile gl4es from source as
// part of this same CMake configure, instead of linking a
// prebuilt .so - so gl4es-patches/ changes just need a normal
// rebuild here, not a build-image rebuild.
// The CMAKE_FIND_ROOT_PATH* overrides below are needed
// because the NDK toolchain file restricts find_package/
// find_path/find_library to its own sysroot by default,
// which would otherwise miss our custom-installed SDL2 (see
// build-image/Dockerfile's SDL2_mixer build, which hit the
// exact same thing).
// -Wl,-z,max-page-size=16384: NDK 26 doesn't 16 KB-align ELF
// LOAD segments by default (only automatic in NDK 28+) - see
// build-image/Dockerfile's ANDROID_16KB_LDFLAGS, which does
// the same for the prebuilt SDL2/SDL2_mixer/fluidsynth-lite
// .so's this links against (gl4es is compiled here with the
// same flag passed straight through, see its add_subdirectory
// above).
// ANDROID_EXTRA_SOURCES is a semicolon-separated CMake list,
// not shell-split - AGP passes each "arguments" string
// straight through as one argv element to cmake, so the
// ';' below survives intact. ANDROID_EXTRA_INCLUDE_DIRS lets
// engine/'s own OpenGL.cc find "xr_session.h" (see
// android/engine-patches/10-android-openxr-cmake.patch,
// which adds it to include_directories()).
// USE_ANDROID_LOG/STATICLIB used to be passed to gl4es's own,
// separate cmake invocation in build-image/Dockerfile - now
// that it's add_subdirectory()'d into this same configure,
// they need to be set here instead, or gl4es silently falls
// back to stdio logging, which never reaches logcat. ANDROID
// itself doesn't need setting here - the NDK toolchain file
// already defines it before any CMakeLists.txt runs.
arguments "-DENABLE_SDL2=ON", "-DENABLE_SOUND=BUNDLED", "-DENABLE_FLUIDSYNTH=BUNDLED", \
"-DANDROID_PREBUILT_DIR=${prebuiltDir}", \
"-DANDROID_GL4ES_DIR=${gl4esDir}", \
"-DUSE_ANDROID_LOG=ON", "-DSTATICLIB=OFF", \
"-DANDROID_EXTRA_INCLUDE_DIRS=${projectDir}/src/main/cpp", \
"-DCMAKE_PREFIX_PATH=${prebuiltDir}/sdl2", \
"-DCMAKE_FIND_ROOT_PATH=${prebuiltDir}/sdl2", \
"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH", \
"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH", \
"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH", \
"-DANDROID_EXTRA_SOURCES=${projectDir}/src/main/cpp/questshock_native.c"
"-DCMAKE_SHARED_LINKER_FLAGS=-Wl,-z,max-page-size=16384", \
"-DANDROID_EXTRA_SOURCES=${projectDir}/src/main/cpp/questshock_native.c;${projectDir}/src/main/cpp/xr_session.c;${projectDir}/src/main/cpp/xr_input.c;${projectDir}/src/main/cpp/xr_overlay.c;${projectDir}/src/main/cpp/xr_swapchain.c;${projectDir}/src/main/cpp/xr_mouse.c;${projectDir}/src/main/cpp/qs_config.c"
abiFilters 'arm64-v8a'
}
}
@@ -92,6 +217,13 @@ android {
}
}
// Generates BuildConfig (specifically BuildConfig.VERSION_NAME, read by
// MenuOverlay.java's header) - off by default since AGP 8.0, so this
// has to be requested explicitly.
buildFeatures {
buildConfig true
}
lint {
abortOnError false
}
+20
View File
@@ -12,6 +12,11 @@
<!-- External mouse input events -->
<uses-feature android:name="android.hardware.type.pc" android:required="false" />
<!-- Immersive OpenXR app now (see android/app/src/main/cpp/xr_session.c),
not a 2D Home panel - vr.headtracking is what actually declares that
to Horizon OS. -->
<uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="true" />
<!-- Plain, unrestricted /sdcard access for the res/data,res/sound the
user drops in and the shaders/soundfont this app extracts there on
first run - see res/GET_ASSETS_QUEST.txt and QuestShockActivity.
@@ -28,17 +33,32 @@
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:hardwareAccelerated="true" >
<!-- Tells Horizon OS this activity wants the compositor for itself
(immersive VR), not the Home 2D-panel path - required for an
OpenXR session to actually start. -->
<meta-data android:name="com.oculus.vr.focusaware" android:value="true" />
<activity android:name="de.ladkau.questshock.QuestShockActivity"
android:label="@string/app_name"
android:alwaysRetainTaskState="true"
android:launchMode="singleInstance"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:screenOrientation="landscape"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- The vendor-neutral, Khronos-defined way to declare an
immersive OpenXR entry point (vs. e.g. Meta's own
com.oculus.intent.category.VR) - see this project's
"favor OpenXR" rule in the README. If Horizon OS still
launches this as a flat panel on-device, the next thing
to try is adding a com.oculus.supportedDevices meta-data
listing the target Quest models - not confirmed
necessary from static analysis alone. -->
<category android:name="org.khronos.openxr.intent.category.IMMERSIVE_HMD" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
File diff suppressed because it is too large Load Diff
+195
View File
@@ -0,0 +1,195 @@
#ifndef QUESTSHOCK_QS_CONFIG_H
#define QUESTSHOCK_QS_CONFIG_H
#include <SDL.h>
#ifdef __cplusplus
extern "C" {
#endif
// Persistent, human-editable JSON config file - see CONFIG.md at the repo
// root for the documented schema. Lives at a plain relative path
// ("questshock.config.json") since the whole engine already runs with its
// cwd chdir()'d to the user-facing /sdcard/questshock/ folder (see
// QuestShockActivity.java's nativeChdir()) before main() ever runs - the
// same way prefs.txt/keybinds.txt (Prefs.c) already do.
//
// Deliberately independent of prefs.txt: this file is never read or written
// as a side effect of prefs.txt load/save, and vice versa.
// Parses the config file if it exists (silent no-op if it doesn't - this
// never creates the file itself) and applies every recognized option
// directly into gShockPrefs/mode_id. Call once, early in main() - see
// android/engine-patches/21-android-config.patch - after LoadPrefs() (so the
// config file can override prefs.txt) and before init_all() (so there's no
// live-vs-restart distinction to worry about: nothing is initialized yet, so
// every field takes full effect as part of this same startup).
void qs_config_load_startup(void);
// Called from the "Save Configuration"/"Load Configuration" button JNI
// handlers (questshock_native.c), which run on Android's UI thread. These
// only enqueue a custom SDL event - the actual file I/O and any
// gShockPrefs/mode_id/message_info() work happens on the engine's own SDL
// main thread instead (see qs_config_handle_event() below), matching this
// codebase's existing convention for crossing this exact thread boundary
// (xr_session.c's xr_poll_events(), questshock_native.c's SDL_TEXTINPUT
// push for keyboard input).
void qs_config_request_save(void);
void qs_config_request_load(void);
// Same cross-thread-dispatch reasoning as qs_config_request_save()/_load()
// above - called from the Video Options tab's controls (MenuOverlay.java),
// which are just as much on Android's UI thread as the Save/Load buttons.
// opengl=true/false selects "opengl"/"software"; resolution_index is 0-4,
// indexing the same table qs_config_current_resolution_index() below
// reads. Applies live immediately (no restart involved - see CONFIG.md);
// unlike Load Configuration, these don't post a message_info() HUD
// notification for every single tap - the tab's own selection highlight is
// the feedback.
void qs_config_request_set_renderer(bool opengl);
void qs_config_request_set_resolution(int resolution_index);
// Same cross-thread-dispatch reasoning as the two above - called from the
// Main Menu tab's Language row (MenuOverlay.java). language_index is 0
// English/1 French/2 German (gShockPrefs.goLanguage's own numbering,
// Prefs.h). Applies live immediately, the same way the game's own options
// menu applies a language change (see qs_config.c's qs_apply_language()).
void qs_config_request_set_language(int language_index);
// Same cross-thread dispatch as the three above - called from the Main Menu
// tab's "Reset Position" button. Re-anchors the player's position in front of
// the game quad (see xr_input_reset_player_position()); never reads or writes
// the config file.
void qs_config_request_reset_position(void);
// Same cross-thread-dispatch reasoning as the four above - called from the
// Video Options tab's "Initial Screen"/"Game Screen" width/distance
// preset rows (MenuOverlay.java). preset_index indexes qs_config.c's own
// shared, offset+step-generated width/distance preset lists (both in
// meters; the offset/step themselves are config-file-only, not exposed
// as buttons), read back via the four qs_config_current_*_screen_*_index()
// getters below. Applies live immediately if the just-changed profile is
// the currently active one (see CONFIG.md) - otherwise just updates the
// stored preference, invisibly, until that profile becomes active (e.g.
// tweaking "Initial Screen" mid-game).
void qs_config_request_set_initial_screen_width(int preset_index);
void qs_config_request_set_initial_screen_distance(int preset_index);
void qs_config_request_set_game_screen_width(int preset_index);
void qs_config_request_set_game_screen_distance(int preset_index);
// Cross-thread requests from the Controller Options tab (MenuOverlay.java),
// enqueued like every request_*() above. action_index indexes
// xr_input_action_name()'s list. Begin/cancel start and stop rebind capture;
// reset restores all bindings (the built-in defaults, then
// questshock.config.default.json's player_controls group if it has one).
void qs_config_request_begin_control_capture(int action_index);
void qs_config_request_cancel_control_capture(void);
void qs_config_request_reset_player_controls(void);
// Called from xr_input.c's xr_input_process_capture() on the engine's own
// thread, so no cross-thread dispatch is needed (as with
// qs_screen_profile_notify_loop_mode() below). Resolves
// MenuOverlay.onControlCaptureResult(int, String) for action_index (raw_name
// NULL on timeout or cancel), and again for displaced_action_index if the new
// binding took the input from another action (-1/NULL when none), so both
// rows can be updated together.
void qs_config_notify_control_capture_result(int action_index, const char *raw_name,
int displaced_action_index,
const char *displaced_raw_name);
// Called from xr_input.c whenever the VR menu's visibility changes. Showing
// the menu pauses a running game (not the main menu, intro or cutscenes) that
// is not already paused; hiding it unpauses only if the menu did the pausing.
// Enqueued like the request_*() functions above; the pause itself runs on the
// engine's thread at pump_events() time.
void qs_config_notify_menu_visibility(bool visible);
// Cheats tab (MenuOverlay.java). Same enqueue-only requests as above; the work
// runs on the engine's thread. cheat_id: 0 give everything, 1 toggle physics,
// 2 next level, 3 previous level, 4-7 toggle unlimited health, energy, ammo,
// items (grenades and drugs). Cheats need a running game (the unlimited
// switches can be set anywhere). The getters are plain scalar reads, safe from
// the UI thread; the unlimited mask has bit 0 health, 1 energy, 2 ammo, 3 items.
void qs_config_request_cheat(int cheat_id);
int qs_config_cheat_unlimited_mask(void);
bool qs_config_cheat_physics_running(void);
// Called once per frame from xr_input.c on the engine's thread; applies the
// unlimited-resource cheats that are switched on.
void qs_config_frame_tick(void);
// Called from xr_input.c's xr_input_suggest_bindings() when the OpenXR runtime
// rejects a supported interaction profile's suggested bindings at startup.
// That is an app bug, not a config problem, so it shows
// MenuOverlay.showFatalControllerBindingError()'s non-cancelable "Exit" dialog;
// xr_input_init() aborts right after.
void qs_config_report_fatal_input_error(const char *profile_display_name);
// Returns true and handles the event if it is one of the custom events the
// request_*()/notify functions above enqueue. Called from pump_events()
// (sdl_events.c, see android/engine-patches/21-android-config.patch) on the
// engine's thread, once per polled event. Returns false for any other event
// type, including before the custom types are registered.
bool qs_config_handle_event(const SDL_Event *event);
// Called directly (no event-queue dispatch - see
// android/engine-patches/22-android-screen-profile.patch and this
// function's own definition in qs_config.c for why) from the engine's
// mainloop.c whenever the loop mode changes, and once from
// qs_config_load_startup() - picks between the "Initial Screen" (menu/
// intro) and "Game Screen" (actual gameplay) presets based on new_mode
// (mainloop.h's SETUP_LOOP/CUTSCENE_LOOP vs. everything else) and applies
// the newly-active one's shape to xr_session.c, but only if it's actually
// different from what was already active.
void qs_screen_profile_notify_loop_mode(short new_mode);
// Read-only queries for the Video Options tab's own selection highlight
// (MenuOverlay.java re-reads these whenever the tab is (re)shown, so it
// reflects the live value even if it was last changed some other way, e.g.
// the Ctrl+G hotkey or Load Configuration). Safe to call directly from
// Android's UI thread despite not going through the event-queue dispatch
// the mutating calls above use - same low-risk reasoning already used for
// Save Configuration's own reads of gShockPrefs/mode_id: these are simple,
// independent POD scalar reads, not a sequence that needs to be atomic
// with anything else.
bool qs_config_current_renderer_is_opengl(void);
int qs_config_current_resolution_index(void);
// -1 (not just an unlikely fallback, a routine, expected result here -
// unlike qs_config_current_resolution_index() above) if the profile's
// current value doesn't exactly match one of qs_config.c's own
// offset+step-generated width/distance presets, e.g. after a hand-edited
// config file sets an in-between value - MenuOverlay.java's own
// setSelected() naturally shows no button selected in that case, no
// special-casing needed.
int qs_config_current_initial_screen_width_index(void);
int qs_config_current_initial_screen_distance_index(void);
int qs_config_current_game_screen_width_index(void);
int qs_config_current_game_screen_distance_index(void);
// Returns the value preset button `index` (0..4) currently shows for the
// width/distance option - shared by both "Initial Screen" and "Game
// Screen" columns (their offset/step is config-file-only, not per-profile
// - see qs_config.c's own comment on the underlying statics), so
// MenuOverlay.java can label its preset buttons correctly even after a
// Load Configuration changes the offset/step. Index is clamped into
// range, not validated - every index 0..4 always has a value.
float qs_config_screen_width_preset_value(int index);
float qs_config_screen_distance_preset_value(int index);
// gShockPrefs.goLanguage (0 English/1 French/2 German, Prefs.h) - read by
// MenuOverlay.java's/KeyboardOverlay.java's periodic header-refresh timer
// to pick which language's chrome text (Strings.java) to display, so a
// language change made mid-session via the game's own options menu (or our
// own Language row, or Load Configuration) is picked up without needing to
// reopen either panel; also doubles as the Main Menu tab's Language row's
// own selection highlight, same as qs_config_current_renderer_is_opengl()/
// qs_config_current_resolution_index() above. Same off-thread-scalar-read
// reasoning as those two getters.
int qs_config_current_language(void);
#ifdef __cplusplus
}
#endif
#endif // QUESTSHOCK_QS_CONFIG_H
@@ -4,12 +4,285 @@
// needs, compiled into the same "main" library as engine/ (see
// android/engine-patches/01-android-shared-lib.patch's ANDROID_EXTRA_SOURCES)
// - engine/ itself is never modified.
#include <ctype.h>
#include <jni.h>
#include <unistd.h>
#include <SDL.h>
#include "qs_config.h"
#include "xr_input.h"
#include "xr_overlay.h"
#include "xr_session.h"
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_QuestShockActivity_nativeChdir(JNIEnv *env, jclass clazz, jstring path) {
const char *cpath = (*env)->GetStringUTFChars(env, path, NULL);
chdir(cpath);
(*env)->ReleaseStringUTFChars(env, path, cpath);
}
// KeyboardOverlay's hand-built on-screen keyboard (see
// KeyboardOverlay.handleCharKeyDown()/handleCharKeyUp()) has no real
// Android IME session behind it, so printable characters can't reach the
// game via Android's usual IME path - instead this builds and pushes an
// SDL_TEXTINPUT event directly, the same event type/shape SDL's own
// Android backend pushes for typed text, using only the public
// SDL_Event/SDL_PushEvent API. The engine's pump_events() (sdl_events.c)
// only picks up printable characters from this event, not from
// SDL_KEYDOWN.
//
// pump_events()'s SDL_TEXTINPUT handling sets sshockKeyStates[code] for
// this character and only ever clears it again on a matching SDL_KEYUP.
// Any character bound to a continuously-polled motion key (space -> jump,
// w -> forward, etc., see MacSrc/Prefs.c's default keybinds.txt) is
// polled every physics tick for as long as that state stays set, exactly
// like a real held key - so nativeSendPrintableCharDown()/Up() are called
// from the key button's own ACTION_DOWN/ACTION_UP (see
// KeyboardOverlay.charKeyTouchListener()), not both at once: pushing the
// release in the same call as the press would set and clear
// sshockKeyStates[code] within a single pump_events() call, before the
// game loop's poll (which runs once per frame, before pump_events - see
// GameSrc/mainloop.c) ever has a chance to observe the press.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_KeyboardOverlay_nativeSendPrintableCharDown(JNIEnv *env, jclass clazz,
jchar c) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_TEXTINPUT;
event.text.timestamp = SDL_GetTicks();
event.text.windowID = 0;
event.text.text[0] = (char)c;
event.text.text[1] = '\0';
SDL_PushEvent(&event);
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_KeyboardOverlay_nativeSendPrintableCharUp(JNIEnv *env, jclass clazz,
jchar c) {
SDL_Event releaseEvent;
SDL_zero(releaseEvent);
releaseEvent.type = SDL_KEYUP;
releaseEvent.key.timestamp = SDL_GetTicks();
releaseEvent.key.windowID = 0;
releaseEvent.key.state = SDL_RELEASED;
releaseEvent.key.repeat = 0;
// SDL keycodes for printable characters are the character's own
// (lowercased) byte value - see sdl_events.c's own comment on this.
releaseEvent.key.keysym.sym = (SDL_Keycode)tolower((unsigned char)c);
releaseEvent.key.keysym.mod = KMOD_NONE;
SDL_PushEvent(&releaseEvent);
}
// KeyboardOverlay's title-bar Close button - the keyboard is a fully
// independent overlay quad from the menu launcher (see xr_overlay.h), so
// this is the only way to hide it once it's open; the controller's menu
// button only ever affects the menu launcher.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_KeyboardOverlay_nativeRequestClose(JNIEnv *env, jclass clazz) {
xr_overlay_set_visible(xr_session_get_keyboard_overlay(), false);
}
// MenuOverlay's "Keyboard" button - only opens the keyboard overlay, never
// touches the menu launcher's own visibility, so both can be shown
// together.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeShowKeyboard(JNIEnv *env, jclass clazz) {
xr_overlay_set_visible(xr_session_get_keyboard_overlay(), true);
}
// MenuOverlay's "Save Configuration"/"Load Configuration" buttons - see
// qs_config.h for why these only enqueue an event rather than doing the
// actual file/engine-state work here directly (this runs on Android's UI
// thread, not the engine's own).
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSaveConfig(JNIEnv *env, jclass clazz) {
qs_config_request_save();
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestLoadConfig(JNIEnv *env, jclass clazz) {
qs_config_request_load();
}
// MenuOverlay's Video Options tab - live-appliable controls, see
// qs_config.h. Same enqueue-only reasoning as the Save/Load buttons above.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSetRenderer(JNIEnv *env, jclass clazz,
jboolean opengl) {
qs_config_request_set_renderer(opengl);
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSetResolution(JNIEnv *env, jclass clazz,
jint resolutionIndex) {
qs_config_request_set_resolution(resolutionIndex);
}
// MenuOverlay's Main Menu tab's Language row - same enqueue-only reasoning as above.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSetLanguage(JNIEnv *env, jclass clazz,
jint languageIndex) {
qs_config_request_set_language(languageIndex);
}
// MenuOverlay's Main Menu tab's "Reset Position" button - same enqueue-only
// reasoning as above.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestResetPosition(JNIEnv *env, jclass clazz) {
qs_config_request_reset_position();
}
// MenuOverlay's Video Options tab - "Initial Screen"/"Game Screen" width/
// distance preset rows, same enqueue-only reasoning as above.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSetInitialScreenWidth(JNIEnv *env, jclass clazz,
jint presetIndex) {
qs_config_request_set_initial_screen_width(presetIndex);
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSetGameScreenWidth(JNIEnv *env, jclass clazz,
jint presetIndex) {
qs_config_request_set_game_screen_width(presetIndex);
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSetInitialScreenDistance(JNIEnv *env,
jclass clazz,
jint presetIndex) {
qs_config_request_set_initial_screen_distance(presetIndex);
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestSetGameScreenDistance(JNIEnv *env, jclass clazz,
jint presetIndex) {
qs_config_request_set_game_screen_distance(presetIndex);
}
// Read-only queries - safe to call directly (no enqueue needed, see
// qs_config.h's own comment on each of these).
JNIEXPORT jboolean JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetRendererIsOpenGl(JNIEnv *env, jclass clazz) {
return qs_config_current_renderer_is_opengl();
}
JNIEXPORT jint JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetResolutionIndex(JNIEnv *env, jclass clazz) {
return qs_config_current_resolution_index();
}
JNIEXPORT jint JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetInitialScreenWidthIndex(JNIEnv *env, jclass clazz) {
return qs_config_current_initial_screen_width_index();
}
JNIEXPORT jint JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetGameScreenWidthIndex(JNIEnv *env, jclass clazz) {
return qs_config_current_game_screen_width_index();
}
JNIEXPORT jint JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetInitialScreenDistanceIndex(JNIEnv *env,
jclass clazz) {
return qs_config_current_initial_screen_distance_index();
}
JNIEXPORT jint JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetGameScreenDistanceIndex(JNIEnv *env, jclass clazz) {
return qs_config_current_game_screen_distance_index();
}
// Preset button *labels* (not the current value) - shared by both
// "Initial Screen" and "Game Screen" columns, since their offset/step is
// config-file-only, not per-profile (see qs_config.h's own comment).
JNIEXPORT jfloat JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetScreenWidthPresetValue(JNIEnv *env, jclass clazz,
jint index) {
return qs_config_screen_width_preset_value(index);
}
JNIEXPORT jfloat JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetScreenDistancePresetValue(JNIEnv *env, jclass clazz,
jint index) {
return qs_config_screen_distance_preset_value(index);
}
JNIEXPORT jint JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetLanguage(JNIEnv *env, jclass clazz) {
return qs_config_current_language();
}
// MenuOverlay's header - polled on a periodic timer (see its own comment),
// not event-driven, so these are plain synchronous reads too.
JNIEXPORT jfloat JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetFps(JNIEnv *env, jclass clazz) {
return xr_session_get_fps();
}
JNIEXPORT jfloat JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetFrameTimeMs(JNIEnv *env, jclass clazz) {
return xr_session_get_frame_ms();
}
JNIEXPORT jfloat JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetCpuUtilization(JNIEnv *env, jclass clazz) {
return xr_session_get_cpu_utilization();
}
JNIEXPORT jfloat JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetGpuUtilization(JNIEnv *env, jclass clazz) {
return xr_session_get_gpu_utilization();
}
// Controller Options tab: actionIndex follows xr_input.c's action order
// (MenuOverlay.java and Strings.java hold the matching labels).
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestBeginControlCapture(JNIEnv *env, jclass clazz,
jint actionIndex) {
qs_config_request_begin_control_capture(actionIndex);
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestCancelControlCapture(JNIEnv *env, jclass clazz) {
qs_config_request_cancel_control_capture();
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestResetPlayerControls(JNIEnv *env, jclass clazz) {
qs_config_request_reset_player_controls();
}
JNIEXPORT jstring JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetControlBindingKey(JNIEnv *env, jclass clazz,
jint actionIndex) {
return (*env)->NewStringUTF(env, xr_input_get_action_binding_name(actionIndex));
}
JNIEXPORT jstring JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetActiveInteractionProfilePath(JNIEnv *env,
jclass clazz) {
return (*env)->NewStringUTF(env, xr_input_get_active_interaction_profile_path());
}
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeSetControllerOptionsTabOpen(JNIEnv *env, jclass clazz,
jboolean open) {
xr_input_set_controller_options_tab_open(open == JNI_TRUE);
}
// Cheats tab: same enqueue-only pattern as the other requests.
JNIEXPORT void JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeRequestCheat(JNIEnv *env, jclass clazz, jint cheatId) {
qs_config_request_cheat(cheatId);
}
JNIEXPORT jint JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetCheatUnlimitedMask(JNIEnv *env, jclass clazz) {
return qs_config_cheat_unlimited_mask();
}
JNIEXPORT jboolean JNICALL
Java_de_ladkau_questshock_MenuOverlay_nativeGetCheatPhysicsRunning(JNIEnv *env, jclass clazz) {
return qs_config_cheat_physics_running();
}
File diff suppressed because it is too large Load Diff
+154
View File
@@ -0,0 +1,154 @@
// Controller input for questshock's immersive Quest build: one OpenXR
// action set (aim pose + trigger click per hand, a menu-toggle button on
// the left controller) plus ray/quad hit-testing. Each hand's ray is
// tried against the keyboard overlay, then the menu overlay (see
// xr_overlay.h, xr_session.c), then - only if neither actually claims it
// this frame (landing on it now, or continuing a touch/drag begun on a
// previous frame - not merely because that overlay happens to be visible)
// - the game quad xr_session.c submits, forwarding trigger edges to
// whichever overlay claims the ray as synthetic touches. The game quad
// itself acts as a plain desktop-style mouse pointer into the engine's
// own UI (see xr_mouse.h) - absolute cursor position while the ray hits
// it, plus a left click on the trigger edge; a pending click there
// likewise keeps claiming the ray ahead of the keyboard/menu until
// released, so the eventual mouse-up isn't lost if the ray strays. Since
// none of the three targets' own feedback (the overlays' on-quad cursor,
// drawn by their Java views; the engine's own mouse cursor sprite for the
// game quad) gives any indication while the ray is short of actually
// landing on something, every claimed target also builds a thin,
// billboarded laser-beam quad per hand from the controller to wherever
// the ray currently crosses that target's plane (see
// xr_input_get_beam_layer()) - so aiming looks and behaves the same
// whether the target is an overlay or the game quad itself.
#ifndef QUESTSHOCK_XR_INPUT_H
#define QUESTSHOCK_XR_INPUT_H
#include <stdbool.h>
#include <stdint.h>
#define XR_USE_PLATFORM_ANDROID 1
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#include <openxr/openxr.h>
#ifdef __cplusplus
extern "C" {
#endif
// Call once, right after the session is created (see xr_session.c's
// xr_create_instance_and_session()) - creates the action set/actions,
// suggests Touch controller bindings, creates the per-hand aim action
// spaces and a view-space reference (for the laser-beam billboard math),
// creates the two per-hand beam swapchains (swapchain_format - the same
// format shared by the game swapchain and both overlays), and attaches
// the action set to the session. Returns false (logged, non-fatal - the
// caller keeps rendering without input) if any of that fails.
bool xr_input_init(XrInstance instance, XrSession session, int64_t swapchain_format);
// Call once per frame from xr_frame_end(), before releasing the acquired
// swapchain image - syncs this frame's action states (always, so edge
// detection stays correct even on frames with nothing to draw), handles
// the menu_toggle button's edge, and hit-tests/dispatches each hand's ray
// against keyboard/menu/game quad in that priority order (see the file
// comment above). draw gates only the laser-beam visuals (and the
// head-pose locate that feeds them) - if false (nothing to draw into this
// frame, e.g. no swapchain image was acquired), hit-testing and
// touch-forwarding still run. baseSpace/time must match whatever
// xr_frame_begin() used to predict this frame.
void xr_input_sync_and_draw(XrSpace baseSpace, XrTime time, bool draw);
// Call once per hand (hand: 0=left, 1=right) after xr_input_sync_and_draw()
// in the same frame - if that hand's ray claimed the keyboard, menu, or
// game quad this frame (see the file comment above), fills *out_quad's
// subImage/pose/size for its laser-beam ribbon and returns true.
// space/eyeVisibility/layerFlags are left for the caller to set, same
// convention as xr_overlay_render_and_build_layer(). Returns false
// (out_quad untouched) if no beam should be shown for that hand this
// frame.
bool xr_input_get_beam_layer(int hand, XrCompositionLayerQuad *out_quad);
// Recenters the player so the game quad ("virtual screen") appears directly
// ahead of wherever they are standing and facing, from their current real head
// pose. Never reads or writes questshock.config.json. Called automatically
// once, from xr_input_sync_and_draw(), on the first frame with a valid head
// pose after startup, unless a complete saved player_position was loaded (see
// xr_input_skip_startup_recenter()): a saved position is relative to a
// previous session's real-space origin, which is not stable across launches.
// Returns false (no-op) if no valid head pose is available yet.
bool xr_input_recenter_player_to_screen(void);
// The Main Menu tab's "Reset Position" button (via qs_config.c). Like
// xr_input_recenter_player_to_screen(), but re-anchors only the player's
// position to the centre in front of the game quad; the current facing (yaw)
// is kept, so the screen does not rotate to follow the gaze. Returns false
// (no-op) if no valid head pose is available yet.
bool xr_input_reset_player_position(void);
// Called once, from qs_config_load_startup() (qs_config.c), when a
// complete saved player_position was actually loaded from
// questshock.config.json - cancels the pending automatic startup recenter
// above so it doesn't immediately override the value that was just
// applied. Safe to call regardless of whether xr_input_init() has even run
// yet (this only touches the plain file-local flag, no XR calls).
void xr_input_skip_startup_recenter(void);
// ===========================================================================
// Remappable controls ("player_controls" config group; see qs_config.c and
// CONFIG.md). menu_toggle is not among them and has no getter/setter: it is
// fixed (see xr_input_sync_and_draw()).
// ===========================================================================
// Number of remappable actions and each one's index<->name mapping, which
// qs_config.c uses to parse/write the player_controls group without its own
// copy of the list. The names are the keys used in questshock.config.json;
// index_from_name() returns false for an unrecognized name.
int xr_input_action_count(void);
const char *xr_input_action_name(int action_index);
bool xr_input_action_index_from_name(const char *name, int *out_index);
// Current binding for one action, as an opaque int and as its string form
// (e.g. "right_b", "trigger", "none" for unbound), the same strings used in
// questshock.config.json and reported by capture.
int xr_input_get_action_binding(int action_index);
const char *xr_input_get_action_binding_name(int action_index);
// Sets one action's binding from a config-file string. Returns false (binding
// unchanged) for an unrecognized name, or for the symmetric "trigger"/
// "squeeze" on an action other than mouse_click/mouse_double_click. Does not
// enforce one-action-per-input the way capture does: a hand-edited file that
// binds two actions to one input is accepted as-is.
bool xr_input_set_action_binding(int action_index, const char *raw_name);
// Restores every action to its built-in default (the table xr_input_init()
// starts from). qs_config.c calls this first for "Reset to Defaults", then
// applies questshock.config.default.json's player_controls group on top if it
// has one.
void xr_input_reset_player_controls(void);
// Begins/cancels rebind capture for one action (an index into
// xr_input_action_name()'s list): the next fresh button or thumbstick-direction
// edge on any hand becomes that action's binding and is reported via
// qs_config_notify_control_capture_result(); with no press, capture cancels
// after 8 seconds. Called via qs_config.c's cross-thread request functions.
// The menu button is never captured.
void xr_input_capture_begin(int action_index);
void xr_input_capture_cancel(void);
// The OpenXR interaction profile currently bound (e.g.
// "/interaction_profiles/oculus/touch_controller"), refreshed once per frame.
// MenuOverlay.java's Controller Options tab uses it to pick a file from
// controller_profiles/ (see CONFIG.md). Empty until the first successful
// query.
const char *xr_input_get_active_interaction_profile_path(void);
// Set by MenuOverlay.java when the Controller Options tab becomes or stops
// being the menu's current tab. While it is open, the menu's thumbstick
// locomotion (snap turn/smooth move) is disabled.
void xr_input_set_controller_options_tab_open(bool open);
void xr_input_shutdown(void);
#ifdef __cplusplus
}
#endif
#endif
+20
View File
@@ -0,0 +1,20 @@
#include "xr_mouse.h"
#include <SDL.h>
#include "mouse.h" // engine/src/Libraries/INPUT/Source/mouse.h - mouse_put_xy()
void xr_mouse_move(int x, int y) { mouse_put_xy((short)x, (short)y); }
void xr_mouse_click(bool down) {
SDL_Event event;
SDL_zero(event);
event.type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
event.button.timestamp = SDL_GetTicks();
event.button.windowID = 0;
event.button.which = 0;
event.button.button = SDL_BUTTON_LEFT;
event.button.state = down ? SDL_PRESSED : SDL_RELEASED;
event.button.clicks = 1;
SDL_PushEvent(&event);
}
+36
View File
@@ -0,0 +1,36 @@
// Bridges VR aim-ray hit-testing (xr_input.c) to the vendored engine's
// mouse input (engine/src/Libraries/INPUT/Source/mouse.h) - lets the
// controller's laser pointer drive the game's own UI (inventory, menus,
// dialogs) exactly like a desktop mouse: absolute cursor position plus a
// single left button, no relative/mouselook mode, no right button.
#ifndef QUESTSHOCK_XR_MOUSE_H
#define QUESTSHOCK_XR_MOUSE_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
// Sets the engine's absolute mouse position (mouse_put_xy()) - call every
// frame the aim ray is actually hitting the game quad; x/y are pixel
// coordinates in the game's own logical resolution (see
// xr_get_game_resolution() in xr_session.h), already clamped by the
// caller. Do not call on frames the ray isn't hitting the game quad - the
// cursor should hold its last position, not snap elsewhere.
void xr_mouse_move(int x, int y);
// Pushes a synthetic SDL_MOUSEBUTTONDOWN/UP (SDL_BUTTON_LEFT) - matches
// KeyboardOverlay's nativeSendPrintableCharDown()/Up() in
// questshock_native.c: a plain SDL_Event built by hand and handed to the
// public SDL_PushEvent(),
// no engine patch needed. pump_events() (sdl_events.c) reads whatever
// mouse_put_xy() last set, not any x/y carried on the event itself - call
// xr_mouse_move() first if position needs updating this frame.
void xr_mouse_click(bool down);
#ifdef __cplusplus
}
#endif
#endif
+503
View File
@@ -0,0 +1,503 @@
#include "xr_overlay.h"
#include <dlfcn.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <android/log.h>
#include <jni.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <SDL.h>
#include "xr_swapchain.h"
#define TAG "QuestShock"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
// Same constant (deliberately not <math.h>'s M_PI, which isn't used
// anywhere else in this codebase and isn't guaranteed by the C standard -
// only POSIX) as xr_session.c's own play-space rebuild math.
#define QS_DEG_TO_RAD (3.14159265358979323846f / 180.0f)
struct XrOverlay {
XrInstance instance; // for error logging only
int width, height;
float distance_m, half_width_m, half_height_m;
float center_x_m, center_y_m;
// The *authored* distance_m (config->distance_m at creation time),
// never touched again afterward by anything, including
// xr_overlay_set_pose() - kept separate from the live, mutable
// distance_m above because that one stops meaning "how far in front of
// the origin" once a rotated set_pose() call (the menu recenter)
// repurposes it as a raw base-space Z coordinate; reusing *that* as a
// "how far in front of me" magnitude on a later recenter would drift
// further with every reopen instead of staying at a stable distance -
// see xr_overlay_get_default_distance_m().
float default_distance_m;
// Rotation about the vertical axis, applied on top of center_x_m/
// center_y_m/distance_m (see xr_overlay_set_pose()) - 0 for every
// overlay except the menu launcher immediately after it's freshly
// reopened (xr_input.c re-centers it in front of wherever the player
// is currently facing, which needs this to keep the quad actually
// facing them instead of whatever direction it started out at).
float yaw_deg;
bool visible;
XrSwapchainState swapchain;
jclass java_class;
jmethodID native_init_method;
jmethodID take_pixels_method;
jmethodID dispatch_touch_method;
jmethodID update_cursor_method;
// This overlay's content lives in this texture, uploaded by
// xr_overlay_upload_source_texture_if_dirty() below. It's created
// through gl4es (glGenTextures/glBindTexture/glTexImage2D), like any
// other texture the engine itself creates, so ordinary
// glTexSubImage2D uploads against it work the normal way.
GLuint source_texture;
// A framebuffer with source_texture as its only color attachment, used
// as the read source for the blit in
// xr_overlay_render_and_build_layer() below. Created via the real
// (non-gl4es) GLES entry points below: that blit bypasses gl4es
// entirely (see xr_overlay_render_and_build_layer() for why), so its
// source framebuffer has to be a real GL object rather than one gl4es
// tracks.
GLuint source_fbo;
uint32_t pixel_generation;
uint32_t source_uploaded_generation;
uint8_t *pixel_cache; // width*height*4 bytes
};
// This file's other GL calls otherwise resolve to gl4es (the only GL
// symbol provider linked into this binary - see android/engine-patches/
// 02-android-opengl-es.patch), fine for anything shared with the engine's
// own gl4es-routed rendering. But the source FBO's blit (see
// xr_overlay_render_and_build_layer()) needs the real driver directly:
// gl4es's fixed-pipeline emulation unconditionally substitutes its own
// shader onto any gl4es-routed draw call, which would silently replace an
// overlay's content with whatever the game itself last rendered. A
// framebuffer blit has no shader stage at all, so going through the real
// driver for it sidesteps the problem entirely - resolved once here and
// shared by every XrOverlay instance, since they're process-wide function
// pointers regardless of how many overlays exist.
typedef void (*PFNQSGETINTEGERV)(GLenum, GLint *);
typedef void (*PFNQSGENFRAMEBUFFERS)(GLsizei, GLuint *);
typedef void (*PFNQSDELETEFRAMEBUFFERS)(GLsizei, const GLuint *);
typedef void (*PFNQSBINDFRAMEBUFFER)(GLenum, GLuint);
typedef void (*PFNQSFRAMEBUFFERTEXTURE2D)(GLenum, GLenum, GLenum, GLuint, GLint);
typedef void (*PFNQSBLITFRAMEBUFFER)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint,
GLbitfield, GLenum);
static PFNQSGETINTEGERV real_glGetIntegerv;
static PFNQSGENFRAMEBUFFERS real_glGenFramebuffers;
static PFNQSDELETEFRAMEBUFFERS real_glDeleteFramebuffers;
static PFNQSBINDFRAMEBUFFER real_glBindFramebuffer;
static PFNQSFRAMEBUFFERTEXTURE2D real_glFramebufferTexture2D;
// glBlitFramebuffer is a GLES 3.0 addition; resolved via eglGetProcAddress
// rather than dlsym, since Android's driver dispatch doesn't guarantee ES3+
// symbols are dlsym-able by name from libGLESv2.so, unlike the GLES2-core
// functions above.
static PFNQSBLITFRAMEBUFFER real_glBlitFramebuffer;
static bool g_real_gles_loaded = false;
static bool xr_overlay_load_real_gles(void) {
if (g_real_gles_loaded)
return true;
void *lib = dlopen("libGLESv2.so", RTLD_NOW | RTLD_LOCAL);
if (lib == NULL) {
LOGE("XR: overlay dlopen(libGLESv2.so) failed: %s", dlerror());
return false;
}
real_glGetIntegerv = (PFNQSGETINTEGERV)dlsym(lib, "glGetIntegerv");
real_glGenFramebuffers = (PFNQSGENFRAMEBUFFERS)dlsym(lib, "glGenFramebuffers");
real_glDeleteFramebuffers = (PFNQSDELETEFRAMEBUFFERS)dlsym(lib, "glDeleteFramebuffers");
real_glBindFramebuffer = (PFNQSBINDFRAMEBUFFER)dlsym(lib, "glBindFramebuffer");
real_glFramebufferTexture2D = (PFNQSFRAMEBUFFERTEXTURE2D)dlsym(lib, "glFramebufferTexture2D");
real_glBlitFramebuffer = (PFNQSBLITFRAMEBUFFER)eglGetProcAddress("glBlitFramebuffer");
g_real_gles_loaded = real_glGetIntegerv && real_glGenFramebuffers &&
real_glDeleteFramebuffers && real_glBindFramebuffer &&
real_glFramebufferTexture2D && real_glBlitFramebuffer;
return g_real_gles_loaded;
}
// FindClass() from this thread (SDL's native thread, attached to the JVM
// via AttachCurrentThread rather than spawned from Java) resolves against
// the bootstrap classloader, which only knows framework classes - it can't
// see app classes like de.ladkau.questshock.KeyboardOverlay at all.
// Routing through the activity's own classloader is the standard,
// documented workaround.
static jclass xr_overlay_find_class(JNIEnv *env, jobject activity, const char *name) {
jclass activityClass = (*env)->GetObjectClass(env, activity);
jmethodID getClassLoader =
(*env)->GetMethodID(env, activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
jobject classLoader = (*env)->CallObjectMethod(env, activity, getClassLoader);
jclass classLoaderClass = (*env)->FindClass(env, "java/lang/ClassLoader");
jmethodID loadClass = (*env)->GetMethodID(env, classLoaderClass, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
jstring className = (*env)->NewStringUTF(env, name);
jclass result = (jclass)(*env)->CallObjectMethod(env, classLoader, loadClass, className);
(*env)->DeleteLocalRef(env, className);
return result;
}
static bool xr_overlay_init_jni(XrOverlay *overlay, const char *java_class_name) {
JNIEnv *env = (JNIEnv *)SDL_AndroidGetJNIEnv();
jobject activity = (jobject)SDL_AndroidGetActivity();
if (env == NULL || activity == NULL) {
LOGE("XR: overlay - no JNIEnv/Activity from SDL");
return false;
}
jclass localClass = xr_overlay_find_class(env, activity, java_class_name);
if (localClass == NULL) {
LOGE("XR: overlay - could not find class %s", java_class_name);
return false;
}
overlay->java_class = (jclass)(*env)->NewGlobalRef(env, localClass);
overlay->native_init_method = (*env)->GetStaticMethodID(env, overlay->java_class, "nativeInit",
"(Landroid/app/Activity;)V");
overlay->take_pixels_method =
(*env)->GetStaticMethodID(env, overlay->java_class, "nativeTakePixelsIfDirty", "()[B");
overlay->dispatch_touch_method =
(*env)->GetStaticMethodID(env, overlay->java_class, "nativeDispatchTouch", "(FFZ)V");
overlay->update_cursor_method =
(*env)->GetStaticMethodID(env, overlay->java_class, "nativeUpdateCursor", "(FFZ)V");
if (!overlay->native_init_method || !overlay->take_pixels_method ||
!overlay->dispatch_touch_method || !overlay->update_cursor_method) {
LOGE("XR: overlay - could not resolve %s JNI methods", java_class_name);
return false;
}
(*env)->CallStaticVoidMethod(env, overlay->java_class, overlay->native_init_method, activity);
// CallStaticVoidMethod doesn't surface Java exceptions on its own - if
// the constructor throws (it runs its View measure/layout/draw calls
// on this native render thread rather than the Android UI thread, a
// plausible crash vector), the exception would otherwise be left
// silently pending and corrupt whatever JNI call runs next.
if ((*env)->ExceptionCheck(env)) {
LOGE("XR: overlay %s.nativeInit() threw a pending Java exception:", java_class_name);
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return false;
}
return true;
}
static bool xr_overlay_create_source_texture(XrOverlay *overlay) {
glGenTextures(1, &overlay->source_texture);
glBindTexture(GL_TEXTURE_2D, overlay->source_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, overlay->width, overlay->height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
GLint prevFbo = 0;
real_glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo);
real_glGenFramebuffers(1, &overlay->source_fbo);
real_glBindFramebuffer(GL_FRAMEBUFFER, overlay->source_fbo);
real_glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
overlay->source_texture, 0);
real_glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)prevFbo);
return overlay->source_texture != 0;
}
XrOverlay *xr_overlay_create(XrInstance instance, XrSession session, int64_t swapchain_format,
const XrOverlayConfig *config) {
if (!xr_overlay_load_real_gles()) {
LOGE("XR: overlay couldn't resolve real GLES functions via dlsym/eglGetProcAddress");
return NULL;
}
XrOverlay *overlay = (XrOverlay *)calloc(1, sizeof(XrOverlay));
if (overlay == NULL)
return NULL;
overlay->instance = instance;
overlay->width = config->width;
overlay->height = config->height;
overlay->distance_m = config->distance_m;
overlay->default_distance_m = config->distance_m;
overlay->half_width_m = config->width_m * 0.5f;
overlay->half_height_m = config->width_m * 0.5f * (float)config->height / (float)config->width;
overlay->center_x_m = config->default_center_x_m;
overlay->center_y_m = config->default_center_y_m;
if (!xr_swapchain_create(instance, session, swapchain_format, config->width, config->height,
&overlay->swapchain)) {
LOGE("XR: overlay %s swapchain setup failed", config->java_class_name);
free(overlay);
return NULL;
}
if (!xr_overlay_create_source_texture(overlay)) {
xr_swapchain_destroy(&overlay->swapchain);
free(overlay);
return NULL;
}
if (!xr_overlay_init_jni(overlay, config->java_class_name)) {
xr_swapchain_destroy(&overlay->swapchain);
free(overlay);
return NULL;
}
overlay->pixel_cache = (uint8_t *)malloc((size_t)config->width * config->height * 4);
if (overlay->pixel_cache == NULL) {
xr_swapchain_destroy(&overlay->swapchain);
free(overlay);
return NULL;
}
overlay->source_uploaded_generation = (uint32_t)-1;
LOGI("XR: overlay %s ready (%dx%d)", config->java_class_name, config->width, config->height);
return overlay;
}
void xr_overlay_destroy(XrOverlay *overlay) {
if (overlay == NULL)
return;
if (overlay->source_texture != 0)
glDeleteTextures(1, &overlay->source_texture);
if (overlay->source_fbo != 0 && real_glDeleteFramebuffers != NULL)
real_glDeleteFramebuffers(1, &overlay->source_fbo);
if (overlay->java_class != NULL) {
JNIEnv *env = (JNIEnv *)SDL_AndroidGetJNIEnv();
if (env != NULL)
(*env)->DeleteGlobalRef(env, overlay->java_class);
}
xr_swapchain_destroy(&overlay->swapchain);
free(overlay->pixel_cache);
free(overlay);
}
// Every function below tolerates overlay == NULL (a no-op, or the
// obvious "not visible"/zeroed-extent default) - xr_overlay_create() can
// fail (e.g. its backing Java class couldn't be resolved), and unlike the
// single static-global menu quad this replaced, an overlay instance is
// otherwise a heap pointer callers (xr_session.c, questshock_native.c) can
// hold onto and use across frames without re-checking for failure every
// time.
void xr_overlay_toggle_visible(XrOverlay *overlay) {
if (overlay != NULL)
overlay->visible = !overlay->visible;
}
void xr_overlay_set_visible(XrOverlay *overlay, bool visible) {
if (overlay != NULL)
overlay->visible = visible;
}
bool xr_overlay_is_visible(const XrOverlay *overlay) { return overlay != NULL && overlay->visible; }
void xr_overlay_get_quad_extent(const XrOverlay *overlay, float *center_x_m, float *center_y_m,
float *distance_m, float *half_width_m, float *half_height_m,
float *yaw_deg) {
if (overlay == NULL) {
*center_x_m = *center_y_m = *distance_m = *half_width_m = *half_height_m = *yaw_deg = 0.0f;
return;
}
*center_x_m = overlay->center_x_m;
*center_y_m = overlay->center_y_m;
*distance_m = overlay->distance_m;
*half_width_m = overlay->half_width_m;
*half_height_m = overlay->half_height_m;
*yaw_deg = overlay->yaw_deg;
}
void xr_overlay_set_position(XrOverlay *overlay, float center_x_m, float center_y_m) {
if (overlay == NULL)
return;
overlay->center_x_m = center_x_m;
overlay->center_y_m = center_y_m;
}
void xr_overlay_set_pose(XrOverlay *overlay, float center_x_m, float center_y_m, float distance_m,
float yaw_deg) {
if (overlay == NULL)
return;
overlay->center_x_m = center_x_m;
overlay->center_y_m = center_y_m;
overlay->distance_m = distance_m;
overlay->yaw_deg = yaw_deg;
}
float xr_overlay_get_default_distance_m(const XrOverlay *overlay) {
return overlay == NULL ? 0.0f : overlay->default_distance_m;
}
void xr_overlay_touch(XrOverlay *overlay, float u, float v, bool down) {
if (overlay == NULL)
return;
JNIEnv *env = (JNIEnv *)SDL_AndroidGetJNIEnv();
if (env == NULL)
return;
// Passed via CallStaticVoidMethodA/jvalue rather than the variadic
// Call*Method form - deliberately sidesteps relying on JNI
// implementations correctly un-doing C's float-to-double default
// argument promotion for varargs float parameters (a well-known JNI
// footgun; Android's ART handles it correctly, but there's no reason
// to depend on that when the jvalue form is unambiguous either way).
jvalue args[3];
args[0].f = u;
args[1].f = v;
args[2].z = (jboolean)down;
(*env)->CallStaticVoidMethodA(env, overlay->java_class, overlay->dispatch_touch_method, args);
}
void xr_overlay_update_cursor(XrOverlay *overlay, float u, float v, bool visible) {
if (overlay == NULL)
return;
JNIEnv *env = (JNIEnv *)SDL_AndroidGetJNIEnv();
if (env == NULL)
return;
// Same jvalue-form rationale as xr_overlay_touch() above.
jvalue args[3];
args[0].f = u;
args[1].f = v;
args[2].z = (jboolean)visible;
(*env)->CallStaticVoidMethodA(env, overlay->java_class, overlay->update_cursor_method, args);
}
// Pulls the Java view's latest pixels (if it redrew since the last check)
// into pixel_cache and bumps pixel_generation - called once per rendered
// frame, before deciding whether source_texture needs a fresh upload.
static void xr_overlay_refresh_pixel_cache(XrOverlay *overlay) {
JNIEnv *env = (JNIEnv *)SDL_AndroidGetJNIEnv();
if (env == NULL)
return;
jbyteArray pixels = (jbyteArray)(*env)->CallStaticObjectMethod(
env, overlay->java_class, overlay->take_pixels_method);
// CallStaticObjectMethod also doesn't surface Java exceptions on its
// own - if nativeTakePixelsIfDirty() itself throws, it would otherwise
// silently look identical to "nothing changed yet" (a null return).
if ((*env)->ExceptionCheck(env)) {
LOGE("XR: overlay nativeTakePixelsIfDirty() threw a pending Java exception:");
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
return;
}
if (pixels == NULL)
return;
(*env)->GetByteArrayRegion(env, pixels, 0, overlay->width * overlay->height * 4,
(jbyte *)overlay->pixel_cache);
(*env)->DeleteLocalRef(env, pixels);
overlay->pixel_generation++;
}
// Uploads pixel_cache into source_texture via plain (gl4es-routed)
// glBindTexture/glTexSubImage2D, matching how the texture was created.
// Skipped when nothing changed since the last upload. Texture-unit-0 state
// is saved and restored around the upload, since this call is gl4es-routed
// and the engine's own next-frame rendering assumes nothing touched its
// texture bindings since it last drew.
static void xr_overlay_upload_source_texture_if_dirty(XrOverlay *overlay) {
if (overlay->source_uploaded_generation == overlay->pixel_generation)
return;
GLint prevActiveTexture = GL_TEXTURE0;
glGetIntegerv(GL_ACTIVE_TEXTURE, &prevActiveTexture);
glActiveTexture(GL_TEXTURE0);
GLint prevTexture2D = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTexture2D);
glBindTexture(GL_TEXTURE_2D, overlay->source_texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, overlay->width, overlay->height, GL_RGBA,
GL_UNSIGNED_BYTE, overlay->pixel_cache);
overlay->source_uploaded_generation = overlay->pixel_generation;
glBindTexture(GL_TEXTURE_2D, (GLuint)prevTexture2D);
if (prevActiveTexture != GL_TEXTURE0)
glActiveTexture((GLenum)prevActiveTexture);
}
bool xr_overlay_render_and_build_layer(XrOverlay *overlay, XrCompositionLayerQuad *out_quad) {
if (overlay == NULL || !overlay->visible)
return false;
if (!xr_swapchain_acquire(overlay->instance, &overlay->swapchain))
return false;
xr_overlay_refresh_pixel_cache(overlay);
xr_overlay_upload_source_texture_if_dirty(overlay);
// Copies source_texture (via source_fbo) directly into the swapchain
// image xr_swapchain_acquire() just bound - sized to exactly
// width x height, so the destination is always the whole image - using
// the real GLES3 hardware blit (glBlitFramebuffer) rather than a
// shader-based full-screen-quad draw. A blit has no vertex/fragment
// shading stage, no shader program, and no texture units involved at
// all, so gl4es's fixed-pipeline-emulation layer - which
// unconditionally substitutes a customized shader (reproducing the
// game's own last-bound texture/fixed-function state) onto any
// gl4es-routed draw call - has nothing to intercept here. It also
// never touches gl4es's own tracked program/vertex-array/
// texture-binding shadow state, so the only piece of state that needs
// save/restore is the READ framebuffer binding; binding only
// GL_READ_FRAMEBUFFER, rather than the combined GL_FRAMEBUFFER target,
// leaves the DRAW side (the swapchain image itself) untouched
// throughout.
//
// Y is flipped between source and destination: source_texture's texel
// row v=0 holds the Java view's Bitmap row 0 (the top of the rendered
// content, standard top-row-first raster order), and reading that same
// texture via an attached FBO, framebuffer y=0 accesses that identical
// row. The destination swapchain framebuffer follows the opposite
// convention - its own y=0 is its bottom edge - so swapping dstY0/dstY1
// keeps the content right-side up (glBlitFramebuffer supports inverted
// src/dst rects for exactly this).
GLint prevReadFbo = 0;
real_glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &prevReadFbo);
real_glBindFramebuffer(GL_READ_FRAMEBUFFER, overlay->source_fbo);
real_glBlitFramebuffer(0, 0, overlay->width, overlay->height, 0, overlay->height,
overlay->width, 0, GL_COLOR_BUFFER_BIT, GL_LINEAR);
real_glBindFramebuffer(GL_READ_FRAMEBUFFER, (GLuint)prevReadFbo);
// Without this, nothing here waits for the blit to actually finish on
// the GPU before xr_swapchain_release() hands the image back to the
// compositor - glBlitFramebuffer only queues the copy. A cross-process
// consumer reading the image before the driver has finished writing it
// is a textbook source of the diagonal-banded/torn corruption seen on
// device (see xr_swapchain_acquire()'s counterpart in OpenGL.cc, which
// had the same gap).
glFinish();
xr_swapchain_release(overlay->instance, &overlay->swapchain);
memset(out_quad, 0, sizeof(*out_quad));
out_quad->type = XR_TYPE_COMPOSITION_LAYER_QUAD;
out_quad->subImage.swapchain = overlay->swapchain.swapchain;
out_quad->subImage.imageRect.extent.width = overlay->swapchain.width;
out_quad->subImage.imageRect.extent.height = overlay->swapchain.height;
// Rotation about the vertical axis only (see the struct field's own
// comment) - same R_y(-yaw_deg) quaternion construction as
// xr_session.c's own play-space rebuild, for the same reason: this
// quad's pose is expressed as "yaw_deg turned from its own local -Z",
// so a point/ray in that rotated frame maps back into the (unrotated)
// base space by rotating by -yaw_deg.
float half = -(overlay->yaw_deg * QS_DEG_TO_RAD) * 0.5f;
out_quad->pose.orientation.x = 0.0f;
out_quad->pose.orientation.y = sinf(half);
out_quad->pose.orientation.z = 0.0f;
out_quad->pose.orientation.w = cosf(half);
out_quad->pose.position.x = overlay->center_x_m;
out_quad->pose.position.y = overlay->center_y_m;
out_quad->pose.position.z = -overlay->distance_m;
out_quad->size.width = overlay->half_width_m * 2.0f;
out_quad->size.height = overlay->half_height_m * 2.0f;
return true;
}
+117
View File
@@ -0,0 +1,117 @@
// Generic "off-screen Android View rendered into its own OpenXR quad,
// hit-tested/touched via a laser pointer" module - each instance owns its
// own swapchain (via xr_swapchain.h), its own visible/position state, and
// the JNI glue to a backing Java class (menu launcher, keyboard, or any
// future such panel) that must expose these static methods, matching the
// pattern MenuOverlay.java already established:
// static void nativeInit(Activity activity)
// static byte[] nativeTakePixelsIfDirty()
// static void nativeDispatchTouch(float u, float v, boolean down)
// static void nativeUpdateCursor(float u, float v, boolean visible)
//
// xr_input.c drives touch/cursor dispatch and (for panels that support it,
// like the keyboard's title bar) dragging via xr_overlay_set_position();
// xr_session.c owns instance lifetime and calls
// xr_overlay_render_and_build_layer() once per frame per instance.
#ifndef QUESTSHOCK_XR_OVERLAY_H
#define QUESTSHOCK_XR_OVERLAY_H
#include <stdbool.h>
#include <stdint.h>
#define XR_USE_PLATFORM_ANDROID 1
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#include <openxr/openxr.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct XrOverlay XrOverlay;
typedef struct {
// Fully-qualified Java class name backing this overlay, e.g.
// "de.ladkau.questshock.KeyboardOverlay" - resolved via the activity's
// own ClassLoader (see xr_overlay_find_class() in xr_overlay.c).
const char *java_class_name;
// Pixel size of the overlay's own content/swapchain.
int width;
int height;
// Initial local-space pose (meters, in front of the viewer along -Z) -
// see xr_overlay_get_quad_extent(). width_m is the quad's physical
// width; its height is derived to preserve width/height's aspect.
float distance_m;
float width_m;
float default_center_x_m;
float default_center_y_m;
} XrOverlayConfig;
// instance/session are used to create this overlay's own swapchain
// (format shared with every other quad this app submits - see
// xr_session.c's chosenFormat). Returns NULL (logged) on failure - the
// caller just has no such panel.
XrOverlay *xr_overlay_create(XrInstance instance, XrSession session, int64_t swapchain_format,
const XrOverlayConfig *config);
void xr_overlay_destroy(XrOverlay *overlay);
void xr_overlay_toggle_visible(XrOverlay *overlay);
void xr_overlay_set_visible(XrOverlay *overlay, bool visible);
bool xr_overlay_is_visible(const XrOverlay *overlay);
// Base-space pose/size of the quad, valid regardless of visibility - shared
// with xr_input.c's ray/quad hit-testing. yaw_deg is rotation about the
// vertical axis (see xr_overlay_set_pose()) - 0 unless something has
// called that.
void xr_overlay_get_quad_extent(const XrOverlay *overlay, float *center_x_m, float *center_y_m,
float *distance_m, float *half_width_m, float *half_height_m,
float *yaw_deg);
// Repositions the quad (base-space X/Y offset, same units/space as
// xr_overlay_get_quad_extent()'s center_x_m/center_y_m) - e.g. driven by
// xr_input.c while the user drags a panel's title bar. Distance from the
// viewer and rotation aren't adjustable this way - only left/right/up/down
// repositioning, not push/pull or turning - see xr_overlay_set_pose() for
// that.
void xr_overlay_set_position(XrOverlay *overlay, float center_x_m, float center_y_m);
// Full reposition: X/Y offset, distance ("push/pull"), and rotation about
// the vertical axis (degrees, same sign convention as
// xr_session_set_player_transform()'s yaw_deg) - used by xr_input.c to
// re-center the menu launcher in front of wherever the player currently
// is/facing each time it's freshly reopened, unlike
// xr_overlay_set_position()'s drag-only X/Y-at-fixed-distance-and-facing.
void xr_overlay_set_pose(XrOverlay *overlay, float center_x_m, float center_y_m, float distance_m,
float yaw_deg);
// The overlay's original, never-mutated distance_m (from XrOverlayConfig at
// creation time) - unlike xr_overlay_get_quad_extent()'s live distance_m,
// which xr_overlay_set_pose() repurposes as a raw base-space Z coordinate
// once any rotation is involved (see xr_overlay_set_pose()'s own comment),
// this stays a stable "how far in front" magnitude across repeated
// recenters. 0 for a NULL overlay.
float xr_overlay_get_default_distance_m(const XrOverlay *overlay);
// Forwards a hit on the quad (in the quad's own 0..1 u/v, top-left origin)
// to the backing Java view as a synthetic touch down/up.
void xr_overlay_touch(XrOverlay *overlay, float u, float v, bool down);
// Updates the on-quad cursor the Java view draws at the current aim hit
// point (same u/v convention as xr_overlay_touch()) - called once per
// frame regardless of click state, so the cursor tracks the ray
// continuously. visible=false hides it.
void xr_overlay_update_cursor(XrOverlay *overlay, float u, float v, bool visible);
// If visible: acquires this overlay's next swapchain image, blits the
// Java view's latest rendered pixels into it, releases the image, and
// fills *out_quad's subImage/pose/size. space/eyeVisibility/layerFlags are
// left for the caller to set (shared/policy choices across every layer
// this app submits, e.g. translucency - not this module's concern).
// Returns false (out_quad untouched) if not visible or something failed -
// the caller should skip submitting a layer for it this frame.
bool xr_overlay_render_and_build_layer(XrOverlay *overlay, XrCompositionLayerQuad *out_quad);
#ifdef __cplusplus
}
#endif
#endif
+892
View File
@@ -0,0 +1,892 @@
#include "xr_session.h"
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <android/log.h>
#include <jni.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#define XR_USE_PLATFORM_ANDROID 1
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <SDL.h>
#include "xr_input.h"
#include "xr_overlay.h"
#include "xr_swapchain.h"
#define TAG "QuestShock"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
// Original, pre-screen-profile-feature default distance for the game
// screen - 2m in front of the local space origin - now just the initial
// value of g_screen_distance_m (below) rather than a fixed constant.
// Width/curve/distance are all configurable (see g_screen_width_m/
// g_screen_curve_deg/g_screen_distance_m above and CONFIG.md's Video
// Options "Initial Screen"/"Game Screen" settings), sized to preserve the
// game's own pixel aspect ratio at whatever physical width is currently
// configured. No per-eye view/projection work is needed for a quad/
// cylinder layer at all - the compositor handles reprojecting it per eye
// itself, which is exactly why this milestone doesn't need xrLocateViews
// or any stereo rendering (see the plan's step A notes).
#define QUAD_DISTANCE_METERS 2.0f
// The menu launcher (just a "Keyboard" button - see MenuOverlay.java) is
// small and sits above where the keyboard defaults to; the keyboard keeps
// its previous size/position. They're independent XrOverlay instances (see
// xr_overlay.h) so both can be shown/hidden/dragged separately - deliberately
// positioned apart by default so they don't start out overlapping.
#define MENU_JAVA_CLASS "de.ladkau.questshock.MenuOverlay"
// 768x800 (was 512x256, then 768x512, then 768x552) - grown to fit the
// header/tabs/Video Options content added on top of the original single
// "Keyboard" button, then again to fit the stats ribbon below the tab
// bar, then again to fit the Video Options tab's screen-size grid; taller
// in world space too since MENU_WIDTH_METERS (the physical size) stays
// fixed and height_m is derived from it by aspect ratio (see
// xr_overlay.c's xr_overlay_init()). Must match MenuOverlay.java's own
// WIDTH/HEIGHT, and xr_input.c's MENU_TITLE_BAR_V_FRACTION denominator.
#define MENU_WIDTH 768
#define MENU_HEIGHT 800
#define MENU_DISTANCE_METERS 1.3f
// Physical size - was 0.35m, too small to read comfortably at
// MENU_DISTANCE_METERS given how much text the header/tabs/stats ribbon
// pack in; same pixel resolution (MENU_WIDTH/HEIGHT above) just displayed
// bigger, not a layout change.
#define MENU_WIDTH_METERS 0.5f
#define MENU_DEFAULT_CENTER_X_METERS 0.0f
#define MENU_DEFAULT_CENTER_Y_METERS 0.15f
#define KEYBOARD_JAVA_CLASS "de.ladkau.questshock.KeyboardOverlay"
#define KEYBOARD_WIDTH 1024
#define KEYBOARD_HEIGHT 768
#define KEYBOARD_DISTANCE_METERS 1.5f
#define KEYBOARD_WIDTH_METERS 0.8f
#define KEYBOARD_DEFAULT_CENTER_X_METERS 0.0f
#define KEYBOARD_DEFAULT_CENTER_Y_METERS -0.45f
static XrInstance g_instance = XR_NULL_HANDLE;
static XrSystemId g_system_id = XR_NULL_SYSTEM_ID;
static XrSession g_session = XR_NULL_HANDLE;
static XrSpace g_local_space = XR_NULL_HANDLE;
// Everything this app submits/locates (game/menu/keyboard/beam quads, hand
// and head poses) is expressed relative to g_play_space, not g_local_space
// directly - it's g_local_space translated/rotated by the inverse of the
// player's own virtual transform (see xr_session_set_player_transform()'s
// own comment in xr_session.h and xr_session_rebuild_play_space() below),
// so moving/turning the player moves/turns everything else relative to
// them without touching any actual pose-building or hit-testing math
// elsewhere in the app - it's all still "relative to the base space",
// which just happens to no longer be g_local_space itself.
static XrSpace g_play_space = XR_NULL_HANDLE;
static float g_player_x = 0.0f;
static float g_player_z = 0.0f;
static float g_player_yaw_deg = 0.0f;
// Set by xr_session_set_player_transform() (including before xr_init() has
// even run - see its own comment), cleared once xr_session_rebuild_play_space()
// actually rebuilds g_play_space from the current x/z/yaw_deg - checked
// once per frame in xr_frame_end() so a stick held at rest costs nothing.
static bool g_player_transform_dirty = false;
static XrSessionState g_session_state = XR_SESSION_STATE_UNKNOWN;
// Distinct from g_session_state - true from a successful xrBeginSession
// until xrEndSession/loss/exit. Many runtimes only advance the *state*
// (e.g. READY -> SYNCHRONIZED -> VISIBLE -> FOCUSED) in response to the
// app actually calling xrWaitFrame/xrBeginFrame/xrEndFrame continuously
// after xrBeginSession - gating frame submission on already having
// reached SYNCHRONIZED+ (as this used to) is a chicken-and-egg deadlock,
// since the runtime never progresses past READY without the frame loop
// running in the first place. Frame calls just need the session to have
// begun, per the standard OpenXR sample pattern - not any particular
// later state.
static bool g_session_running = false;
static XrSwapchainState g_game_swapchain;
static XrOverlay *g_menu_overlay = NULL;
static XrOverlay *g_keyboard_overlay = NULL;
static XrTime g_predicted_display_time = 0;
static bool g_frame_should_render = false;
static bool g_have_acquired_game_image = false;
// XR_META_performance_metrics support (see xr_session_init_performance_metrics()
// below) - only present if the runtime advertised it at xrCreateInstance
// time (checked via xr_instance_extension_supported()), since unlike the
// two always-required KHR extensions above, this one is a device-capability
// extra that a build shouldn't hard-depend on.
static bool g_performance_metrics_supported = false;
static PFN_xrSetPerformanceMetricsStateMETA g_xrSetPerformanceMetricsStateMETA = NULL;
static PFN_xrQueryPerformanceMetricsCounterMETA g_xrQueryPerformanceMetricsCounterMETA = NULL;
// Resolved once, at startup, by string-matching the runtime's own
// human-readable counter path names (see xr_session_init_performance_metrics())
// rather than hardcoding the exact path strings the spec defines - a
// substring match is robust to spec/runtime wording we can't verify without
// on-device testing. XR_NULL_PATH (0) if no match was found.
static XrPath g_cpu_utilization_path = XR_NULL_PATH;
static XrPath g_gpu_utilization_path = XR_NULL_PATH;
// XR_KHR_composition_layer_cylinder support - same "only if the runtime
// advertised it" reasoning as g_performance_metrics_supported above. If
// unsupported, the curve is forced to 0 (flat) everywhere regardless of
// configuration (see xr_get_game_quad_extent()) so the game screen just
// silently stays flat instead of failing to submit a layer at all.
static bool g_cylinder_layer_supported = false;
// The game screen's currently-configured shape (see qs_config.c's
// qs_screen_profile_notify_loop_mode(), which is what actually calls
// xr_session_set_game_screen_shape() below - this file has no notion of
// "which profile" is active, only "what shape is current"). Defaults
// match the game quad's own original, pre-this-feature hardcoded width
// (1.6m) and lack of curve, so a build that never touches the new config
// options renders identically to before.
static float g_screen_width_m = 1.6f;
static float g_screen_curve_deg = 0.0f;
static float g_screen_distance_m = QUAD_DISTANCE_METERS;
static bool xr_check(XrResult result, const char *what) {
if (XR_SUCCEEDED(result))
return true;
char resultString[XR_MAX_RESULT_STRING_SIZE] = {0};
if (g_instance != XR_NULL_HANDLE)
xrResultToString(g_instance, result, resultString);
LOGE("XR: %s failed: %s (%d)", what, resultString[0] ? resultString : "?", (int)result);
return false;
}
static PFN_xrVoidFunction xr_get_proc(const char *name) {
PFN_xrVoidFunction fn = NULL;
// xrGetInstanceProcAddr itself works with a NULL instance for the
// handful of functions (like xrInitializeLoaderKHR) that must be called
// before an instance exists.
if (!xr_check(xrGetInstanceProcAddr(g_instance, name, &fn), name))
return NULL;
return fn;
}
// Queried before xrCreateInstance (which is why this takes no instance
// handle - xrEnumerateInstanceExtensionProperties is one of the few
// functions that works without one) to decide whether it's safe to add
// `name` to enabledExtensionNames - passing an unsupported extension there
// would fail instance creation outright, unlike a missing optional feature
// discovered afterward.
static bool xr_instance_extension_supported(const char *name) {
uint32_t count = 0;
if (!xr_check(xrEnumerateInstanceExtensionProperties(NULL, 0, &count, NULL),
"xrEnumerateInstanceExtensionProperties"))
return false;
XrExtensionProperties *props = (XrExtensionProperties *)malloc(sizeof(XrExtensionProperties) * count);
for (uint32_t i = 0; i < count; i++)
props[i].type = XR_TYPE_EXTENSION_PROPERTIES;
bool supported = false;
if (xr_check(xrEnumerateInstanceExtensionProperties(NULL, count, &count, props),
"xrEnumerateInstanceExtensionProperties")) {
for (uint32_t i = 0; i < count; i++) {
if (strcmp(props[i].extensionName, name) == 0) {
supported = true;
break;
}
}
}
free(props);
return supported;
}
// Case-insensitively checks whether `needle` occurs anywhere in `haystack` -
// used to identify a counter path (e.g. ".../device/cpu_utilization_average")
// by a short, stable substring instead of matching its exact full spelling.
static bool xr_path_name_contains(const char *haystack, const char *needle) {
size_t hlen = strlen(haystack);
char lower[256];
if (hlen >= sizeof(lower))
hlen = sizeof(lower) - 1;
for (size_t i = 0; i < hlen; i++)
lower[i] = (char)tolower((unsigned char)haystack[i]);
lower[hlen] = '\0';
return strstr(lower, needle) != NULL;
}
// Enables XR_META_performance_metrics (if the runtime advertised it - see
// xr_instance_extension_supported() above) and resolves the CPU/GPU
// device-utilization counter paths xr_session_update_frame_stats() polls
// every frame. Called once, right after xrCreateSession succeeds. Leaves
// g_cpu_utilization_path/g_gpu_utilization_path at XR_NULL_PATH (their
// getters then report -1.0f) if anything here doesn't pan out - this is a
// nice-to-have stats display, not something worth failing session bring-up
// over.
static void xr_session_init_performance_metrics(void) {
if (!g_performance_metrics_supported)
return;
PFN_xrEnumeratePerformanceMetricsCounterPathsMETA enumeratePaths =
(PFN_xrEnumeratePerformanceMetricsCounterPathsMETA)xr_get_proc(
"xrEnumeratePerformanceMetricsCounterPathsMETA");
g_xrSetPerformanceMetricsStateMETA = (PFN_xrSetPerformanceMetricsStateMETA)xr_get_proc(
"xrSetPerformanceMetricsStateMETA");
g_xrQueryPerformanceMetricsCounterMETA = (PFN_xrQueryPerformanceMetricsCounterMETA)xr_get_proc(
"xrQueryPerformanceMetricsCounterMETA");
if (enumeratePaths == NULL || g_xrSetPerformanceMetricsStateMETA == NULL ||
g_xrQueryPerformanceMetricsCounterMETA == NULL)
return;
XrPerformanceMetricsStateMETA state = {XR_TYPE_PERFORMANCE_METRICS_STATE_META};
state.enabled = XR_TRUE;
if (!xr_check(g_xrSetPerformanceMetricsStateMETA(g_session, &state),
"xrSetPerformanceMetricsStateMETA"))
return;
uint32_t pathCount = 0;
if (!xr_check(enumeratePaths(g_instance, 0, &pathCount, NULL),
"xrEnumeratePerformanceMetricsCounterPathsMETA"))
return;
XrPath *paths = (XrPath *)malloc(sizeof(XrPath) * pathCount);
if (!xr_check(enumeratePaths(g_instance, pathCount, &pathCount, paths),
"xrEnumeratePerformanceMetricsCounterPathsMETA")) {
free(paths);
return;
}
for (uint32_t i = 0; i < pathCount; i++) {
char pathName[256];
uint32_t pathNameLen = 0;
if (!xr_check(xrPathToString(g_instance, paths[i], sizeof(pathName), &pathNameLen, pathName),
"xrPathToString"))
continue;
if (g_cpu_utilization_path == XR_NULL_PATH && xr_path_name_contains(pathName, "cpu_utilization"))
g_cpu_utilization_path = paths[i];
if (g_gpu_utilization_path == XR_NULL_PATH && xr_path_name_contains(pathName, "gpu_utilization"))
g_gpu_utilization_path = paths[i];
}
free(paths);
LOGI("XR: performance metrics cpu_utilization=%s gpu_utilization=%s",
g_cpu_utilization_path != XR_NULL_PATH ? "found" : "not found",
g_gpu_utilization_path != XR_NULL_PATH ? "found" : "not found");
}
// The Android OpenXR loader needs the JavaVM/context before anything else -
// separate from XR_KHR_android_create_instance below, which only affects
// xrCreateInstance itself. Skipping this is a common cause of
// xrCreateInstance silently failing to find a runtime on Android.
static bool xr_initialize_android_loader(JavaVM *vm, jobject activity) {
PFN_xrInitializeLoaderKHR initializeLoader =
(PFN_xrInitializeLoaderKHR)xr_get_proc("xrInitializeLoaderKHR");
if (initializeLoader == NULL) {
LOGE("XR: xrInitializeLoaderKHR not available - no Android OpenXR loader present?");
return false;
}
XrLoaderInitInfoAndroidKHR loaderInitInfo = {XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR};
loaderInitInfo.applicationVM = vm;
loaderInitInfo.applicationContext = activity;
return xr_check(initializeLoader((const XrLoaderInitInfoBaseHeaderKHR *)&loaderInitInfo),
"xrInitializeLoaderKHR");
}
// eglGetCurrentDisplay()/eglGetCurrentContext() hand us the display/context,
// but not the EGLConfig they were created with - eglQueryContext's
// EGL_CONFIG_ID plus eglChooseConfig is the standard way to recover it (the
// same trick Khronos' own hello_xr sample uses).
static EGLConfig xr_get_current_egl_config(EGLDisplay display, EGLContext context) {
EGLint configId = 0;
eglQueryContext(display, context, EGL_CONFIG_ID, &configId);
EGLint attribs[] = {EGL_CONFIG_ID, configId, EGL_NONE};
EGLConfig config = NULL;
EGLint numConfigs = 0;
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
return config;
}
#define QS_DEG_TO_RAD (3.14159265358979323846f / 180.0f)
// Destroys/recreates g_play_space from g_local_space, offset by the
// inverse of the player's current virtual transform (g_player_x/z/yaw_deg) -
// see xr_session_set_player_transform()'s comment in xr_session.h for why
// this is the inverse rather than the transform itself. Given
// V = Translate(x, 0, z) * Rotate_Y(yaw_deg) (the player's own transform,
// "apparent pose in play space = V composed with real pose in local
// space"), the new space's poseInReferenceSpace must be V's inverse:
// orientation = Rotate_Y(-yaw_deg), position = Rotate_Y(-yaw_deg) * (-x, 0, -z).
// Called once, right after g_local_space itself is created (picking up
// whatever qs_config_load_startup() already seeded before xr_init() ever
// ran), and once per frame from xr_frame_end() whenever
// g_player_transform_dirty says the transform actually changed since the
// last rebuild - a plain stick-at-rest frame costs nothing beyond that one
// bool check. g_session must already exist.
static void xr_session_rebuild_play_space(void) {
if (g_play_space != XR_NULL_HANDLE) {
xrDestroySpace(g_play_space);
g_play_space = XR_NULL_HANDLE;
}
float theta = g_player_yaw_deg * QS_DEG_TO_RAD;
float half = -theta * 0.5f;
float c = cosf(-theta), s = sinf(-theta);
float vx = -g_player_x, vz = -g_player_z;
XrReferenceSpaceCreateInfo spaceInfo = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
spaceInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
spaceInfo.poseInReferenceSpace.orientation.x = 0.0f;
spaceInfo.poseInReferenceSpace.orientation.y = sinf(half);
spaceInfo.poseInReferenceSpace.orientation.z = 0.0f;
spaceInfo.poseInReferenceSpace.orientation.w = cosf(half);
spaceInfo.poseInReferenceSpace.position.x = vx * c + vz * s;
spaceInfo.poseInReferenceSpace.position.y = 0.0f;
spaceInfo.poseInReferenceSpace.position.z = -vx * s + vz * c;
xr_check(xrCreateReferenceSpace(g_session, &spaceInfo, &g_play_space),
"xrCreateReferenceSpace(play)");
g_player_transform_dirty = false;
}
void xr_session_set_player_transform(float x, float z, float yaw_deg) {
g_player_x = x;
g_player_z = z;
g_player_yaw_deg = yaw_deg;
g_player_transform_dirty = true;
}
void xr_session_get_player_transform(float *x, float *z, float *yaw_deg) {
*x = g_player_x;
*z = g_player_z;
*yaw_deg = g_player_yaw_deg;
}
XrSpace xr_session_get_local_space(void) { return g_local_space; }
XrTime xr_session_get_predicted_display_time(void) { return g_predicted_display_time; }
static bool xr_create_instance_and_session(int game_width, int game_height) {
JNIEnv *env = (JNIEnv *)SDL_AndroidGetJNIEnv();
jobject activity = (jobject)SDL_AndroidGetActivity();
if (env == NULL || activity == NULL) {
LOGE("XR: no JNIEnv/Activity from SDL - can't init OpenXR");
return false;
}
JavaVM *vm = NULL;
(*env)->GetJavaVM(env, &vm);
if (!xr_initialize_android_loader(vm, activity))
return false;
g_performance_metrics_supported =
xr_instance_extension_supported(XR_META_PERFORMANCE_METRICS_EXTENSION_NAME);
g_cylinder_layer_supported =
xr_instance_extension_supported(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME);
// The two KHR extensions here are always required; the other two are
// each independently optional device capabilities (see
// g_performance_metrics_supported/g_cylinder_layer_supported's own
// comments) - appended only if actually advertised, since listing an
// unsupported extension fails xrCreateInstance entirely, not just that
// one feature.
const char *extensions[4] = {
XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME,
XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME,
};
uint32_t extensionCount = 2;
if (g_performance_metrics_supported)
extensions[extensionCount++] = XR_META_PERFORMANCE_METRICS_EXTENSION_NAME;
if (g_cylinder_layer_supported)
extensions[extensionCount++] = XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME;
XrInstanceCreateInfoAndroidKHR androidInfo = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR};
androidInfo.applicationVM = vm;
androidInfo.applicationActivity = activity;
XrInstanceCreateInfo createInfo = {XR_TYPE_INSTANCE_CREATE_INFO};
createInfo.next = &androidInfo;
createInfo.enabledExtensionCount = extensionCount;
createInfo.enabledExtensionNames = extensions;
strncpy(createInfo.applicationInfo.applicationName, "QuestShock",
XR_MAX_APPLICATION_NAME_SIZE - 1);
strncpy(createInfo.applicationInfo.engineName, "Shockolate", XR_MAX_ENGINE_NAME_SIZE - 1);
createInfo.applicationInfo.applicationVersion = 1;
createInfo.applicationInfo.engineVersion = 1;
createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
if (!xr_check(xrCreateInstance(&createInfo, &g_instance), "xrCreateInstance"))
return false;
XrSystemGetInfo systemInfo = {XR_TYPE_SYSTEM_GET_INFO};
systemInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
if (!xr_check(xrGetSystem(g_instance, &systemInfo, &g_system_id), "xrGetSystem"))
return false;
// Required by spec before creating an OpenGL ES-backed session, even
// though we don't gate on the returned min/max API version here.
PFN_xrGetOpenGLESGraphicsRequirementsKHR getGLESRequirements =
(PFN_xrGetOpenGLESGraphicsRequirementsKHR)xr_get_proc(
"xrGetOpenGLESGraphicsRequirementsKHR");
if (getGLESRequirements == NULL)
return false;
XrGraphicsRequirementsOpenGLESKHR glesRequirements = {
XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR};
if (!xr_check(getGLESRequirements(g_instance, g_system_id, &glesRequirements),
"xrGetOpenGLESGraphicsRequirementsKHR"))
return false;
EGLDisplay display = eglGetCurrentDisplay();
EGLContext context = eglGetCurrentContext();
if (display == EGL_NO_DISPLAY || context == EGL_NO_CONTEXT) {
LOGE("XR: no current EGL display/context - call xr_init() after init_opengl()");
return false;
}
XrGraphicsBindingOpenGLESAndroidKHR graphicsBinding = {
XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR};
graphicsBinding.display = display;
graphicsBinding.config = xr_get_current_egl_config(display, context);
graphicsBinding.context = context;
XrSessionCreateInfo sessionInfo = {XR_TYPE_SESSION_CREATE_INFO};
sessionInfo.next = &graphicsBinding;
sessionInfo.systemId = g_system_id;
if (!xr_check(xrCreateSession(g_instance, &sessionInfo, &g_session), "xrCreateSession"))
return false;
xr_session_init_performance_metrics();
XrReferenceSpaceCreateInfo spaceInfo = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
spaceInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
spaceInfo.poseInReferenceSpace.orientation.w = 1.0f;
if (!xr_check(xrCreateReferenceSpace(g_session, &spaceInfo, &g_local_space),
"xrCreateReferenceSpace"))
return false;
// Picks up whatever qs_config_load_startup() already stored into
// g_player_x/z/yaw_deg via xr_session_set_player_transform() before
// this function ever ran (that call is pure state, no XR API calls, so
// it works fine even this early) - so a saved position is already in
// effect from the very first frame, not just after the player first
// moves a thumbstick.
xr_session_rebuild_play_space();
// Prefer a plain linear 8-bit format over GL_SRGB8_ALPHA8: the source
// SDL surface pixels are already sRGB-encoded (as ordinary 8-bit image
// data conventionally is) and get uploaded/sampled as plain linear
// GL_RGBA with no decode step anywhere in this path, matching the
// desktop SDL_RenderCopy path this replaces - an sRGB swapchain format
// would auto-gamma-encode on write and double-encode already-encoded
// data. Every swapchain below (game quad, menu/keyboard overlays, and
// - via xr_input_init() - the per-hand laser-beam overlays) shares
// this one choice - the compositor's supported format set doesn't
// depend on swapchain size.
uint32_t formatCount = 0;
xrEnumerateSwapchainFormats(g_session, 0, &formatCount, NULL);
int64_t *formats = (int64_t *)malloc(sizeof(int64_t) * formatCount);
xrEnumerateSwapchainFormats(g_session, formatCount, &formatCount, formats);
int64_t chosenFormat = formats[0];
for (uint32_t i = 0; i < formatCount; i++) {
LOGI("XR: swapchain format[%u] = 0x%llx", i, (unsigned long long)formats[i]);
if (formats[i] == GL_RGBA8) {
chosenFormat = GL_RGBA8;
break;
}
}
free(formats);
// Non-fatal if it fails (e.g. no controllers bound yet) - rendering
// keeps working either way, just without the laser pointer/beams.
xr_input_init(g_instance, g_session, chosenFormat);
if (!xr_swapchain_create(g_instance, g_session, chosenFormat, game_width, game_height,
&g_game_swapchain)) {
LOGE("XR: game swapchain setup failed");
return false;
}
// Both non-fatal - the game keeps rendering with no such panel if
// either fails (e.g. the Java class couldn't be resolved via JNI).
XrOverlayConfig menuConfig = {
.java_class_name = MENU_JAVA_CLASS,
.width = MENU_WIDTH,
.height = MENU_HEIGHT,
.distance_m = MENU_DISTANCE_METERS,
.width_m = MENU_WIDTH_METERS,
.default_center_x_m = MENU_DEFAULT_CENTER_X_METERS,
.default_center_y_m = MENU_DEFAULT_CENTER_Y_METERS,
};
g_menu_overlay = xr_overlay_create(g_instance, g_session, chosenFormat, &menuConfig);
XrOverlayConfig keyboardConfig = {
.java_class_name = KEYBOARD_JAVA_CLASS,
.width = KEYBOARD_WIDTH,
.height = KEYBOARD_HEIGHT,
.distance_m = KEYBOARD_DISTANCE_METERS,
.width_m = KEYBOARD_WIDTH_METERS,
.default_center_x_m = KEYBOARD_DEFAULT_CENTER_X_METERS,
.default_center_y_m = KEYBOARD_DEFAULT_CENTER_Y_METERS,
};
g_keyboard_overlay = xr_overlay_create(g_instance, g_session, chosenFormat, &keyboardConfig);
LOGI("XR: instance/session ready (game %dx%d, menu %dx%d, keyboard %dx%d)", game_width,
game_height, MENU_WIDTH, MENU_HEIGHT, KEYBOARD_WIDTH, KEYBOARD_HEIGHT);
return true;
}
bool xr_init(int game_width, int game_height) {
if (!xr_create_instance_and_session(game_width, game_height)) {
LOGE("XR: bring-up failed - falling back to the normal window present path");
xr_shutdown();
return false;
}
return true;
}
XrOverlay *xr_session_get_menu_overlay(void) { return g_menu_overlay; }
XrOverlay *xr_session_get_keyboard_overlay(void) { return g_keyboard_overlay; }
void xr_poll_events(void) {
if (g_instance == XR_NULL_HANDLE)
return;
while (true) {
XrEventDataBuffer event = {XR_TYPE_EVENT_DATA_BUFFER};
XrResult result = xrPollEvent(g_instance, &event);
if (result == XR_EVENT_UNAVAILABLE)
break;
if (!xr_check(result, "xrPollEvent"))
break;
if (event.type == XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) {
XrEventDataSessionStateChanged *stateEvent = (XrEventDataSessionStateChanged *)&event;
g_session_state = stateEvent->state;
LOGI("XR: session state -> %d", (int)g_session_state);
if (g_session_state == XR_SESSION_STATE_READY) {
XrSessionBeginInfo beginInfo = {XR_TYPE_SESSION_BEGIN_INFO};
beginInfo.primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
g_session_running =
xr_check(xrBeginSession(g_session, &beginInfo), "xrBeginSession");
} else if (g_session_state == XR_SESSION_STATE_STOPPING) {
xr_check(xrEndSession(g_session), "xrEndSession");
g_session_running = false;
} else if (g_session_state == XR_SESSION_STATE_EXITING ||
g_session_state == XR_SESSION_STATE_LOSS_PENDING) {
g_session_running = false;
}
}
}
// xrPollEvent() leaves gl4es reporting a stray GL_INVALID_OPERATION on
// every call while the session is running - drain it (looped, since
// more than one can accumulate across xrPollEvent()'s possibly-multiple
// iterations above) so it doesn't surface as a false positive at the
// next unrelated glGetError() check in this app's own rendering code.
while (glGetError() != GL_NO_ERROR) {
}
}
bool xr_is_session_running(void) { return g_session_running; }
bool xr_frame_begin(void) {
g_have_acquired_game_image = false;
if (!xr_is_session_running())
return false;
XrFrameWaitInfo waitInfo = {XR_TYPE_FRAME_WAIT_INFO};
XrFrameState frameState = {XR_TYPE_FRAME_STATE};
if (!xr_check(xrWaitFrame(g_session, &waitInfo, &frameState), "xrWaitFrame"))
return false;
g_predicted_display_time = frameState.predictedDisplayTime;
g_frame_should_render = frameState.shouldRender;
XrFrameBeginInfo beginInfo = {XR_TYPE_FRAME_BEGIN_INFO};
if (!xr_check(xrBeginFrame(g_session, &beginInfo), "xrBeginFrame"))
return false;
if (!g_frame_should_render)
return false;
g_have_acquired_game_image = xr_swapchain_acquire(g_instance, &g_game_swapchain);
return g_have_acquired_game_image;
}
// Backs xr_session_get_fps()/get_frame_ms() (see xr_session.h) - exponential
// smoothing (rather than a plain per-frame instantaneous value) so
// MenuOverlay's header display doesn't visibly jitter every single frame.
// Called once per xr_frame_end() that reaches its own end (i.e. once per
// real XR frame, whether or not the game itself actually rendered anything
// new into it this frame - matches the OpenXR compositor's own frame
// cadence, which is what "FPS" means to someone looking at this display).
static float s_fps = 0.0f;
static float s_frame_ms = 0.0f;
static float s_cpu_utilization = -1.0f;
static float s_gpu_utilization = -1.0f;
// Reads one XR_META_performance_metrics counter (if it was found at
// startup - see xr_session_init_performance_metrics()) and folds it into
// *smoothed with the same exponential smoothing as FPS/frame time above.
// Leaves *smoothed at -1.0f (its "unsupported" sentinel) untouched if the
// path wasn't found, the query fails, or the runtime didn't mark its
// floatValue valid this call.
static void xr_session_update_utilization(XrPath path, float *smoothed) {
if (path == XR_NULL_PATH || g_xrQueryPerformanceMetricsCounterMETA == NULL)
return;
XrPerformanceMetricsCounterMETA counter = {XR_TYPE_PERFORMANCE_METRICS_COUNTER_META};
if (!xr_check(g_xrQueryPerformanceMetricsCounterMETA(g_session, path, &counter),
"xrQueryPerformanceMetricsCounterMETA"))
return;
if (!(counter.counterFlags & XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META))
return;
const float kSmoothing = 0.1f;
*smoothed =
(*smoothed < 0.0f) ? counter.floatValue : *smoothed * (1.0f - kSmoothing) + counter.floatValue * kSmoothing;
}
static void xr_session_update_frame_stats(void) {
static Uint32 s_last_ticks = 0;
Uint32 now = SDL_GetTicks();
if (s_last_ticks != 0) {
Uint32 delta_ms = now - s_last_ticks;
if (delta_ms > 0) {
float instant_fps = 1000.0f / (float)delta_ms;
const float kSmoothing = 0.1f;
s_fps = (s_fps == 0.0f) ? instant_fps : s_fps * (1.0f - kSmoothing) + instant_fps * kSmoothing;
s_frame_ms =
(s_frame_ms == 0.0f) ? (float)delta_ms : s_frame_ms * (1.0f - kSmoothing) + (float)delta_ms * kSmoothing;
}
}
s_last_ticks = now;
xr_session_update_utilization(g_cpu_utilization_path, &s_cpu_utilization);
xr_session_update_utilization(g_gpu_utilization_path, &s_gpu_utilization);
}
float xr_session_get_fps(void) { return s_fps; }
float xr_session_get_frame_ms(void) { return s_frame_ms; }
float xr_session_get_cpu_utilization(void) { return s_cpu_utilization; }
float xr_session_get_gpu_utilization(void) { return s_gpu_utilization; }
void xr_frame_end(void) {
if (g_session == XR_NULL_HANDLE)
return;
// Rebuilt before xr_input_sync_and_draw() below so this same frame's
// hit-testing and layer submission both see whatever the player's
// thumbstick input (or a config-driven "Reset Position"/Load
// Configuration) changed last frame - a no-op check on every frame
// nothing moved.
if (g_player_transform_dirty)
xr_session_rebuild_play_space();
// Syncs actions and hit-tests/dispatches each hand's ray against
// keyboard/menu/game quad (see xr_input.c) before the game swapchain
// image is released below - this always runs, even when there's
// nothing to draw (no acquired image this frame), so edge detection
// (trigger/menu-button clicks) doesn't miss a frame. Any resulting
// laser-beam quads are submitted as their own composition layers
// further down, not drawn into the game swapchain itself.
if (xr_is_session_running())
xr_input_sync_and_draw(g_play_space, g_predicted_display_time,
g_have_acquired_game_image);
if (g_have_acquired_game_image)
xr_swapchain_release(g_instance, &g_game_swapchain);
if (!xr_is_session_running())
return;
// Up to 5 layers: the game screen (if a frame was actually rendered) -
// a flat quad, or a curved cylinder if the currently-active screen
// profile has a nonzero curve (see xr_get_game_quad_extent()'s own
// comment; xr_input.c's xr_input_try_game_quad() hit-tests whichever
// shape is actually submitted here, always agreeing since both read
// the same getter) - the menu launcher and keyboard overlays while
// visible - each gets its own acquire/render/release cycle against
// its own swapchain (see xr_overlay_render_and_build_layer()) any
// time before xrEndFrame, unlike the game screen there's no per-frame
// engine rendering to wrap around here, just each overlay's own blit -
// and, per hand, a laser-beam quad while that hand's ray is aimed at
// the keyboard, menu, or the game screen itself (see
// xr_input_get_beam_layer()).
float gameDistance, gameHalfWidth, gameHalfHeight, gameRadius, gameCentralAngle;
xr_get_game_quad_extent(&gameDistance, &gameHalfWidth, &gameHalfHeight, &gameRadius,
&gameCentralAngle);
bool gameScreenCurved = gameCentralAngle > 0.0f;
XrCompositionLayerQuad gameQuad = {XR_TYPE_COMPOSITION_LAYER_QUAD};
XrCompositionLayerCylinderKHR gameCylinder = {XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR};
if (gameScreenCurved) {
gameCylinder.space = g_play_space;
gameCylinder.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
gameCylinder.subImage.swapchain = g_game_swapchain.swapchain;
gameCylinder.subImage.imageRect.extent.width = g_game_swapchain.width;
gameCylinder.subImage.imageRect.extent.height = g_game_swapchain.height;
gameCylinder.pose.orientation.w = 1.0f;
gameCylinder.pose.position.z = -gameDistance;
gameCylinder.radius = gameRadius;
gameCylinder.centralAngle = gameCentralAngle;
gameCylinder.aspectRatio = (float)g_game_swapchain.width / (float)g_game_swapchain.height;
} else {
gameQuad.space = g_play_space;
gameQuad.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
gameQuad.subImage.swapchain = g_game_swapchain.swapchain;
gameQuad.subImage.imageRect.extent.width = g_game_swapchain.width;
gameQuad.subImage.imageRect.extent.height = g_game_swapchain.height;
gameQuad.pose.orientation.w = 1.0f;
gameQuad.pose.position.z = -gameDistance;
gameQuad.size.width = gameHalfWidth * 2.0f;
gameQuad.size.height = gameHalfHeight * 2.0f;
}
const XrCompositionLayerBaseHeader *layers[5];
uint32_t layerCount = 0;
if (g_have_acquired_game_image)
layers[layerCount++] = gameScreenCurved ? (XrCompositionLayerBaseHeader *)&gameCylinder
: (XrCompositionLayerBaseHeader *)&gameQuad;
XrCompositionLayerQuad menuQuad;
if (g_frame_should_render && xr_overlay_render_and_build_layer(g_menu_overlay, &menuQuad)) {
menuQuad.space = g_play_space;
menuQuad.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
layers[layerCount++] = (XrCompositionLayerBaseHeader *)&menuQuad;
}
XrCompositionLayerQuad keyboardQuad;
if (g_frame_should_render &&
xr_overlay_render_and_build_layer(g_keyboard_overlay, &keyboardQuad)) {
keyboardQuad.space = g_play_space;
keyboardQuad.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
// Lets the keyboard sit on screen translucently while playing
// rather than fully hiding whatever's behind it - KeyboardOverlay
// writes real sub-255 alpha into the swapchain texture (see
// OverlayPanel.compositeAndPublish()), already in Android's
// default premultiplied format, which is what this flag's absence
// of UNPREMULTIPLIED_ALPHA_BIT assumes. The menu launcher above
// deliberately doesn't get this flag - it stays fully opaque.
keyboardQuad.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layers[layerCount++] = (XrCompositionLayerBaseHeader *)&keyboardQuad;
}
// Submitted last (frontmost) so a beam doesn't z-fight against the
// panel surface it's aimed at/terminates on - see
// xr_input_get_beam_layer(). Translucent for the same reason the
// keyboard is (see comment above).
XrCompositionLayerQuad beamQuad[2];
for (int hand = 0; hand < 2; hand++) {
if (xr_input_get_beam_layer(hand, &beamQuad[hand])) {
beamQuad[hand].space = g_play_space;
beamQuad[hand].eyeVisibility = XR_EYE_VISIBILITY_BOTH;
beamQuad[hand].layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
layers[layerCount++] = (XrCompositionLayerBaseHeader *)&beamQuad[hand];
}
}
XrFrameEndInfo endInfo = {XR_TYPE_FRAME_END_INFO};
endInfo.displayTime = g_predicted_display_time;
endInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
endInfo.layerCount = layerCount;
endInfo.layers = layerCount > 0 ? layers : NULL;
xr_check(xrEndFrame(g_session, &endInfo), "xrEndFrame");
xr_session_update_frame_stats();
}
void xr_shutdown(void) {
xr_swapchain_destroy(&g_game_swapchain);
if (g_local_space != XR_NULL_HANDLE)
xrDestroySpace(g_local_space);
g_local_space = XR_NULL_HANDLE;
if (g_play_space != XR_NULL_HANDLE)
xrDestroySpace(g_play_space);
g_play_space = XR_NULL_HANDLE;
// Before the session/instance they were created from.
xr_input_shutdown();
xr_overlay_destroy(g_menu_overlay);
g_menu_overlay = NULL;
xr_overlay_destroy(g_keyboard_overlay);
g_keyboard_overlay = NULL;
if (g_session != XR_NULL_HANDLE)
xrDestroySession(g_session);
g_session = XR_NULL_HANDLE;
if (g_instance != XR_NULL_HANDLE)
xrDestroyInstance(g_instance);
g_instance = XR_NULL_HANDLE;
g_session_state = XR_SESSION_STATE_UNKNOWN;
g_session_running = false;
g_performance_metrics_supported = false;
g_xrSetPerformanceMetricsStateMETA = NULL;
g_xrQueryPerformanceMetricsCounterMETA = NULL;
g_cpu_utilization_path = XR_NULL_PATH;
g_gpu_utilization_path = XR_NULL_PATH;
g_cylinder_layer_supported = false;
// g_screen_width_m/g_screen_curve_deg/g_screen_distance_m deliberately
// NOT reset here - same reasoning as xr_session_set_player_transform()'s
// own state: it's meant to persist across a shutdown/reinit within the
// same process (e.g. an Android lifecycle pause/resume), not just
// within one XR session.
}
void xr_session_set_game_screen_shape(float width_m, float curve_deg, float distance_m) {
g_screen_width_m = width_m;
g_screen_curve_deg = curve_deg;
g_screen_distance_m = distance_m;
}
// Single source of truth for the game screen's current shape, read by
// both xr_frame_end() (to build/submit the actual layer) and
// xr_input_try_game_quad() (xr_input.c, to hit-test the laser pointer
// against it). half_width_m is meaningful only when *central_angle_rad is
// 0 (flat); a curved screen's horizontal extent is bounded by
// *central_angle_rad instead, with *half_height_m always the vertical
// bound either way.
void xr_get_game_quad_extent(float *distance_m, float *half_width_m, float *half_height_m,
float *radius_m, float *central_angle_rad) {
float curveDeg = g_cylinder_layer_supported ? g_screen_curve_deg : 0.0f;
float aspect = (float)g_game_swapchain.height / (float)g_game_swapchain.width;
*distance_m = g_screen_distance_m;
*half_width_m = g_screen_width_m * 0.5f;
*half_height_m = g_screen_width_m * 0.5f * aspect;
if (curveDeg > 0.0f) {
float theta = curveDeg * QS_DEG_TO_RAD;
*central_angle_rad = theta;
*radius_m = g_screen_width_m / theta;
} else {
*central_angle_rad = 0.0f;
*radius_m = 0.0f;
}
}
void xr_get_game_resolution(int *width, int *height) {
// Not g_game_swapchain.width/height: that's the fixed physical size of
// the swapchain image the game is composited into (see xr_init()) -
// android_draw_surface_as_quad() (OpenGL.cc, engine-patches/11) always
// stretch-blits drawSurface to fill that image regardless of
// drawSurface's own pixel size, so the swapchain's size has no relation
// to the coordinate space MouseX/MouseY actually live in. gScreenWide/
// gScreenHigh (InitMac.h) is drawSurface's current size - the
// resolution the in-game options menu can change at runtime
// (ShockBitmap.c's ChangeScreenSize()) independently of the swapchain,
// which is created once at launch and never resized. Using the fixed
// swapchain size here after such a change mapped the laser pointer's
// quad-space hit into the wrong coordinate space entirely, moving
// MouseX/MouseY out of the engine's actual screen bounds - which is
// what made the cursor disappear and become unclickable.
extern int32_t gScreenWide, gScreenHigh;
*width = gScreenWide;
*height = gScreenHigh;
}
+167
View File
@@ -0,0 +1,167 @@
// Minimal OpenXR bring-up for questshock's immersive Quest build. Keeps the
// game's own rendering untouched (see android/engine-patches/
// 11-android-openxr-present.patch) - this module only owns the OpenXR
// instance/session/swapchains and the final "submit quad layers instead of
// presenting to a window" step. No stereo rendering - the game composite is
// shown as a single flat quad floating in front of the viewer.
#ifndef QUESTSHOCK_XR_SESSION_H
#define QUESTSHOCK_XR_SESSION_H
#include <stdbool.h>
#include "xr_overlay.h"
#ifdef __cplusplus
extern "C" {
#endif
// Call once, right after init_opengl() (OpenGL.cc) has created and made
// current the GL context SDL/gl4es already use - creates the OpenXR
// instance/session sharing that same EGL display/context, plus the game
// quad's own swapchain, sized to the game's logical resolution
// (game_width/height, i.e. grd_cap->w/h - see Shock.c's InitSDL()). Also
// creates the menu launcher and keyboard overlay quads (see xr_overlay.h) -
// two independent XrOverlay instances, each with their own swapchain,
// visibility, and position, retrievable via xr_session_get_menu_overlay()/
// xr_session_get_keyboard_overlay() below. Returns false if OpenXR
// bring-up failed (e.g. no runtime installed) - callers should fall back
// to the existing window-present path in that case.
bool xr_init(int game_width, int game_height);
// The menu launcher (small "Keyboard" button panel, toggled by the
// controller's menu button) and keyboard (the on-screen key grid, shown/
// hidden independently via MenuOverlay's "Keyboard" button and
// KeyboardOverlay's own Close button) overlay quads - used by xr_input.c
// for ray/quad hit-testing and touch/cursor dispatch, and by
// questshock_native.c's JNI glue (nativeShowKeyboard()/
// nativeRequestClose()). NULL if xr_init() failed before creating them.
XrOverlay *xr_session_get_menu_overlay(void);
XrOverlay *xr_session_get_keyboard_overlay(void);
// Pumps XR session-state events. Call once per frame, before
// xr_frame_begin(). Must still be called even when xr_init() returned
// false (no-op in that case).
void xr_poll_events(void);
// True once the session has reached a state where frames are expected
// (XR_SESSION_STATE_SYNCHRONIZED or later) - i.e. it's safe/required to
// start calling xr_frame_begin()/xr_frame_end() each frame.
bool xr_is_session_running(void);
// Begins the XR frame (xrWaitFrame/xrBeginFrame) and, if the runtime wants
// this frame rendered, acquires the game quad's next swapchain image and
// binds its framebuffer as the current render target - ready for the
// caller to draw into exactly as it would have drawn to the default
// framebuffer. Returns true if the caller should draw this frame;
// xr_frame_end() must be called unconditionally afterward either way (a
// begun XR frame must always be ended, rendered or not).
bool xr_frame_begin(void);
// Releases the game quad's swapchain image (if one was acquired this
// frame), then does the same acquire/render/release cycle for the menu
// launcher and keyboard overlay quads via xr_overlay_render_and_build_layer()
// for whichever of them is currently visible, and submits whichever of the
// three quads actually rendered this frame as composition layers
// positioned in front of the play space's origin (see
// xr_session_set_player_transform() above), then ends the XR frame.
void xr_frame_end(void);
void xr_shutdown(void);
// Play-space geometry of the single game screen xr_frame_end() submits
// (distance in front of the play space origin, half-width/half-height,
// all in meters) - shared with xr_input.c's ray/quad hit-testing so the
// laser pointer always matches whatever's actually visible. *radius_m/
// *central_angle_rad are 0 when flat, in which case *half_width_m is the
// horizontal extent; otherwise the screen is a curved cylinder segment
// and the caller uses *central_angle_rad instead of *half_width_m for the
// horizontal bound (*half_height_m stays meaningful either way). Curving
// is currently unused - qs_config.c has no config surface for it - but
// kept working so it can be re-enabled later.
void xr_get_game_quad_extent(float *distance_m, float *half_width_m, float *half_height_m,
float *radius_m, float *central_angle_rad);
// Sets the game screen's current physical width (meters) and curve (wrap
// angle in degrees, 0 = flat) - a plain state setter, no XR calls, same
// category as xr_session_set_player_transform() above (safe to call
// before xr_init() has even run). Read by both xr_frame_end() (to build/
// submit the actual layer) and, via xr_get_game_quad_extent() above,
// xr_input.c's hit-testing. Driven by qs_config.c's
// qs_screen_profile_notify_loop_mode(), which decides which of the
// "Initial Screen"/"Game Screen" config profiles (see CONFIG.md) is
// currently active - this function itself has no notion of "profiles",
// only "what shape is current".
void xr_session_set_game_screen_shape(float width_m, float curve_deg, float distance_m);
// The engine's current screen resolution (gScreenWide/gScreenHigh,
// InitMac.h) - not the game quad's own swapchain size, which is fixed at
// launch and never changes - the logical coordinate space xr_input.c needs
// to convert a game-quad ray hit's normalized u,v into engine mouse
// coordinates (see xr_mouse.h). Can change at runtime via the in-game
// options menu (ShockBitmap.c's ChangeScreenSize()), independently of the
// swapchain.
void xr_get_game_resolution(int *width, int *height);
// Exponentially-smoothed frame rate/frame time, updated once per real
// rendered frame in xr_frame_end() - read by MenuOverlay's header (see
// questshock_native.c's nativeGetFps()/nativeGetFrameTimeMs()). 0 before
// the second frame has run (nothing to compute a delta from yet).
float xr_session_get_fps(void);
float xr_session_get_frame_ms(void);
// Device-wide CPU/GPU utilization percentage (0-100), via the
// XR_META_performance_metrics extension - same per-frame update cadence as
// the FPS/frame-time getters above. Returns -1.0f if the extension isn't
// supported by the runtime, or its cpu_utilization/gpu_utilization counter
// couldn't be found among the ones it advertises.
float xr_session_get_cpu_utilization(void);
float xr_session_get_gpu_utilization(void);
// The player's virtual position/orientation - horizontal-plane only (x/z
// plus a yaw rotation about the vertical axis); height always comes from
// the real tracked HMD pose, never from this. Everything the app submits
// (game/menu/keyboard/beam quads) and every hand/head pose it locates is
// expressed relative to a second reference space, derived from the real
// LOCAL space by this transform's inverse (see xr_session.c's own
// xr_session_rebuild_play_space()) - so changing it moves/turns the player
// relative to those otherwise-fixed quads, letting them walk up to and
// square up with the game quad ("virtual screen") without needing any
// physical room-scale space to do it in.
//
// xr_session_set_player_transform() only stores the three floats (no XR
// calls) - safe to call before xr_init() has even run, which is how
// qs_config_load_startup() seeds the saved position before the OpenXR
// session/spaces exist yet (xr_init() picks it up when it creates its own
// spaces); also used live by xr_input.c's thumbstick locomotion and
// "Reset Position" recenter (xr_input_recenter_player_to_screen()) and
// qs_config.c's "Load Configuration", and read back by "Save Configuration"
// via the getter.
void xr_session_set_player_transform(float x, float z, float yaw_deg);
void xr_session_get_player_transform(float *x, float *z, float *yaw_deg);
// The real, physical tracking-origin reference space - used only by
// xr_input_recenter_player_to_screen() (xr_input.c), which needs the
// player's CURRENT real head pose (not one already bent through the
// existing play-space transform - see xr_session_set_player_transform()'s
// own comment above) to compute a brand new one. Every other consumer in
// this app (rendering, hit-testing) uses the play space instead - see
// xr_session_rebuild_play_space()'s own comment for why this one stays a
// separate, never-swapped-out space.
XrSpace xr_session_get_local_space(void);
// The most recent xrWaitFrame-predicted display time (xr_frame_begin()'s
// own g_predicted_display_time) - for the same reason as
// xr_session_get_local_space() above, xr_input_recenter_player_to_screen()
// needs a valid XrTime to locate a space with but isn't itself called from
// the normal per-frame xr_frame_end()/xr_input_sync_and_draw() call chain
// that already threads one through (it's triggered by a button press,
// dispatched via qs_config.c's cross-thread event queue instead). A frame
// or so of staleness doesn't matter for a one-shot recenter. 0 before the
// first frame has ever begun.
XrTime xr_session_get_predicted_display_time(void);
#ifdef __cplusplus
}
#endif
#endif
+160
View File
@@ -0,0 +1,160 @@
#include "xr_swapchain.h"
#include <dlfcn.h>
#include <android/log.h>
#define TAG "QuestShock"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
static bool xr_check(XrInstance instance, XrResult result, const char *what) {
if (XR_SUCCEEDED(result))
return true;
char resultString[XR_MAX_RESULT_STRING_SIZE] = {0};
if (instance != XR_NULL_HANDLE)
xrResultToString(instance, result, resultString);
LOGE("XR: %s failed: %s (%d)", what, resultString[0] ? resultString : "?", (int)result);
return false;
}
// This file's other GL calls otherwise resolve to gl4es (the only GL
// symbol provider linked into this binary - see android/engine-patches/
// 02-android-opengl-es.patch), which is fine for anything shared with the
// engine's own gl4es-routed rendering. But the swapchain images OpenXR
// hands us are real driver texture objects gl4es never created itself,
// and gl4es's own glFramebufferTexture2D can't attach a texture it has no
// tracked metadata for. So the FBO *container* is created via gl4es's own
// glGenFramebuffers/glBindFramebuffer (so gl4es recognizes the id as its
// own and its own per-frame glBindFramebuffer succeeds), while the
// texture-attach step - the specifically foreign part - goes through the
// real driver directly, via dlsym against libGLESv2.so.
typedef void (*PFNQSFRAMEBUFFERTEXTURE2D)(GLenum, GLenum, GLenum, GLuint, GLint);
typedef GLenum (*PFNQSCHECKFRAMEBUFFERSTATUS)(GLenum);
static PFNQSFRAMEBUFFERTEXTURE2D real_glFramebufferTexture2D;
static PFNQSCHECKFRAMEBUFFERSTATUS real_glCheckFramebufferStatus;
static bool g_real_gles_loaded = false;
static bool xr_swapchain_load_real_gles(void) {
if (g_real_gles_loaded)
return true;
void *lib = dlopen("libGLESv2.so", RTLD_NOW | RTLD_LOCAL);
if (lib == NULL) {
LOGE("XR: swapchain dlopen(libGLESv2.so) failed: %s", dlerror());
return false;
}
real_glFramebufferTexture2D = (PFNQSFRAMEBUFFERTEXTURE2D)dlsym(lib, "glFramebufferTexture2D");
real_glCheckFramebufferStatus =
(PFNQSCHECKFRAMEBUFFERSTATUS)dlsym(lib, "glCheckFramebufferStatus");
g_real_gles_loaded = real_glFramebufferTexture2D && real_glCheckFramebufferStatus;
return g_real_gles_loaded;
}
bool xr_swapchain_create(XrInstance instance, XrSession session, int64_t format, int width,
int height, XrSwapchainState *out) {
if (!xr_swapchain_load_real_gles()) {
LOGE("XR: swapchain couldn't resolve real GLES FBO functions via dlsym");
return false;
}
out->width = width;
out->height = height;
XrSwapchainCreateInfo swapchainInfo = {XR_TYPE_SWAPCHAIN_CREATE_INFO};
swapchainInfo.usageFlags =
XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_SAMPLED_BIT;
swapchainInfo.format = format;
swapchainInfo.sampleCount = 1;
swapchainInfo.width = (uint32_t)width;
swapchainInfo.height = (uint32_t)height;
swapchainInfo.faceCount = 1;
swapchainInfo.arraySize = 1;
swapchainInfo.mipCount = 1;
if (!xr_check(instance, xrCreateSwapchain(session, &swapchainInfo, &out->swapchain),
"xrCreateSwapchain"))
return false;
uint32_t imageCount = 0;
xrEnumerateSwapchainImages(out->swapchain, 0, &imageCount, NULL);
if (imageCount > XR_SWAPCHAIN_MAX_IMAGES) {
LOGE("XR: swapchain reports %u images, only room for %d", imageCount,
XR_SWAPCHAIN_MAX_IMAGES);
return false;
}
// Zero-initialized, not just `.type` set per element - these structs
// also carry a `next` field the runtime may read, and an uninitialized
// stack array would leave it as garbage.
XrSwapchainImageOpenGLESKHR images[XR_SWAPCHAIN_MAX_IMAGES] = {0};
for (uint32_t i = 0; i < imageCount; i++)
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
if (!xr_check(instance,
xrEnumerateSwapchainImages(out->swapchain, imageCount, &imageCount,
(XrSwapchainImageBaseHeader *)images),
"xrEnumerateSwapchainImages"))
return false;
out->image_count = imageCount;
// Wraps each swapchain-provided texture in its own framebuffer, matching
// how OpenGL.cc's own CreateFrameBuffer() wraps backupBuffer - just
// without a depth/stencil attachment, since the final composite draw
// (see opengl_swap_and_restore) never needs one. The Gen/Bind calls are
// gl4es's own (linked, not dlsym'd) - see the comment above
// real_glFramebufferTexture2D for why.
bool all_complete = true;
for (uint32_t i = 0; i < imageCount; i++) {
glGenFramebuffers(1, &out->fbos[i]);
glBindFramebuffer(GL_FRAMEBUFFER, out->fbos[i]);
real_glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
images[i].image, 0);
GLenum status = real_glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
LOGE("XR: swapchain FBO %u incomplete: 0x%x", i, status);
all_complete = false;
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return all_complete;
}
void xr_swapchain_destroy(XrSwapchainState *state) {
for (uint32_t i = 0; i < state->image_count; i++) {
if (state->fbos[i] != 0)
glDeleteFramebuffers(1, &state->fbos[i]);
}
state->image_count = 0;
if (state->swapchain != XR_NULL_HANDLE)
xrDestroySwapchain(state->swapchain);
state->swapchain = XR_NULL_HANDLE;
}
// Acquires the next image of the given swapchain, waits for the runtime to
// finish with it, and binds its framebuffer (sized to exactly fill it) as
// the current render target.
bool xr_swapchain_acquire(XrInstance instance, XrSwapchainState *state) {
uint32_t imageIndex = 0;
XrSwapchainImageAcquireInfo acquireInfo = {XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO};
if (!xr_check(instance, xrAcquireSwapchainImage(state->swapchain, &acquireInfo, &imageIndex),
"xrAcquireSwapchainImage"))
return false;
XrSwapchainImageWaitInfo waitImageInfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO};
waitImageInfo.timeout = XR_INFINITE_DURATION;
if (!xr_check(instance, xrWaitSwapchainImage(state->swapchain, &waitImageInfo),
"xrWaitSwapchainImage"))
return false;
// gl4es's own (linked, not dlsym'd) bind - this targets an FBO id gl4es
// itself created (see xr_swapchain_create()), so its own "current FBO"
// bookkeeping updates correctly and its immediate-mode draw calls
// (android_draw_surface_as_quad()) land in the right place.
glBindFramebuffer(GL_FRAMEBUFFER, state->fbos[imageIndex]);
glViewport(0, 0, state->width, state->height);
return true;
}
void xr_swapchain_release(XrInstance instance, XrSwapchainState *state) {
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO};
xr_check(instance, xrReleaseSwapchainImage(state->swapchain, &releaseInfo),
"xrReleaseSwapchainImage");
}
+55
View File
@@ -0,0 +1,55 @@
// Generic OpenXR swapchain + per-image GL framebuffer helper, shared by
// every quad this app submits - the game quad (xr_session.c) and every
// xr_overlay.c instance (menu launcher, keyboard) - since they all need
// exactly the same setup, just at their own size/format.
#ifndef QUESTSHOCK_XR_SWAPCHAIN_H
#define QUESTSHOCK_XR_SWAPCHAIN_H
#include <stdbool.h>
#include <stdint.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#define XR_USE_PLATFORM_ANDROID 1
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
// Up to this many swapchain images/FBOs - real runtimes report small counts
// (2-4); this is just a fixed upper bound for the cache arrays below.
#define XR_SWAPCHAIN_MAX_IMAGES 8
typedef struct {
XrSwapchain swapchain;
GLuint fbos[XR_SWAPCHAIN_MAX_IMAGES];
uint32_t image_count;
int width;
int height;
} XrSwapchainState;
// Creates the swapchain and wraps each of its images in its own GL
// framebuffer, ready to bind and render into directly. instance is only
// used to log a human-readable error string on failure.
bool xr_swapchain_create(XrInstance instance, XrSession session, int64_t format, int width,
int height, XrSwapchainState *out);
void xr_swapchain_destroy(XrSwapchainState *state);
// Acquires the next image, waits for the runtime to finish with it, and
// binds its framebuffer (sized to exactly fill it) as the current render
// target.
bool xr_swapchain_acquire(XrInstance instance, XrSwapchainState *state);
void xr_swapchain_release(XrInstance instance, XrSwapchainState *state);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,586 @@
package de.ladkau.questshock;
import android.app.Activity;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import org.libsdl.app.SDLActivity;
/**
* The on-screen keyboard quad (see OverlayPanel for the shared off-screen-
* render/touch/cursor plumbing this builds on) - a hand-built, full
* US-layout key grid (there's no system IME to borrow once immersive) plus
* a text field echoing what's been sent. Every key that reaches the game
* (everything but Close/Shift/Ctrl/Alt, which are local UI actions - see
* handleKeyDown()/handleKeyUp() and handleCharKeyDown()/handleCharKeyUp())
* is driven by that key button's own ACTION_DOWN/ACTION_UP (see
* charKeyTouchListener()/controlKeyTouchListener()), which
* OverlayPanel.handleTouch() dispatches for exactly as long as the
* controller's trigger is physically held while aimed at it - so a key
* held on this keyboard behaves like a real key held on a physical one,
* not an instant tap. Non-printable keys go through an
* SDLActivity.onNativeKeyDown()/onNativeKeyUp() pair, the same one a
* physical Bluetooth keyboard's presses already drive; printable keys go
* through a synthesized SDL_TEXTINPUT/SDL_KEYUP pair pushed from native
* code (see nativeSendPrintableCharDown()/Up() in questshock_native.c) -
* except while a Ctrl/Alt "armed" modifier is active, when they go through
* the same onNativeKeyDown()/onNativeKeyUp() path instead, so the modifier
* carries across (see toggleModifier()). Shift is a purely local layer
* toggle (uppercase/symbols vs lowercase/numbers), never itself sent to the
* game.
*
* This is a fully independent overlay quad from MenuOverlay's small
* launcher - opened via that launcher's "Keyboard" button
* (nativeShowKeyboard()) but otherwise self-contained: once open, the
* controller's menu button (which only ever affects the menu launcher, see
* xr_input.c) doesn't hide it, so it stays up as a standing input panel
* while actually playing rather than a modal you open and close. The only
* way to hide it is its own title bar's Close button (buildTitleBar()),
* which also doubles as a drag handle for repositioning it (handled
* entirely on the native side - see xr_input.c - since it never reaches
* this class's own touch dispatch). contentAlpha() renders the whole panel
* semi-transparent so whatever's behind it stays visible while it's up.
*/
public class KeyboardOverlay extends OverlayPanel {
// Matches xr_session.c's KEYBOARD_WIDTH/KEYBOARD_HEIGHT swapchain size -
// fixed, not tied to any real display metric, since this tree is never
// shown in a real window.
private static final int WIDTH = 1024;
private static final int HEIGHT = 768;
private static final int TYPED_TEXT_HEIGHT = 100;
// Height of the title bar (buildTitleBar()) and width of its Close
// button - xr_input.c's KEYBOARD_TITLE_BAR_V_FRACTION/
// KEYBOARD_CLOSE_BUTTON_U_FRACTION must be kept in sync with these (as
// fractions of WIDTH/HEIGHT above), since the drag-handle-vs-Close-
// button-vs-rest-of-the-keyboard decision happens entirely on the
// native side, before a hit ever reaches this class's own touch
// dispatch.
private static final int TITLE_BAR_HEIGHT = 90;
private static final int CLOSE_BUTTON_WIDTH = 160;
// ~70% opaque - readable but lets whatever's behind the panel (the game
// quad, or empty space) show through while it's left up during play.
private static final int PANEL_ALPHA = 180;
private static KeyboardOverlay instance;
private TextView typedTextView;
private final StringBuilder typedText = new StringBuilder();
// Title bar chrome text - the only pieces of this panel that get
// translated (see Strings.java's own comment on why the actual key
// labels don't). Set from MenuOverlay.nativeGetLanguage() at the top of
// buildContent() (see OverlayPanel's constructor note on why a field a
// subclass's buildContent() depends on can't rely on normal field-
// initializer timing) and kept in sync afterward by applyTranslations()
// below, called from MenuOverlay's own periodic language-refresh check.
private int currentLanguage = Strings.ENGLISH;
private TextView titleLabel;
private Button closeButton;
// Shift is a local-only layer toggle (never itself sent to the game -
// see updateShiftVisual()); Ctrl/Alt are one-shot "armed" modifiers,
// sent to the game the moment they're pressed and released again as
// soon as the next key consumes them (see toggleModifier()/
// releaseArmedModifiers()) - there's no press-and-hold gesture with a
// laser pointer + trigger click, so armed-then-consumed stands in for
// holding the key down.
private boolean shiftActive = false;
private boolean ctrlArmed = false;
private boolean altArmed = false;
private Button shiftButton;
private Button ctrlButton;
private Button altButton;
// Every CharKey created by addRow(), so updateShiftVisual() can relabel
// all of them at once when Shift toggles. Assigned (not a field
// initializer) at the top of buildContent() - see OverlayPanel's
// constructor note on why a field a subclass's buildContent() depends
// on can't rely on normal field-initializer timing.
private List<CharKey> charKeys;
// A key whose printed character (and, while unmodified, whose game
// input) depends on the Shift layer - covers letters, digits, and
// punctuation uniformly (e.g. 'q'/'Q', '1'/'!', '-'/'_'). androidKeyCode
// is only used for the Ctrl/Alt-combo path (see handleCharKeyDown()) -
// the unmodified path goes through nativeSendPrintableCharDown()/Up()
// instead, which doesn't need an Android keycode at all.
private static final class CharKey {
final char base;
final char shifted;
final int androidKeyCode;
Button button;
CharKey(char base, char shifted, int androidKeyCode) {
this.base = base;
this.shifted = shifted;
this.androidKeyCode = androidKeyCode;
}
}
private static CharKey charKey(char base, char shifted, int androidKeyCode) {
return new CharKey(base, shifted, androidKeyCode);
}
// Space is a CharKey like any other (see addRow()), but a literal
// space character makes for an unreadable, blank-looking button - keep
// showing the word "Space" instead, same as before it became a CharKey.
private static String charKeyLabel(CharKey key, boolean shiftActive) {
if (key.base == ' ') {
return "Space";
}
return String.valueOf(shiftActive ? key.shifted : key.base);
}
private KeyboardOverlay(Activity activity) {
super(activity, WIDTH, HEIGHT);
}
@Override
protected int contentAlpha() {
return PANEL_ALPHA;
}
@Override
protected View buildContent() {
charKeys = new ArrayList<>();
currentLanguage = MenuOverlay.nativeGetLanguage();
LinearLayout panel = new LinearLayout(activity);
panel.setOrientation(LinearLayout.VERTICAL);
panel.setBackgroundColor(0xFF202020);
panel.addView(buildTitleBar(),
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, TITLE_BAR_HEIGHT));
typedTextView = new TextView(activity);
typedTextView.setTextColor(0xFFFFFFFF);
typedTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 28);
typedTextView.setBackgroundColor(0xFF303030);
typedTextView.setPadding(20, 20, 20, 20);
panel.addView(typedTextView, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, TYPED_TEXT_HEIGHT));
// Rows follow real keyboard geometry where it helps (Tab starting
// the QWERTY row, Enter ending the home row, Shift starting the
// bottom-letter row, a compact arrow cluster bottom-right) so the
// layout reads as a familiar keyboard rather than an arbitrary grid.
addRow(panel, "Esc", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10",
"F11", "F12", "Back");
addRow(panel,
charKey('`', '~', KeyEvent.KEYCODE_GRAVE),
charKey('1', '!', KeyEvent.KEYCODE_1),
charKey('2', '@', KeyEvent.KEYCODE_2),
charKey('3', '#', KeyEvent.KEYCODE_3),
charKey('4', '$', KeyEvent.KEYCODE_4),
charKey('5', '%', KeyEvent.KEYCODE_5),
charKey('6', '^', KeyEvent.KEYCODE_6),
charKey('7', '&', KeyEvent.KEYCODE_7),
charKey('8', '*', KeyEvent.KEYCODE_8),
charKey('9', '(', KeyEvent.KEYCODE_9),
charKey('0', ')', KeyEvent.KEYCODE_0),
charKey('-', '_', KeyEvent.KEYCODE_MINUS),
charKey('=', '+', KeyEvent.KEYCODE_EQUALS));
addRow(panel, "Tab",
charKey('q', 'Q', KeyEvent.KEYCODE_Q), charKey('w', 'W', KeyEvent.KEYCODE_W),
charKey('e', 'E', KeyEvent.KEYCODE_E), charKey('r', 'R', KeyEvent.KEYCODE_R),
charKey('t', 'T', KeyEvent.KEYCODE_T), charKey('y', 'Y', KeyEvent.KEYCODE_Y),
charKey('u', 'U', KeyEvent.KEYCODE_U), charKey('i', 'I', KeyEvent.KEYCODE_I),
charKey('o', 'O', KeyEvent.KEYCODE_O), charKey('p', 'P', KeyEvent.KEYCODE_P),
charKey('[', '{', KeyEvent.KEYCODE_LEFT_BRACKET),
charKey(']', '}', KeyEvent.KEYCODE_RIGHT_BRACKET),
charKey('\\', '|', KeyEvent.KEYCODE_BACKSLASH));
addRow(panel, "Ctrl",
charKey('a', 'A', KeyEvent.KEYCODE_A), charKey('s', 'S', KeyEvent.KEYCODE_S),
charKey('d', 'D', KeyEvent.KEYCODE_D), charKey('f', 'F', KeyEvent.KEYCODE_F),
charKey('g', 'G', KeyEvent.KEYCODE_G), charKey('h', 'H', KeyEvent.KEYCODE_H),
charKey('j', 'J', KeyEvent.KEYCODE_J), charKey('k', 'K', KeyEvent.KEYCODE_K),
charKey('l', 'L', KeyEvent.KEYCODE_L),
charKey(';', ':', KeyEvent.KEYCODE_SEMICOLON),
charKey('\'', '"', KeyEvent.KEYCODE_APOSTROPHE),
"Enter");
addRow(panel, "Shift",
charKey('z', 'Z', KeyEvent.KEYCODE_Z), charKey('x', 'X', KeyEvent.KEYCODE_X),
charKey('c', 'C', KeyEvent.KEYCODE_C), charKey('v', 'V', KeyEvent.KEYCODE_V),
charKey('b', 'B', KeyEvent.KEYCODE_B), charKey('n', 'N', KeyEvent.KEYCODE_N),
charKey('m', 'M', KeyEvent.KEYCODE_M),
charKey(',', '<', KeyEvent.KEYCODE_COMMA),
charKey('.', '>', KeyEvent.KEYCODE_PERIOD),
charKey('/', '?', KeyEvent.KEYCODE_SLASH),
"Up");
addRow(panel, "Alt", charKey(' ', ' ', KeyEvent.KEYCODE_SPACE), "Left", "Down", "Right");
return panel;
}
// The title bar: a decorative "drag here" label (not itself
// interactive - see the class doc, dragging is handled entirely by
// xr_input.c before a hit ever reaches here) plus a real Close button,
// which is dispatched as an ordinary click like any other key. Its
// height and the Close button's width must stay in sync with
// xr_input.c's KEYBOARD_TITLE_BAR_V_FRACTION/
// KEYBOARD_CLOSE_BUTTON_U_FRACTION.
private LinearLayout buildTitleBar() {
LinearLayout bar = new LinearLayout(activity);
bar.setOrientation(LinearLayout.HORIZONTAL);
// Matches MenuOverlay's own header bar style.
bar.setBackgroundColor(0xFF000080);
titleLabel = new TextView(activity);
titleLabel.setText(Strings.get("keyboard_drag_title", currentLanguage));
titleLabel.setTextColor(0xFFFFFFFF);
titleLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
titleLabel.setGravity(Gravity.CENTER_VERTICAL);
titleLabel.setPadding(24, 0, 0, 0);
bar.addView(titleLabel, new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
closeButton = new Button(activity);
closeButton.setText(Strings.get("close", currentLanguage));
closeButton.setOnClickListener(v -> nativeRequestClose());
closeButton.setOnTouchListener(CLICK_ON_TOUCH_UP);
closeButton.setBackground(buttonBackground());
closeButton.setTextColor(buttonTextColors());
registerHoverable(closeButton);
bar.addView(closeButton,
new LinearLayout.LayoutParams(CLOSE_BUTTON_WIDTH, ViewGroup.LayoutParams.MATCH_PARENT));
return bar;
}
// Each row fills the panel's remaining height evenly (weight 1 on the
// row itself). Accepts a mix of String (a fixed-action control key,
// handled by handleKeyDown()/handleKeyUp()) and CharKey (a
// Shift-sensitive character key, handled by handleCharKeyDown()/
// handleCharKeyUp()) per item, so a row can match real keyboard
// geometry (e.g. "Tab" followed by a run of CharKeys).
// Within a row, CharKeys and most control keys share width equally
// except Space (wider, like a real keyboard) and Esc/Back/Enter/Tab/
// Shift/Ctrl/Alt (narrower, see keyWeight()).
private void addRow(LinearLayout panel, Object... items) {
LinearLayout row = new LinearLayout(activity);
row.setOrientation(LinearLayout.HORIZONTAL);
for (Object item : items) {
Button key = new Button(activity);
key.setBackground(buttonBackground());
key.setTextColor(buttonTextColors());
registerHoverable(key);
float weight;
if (item instanceof CharKey) {
CharKey charKey = (CharKey) item;
charKey.button = key;
key.setText(charKeyLabel(charKey, shiftActive));
key.setOnTouchListener(charKeyTouchListener(charKey));
charKeys.add(charKey);
// Space is a CharKey too (base == shifted == ' '), but keeps
// its traditional wide key like the other control keys do.
weight = (charKey.base == ' ') ? 4f : 1f;
} else {
String label = (String) item;
key.setText(label);
weight = keyWeight(label);
// Shift/Ctrl/Alt are local UI toggles with their own
// instantaneous press/release semantics (see
// toggleModifier()), not a value forwarded to the game for
// as long as the key is held - a plain click is enough.
// Every other control key reaches the game and needs real
// hold-duration semantics (see controlKeyTouchListener()).
if (label.equals("Shift") || label.equals("Ctrl") || label.equals("Alt")) {
key.setOnClickListener(v -> handleToggleKey(label));
key.setOnTouchListener(CLICK_ON_TOUCH_UP);
} else {
key.setOnTouchListener(controlKeyTouchListener(label));
}
if (label.equals("Shift")) {
shiftButton = key;
} else if (label.equals("Ctrl")) {
ctrlButton = key;
} else if (label.equals("Alt")) {
altButton = key;
}
}
row.addView(key, new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.MATCH_PARENT, weight));
}
panel.addView(row, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f));
}
// Drives a control key (everything controlKeyCode() maps, i.e. every
// key in addRow() except CharKeys and the Shift/Ctrl/Alt toggles) from
// its button's own touch lifecycle, so it reaches the game for exactly
// as long as the controller's trigger is held on it (see the class
// doc). ACTION_CANCEL (the ray straying off the button, or another
// overlay claiming it - see xr_input.c) releases the key the same as
// ACTION_UP, so a key can never be left stuck down.
private View.OnTouchListener controlKeyTouchListener(String label) {
return (v, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
handleKeyDown(label);
break;
case MotionEvent.ACTION_UP:
v.setPressed(false);
handleKeyUp(label);
break;
case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
handleKeyUp(label);
break;
}
return true;
};
}
// Same as controlKeyTouchListener() above, for a CharKey.
private View.OnTouchListener charKeyTouchListener(CharKey key) {
return (v, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
handleCharKeyDown(key);
break;
case MotionEvent.ACTION_UP:
v.setPressed(false);
handleCharKeyUp(key);
break;
case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
handleCharKeyUp(key);
break;
}
return true;
};
}
private static float keyWeight(String label) {
if (label.equals("Back") || label.equals("Esc") || label.equals("Enter")
|| label.equals("Tab") || label.equals("Shift") || label.equals("Ctrl")
|| label.equals("Alt")) {
return 1.5f;
}
return 1f;
}
// Maps a control key's label to the Android keycode forwarded via
// SDLActivity.onNativeKeyDown()/onNativeKeyUp() - the same pair a
// physical Bluetooth keyboard's key events already drive (see
// SDLActivity.handleKeyEvent()). F-keys are contiguous in
// android.view.KeyEvent (KEYCODE_F1..KEYCODE_F12), so "F1".."F12" are
// computed rather than listed individually.
private static int controlKeyCode(String label) {
switch (label) {
case "Back": return KeyEvent.KEYCODE_DEL;
case "Esc": return KeyEvent.KEYCODE_ESCAPE;
case "Enter": return KeyEvent.KEYCODE_ENTER;
case "Tab": return KeyEvent.KEYCODE_TAB;
case "Up": return KeyEvent.KEYCODE_DPAD_UP;
case "Down": return KeyEvent.KEYCODE_DPAD_DOWN;
case "Left": return KeyEvent.KEYCODE_DPAD_LEFT;
case "Right": return KeyEvent.KEYCODE_DPAD_RIGHT;
default:
if (label.charAt(0) == 'F') {
int n = Integer.parseInt(label.substring(1));
return KeyEvent.KEYCODE_F1 + (n - 1);
}
throw new IllegalArgumentException("no keycode for " + label);
}
}
// Shift is a local layer toggle; Ctrl/Alt are one-shot armed modifiers
// (see toggleModifier()) - neither is forwarded to the game as a key of
// its own, so a plain click (rather than the hold-duration dispatch
// every other key below uses) is enough.
private void handleToggleKey(String label) {
if (label.equals("Shift")) {
shiftActive = !shiftActive;
updateShiftVisual();
return;
}
toggleModifier(label);
}
// Everything controlKeyCode() maps (Back/Esc/Enter/Tab/arrows/F1-F12)
// is non-printable, so it's forwarded as a real Android key event via
// that code - down on this key's own ACTION_DOWN, up on ACTION_UP/
// CANCEL (see controlKeyTouchListener()), the same down/up split a
// physical Bluetooth keyboard's own key events already carry. This all
// matters beyond just the visible typedTextView below: the engine's
// cutscene skip handler (cutsloop.c's cutscene_key_handler()) only
// reacts to Esc/Enter/Space, so those need to reach the game as actual
// game input, not just be echoed locally.
private void handleKeyDown(String label) {
int keyCode = controlKeyCode(label);
SDLActivity.onNativeKeyDown(keyCode);
if (label.equals("Back")) {
if (typedText.length() > 0) {
typedText.setLength(typedText.length() - 1);
}
} else {
typedText.append('[').append(label).append(']');
}
typedTextView.setText(typedText.toString());
}
private void handleKeyUp(String label) {
SDLActivity.onNativeKeyUp(controlKeyCode(label));
releaseArmedModifiers();
}
// A CharKey's printed character depends only on the Shift layer
// (updateShiftVisual() keeps its button's label in sync). Which game
// input it produces depends on whether a modifier is armed: unmodified,
// it goes through nativeSendPrintableCharDown()/Up() below like a
// normal typed character; with Ctrl/Alt armed, it instead goes through
// the same onNativeKeyDown()/onNativeKeyUp() path handleKeyDown()/
// handleKeyUp() use for control keys, since that's the only path that
// carries ev.key.keysym.mod through to the engine (sdl_events.c's
// pump_events() reads Ctrl/Alt only off that path, never off
// SDL_TEXTINPUT).
private void handleCharKeyDown(CharKey key) {
char c = shiftActive ? key.shifted : key.base;
if (ctrlArmed || altArmed) {
SDLActivity.onNativeKeyDown(key.androidKeyCode);
} else {
nativeSendPrintableCharDown(c);
}
typedText.append(c);
typedTextView.setText(typedText.toString());
}
private void handleCharKeyUp(CharKey key) {
char c = shiftActive ? key.shifted : key.base;
if (ctrlArmed || altArmed) {
SDLActivity.onNativeKeyUp(key.androidKeyCode);
releaseArmedModifiers();
} else {
nativeSendPrintableCharUp(c);
}
}
// Ctrl/Alt are "armed" rather than held: pressing one immediately sends
// its keydown (so SDL's own modifier tracking picks it up for whatever
// key comes next - see handleCharKeyDown()/handleKeyDown()) and
// brackets its label for feedback; pressing the same key again before
// it's been used cancels it (sends the matching keyup, un-brackets).
// The normal case - actually being consumed by the next key press - is
// handled by releaseArmedModifiers() below, not here.
private void toggleModifier(String label) {
boolean ctrl = label.equals("Ctrl");
Button button = ctrl ? ctrlButton : altButton;
int keyCode = ctrl ? KeyEvent.KEYCODE_CTRL_LEFT : KeyEvent.KEYCODE_ALT_LEFT;
boolean nowArmed = ctrl ? !ctrlArmed : !altArmed;
if (ctrl) {
ctrlArmed = nowArmed;
} else {
altArmed = nowArmed;
}
if (nowArmed) {
SDLActivity.onNativeKeyDown(keyCode);
} else {
SDLActivity.onNativeKeyUp(keyCode);
}
button.setText(nowArmed ? "[" + label + "]" : label);
}
// Called after any key actually reaches the game (a control key's
// handleKeyUp(), or a CharKey's handleCharKeyUp()) so an armed Ctrl/Alt
// only ever applies to the very next key, then releases - matching a
// real Ctrl/Alt+key combo's keyup once the combo is done.
private void releaseArmedModifiers() {
if (ctrlArmed) {
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_CTRL_LEFT);
ctrlArmed = false;
ctrlButton.setText("Ctrl");
}
if (altArmed) {
SDLActivity.onNativeKeyUp(KeyEvent.KEYCODE_ALT_LEFT);
altArmed = false;
altButton.setText("Alt");
}
}
// Shift never itself reaches the game (see class doc) - it only flips
// which character each CharKey shows/sends, including its own label.
// Note this means a Ctrl+Shift+key chord won't carry Shift to the
// engine (Ctrl/Alt are real forwarded modifier keys, Shift here isn't) -
// not worth solving unless it actually comes up.
private void updateShiftVisual() {
shiftButton.setText(shiftActive ? "[Shift]" : "Shift");
for (CharKey key : charKeys) {
key.button.setText(charKeyLabel(key, shiftActive));
}
}
// Synthesizes the SDL_TEXTINPUT/SDL_KEYUP pair pump_events()
// (sdl_events.c) requires for printable characters (see
// handleCharKeyDown()/handleCharKeyUp() above), by building and
// pushing them directly in native code rather than through Android's
// IME (there's no real IME session behind this off-screen,
// never-attached grid for that plumbing to hook into).
private static native void nativeSendPrintableCharDown(char c);
private static native void nativeSendPrintableCharUp(char c);
// Hides this overlay's quad (xr_overlay_set_visible(..., false)) - the
// only way to do so, since the controller's menu button doesn't affect
// the keyboard (see this class's doc comment and xr_input.c).
private static native void nativeRequestClose();
// Called from MenuOverlay's own periodic header-refresh timer when it
// detects the game's language preference changed mid-session (via its
// own options menu) - re-labels this panel's title bar chrome to match.
// A plain Java call (both classes are in this same package), not JNI -
// runOnUiThread() here is defensive/self-documenting more than
// strictly needed today, since MenuOverlay's own timer already runs on
// the UI thread itself (Activity.runOnUiThread() is a no-op wrapper
// when already on that thread).
public static void applyTranslations(final int language) {
if (instance == null) {
return;
}
instance.activity.runOnUiThread(() -> {
instance.currentLanguage = language;
instance.titleLabel.setText(Strings.get("keyboard_drag_title", language));
instance.closeButton.setText(Strings.get("close", language));
instance.redrawContent();
});
}
// Called from xr_overlay.c's xr_overlay_init_jni(), on the render
// thread, right after it resolves this class via the activity's own
// ClassLoader (plain FindClass() can't see app classes from a thread
// that was attached to the JVM rather than spawned from Java).
public static void nativeInit(Activity activity) {
if (instance == null) {
instance = new KeyboardOverlay(activity);
}
}
public static byte[] nativeTakePixelsIfDirty() {
return instance == null ? null : instance.takePixelsIfDirty();
}
public static void nativeDispatchTouch(final float u, final float v, final boolean down) {
if (instance != null) {
instance.dispatchTouch(u, v, down);
}
}
public static void nativeUpdateCursor(final float u, final float v, final boolean visible) {
if (instance != null) {
instance.dispatchUpdateCursor(u, v, visible);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,378 @@
package de.ladkau.questshock;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* Shared machinery for an off-screen, never-attached-to-a-window View tree
* rendered into its own OpenXR quad (see android/app/src/main/cpp/
* xr_overlay.c, which owns the quad's swapchain and drives whichever
* concrete subclass via JNI - construction, touch input, and pixel
* readback). Rendering to a Bitmap and dispatching synthetic MotionEvents
* into an unattached hierarchy both work the same way they would for an
* attached View - draw(Canvas)/dispatchTouchEvent() don't require a
* ViewRootImpl/window, just a measured+laid-out tree.
*
* Subclasses (MenuOverlay, KeyboardOverlay) provide their own content via
* buildContent() and, if they want translucency, contentAlpha() - and, since
* Java has no static virtual dispatch and each overlay needs its own
* singleton, each subclass still declares its own thin nativeInit()/
* nativeTakePixelsIfDirty()/nativeDispatchTouch()/nativeUpdateCursor()
* static methods (matching what xr_overlay.c's JNI glue resolves by class
* name) that just delegate into the instance methods here
* (takePixelsIfDirty()/dispatchTouch()/dispatchUpdateCursor()).
*/
abstract class OverlayPanel {
private static final float CURSOR_RADIUS = 10f;
// Button's own click handling (View.onTouchEvent()'s ACTION_UP case)
// calls View.post(mPerformClick) rather than invoking performClick()
// directly; post() queues the runnable to run once the view is attached
// to a window and returns true immediately even when unattached, so on
// this permanently-unattached tree that queued click silently never
// fires - dispatchTouchEvent() still delivers the down/up events
// correctly, only the click callback is swallowed. Registering this as
// each button's OnTouchListener bypasses that path entirely: returning
// true here skips View's internal onTouchEvent() (see
// ViewGroup/View#dispatchTouchEvent), so performClick() (which still
// runs any OnClickListener set via setOnClickListener()) is called
// directly instead.
protected static final View.OnTouchListener CLICK_ON_TOUCH_UP = (v, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
break;
case MotionEvent.ACTION_UP:
v.setPressed(false);
v.performClick();
break;
case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
break;
}
return true;
};
// A plain, instantly-drawn StateListDrawable rather than the platform
// default Button background (a Material ripple): ripples animate via
// continuous invalidation callbacks tied to a real attached window's
// vsync, which never fires here (this tree is never attached to a
// window) - so setPressed()/setHovered() state changes would otherwise
// produce no visible change at all, independent of this project's own
// touch handling (which already calls setPressed() correctly - see
// CLICK_ON_TOUCH_UP above). Every button this project creates
// (MenuOverlay, KeyboardOverlay) should use this (or
// MenuOverlay.selectableButtonBackground(), which adds a persistent
// "selected" state on top of the same normal/hovered/pressed colors) -
// paired with buttonTextColors() below, since the normal/hovered state
// is light enough to need dark text while pressed/selected need white.
protected static Drawable buttonBackground() {
StateListDrawable drawable = new StateListDrawable();
drawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(PRESSED_COLOR));
drawable.addState(new int[]{android.R.attr.state_hovered}, new ColorDrawable(HOVERED_COLOR));
drawable.addState(new int[]{}, new ColorDrawable(NORMAL_COLOR));
return drawable;
}
// See buttonBackground() above - light gray (normal/hovered) needs dark
// text; the accent colors (pressed, and MenuOverlay's own "selected"
// state) need white. Every button should get both this and
// buttonBackground()/selectableButtonBackground() together.
protected static ColorStateList buttonTextColors() {
return new ColorStateList(
new int[][]{
new int[]{android.R.attr.state_pressed},
new int[]{android.R.attr.state_selected},
new int[]{},
},
new int[]{0xFFFFFFFF, 0xFFFFFFFF, 0xFF202020});
}
protected static final int NORMAL_COLOR = 0xFFC8C8C8;
protected static final int HOVERED_COLOR = 0xFFAEC2E8;
protected static final int PRESSED_COLOR = 0xFF3355AA;
protected final Activity activity;
private final int width;
private final int height;
private final View root;
// Views registered via registerHoverable() (every button, from both
// buildContent() and any later-added content) - hit-tested against the
// cursor position on every updateCursor() call so aiming at (not
// clicking) one visibly highlights it via android.R.attr.state_hovered
// (a real View state since API 14, paired with buttonBackground()
// above).
private final List<View> hoverableViews = new ArrayList<>();
private View hoveredView = null;
// contentBitmap holds just the panel's own rendered content (no cursor),
// redrawn only when that content actually changes (redrawContent(), via
// handleTouch() or a subclass's own key handling) via root.draw() - a
// full off-screen View-tree traversal that gets noticeably more
// expensive on a busier content tree. bitmap is what's actually
// published to native (see takePixelsIfDirty()): compositeAndPublish()
// cheaply blits contentBitmap plus the cursor circle into it. Splitting
// these two apart matters because updateCursor() below fires every
// single frame (~90Hz) while aiming at the panel - if it called the
// expensive root.draw() path every time (as an earlier version did), a
// busy content tree made each redraw slow enough that runOnUiThread()
// posts piled up faster than the UI thread could drain them, so the
// cursor visibly lagged behind the controller's actual aim instead of
// tracking it.
private final Bitmap contentBitmap;
private final Canvas contentCanvas;
private final Bitmap bitmap;
private final Canvas canvas;
private final Paint cursorPaint;
// Draws contentBitmap at contentAlpha() - see compositeAndPublish().
private final Paint contentAlphaPaint;
private final Object pixelLock = new Object();
private byte[] pendingPixels;
// Only ever touched on the UI thread (both dispatchUpdateCursor() and
// compositeAndPublish() run/are posted there) - no lock needed, unlike
// pendingPixels above.
private boolean cursorVisible = false;
private float cursorX = 0f;
private float cursorY = 0f;
protected OverlayPanel(Activity activity, int width, int height) {
this.activity = activity;
this.width = width;
this.height = height;
root = buildContent();
int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
root.measure(widthSpec, heightSpec);
root.layout(0, 0, width, height);
contentBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
contentCanvas = new Canvas(contentBitmap);
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
cursorPaint = new Paint();
cursorPaint.setColor(0xFFFFFFFF);
cursorPaint.setAntiAlias(true);
// contentAlpha() must not depend on any subclass instance state -
// it's called here, from the superclass constructor, before the
// subclass's own field initializers/constructor body have run (the
// usual Java construction order: this class's fields/constructor
// first, then the subclass's). A static constant is the only thing
// that's safe to return.
contentAlphaPaint = new Paint();
contentAlphaPaint.setAlpha(contentAlpha());
redrawContent();
}
// Builds this overlay's content View tree - called once, from this
// class's own constructor (see the note on contentAlpha() above: don't
// rely on subclass instance fields being initialized yet here; if a
// subclass needs its own mutable state available while building its
// content, e.g. a list of buttons to later relabel, initialize that
// field's value at the top of this method instead of via a field
// initializer).
protected abstract View buildContent();
// 0-255; defaults to fully opaque. Override for translucency (see the
// constructor's note on what's safe to depend on here).
protected int contentAlpha() {
return 255;
}
// Polled once per frame while this overlay's quad is visible (see
// xr_overlay_render_and_build_layer()) - returns the current pixels
// only once per redraw (null otherwise), so the native side knows when
// it can skip re-uploading a texture that hasn't actually changed.
protected final byte[] takePixelsIfDirty() {
synchronized (pixelLock) {
byte[] pixels = pendingPixels;
pendingPixels = null;
return pixels;
}
}
// u/v are this quad's own hit-test coordinates (0..1, top-left origin)
// - computed by xr_input.c's ray/quad intersection against xr_overlay.c's
// reported quad geometry, forwarded here as a synthetic tap. Runs on the
// UI thread since the View/Bitmap/Canvas objects here are otherwise only
// ever touched from there.
protected final void dispatchTouch(final float u, final float v, final boolean down) {
activity.runOnUiThread(() -> handleTouch(u, v, down));
}
// u/v are the same hit-test coordinates dispatchTouch() uses, but
// polled once per frame regardless of click state rather than only on
// click edges - lets the cursor track the aim ray continuously instead
// of only jumping when a trigger is pressed. visible=false (no hand's
// ray currently on the quad) hides it.
protected final void dispatchUpdateCursor(final float u, final float v,
final boolean visible) {
activity.runOnUiThread(() -> updateCursor(u, v, visible));
}
private void updateCursor(float u, float v, boolean visible) {
float x = u * width;
float y = v * height;
if (visible == cursorVisible && x == cursorX && y == cursorY) {
return;
}
cursorVisible = visible;
cursorX = x;
cursorY = y;
if (updateHoverState(x, y, visible)) {
// redrawContent() (called inside updateHoverState()) already
// composited and published this frame's pixels - nothing more
// to do.
return;
}
compositeAndPublish();
}
// Registers a button (or any View) to be hit-tested against the cursor
// position - called once per button, alongside buttonBackground()/
// setOnTouchListener(), from buildContent() (or any later content
// rebuild).
protected final void registerHoverable(View view) {
hoverableViews.add(view);
}
// Clears whatever's currently hovered without waiting for the cursor to
// actually move off of it - call after hiding/showing content (e.g. a
// tab switch), since a view that was hovered right before becoming
// GONE would otherwise still be internally tracked as hovered (and
// wrongly show that way again) if it's later made VISIBLE again before
// the cursor position next changes.
protected final void resetHover() {
if (hoveredView != null) {
hoveredView.setHovered(false);
hoveredView = null;
}
}
// Absolute bounds of view within this panel's own coordinate space
// (i.e. relative to root, which is always laid out at (0,0,width,
// height) - see the constructor) - View's own getLeft()/getTop() are
// parent-relative, so this walks up the parent chain summing them,
// additionally subtracting each ancestor's own getScrollX()/getScrollY()
// (0 for a plain ViewGroup, non-zero for e.g. a ScrollView - see
// MenuOverlay's Controller Options tab) so a view inside a scrolled
// container reports its actual on-screen position, not its laid-out one.
// Assumes view is actually part of this panel's tree (every registered
// view always is, since registerHoverable() is only ever called from
// buildContent()).
private Rect absoluteBounds(View view) {
int left = 0;
int top = 0;
View current = view;
while (true) {
left += current.getLeft();
top += current.getTop();
if (current == root || !(current.getParent() instanceof View)) {
break;
}
View parent = (View) current.getParent();
left -= parent.getScrollX();
top -= parent.getScrollY();
current = parent;
}
return new Rect(left, top, left + view.getWidth(), top + view.getHeight());
}
// Returns true if the hovered view changed (and so redrawContent() -
// which always publishes too - already ran); false if there's nothing
// more for updateCursor() to do beyond its own compositeAndPublish().
private boolean updateHoverState(float x, float y, boolean visible) {
View newHovered = null;
if (visible) {
for (View candidate : hoverableViews) {
if (candidate.getVisibility() != View.VISIBLE) {
continue;
}
if (absoluteBounds(candidate).contains((int) x, (int) y)) {
newHovered = candidate;
break;
}
}
}
if (newHovered == hoveredView) {
return false;
}
if (hoveredView != null) {
hoveredView.setHovered(false);
}
if (newHovered != null) {
newHovered.setHovered(true);
}
hoveredView = newHovered;
redrawContent();
return true;
}
private void handleTouch(float u, float v, boolean down) {
float x = u * width;
float y = v * height;
long time = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(
time, time, down ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP, x, y, 0);
try {
root.dispatchTouchEvent(event);
} finally {
event.recycle();
}
redrawContent();
}
// Re-runs the full off-screen View-tree draw (expensive - see the
// contentBitmap field comment above) - call only when the panel's
// actual content changed, not for the cursor-only updates
// compositeAndPublish() below handles on its own.
protected final void redrawContent() {
contentCanvas.drawColor(0xFF202020);
root.draw(contentCanvas);
compositeAndPublish();
}
// Cheap per-frame path: blits the last-rendered contentBitmap (no View
// traversal) plus the cursor circle into bitmap and publishes it.
// contentBitmap itself is fully opaque (redrawContent() draws an opaque
// background first); contentAlpha() translucency is applied right here
// instead, via contentAlphaPaint - which needs bitmap cleared to fully
// transparent first, since otherwise each frame's alpha-blended draw
// would blend against whatever was left over in bitmap from the
// previous frame rather than against nothing, compounding into a
// ghosting trail across frames.
private void compositeAndPublish() {
bitmap.eraseColor(0);
canvas.drawBitmap(contentBitmap, 0, 0, contentAlphaPaint);
if (cursorVisible) {
canvas.drawCircle(cursorX, cursorY, CURSOR_RADIUS, cursorPaint);
}
byte[] pixels = new byte[width * height * 4];
// ARGB_8888's actual in-memory byte order is R,G,B,A - matches
// GL_RGBA/GL_UNSIGNED_BYTE on the native side with no swizzling.
bitmap.copyPixelsToBuffer(ByteBuffer.wrap(pixels));
synchronized (pixelLock) {
pendingPixels = pixels;
}
}
}
@@ -2,10 +2,12 @@ package de.ladkau.questshock;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import androidx.core.app.ActivityCompat;
import java.io.File;
import java.io.FileOutputStream;
@@ -13,27 +15,38 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.libsdl.app.SDLActivity;
import org.libsdl.app.SDLSurface;
/**
* Everything here runs before super.onCreate() (which is what loads the
* native libraries and eventually calls Shockolate's own main()) - see
* android/engine-patches/ for why: engine/ itself is never modified, so
* this Java-side setup is the only place left to prepare
* /sdcard/questshock/ the way Shockolate's plain relative-path file I/O
* ("res/data/...", confirmed via grep - none of it goes through SDL_RWops,
* so Android's asset-manager fallback for SDL_RWFromFile doesn't apply
* here) expects to find it.
* Prepares /sdcard/questshock/ the way Shockolate's plain relative-path
* file I/O ("res/data/...", confirmed via grep - none of it goes through
* SDL_RWops, so Android's asset-manager fallback for SDL_RWFromFile
* doesn't apply here) expects to find it - see android/engine-patches/ for
* why this is done from Java instead of patching engine/ itself, which is
* never modified.
*
* super.onCreate() (SDLActivity's) must always run first and unconditionally
* - Android throws SuperNotCalledException otherwise, checked right after
* onCreate() returns, regardless of what this subclass does afterwards.
* SDLActivity's own onCreate() only loads libraries, sets up JNI and the
* surface - the actual native SDL_main thread doesn't start until later, from
* one of several lifecycle paths (onResume(), onWindowFocusChanged(), and
* SDLSurface.surfaceChanged() - see GameSurface below for why that last one
* needs its own fix) - so it's safe to do our own checks (and set
* SDLActivity.mBrokenLibraries, which most - but not all - of those paths
* gate on) afterwards.
*/
public class QuestShockActivity extends SDLActivity {
private static final String TAG = "QuestShock";
private static final int PERMISSION_REQUEST_STORAGE = 1;
private static final String GAME_DIR = "/sdcard/questshock";
// Package-visible: MenuOverlay reads controller_profiles/ from here.
static final String GAME_DIR = "/sdcard/questshock";
// Loaded here (rather than waiting for SDLActivity's own
// getLibraries()/loadLibraries(), which only runs from super.onCreate())
// purely to get nativeChdir() below - Android's dynamic linker resolves
// "main"'s own dependencies (SDL2, SDL2_mixer, fluidsynth) from the
// APK's native library directory regardless of Java-side load order, so
// APK's native library directory regardless of Java-side load order, sox
// loading it early here is safe. SDLActivity loading "main" again later
// is a harmless no-op (System.loadLibrary is idempotent per
// ClassLoader).
@@ -45,8 +58,6 @@ public class QuestShockActivity extends SDLActivity {
// has no public chdir() (confirmed against the actual API 34 stub jar).
private static native void nativeChdir(String path);
private Bundle mSavedInstanceState;
@Override
protected String[] getLibraries() {
return new String[] {
@@ -57,9 +68,50 @@ public class QuestShockActivity extends SDLActivity {
};
}
// SDLSurface.surfaceChanged() (org/libsdl/app/, vendored from SDL2's own
// template) starts the native SDL thread directly - unlike onResume()/
// onWindowFocusChanged(), it never checks SDLActivity.mBrokenLibraries
// first. Since surfaceChanged() fires on essentially every launch
// regardless of that flag, setting mBrokenLibraries alone (see onCreate()/
// setUpGameDirAndContinue()) does not actually stop the engine from
// starting. Route through a subclass that adds the missing check instead
// of patching the vendored file directly.
private static class GameSurface extends SDLSurface {
GameSurface(Context context) {
super(context);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (SDLActivity.mBrokenLibraries) {
return;
}
super.surfaceChanged(holder, format, width, height);
}
}
@Override
protected SDLSurface createSDLSurface(Context context) {
return new GameSurface(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
mSavedInstanceState = savedInstanceState;
super.onCreate(savedInstanceState);
if (SDLActivity.mBrokenLibraries) {
// SDLActivity's own onCreate() already showed its "SDL Error"
// dialog for this - nothing left for us to do.
return;
}
// Provisionally block the native engine from starting - cleared only
// once setUpGameDirAndContinue() confirms game data is present. Must
// happen before requestPermissions() below: the storage-permission
// dialog closing can fire onWindowFocusChanged(true) - which starts
// the native SDLThread - before the async onRequestPermissionsResult()
// callback (which is what actually calls setUpGameDirAndContinue())
// gets a chance to run, so mBrokenLibraries has to already be true
// going into that race, not set afterwards.
SDLActivity.mBrokenLibraries = true;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
@@ -92,29 +144,52 @@ public class QuestShockActivity extends SDLActivity {
// is already there, assume a previous run already extracted everything.
File marker = new File(gameDir, "GET_ASSETS_QUEST.txt");
if (!marker.exists()) {
copyAssetDir("shaders", new File(gameDir, "shaders"));
copyAssetFile("res/soundfont.sf2", new File(gameDir, "res/soundfont.sf2"));
copyAssetFile("GET_ASSETS_QUEST.txt", marker);
copyAssetDir("shaders", new File(gameDir, "shaders"), false);
copyAssetFile("res/soundfont.sf2", new File(gameDir, "res/soundfont.sf2"), false);
copyAssetFile("GET_ASSETS_QUEST.txt", marker, false);
}
// Refreshed on every launch (unlike the marker-gated block above) so
// it always matches the installed build - qs_config.c reads this as
// the initial config only when questshock.config.json doesn't exist
// yet, never overwriting a user's own saved config.
copyAssetFile("questshock.config.default.json",
new File(gameDir, "questshock.config.default.json"), true);
// Refreshed on every launch. MenuOverlay's Controller Options tab
// matches the active OpenXR interaction profile against these files'
// "interaction_profile" and shows the paired image (see CONFIG.md).
// Only the bundled filenames are overwritten, so profiles a user adds
// to this folder are kept.
copyAssetDir("controller_profiles", new File(gameDir, "controller_profiles"), true);
// Shockolate's engine/ is never patched to check this itself (see the
// class doc above) - it just does plain fopen("res/data/...", ...)
// and, on a fresh install with no game data copied in yet, that
// fails deep inside startup (init_popups(), which doesn't NULL-check
// the load) as a hard native crash instead of a message. Catch the
// missing-data case here instead, before super.onCreate() ever
// starts Shockolate's native main().
// missing-data case here instead, before Shockolate's native
// SDL_main ever starts.
if (!isNonEmptyDir(new File(gameDir, "res/data")) || !isNonEmptyDir(new File(gameDir, "res/sound"))) {
// mBrokenLibraries is already true (set in onCreate()) - leave it
// that way. Every path that starts the native SDL_main thread
// (onWindowFocusChanged(), resumeNativeThread(), etc.) already
// checks this flag before doing anything native, so this
// reliably prevents the engine from starting without having to
// duplicate all of SDLActivity's own lifecycle guards ourselves.
showMissingAssetsDialog();
return;
}
// chdir() is process-wide, not per-thread - already in effect for
// every thread (including the one that will run Shockolate's own
// SDL_main) by the time super.onCreate() below starts it.
// SDL_main) by the time the native thread actually starts. Done
// before clearing mBrokenLibraries below so the engine can never
// start pre-chdir.
nativeChdir(GAME_DIR);
super.onCreate(mSavedInstanceState);
// Assets confirmed present - safe to let the native engine start now.
SDLActivity.mBrokenLibraries = false;
}
private static boolean isNonEmptyDir(File dir) {
@@ -151,8 +226,8 @@ public class QuestShockActivity extends SDLActivity {
.show();
}
private void copyAssetFile(String assetPath, File dest) {
if (dest.exists()) {
private void copyAssetFile(String assetPath, File dest, boolean overwrite) {
if (dest.exists() && !overwrite) {
return;
}
File parent = dest.getParentFile();
@@ -172,7 +247,7 @@ public class QuestShockActivity extends SDLActivity {
}
}
private void copyAssetDir(String assetDir, File destDir) {
private void copyAssetDir(String assetDir, File destDir, boolean overwrite) {
AssetManager assets = getAssets();
String[] entries;
try {
@@ -186,7 +261,7 @@ public class QuestShockActivity extends SDLActivity {
}
destDir.mkdirs();
for (String entry : entries) {
copyAssetFile(assetDir + "/" + entry, new File(destDir, entry));
copyAssetFile(assetDir + "/" + entry, new File(destDir, entry), overwrite);
}
}
}
@@ -0,0 +1,217 @@
package de.ladkau.questshock;
import java.util.HashMap;
import java.util.Map;
/**
* Best-effort (not professionally reviewed) translations for this app's own
* UI chrome text - the menu/keyboard panels this project draws itself, not
* the game's own resource-string text (which already has its own separate
* English/French/German data files). Selected by gShockPrefs.goLanguage (0
* English/1 French/2 German, Prefs.h) via MenuOverlay's native language
* query (qs_config_current_language()) - see MenuOverlay's periodic header-
* refresh timer, which also pushes it to KeyboardOverlay.
*
* Deliberately excludes the keyboard's own alphanumeric key labels (a-z,
* Tab, Space, Esc, ...) - those represent physical key positions/characters
* rather than translatable UI copy - and the restart-confirmation dialog's
* message text, which is built in native code (qs_config.c's
* qs_show_restart_dialog()) with an interpolated option-name list and is
* not currently reachable in practice (see CONFIG.md - neither Video
* Options option is flagged restart-required today).
*/
final class Strings {
static final int ENGLISH = 0;
static final int FRENCH = 1;
static final int GERMAN = 2;
private static final Map<String, String[]> TABLE = new HashMap<>();
private static void put(String key, String en, String fr, String de) {
TABLE.put(key, new String[]{en, fr, de});
}
static {
put("keyboard", "Keyboard", "Clavier", "Tastatur");
put("save_configuration", "Save Configuration", "Enregistrer la configuration",
"Konfiguration speichern");
put("load_configuration", "Load Configuration", "Charger la configuration",
"Konfiguration laden");
put("reset_position", "Reset Position", "Réinitialiser la position",
"Position zurücksetzen");
put("main_menu", "Main Menu", "Menu principal", "Hauptmenü");
put("video_options", "Video Options", "Options vidéo", "Videooptionen");
put("dismiss", "Dismiss", "Fermer", "Schließen");
put("restart_now", "Restart Now", "Redémarrer maintenant", "Jetzt neu starten");
put("renderer", "Renderer", "Moteur de rendu", "Renderer");
put("resolution", "Resolution", "Résolution", "Auflösung");
put("software", "Software", "Logiciel", "Software");
put("language", "Language", "Langue", "Sprache");
put("english", "English", "Anglais", "Englisch");
put("french", "French", "Français", "Französisch");
put("german", "German", "Allemand", "Deutsch");
put("initial_screen", "Initial Screen", "Écran initial", "Startbildschirm");
put("game_screen", "Game Screen", "Écran de jeu", "Spielbildschirm");
put("width", "Width", "Largeur", "Breite");
put("distance", "Distance", "Distance", "Abstand");
// "OpenGL" is a proper/brand name - not translated, same in every
// language, so it has no entry here; call sites just use it as a
// literal.
put("keyboard_drag_title", "Keyboard - drag here to move",
"Clavier - faites glisser ici pour déplacer",
"Tastatur - hier ziehen zum Verschieben");
put("close", "Close", "Fermer", "Schließen");
// Controller Options tab: action row labels, keyed by xr_input.c's
// action names (see MenuOverlay.ACTION_KEYS).
put("controller_options", "Controller Options", "Options de manette", "Controller-Optionen");
put("action_move_forward", "Move Forward", "Avancer", "Vorwärts gehen");
put("action_move_back", "Move Back", "Reculer", "Rückwärts gehen");
put("action_strafe_left", "Strafe Left", "Pas latéral gauche", "Seitwärts links");
put("action_strafe_right", "Strafe Right", "Pas latéral droit", "Seitwärts rechts");
put("action_turn_left", "Turn Left", "Tourner à gauche", "Nach links drehen");
put("action_turn_right", "Turn Right", "Tourner à droite", "Nach rechts drehen");
put("action_jump", "Jump", "Sauter", "Springen");
put("action_mouse_click", "Click", "Cliquer", "Klicken");
put("action_mouse_double_click", "Double-Click", "Double-clic", "Doppelklick");
// Hotkey actions (see xr_input.c); all unbound by default.
put("action_stand", "Stand", "Debout", "Stehen");
put("action_crouch", "Crouch", "Accroupi", "Ducken");
put("action_prone", "Prone", "Couché", "Liegen");
put("action_pause", "Pause Game", "Mettre en pause", "Spiel pausieren");
put("action_full_view", "Fullscreen View", "Vue plein écran", "Vollbildansicht");
put("action_normal_view", "Normal View", "Vue normale", "Normale Ansicht");
put("action_map_view", "Automap View", "Vue de la carte", "Automap-Ansicht");
put("action_save_game", "Save Game", "Sauvegarder", "Spiel speichern");
put("action_load_game", "Load Game", "Charger", "Spiel laden");
put("action_select_grenade", "Select Grenade", "Sélectionner une grenade",
"Granate auswählen");
put("action_arm_grenade", "Arm Grenade", "Armer la grenade", "Granate scharfmachen");
put("action_select_drug", "Select Drug", "Sélectionner une drogue", "Droge auswählen");
put("action_use_drug", "Use Drug", "Utiliser la drogue", "Droge benutzen");
put("action_toggle_online_help", "Toggle Online Help", "Basculer l'aide en ligne",
"Online-Hilfe umschalten");
put("action_show_help", "Show Help", "Afficher l'aide", "Hilfe anzeigen");
put("action_toggle_music", "Toggle Music", "Basculer la musique", "Musik umschalten");
put("action_quit", "Quit Game", "Quitter le jeu", "Spiel beenden");
put("action_cycle_weapon_next", "Next Weapon", "Arme suivante", "Nächste Waffe");
put("action_cycle_weapon_prev", "Previous Weapon", "Arme précédente", "Vorherige Waffe");
put("action_cycle_detail", "Cycle Detail Level", "Changer le niveau de détail",
"Detailgrad wechseln");
put("action_reload_weapon_primary", "Reload Weapon (Primary)",
"Recharger l'arme (principal)", "Waffe nachladen (primär)");
put("action_reload_weapon_secondary", "Reload Weapon (Secondary)",
"Recharger l'arme (secondaire)", "Waffe nachladen (sekundär)");
put("action_hud_color", "Cycle HUD Color", "Changer la couleur de l'interface",
"HUD-Farbe wechseln");
put("action_clear_fullscreen", "Clear Fullscreen View", "Quitter la vue plein écran",
"Vollbildansicht schließen");
put("action_mfd_left_1", "Left MFD: Weapon", "MFD gauche : arme", "Linkes MFD: Waffe");
put("action_mfd_left_2", "Left MFD: Item", "MFD gauche : objet", "Linkes MFD: Gegenstand");
put("action_mfd_left_3", "Left MFD: Map", "MFD gauche : carte", "Linkes MFD: Karte");
put("action_mfd_left_4", "Left MFD: Target", "MFD gauche : cible", "Linkes MFD: Ziel");
put("action_mfd_left_5", "Left MFD: Info", "MFD gauche : info", "Linkes MFD: Info");
put("action_mfd_right_1", "Right MFD: Weapon", "MFD droit : arme", "Rechtes MFD: Waffe");
put("action_mfd_right_2", "Right MFD: Item", "MFD droit : objet",
"Rechtes MFD: Gegenstand");
put("action_mfd_right_3", "Right MFD: Map", "MFD droit : carte", "Rechtes MFD: Karte");
put("action_mfd_right_4", "Right MFD: Target", "MFD droit : cible", "Rechtes MFD: Ziel");
put("action_mfd_right_5", "Right MFD: Info", "MFD droit : info", "Rechtes MFD: Info");
put("action_fire_weapon", "Fire Weapon", "Tirer", "Waffe abfeuern");
// Cheats tab.
put("cheats", "Cheats", "Triches", "Cheats");
put("cheats_note", "Cheats need a running game.", "Les triches nécessitent une partie en cours.",
"Cheats benötigen ein laufendes Spiel.");
put("cheat_give_all", "Give All Items & Weapons", "Tout obtenir", "Alles erhalten");
put("cheat_physics", "Physics", "Physique", "Physik");
put("cheat_level_up", "Next Level", "Niveau suivant", "Nächstes Level");
put("cheat_level_down", "Previous Level", "Niveau précédent", "Vorheriges Level");
put("cheat_unlimited_health", "Unlimited Health", "Santé illimitée", "Unbegrenzt Leben");
put("cheat_unlimited_energy", "Unlimited Energy", "Énergie illimitée", "Unbegrenzt Energie");
put("cheat_unlimited_ammo", "Unlimited Ammo", "Munitions illimitées", "Unbegrenzt Munition");
put("cheat_unlimited_items", "Unlimited Items", "Objets illimités", "Unbegrenzt Items");
put("action_free_left_thumbstick_view", "Free View (Left Stick)",
"Vue libre (stick gauche)", "Freie Ansicht (linker Stick)");
put("action_free_right_thumbstick_view", "Free View (Right Stick)",
"Vue libre (stick droit)", "Freie Ansicht (rechter Stick)");
// Cyberspace actions (active only in cyberspace, see xr_input.c).
put("action_cyber_thrust", "Cyberspace: Thrust", "Cyberespace : poussée",
"Cyberspace: Schub");
put("action_cyber_climb", "Cyberspace: Climb", "Cyberespace : monter",
"Cyberspace: Steigen");
put("action_cyber_dive", "Cyberspace: Dive", "Cyberespace : plonger",
"Cyberspace: Sinken");
put("action_cyber_bank_left", "Cyberspace: Bank Left", "Cyberespace : virage à gauche",
"Cyberspace: Links kippen");
put("action_cyber_bank_right", "Cyberspace: Bank Right", "Cyberespace : virage à droite",
"Cyberspace: Rechts kippen");
put("action_cyber_roll_left", "Cyberspace: Roll Left", "Cyberespace : roulis gauche",
"Cyberspace: Links rollen");
put("action_cyber_roll_right", "Cyberspace: Roll Right", "Cyberespace : roulis droit",
"Cyberspace: Rechts rollen");
put("action_cyber_climb_left", "Cyberspace: Climb Left", "Cyberespace : monter à gauche",
"Cyberspace: Links steigen");
put("action_cyber_climb_right", "Cyberspace: Climb Right", "Cyberespace : monter à droite",
"Cyberspace: Rechts steigen");
put("action_cyber_dive_left", "Cyberspace: Dive Left", "Cyberespace : plonger à gauche",
"Cyberspace: Links sinken");
put("action_cyber_dive_right", "Cyberspace: Dive Right", "Cyberespace : plonger à droite",
"Cyberspace: Rechts sinken");
put("capture_prompt", "Press a button…", "Appuyez sur un bouton…", "Taste drücken…");
put("reset_to_defaults", "Reset to Defaults", "Réinitialiser", "Auf Standard zurücksetzen");
put("generic_profile_note",
"This controller only exposes a trigger and a menu button - most actions above have "
+ "nothing to bind to.",
"Cette manette n'expose qu'une gâchette et un bouton menu - la plupart des actions "
+ "ci-dessus n'ont rien à quoi être assignées.",
"Dieser Controller bietet nur einen Trigger und eine Menütaste - die meisten "
+ "Aktionen oben haben nichts, woran sie gebunden werden können.");
// Raw physical-input display names (xr_input.c's kRawInputNames);
// "none" is the unbound sentinel.
put("raw_left_trigger", "Left Trigger", "Gâchette gauche", "Linker Trigger");
put("raw_right_trigger", "Right Trigger", "Gâchette droite", "Rechter Trigger");
put("raw_left_squeeze", "Left Grip", "Préhension gauche", "Linker Griff");
put("raw_right_squeeze", "Right Grip", "Préhension droite", "Rechter Griff");
put("raw_left_x", "X Button", "Bouton X", "X-Taste");
put("raw_left_y", "Y Button", "Bouton Y", "Y-Taste");
put("raw_right_a", "A Button", "Bouton A", "A-Taste");
put("raw_right_b", "B Button", "Bouton B", "B-Taste");
put("raw_left_thumbstick_click", "Left Stick Click", "Clic du stick gauche",
"Linker Stick-Klick");
put("raw_right_thumbstick_click", "Right Stick Click", "Clic du stick droit",
"Rechter Stick-Klick");
put("raw_left_thumbstick_up", "Left Stick Up", "Stick gauche haut", "Linker Stick hoch");
put("raw_left_thumbstick_down", "Left Stick Down", "Stick gauche bas", "Linker Stick runter");
put("raw_left_thumbstick_left", "Left Stick Left", "Stick gauche à gauche",
"Linker Stick links");
put("raw_left_thumbstick_right", "Left Stick Right", "Stick gauche à droite",
"Linker Stick rechts");
put("raw_right_thumbstick_up", "Right Stick Up", "Stick droit haut", "Rechter Stick hoch");
put("raw_right_thumbstick_down", "Right Stick Down", "Stick droit bas",
"Rechter Stick runter");
put("raw_right_thumbstick_left", "Right Stick Left", "Stick droit à gauche",
"Rechter Stick links");
put("raw_right_thumbstick_right", "Right Stick Right", "Stick droit à droite",
"Rechter Stick rechts");
put("raw_trigger", "Either Trigger", "L'une ou l'autre gâchette", "Beliebiger Trigger");
put("raw_squeeze", "Either Grip", "L'une ou l'autre préhension", "Beliebiger Griff");
put("raw_none", "(unbound)", "(non assigné)", "(nicht zugewiesen)");
}
private Strings() {}
static String get(String key, int language) {
String[] variants = TABLE.get(key);
if (variants == null) {
return key;
}
if (language < 0 || language >= variants.length) {
language = ENGLISH;
}
return variants[language];
}
}
+12 -1
View File
@@ -9,7 +9,18 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.1'
// 8.5.1+ needed for AGP to automatically 16 KB-align native
// libraries' zip entries within the APK - the actual .so's are
// already ELF-segment-aligned for this regardless of AGP version
// (see build-image/Dockerfile's ANDROID_16KB_LDFLAGS and
// app/build.gradle's own CMAKE_SHARED_LINKER_FLAGS), but that alone
// doesn't get them 16 KB-aligned *within the APK's zip*, which is
// what Android Studio's "not compatible with 16 KB devices"
// warning is actually about. Needs Gradle 8.7+ (see
// gradle/wrapper/gradle-wrapper.properties) and JDK 17 in whatever
// runs gradlew (already the case - see build-image/Dockerfile's
// openjdk-17-jdk-headless).
classpath 'com.android.tools.build:gradle:8.5.2'
}
}
@@ -1,19 +1,30 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,9 +46,17 @@
diff -ru a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt 2026-07-31 14:04:53.195646458 +0200
+++ b/CMakeLists.txt 2026-07-31 14:05:05.703429751 +0200
@@ -46,9 +46,27 @@
add_compile_options(-fsigned-char -fno-strict-aliasing)
-# Find OpenGL
+# Find OpenGL. Android has no desktop GL/GLX for CMake's FindOpenGL module
+# to find - link the prebuilt GL4ES instead (translates this file's
+# to find - build GL4ES from source instead (translates this file's
+# desktop-style GL calls into GLES/EGL; it links GLESv2/EGL itself, so
+# the engine doesn't need to link them directly).
+# the engine doesn't need to link them directly), via add_subdirectory
+# rather than a prebuilt .so: ANDROID_GL4ES_DIR (passed in by
+# android/app/build.gradle, same as ANDROID_PREBUILT_DIR) is a scratch,
+# patched copy of android/gl4es-src/ staged by
+# build-image/prepare-android-project.sh (mirrors how this file itself is
+# staged/patched before Gradle ever sees it) - building it as part of this
+# same CMake configure means Gradle's own incremental CMake/Ninja build
+# only recompiles it when gl4es-src/gl4es-patches actually changed, same
+# as this file, instead of needing a full build-image rebuild for every
+# gl4es-patches change.
if(ENABLE_OPENGL)
- find_package(OpenGL REQUIRED)
+ if(ANDROID)
+ set(OPENGL_INCLUDE_DIRS ${ANDROID_PREBUILT_DIR}/gl4es/include)
+ set(OPENGL_LIBRARIES ${ANDROID_PREBUILT_DIR}/gl4es/lib/libGL.so)
+ add_subdirectory(${ANDROID_GL4ES_DIR} ${CMAKE_BINARY_DIR}/gl4es-build)
+ set(OPENGL_INCLUDE_DIRS ${ANDROID_GL4ES_DIR}/include)
+ set(OPENGL_LIBRARIES GL)
+ else()
+ find_package(OpenGL REQUIRED)
+ endif()
@@ -9,7 +9,7 @@
+ // Android - EGL only ever gives out GLES contexts. Quest hardware
+ // (Adreno on the XR2/XR2 Gen 2) supports GLES 3.2, which - unlike
+ // GLES 2.0 - has GL_UNPACK_ROW_LENGTH and GL_CLAMP_TO_BORDER as core
+ // (see android/engine-patches/03-android-opengl-es-render.patch),
+ // (see android/engine-patches/04-android-opengl-es-render.patch),
+ // avoiding needing workarounds for either in OpenGL.cc.
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
@@ -0,0 +1,29 @@
--- a/src/MacSrc/Shock.c
+++ b/src/MacSrc/Shock.c
@@ -162,9 +162,26 @@
void InitSDL() {
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
+#ifdef __ANDROID__
+ // SDL2 2.28.5's AAudio backend (Android's default since API 26) only
+ // ever allows one open non-capture (playback) device at a time - it
+ // keeps a single static handle and asserts on a second open
+ // ('SDL_assert((audioDevice == NULL) || iscapture)' in
+ // src/audio/aaudio/SDL_aaudio.c). SDLSound.c opens two: one directly via
+ // SDL_OpenAudioDevice() for cutscene audio, one via Mix_OpenAudio() for
+ // SFX/MIDI. The older OpenSL ES backend has no such limitation, so force
+ // it instead of AAudio. Uses SDL_HINT_OVERRIDE priority so nothing set
+ // earlier (or by SDL/the platform) can take precedence over it.
+ SDL_SetHintWithPriority(SDL_HINT_AUDIODRIVER, "openslES", SDL_HINT_OVERRIDE);
+#endif
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) < 0) {
DEBUG("%s: Init failed", __FUNCTION__);
}
+#ifdef __ANDROID__
+ // Standing diagnostic: reports which audio driver SDL actually selected,
+ // to confirm the openslES override above took effect on-device.
+ INFO("SDL audio driver: %s", SDL_GetCurrentAudioDriver());
+#endif
// TODO: figure out some universal set of settings that work...
#ifdef __ANDROID__
@@ -0,0 +1,27 @@
--- a/src/Libraries/INPUT/Source/sdl_events.c
+++ b/src/Libraries/INPUT/Source/sdl_events.c
@@ -737,7 +737,24 @@
break;
case SDL_WINDOWEVENT_MOVED:
+ break;
+
case SDL_WINDOWEVENT_RESIZED:
+#ifdef __ANDROID__
+ // Android's SDL video backend (Android_SendResize() in
+ // src/video/android/SDL_androidvideo.c) only ever sends
+ // RESIZED for surface-driven resizes - e.g. the Quest Home
+ // shell settling the 2D panel into its requested <layout>
+ // defaultWidth/defaultHeight after activity launch - never
+ // SIZE_CHANGED (unlike desktop platforms, where an
+ // app-driven SDL_SetWindowSize() triggers both, handled
+ // above). Without this, opengl_resize() never re-runs after
+ // that late resize, leaving the GL viewport stuck at
+ // whatever (smaller) size the window first reported,
+ // rendered into one corner of the now-larger surface.
+ if (can_use_opengl())
+ opengl_resize(ev.window.data1, ev.window.data2);
+#endif
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
@@ -0,0 +1,10 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -440,6 +440,7 @@
${FLUIDSYNTH_LIBRARIES}
${OPENGL_LIBRARIES}
${ALSA_LIBRARIES}
+ $<$<BOOL:${ANDROID}>:log>
)
# Turn on address sanitizing if wanted (desktop only - not meaningful for
@@ -0,0 +1,45 @@
--- a/src/Libraries/LG/Source/LOG/src/log.c
+++ b/src/Libraries/LG/Source/LOG/src/log.c
@@ -28,6 +28,10 @@
#include "log.h"
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+
static struct {
void *udata;
log_LockFn lock;
@@ -99,6 +103,23 @@
time_t t = time(NULL);
struct tm *lt = localtime(&t);
+#ifdef __ANDROID__
+ /* Plain stdout/stderr isn't captured by logcat on this platform (unlike
+ e.g. gl4es's own "LIBGL"-tagged logging, which goes through this same
+ API directly) - route there instead so every existing INFO/DEBUG/WARN/
+ ERROR call site in the engine becomes visible for on-device debugging,
+ with no changes needed at those call sites. */
+ if (!L.quiet) {
+ static const int android_priority[] = {
+ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
+ };
+ va_list args;
+ va_start(args, fmt);
+ __android_log_vprint(android_priority[level], "QuestShock", fmt, args);
+ va_end(args);
+ }
+#else
/* Log to stderr */
if (!L.quiet) {
va_list args;
@@ -116,6 +137,7 @@
va_end(args);
fprintf(stderr, "\n");
}
+#endif
/* Log to file */
if (L.fp) {
@@ -0,0 +1,68 @@
--- a/src/MacSrc/ShockBitmap.c
+++ b/src/MacSrc/ShockBitmap.c
@@ -27,6 +27,9 @@
#include "Shock.h"
#include "ShockBitmap.h"
#include "2d.h"
+#ifdef __ANDROID__
+#include "OpenGL.h"
+#endif
//--------------------
// Globals
@@ -42,11 +45,26 @@
SDL_RenderClear(renderer);
+#ifndef __ANDROID__
+ // On Android there's exactly one OS-controlled-size surface - no
+ // desktop-style window to resize, move, or toggle fullscreen on.
+ // SDL_SetWindowSize() still "succeeds" there (Android has no
+ // SetWindowSize driver hook, so SDL's generic layer just overwrites its
+ // own cached window->w/h to the requested game resolution, e.g.
+ // 640x480, and synthesizes a resize event from that) - which desyncs
+ // SDL's own notion of the window size from the real, unchanged Android
+ // surface size (e.g. 1600x1200), and that desync is exactly what then
+ // makes both SDL's internal renderer viewport and this engine's own
+ // custom GL viewport (OpenGL.cc's opengl_resize(), driven by that same
+ // now-wrong cached size) shrink to the game's resolution instead of
+ // filling the real surface. Skip the desktop-only calls on Android
+ // entirely, leaving SDL's window-size bookkeeping untouched.
extern bool fullscreenActive;
SDL_SetWindowFullscreen(window, fullscreenActive ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_SetWindowSize(window, width, height);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+#endif
SDL_RenderSetLogicalSize(renderer, width, height);
@@ -54,6 +72,28 @@
gScreenWide = width;
gScreenHigh = height;
+
+#ifdef __ANDROID__
+ // Skipping SDL_SetWindowSize() above (see the comment for why) also
+ // means no native resize event ever fires on Android when the in-game
+ // resolution changes - opengl_resize() (OpenGL.cc) only ever runs from
+ // that event (see sdl_events.c) or once at OpenGL init, and it's what
+ // (re)creates backupBuffer, the offscreen 3D-view render target, sized
+ // to the logical resolution just changed above. Without this, it stays
+ // stuck at whatever size it was at launch while the rest of the game
+ // (drawSurface/gScreenWide/gScreenHigh, just updated above) moves on to
+ // the new resolution - the actual cause of the display breaking and
+ // becoming unresponsive to further input after changing resolution
+ // in-game. Call it directly instead - after gScreenWide/gScreenHigh
+ // update above, same as the desktop resize event (delivered via
+ // SDL_PollEvent(), so always processed after this function has already
+ // returned) - using the same physical window size init_opengl() itself
+ // used (SDL_GetWindowSize()); that never changes on Android, only the
+ // logical size set above does.
+ int physWidth, physHeight;
+ SDL_GetWindowSize(window, &physWidth, &physHeight);
+ opengl_resize(physWidth, physHeight);
+#endif
}
//------------------------------------------------------------------------------------
@@ -0,0 +1,39 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,19 @@
endif(WIN32)
endif(ENABLE_OPENGL)
+# OpenXR loader (Android only for now - see android/app/src/main/cpp/
+# xr_session.c, which submits the game's existing render as a composition
+# layer instead of presenting to a normal window/surface). EGL is linked
+# explicitly too - xr_session.c calls eglGetCurrentDisplay/Context/
+# QueryContext/ChooseConfig directly (to share the GL context gl4es/SDL
+# already made), and unlike GL itself (where gl4es's own libGL.so already
+# provides every symbol the engine or xr_session.c call), there's no other
+# EGL provider in this link.
+if(ANDROID)
+ set(OPENXR_INCLUDE_DIRS ${ANDROID_PREBUILT_DIR}/openxr/include)
+ set(OPENXR_LIBRARIES ${ANDROID_PREBUILT_DIR}/openxr/lib/libopenxr_loader.so EGL)
+endif(ANDROID)
+
if(ENABLE_SDL2 MATCHES "ON")
find_package(SDL2 REQUIRED)
if(SDL2_FOUND)
@@ -109,6 +122,8 @@
${SDL2_MIXER_INCLUDE_DIRS}
${FLUIDSYNTH_INCLUDE_DIRS}
${OPENGL_INCLUDE_DIRS}
+ ${OPENXR_INCLUDE_DIRS}
+ ${ANDROID_EXTRA_INCLUDE_DIRS}
)
if(NOT WIN32)
@@ -439,6 +454,7 @@
${SDL2_MIXER_LIBRARIES}
${FLUIDSYNTH_LIBRARIES}
${OPENGL_LIBRARIES}
+ ${OPENXR_LIBRARIES}
${ALSA_LIBRARIES}
$<$<BOOL:${ANDROID}>:log>
)
@@ -0,0 +1,267 @@
--- a/src/MacSrc/OpenGL.cc 2026-07-25 07:10:06.189412183 +0200
+++ b/src/MacSrc/OpenGL.cc 2026-07-25 07:12:05.356301052 +0200
@@ -36,6 +36,7 @@
if (loc >= 0)
glUniform1f(loc, size);
}
+#include "xr_session.h"
#endif // __ANDROID__
extern "C" {
@@ -382,6 +383,21 @@
#endif
opengl_resize(width, height);
+#ifdef __ANDROID__
+ // Bring up the OpenXR session now that the shared GL context above is
+ // current (xr_init() reuses it via eglGetCurrentContext/Display - see
+ // xr_session.c) - sized to the game's own logical resolution, not the
+ // physical window, since the swapchain is composited by the XR runtime
+ // rather than upscaled by us into a physical-window-sized viewport (see
+ // opengl_swap_and_restore()/android_composite_software_frame() below).
+ // Failure here (e.g. no OpenXR runtime installed) just means the
+ // immersive path never activates - SDLDraw() falls back to the plain
+ // window-present path for the rest of the run.
+ int xr_logical_width, xr_logical_height;
+ SDL_RenderGetLogicalSize(renderer, &xr_logical_width, &xr_logical_height);
+ xr_init(xr_logical_width, xr_logical_height);
+#endif
+
// Now make the palettes
opaquePalette = SDL_AllocPalette(256);
transparentPalette = SDL_AllocPalette(256);
@@ -498,7 +514,109 @@
*y_scale = output_height / screen_height;
}
+#ifdef __ANDROID__
+// Shared by opengl_swap_and_restore()'s UI-overlay blit and
+// android_composite_software_frame() below - draws an SDL_Surface as a
+// fullscreen textured quad via gl4es. SDL's own renderer can't be used
+// here: it's tied to the window's own EGL surface, not whatever XR
+// swapchain framebuffer the caller already bound via xr_frame_begin().
+static void android_draw_surface_as_quad(SDL_Surface *ui, bool blend) {
+ SDL_Surface *uiRgba = SDL_ConvertSurfaceFormat(ui, SDL_PIXELFORMAT_RGBA32, 0);
+ if (uiRgba == nullptr)
+ return;
+
+ glUseProgram(textureShaderProgram.shaderProgram);
+ GLint tcAttrib = textureShaderProgram.tcAttrib;
+ GLint lightAttrib = textureShaderProgram.lightAttrib;
+ glUniform1i(textureShaderProgram.uniNightSight, false);
+ glUniformMatrix4fv(textureShaderProgram.uniView, 1, false, IdentityMatrix);
+ glUniformMatrix4fv(textureShaderProgram.uniProj, 1, false, IdentityMatrix);
+
+ // Persistent texture, reused every call instead of a fresh
+ // gen/upload/delete each frame.
+ static GLuint s_uiTexture = 0;
+ if (s_uiTexture == 0)
+ glGenTextures(1, &s_uiTexture);
+ bind_texture(s_uiTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, uiRgba->w, uiRgba->h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ uiRgba->pixels);
+
+ set_blend_mode(blend);
+
+ // Real per-vertex arrays, not glBegin/glVertexAttrib/glVertex3f
+ // immediate mode: glVertexAttrib*() is GLES2's *constant*-attribute
+ // API - without an enabled vertex array it sets one value for the
+ // whole draw call, not a fresh value per vertex. gl4es's immediate-mode
+ // emulation only reproduces desktop GL's per-vertex-capture behavior
+ // for attribute 0 (position, driven directly by glVertex3f), not for
+ // custom attributes like this shader's texcoords/light.
+ //
+ // V is flipped (1 at the bottom, 0 at the top): GL texture v=0
+ // addresses the first row of data passed to glTexImage2D, but uiRgba
+ // (an SDL surface) stores its rows top-down.
+ struct QuadVertex {
+ float x, y, z;
+ float u, v;
+ float light;
+ };
+ static const QuadVertex quadVerts[4] = {
+ {1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f},
+ {1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
+ {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ };
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(tcAttrib);
+ glEnableVertexAttribArray(lightAttrib);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QuadVertex), &quadVerts[0].x);
+ glVertexAttribPointer(tcAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(QuadVertex), &quadVerts[0].u);
+ glVertexAttribPointer(lightAttrib, 1, GL_FLOAT, GL_FALSE, sizeof(QuadVertex),
+ &quadVerts[0].light);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ // The engine's other rendering uses glBegin/glVertexAttrib/glVertex3f
+ // immediate mode for attribute 0, which depends on it not having an
+ // enabled array bound.
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(tcAttrib);
+ glDisableVertexAttribArray(lightAttrib);
+ glFlush();
+
+ SDL_FreeSurface(uiRgba);
+}
+
+void android_composite_software_frame(SDL_Surface *ui) {
+ // Deliberately no SDL_GL_MakeCurrent() here - see the comment in
+ // opengl_swap_and_restore() below for why.
+ glClear(GL_COLOR_BUFFER_BIT);
+ android_draw_surface_as_quad(ui, false);
+}
+#endif
+
void opengl_swap_and_restore(SDL_Surface *ui) {
+#ifdef __ANDROID__
+ // No SDL_GL_MakeCurrent() here on Android, deliberately - unlike the
+ // desktop path below. init_opengl() already made (window, context)
+ // current once; re-asserting it every frame turned out to reset
+ // gl4es's own internal "current framebuffer" bookkeeping back to
+ // whatever it associates with that context/surface pair (observed
+ // on-device: the XR swapchain image reliably received our real
+ // glClear/bind from xr_frame_begin(), but every actual gl4es-routed
+ // draw call after a fresh SDL_GL_MakeCurrent() here kept landing
+ // somewhere else - the quad stayed permanently black). Confirmed this
+ // exact class of gl4es/OpenXR interaction against RTCWQuest (Team
+ // Beef Studios), a shipped gl4es+Khronos-OpenXR-loader Quest port:
+ // it makes its EGL context current exactly once at init and never
+ // again per-frame, for the same reason.
+ //
+ // xr_frame_begin() (called from SDLDraw()) already bound the XR
+ // swapchain's framebuffer and a full-size viewport - no physical-
+ // window letterboxing needed here either, unlike the desktop/2D-panel
+ // path below, since the swapchain is sized to exactly the game's
+ // logical resolution (see xr_init()).
+ glClear(GL_COLOR_BUFFER_BIT);
+#else
// restore the view backup (without HUD overlay) for incremental
// updates in the subsequent frame
SDL_GL_MakeCurrent(window, context);
@@ -510,6 +628,7 @@
// Set the drawable area for the 3d view
glViewport(phys_offset_x * x_hdpi_scale, phys_offset_y * y_hdpi_scale, phys_width * x_hdpi_scale,
phys_height * y_hdpi_scale);
+#endif
set_blend_mode(false);
// Bind and setup our general shader program
@@ -552,6 +671,11 @@
if (err != GL_NO_ERROR)
ERROR("OpenGL error: %i", err);
+#ifdef __ANDROID__
+ // Blit the UI canvas over the 3d view (see android_draw_surface_as_quad()
+ // above - SDL's renderer can't target the XR swapchain framebuffer).
+ android_draw_surface_as_quad(ui, true);
+#else
// Blit the UI canvas over the 3d view
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, ui);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
@@ -561,6 +685,7 @@
// Finally, swap to the screen
SDL_RenderPresent(renderer);
+#endif
}
void toggle_opengl() {
--- a/src/MacSrc/OpenGL.h 2026-07-19 13:11:51.000000000 +0200
+++ b/src/MacSrc/OpenGL.h 2026-07-25 07:10:06.353410581 +0200
@@ -22,6 +22,15 @@
void opengl_swap_and_restore(SDL_Surface *ui);
void opengl_change_palette();
+#ifdef __ANDROID__
+// Composites a plain software-rendered frame (the same content SDLDraw's
+// non-OpenGL fallback would otherwise present via SDL_RenderCopy) into the
+// XR swapchain image already bound by xr_frame_begin() - see Shock.c's
+// SDLDraw(), which needs this for the splash screen/cutscenes/menus that
+// render this way instead of through opengl_swap_and_restore().
+void android_composite_software_frame(SDL_Surface *ui);
+#endif
+
void opengl_set_viewport(int x, int y, int width, int height);
int opengl_draw_tmap(int n, g3s_phandle *vp, grs_bitmap *bm);
int opengl_light_tmap(int n, g3s_phandle *vp, grs_bitmap *bm);
--- a/src/MacSrc/Shock.c 2026-07-25 07:10:06.181412261 +0200
+++ b/src/MacSrc/Shock.c 2026-07-25 07:10:06.353410581 +0200
@@ -30,6 +30,10 @@
#include <math.h>
#include <SDL.h>
+#ifdef __ANDROID__
+#include "xr_session.h"
+#endif
+
#include "InitMac.h"
#include "Modding.h"
#include "OpenGL.h"
@@ -301,6 +305,28 @@
}
void SDLDraw() {
+#ifdef __ANDROID__
+ // Diagnostic: logs once per transition (including the very first
+ // frame) between the OpenGL 3D render path and the plain
+ // software-composited 2D path (splash/menus/cutscenes) below - so a
+ // logcat capture immediately shows which one is active without
+ // needing to infer it from screenshots.
+ static int s_last_render_mode = -1; // -1 = not yet logged
+
+ // The true once-a-frame present hook for the immersive OpenXR path -
+ // unlike opengl_swap_and_restore() below, this runs every frame
+ // regardless of should_opengl_swap() (e.g. also during the splash
+ // screen/cutscenes/menus, which render through the plain software
+ // path below, not the OpenGL one). xr_poll_events() needs exactly that
+ // - called unconditionally - to ever observe the session reach a
+ // running state in the first place.
+ xr_poll_events();
+ if (!xr_frame_begin()) {
+ xr_frame_end();
+ return;
+ }
+#endif
+
if (should_opengl_swap()) {
// We want the UI background to be transparent!
sdlPalette->colors[255].a = 0x00;
@@ -310,14 +336,35 @@
// Set the palette back, and we are done
sdlPalette->colors[255].a = 0xff;
+#ifdef __ANDROID__
+ if (s_last_render_mode != 1) {
+ s_last_render_mode = 1;
+ INFO("Game rendering active: OpenGL (3D) mode");
+ }
+ xr_frame_end();
+#endif
return;
}
+#ifdef __ANDROID__
+ if (s_last_render_mode != 0) {
+ s_last_render_mode = 0;
+ INFO("Game rendering active: software (2D) mode");
+ }
+ // Same software-rendered frame the desktop path below would present
+ // via SDL_RenderCopy/SDL_RenderPresent, composited into the XR
+ // swapchain image xr_frame_begin() bound above instead - SDL's
+ // renderer is tied to the window's own EGL surface, not that FBO.
+ android_composite_software_frame(drawSurface);
+ xr_frame_end();
+ return;
+#endif
+
// Clear the screen!
SDL_RenderClear(renderer);
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, drawSurface);
- // Blit to the screen by drawing the surface
+ // Blit to the screen by drawing the surface
SDL_Rect srcRect = {0, 0, gScreenWide, gScreenHigh};
SDL_RenderCopy(renderer, texture, &srcRect, NULL);
SDL_DestroyTexture(texture);
@@ -0,0 +1,30 @@
--- a/src/MacSrc/OpenGL.cc 2026-08-22 09:00:00.000000000 +0200
+++ b/src/MacSrc/OpenGL.cc 2026-08-22 09:05:00.000000000 +0200
@@ -562,7 +562,14 @@
static bool opengl_cache_texture(CachedTexture toCache, grs_bitmap *bm) {
SDL_GL_MakeCurrent(window, context);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, bm->row);
+ // GL_UNPACK_ROW_LENGTH must describe the buffer actually passed to
+ // glTexImage2D() below (toCache.converted->pixels, a separately
+ // allocated SDL_PIXELFORMAT_RGBA32 surface from
+ // SDL_ConvertSurfaceFormat()) - not bm->row, the original 8-bit
+ // source bitmap's own unrelated row stride. Using bm->row here fed
+ // gl4es's GL_UNPACK_ROW_LENGTH emulation the wrong stride whenever
+ // the two differed, corrupting the texture upload.
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, toCache.converted->pitch / 4);
if (texturesByBitsPtr.size() < MAX_CACHED_TEXTURES) {
// We have enough room, generate the new texture
@@ -696,7 +703,10 @@
t->lastDrawTime = *tmd_ticks;
if (isDirty) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, bm->row);
+ // Same fix as opengl_cache_texture() above - t->converted->pixels
+ // is what's actually uploaded, so its own pitch is what
+ // GL_UNPACK_ROW_LENGTH needs to describe, not bm->row.
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, t->converted->pitch / 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bm->w, bm->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, t->converted->pixels);
}
}
@@ -0,0 +1,15 @@
--- a/src/MacSrc/OpenGL.cc
+++ b/src/MacSrc/OpenGL.cc
@@ -566,7 +566,11 @@
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(tcAttrib);
glDisableVertexAttribArray(lightAttrib);
- glFlush();
+ // glFinish(), not glFlush(): xr_swapchain_release() (called by our
+ // caller right after this returns) hands the image to the OpenXR
+ // runtime for cross-process consumption, which requires the GPU write
+ // to have actually landed, not just be queued.
+ glFinish();
SDL_FreeSurface(uiRgba);
}
@@ -0,0 +1,16 @@
--- a/src/MacSrc/OpenGL.cc
+++ b/src/MacSrc/OpenGL.cc
@@ -525,6 +525,13 @@
bind_texture(s_uiTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ // uiRgba is tightly packed, but gl4es implements GL_UNPACK_ROW_LENGTH/
+ // GL_UNPACK_ALIGNMENT client-side and persists whatever was last set
+ // across draw calls in the same context. Reset both to the packed
+ // defaults here so this upload doesn't inherit unrelated unpack state
+ // set elsewhere in the frame.
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, uiRgba->w, uiRgba->h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
uiRgba->pixels);
@@ -0,0 +1,11 @@
--- a/src/MacSrc/SDLSound.c
+++ b/src/MacSrc/SDLSound.c
@@ -42,7 +42,7 @@
}
if (Mix_OpenAudio(48000, AUDIO_S16SYS, 2, 2048) < 0) {
- ERROR("%s: Couldn't open audio device", __FUNCTION__);
+ ERROR("%s: Couldn't open audio device: %s", __FUNCTION__, SDL_GetError());
}
Mix_AllocateChannels(SND_MAX_SAMPLES);
@@ -0,0 +1,181 @@
--- a/src/MacSrc/SDLSound.c
+++ b/src/MacSrc/SDLSound.c
@@ -19,24 +19,6 @@
// Startup the sound system
- SDL_AudioSpec spec, obtained;
- spec.freq = 48000;
- spec.format = AUDIO_S16SYS;
- spec.channels = 2;
- spec.samples = 2048;
- spec.callback = AudioStreamCallback;
- spec.userdata = (void *)&cutscene_audiostream;
-
- extern SDL_AudioDeviceID device;
- device = SDL_OpenAudioDevice(NULL, 0, &spec, &obtained, 0);
-
- if (device == 0) {
- ERROR("Could not open SDL audio: %s", SDL_GetError());
- } else {
- INFO("Opened Music Stream, deviceID %d, freq %d, size %d, format %d, channels %d, samples %d", device,
- obtained.freq, obtained.size, obtained.format, obtained.channels, obtained.samples);
- }
-
if (Mix_Init(MIX_INIT_MP3) < 0) {
ERROR("%s: Init failed", __FUNCTION__);
}
@@ -50,10 +32,18 @@
Mix_HookMusic(MusicCallback, (void *)&MusicDev);
Mix_VolumeMusic(MIX_MAX_VOLUME); // use max volume for music stream
+ // Cutscene/audiolog playback (AudioStreamCallback, see cutsloop.c) used to
+ // run through its own SDL_OpenAudioDevice() device, separate from this
+ // one - SDL only ever allows one open non-capture device on Android's
+ // audio backends, so that second open always failed with "Audio device
+ // already open" and both SFX and MIDI music (both routed through this
+ // Mix_OpenAudio device) silently never played. Mixed into this device's
+ // post-mix stage instead, so there is only ever one device open.
+ Mix_SetPostMix(AudioStreamCallback, (void *)&cutscene_audiostream);
+
InitReadXMI();
atexit(Mix_CloseAudio);
- atexit(SDL_CloseAudio);
return OK;
}
--- a/src/MacSrc/Shock.c
+++ b/src/MacSrc/Shock.c
@@ -60,8 +60,6 @@
SDL_Palette *sdlPalette;
SDL_Renderer *renderer;
-SDL_AudioDeviceID device;
-
int num_args;
char **arg_values;
--- a/src/GameSrc/cutsloop.c
+++ b/src/GameSrc/cutsloop.c
@@ -83,15 +83,25 @@
extern char FrnSubtitle[256];
extern char GerSubtitle[256];
-extern SDL_AudioDeviceID device;
-
-
+// Runs as SDL_mixer's post-mix hook (see snd_start_digital() in
+// SDLSound.c) rather than a dedicated SDL audio device's callback, so
+// SFX/MIDI music sharing the same device are already mixed into `stream`
+// by the time this runs - mix in rather than overwrite, so they aren't
+// silenced whenever a cutscene or audiolog is playing.
void AudioStreamCallback(void *userdata, unsigned char *stream, int len)
{
+ static Uint8 mixbuf[MOVIE_DEFAULT_BLOCKLEN * 4];
SDL_AudioStream *as = *(SDL_AudioStream **)userdata;
- if (as != NULL && SDL_AudioStreamAvailable(as) > 0)
- SDL_AudioStreamGet(as, stream, len);
+ if (as == NULL || SDL_AudioStreamAvailable(as) <= 0)
+ return;
+
+ if (len > (int)sizeof(mixbuf))
+ len = (int)sizeof(mixbuf);
+
+ int got = SDL_AudioStreamGet(as, mixbuf, len);
+ if (got > 0)
+ SDL_MixAudioFormat(stream, mixbuf, AUDIO_S16SYS, got, SDL_MIX_MAXVOLUME);
}
@@ -153,11 +163,13 @@
if (cutscene_audiostream != NULL)
{
- SDL_PauseAudioDevice(device, 1);
- SDL_Delay(1);
-
+ // AudioStreamCallback (SDL_mixer's post-mix hook) runs continuously on
+ // SDL_mixer's own audio thread and reads this pointer - lock around
+ // freeing it so that thread can't be mid-read when it's freed.
+ SDL_LockAudio();
SDL_FreeAudioStream(cutscene_audiostream);
cutscene_audiostream = NULL;
+ SDL_UnlockAudio();
if (cutscene_audiobuffer)
{
@@ -184,8 +196,6 @@
if (cutscene_audiostream)
{
- SDL_PauseAudioDevice(device, 0);
-
if (cutscene_audiobuffer_size > 0)
{
// === adjust volume in buffer here ===
@@ -325,10 +335,9 @@
if (sfx_on)
{
- SDL_PauseAudioDevice(device, 1);
- SDL_Delay(1);
-
+ SDL_LockAudio();
cutscene_audiostream = SDL_NewAudioStream(AUDIO_U8, 1, fix_int(amovie->a.sampleRate), AUDIO_S16SYS, 2, 48000);
+ SDL_UnlockAudio();
cutscene_audiobuffer_pos = cutscene_audiobuffer;
}
--- a/src/GameSrc/audiolog.c
+++ b/src/GameSrc/audiolog.c
@@ -61,8 +61,6 @@
extern uchar curr_alog_vol;
extern char which_lang;
-extern SDL_AudioDeviceID device;
-
errtype audiolog_init(void) { return OK; }
errtype audiolog_play(int email_id) {
@@ -114,10 +112,9 @@
DEBUG("%s: Playing email", __FUNCTION__);
- SDL_PauseAudioDevice(device, 1);
- SDL_Delay(1);
-
+ SDL_LockAudio();
cutscene_audiostream = SDL_NewAudioStream(AUDIO_U8, 1, fix_int(palog->a.sampleRate), AUDIO_S16SYS, 2, 48000);
+ SDL_UnlockAudio();
audiolog_audiobuffer_pos = audiolog_audiobuffer;
@@ -150,11 +147,14 @@
}
if (cutscene_audiostream != NULL) {
- SDL_PauseAudioDevice(device, 1);
- SDL_Delay(1);
-
+ // AudioStreamCallback (SDL_mixer's post-mix hook, see cutsloop.c)
+ // runs continuously on SDL_mixer's own audio thread and reads this
+ // pointer - lock around freeing it so that thread can't be
+ // mid-read when it's freed.
+ SDL_LockAudio();
SDL_FreeAudioStream(cutscene_audiostream);
cutscene_audiostream = NULL;
+ SDL_UnlockAudio();
if (audiolog_audiobuffer) {
free(audiolog_audiobuffer);
@@ -177,8 +177,6 @@
errtype audiolog_loop_callback(void) {
if (cutscene_audiostream) {
- SDL_PauseAudioDevice(device, 0);
-
if (audiolog_audiobuffer_size > 0) {
int i, vol = curr_alog_vol * 127 / 100; // convert from 0-100 to 0-127
@@ -0,0 +1,17 @@
--- a/src/MusicSrc/MusicDevice.c
+++ b/src/MusicSrc/MusicDevice.c
@@ -569,6 +569,14 @@
// connected
ndev->dev.isOpen = 1;
ndev->dev.outputIndex = outputIndex;
+#else
+ // No native MIDI backend implemented for this platform (e.g. Android) -
+ // report failure so InitDecXMI()'s caller falls back to another device
+ // instead of treating an unopened device as successfully initialized.
+ (void)outputIndex;
+ (void)samplerate;
+ WARN("NativeMidiInit(): native MIDI is not implemented on this platform");
+ return -1;
#endif
// suppress compiler warnings
(void)outputIndex;
@@ -0,0 +1,455 @@
--- a/src/MacSrc/OpenGL.cc
+++ b/src/MacSrc/OpenGL.cc
@@ -391,7 +391,16 @@
}
void opengl_resize(int width, int height) {
+#ifndef __ANDROID__
+ // Skipped on Android - see opengl_swap_and_restore()'s comment below for
+ // why re-asserting an already-current context/surface every call breaks
+ // gl4es's own "current framebuffer" bookkeeping, even though the real
+ // driver binding never actually changes. This turned out to be the
+ // actual source of the persistent per-frame GL_INVALID_OPERATION (1282)
+ // that plagued 3D rendering: this same unconditional call was present at
+ // the top of nearly every function in this file, not just here.
SDL_GL_MakeCurrent(window, context);
+#endif
int logical_width, logical_height;
SDL_RenderGetLogicalSize(renderer, &logical_width, &logical_height);
@@ -443,7 +452,10 @@
}
void opengl_end_frame() {
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
// Done rendering to the frame buffer, reset back to normal
BindFrameBuffer(nullptr);
@@ -470,7 +482,10 @@
static bool nightsight_active() { return WareActive(player_struct.hardwarez_status[HARDWARE_GOGGLE_INFRARED]); }
void opengl_start_frame() {
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
// Start rendering to our frame buffer canvas
BindFrameBuffer(&backupBuffer);
@@ -500,6 +515,130 @@
}
#ifdef __ANDROID__
+// Real per-vertex arrays, not glBegin/glVertexAttrib/glVertex3f immediate
+// mode: glVertexAttrib*() is GLES2's *constant*-attribute API - without an
+// enabled vertex array it sets one value for the whole draw call, not a
+// fresh value per vertex. gl4es's immediate-mode emulation only reproduces
+// desktop GL's per-vertex-capture behavior for attribute 0 (position,
+// driven directly by glVertex3f), not for custom attributes like this
+// shader's texcoords/light. That means every one of this file's
+// glBegin(GL_TRIANGLE_STRIP)-based draws - not just the UI-overlay quad
+// this was first found on, but also opengl_light_tmap() (every textured
+// wall/floor polygon), opengl_bitmap() (sprites) and opengl_draw_poly()
+// (flat/gouraud polygons) via draw_vertex() - draws every vertex with
+// whatever texcoord/light was set for the *last* vertex instead of its
+// own, which is what actually produced flat-colored/untextured world
+// geometry after this patch's first revision only fixed the final
+// screen-composite quad (the one bug this was originally found on).
+//
+// android_imm_begin()/android_imm_vertex()/android_imm_end() below emulate
+// just enough of glBegin(GL_TRIANGLE_STRIP)/glVertexAttrib*()/glVertex3f()
+// immediate mode to replace every such call site on Android, by buffering
+// vertices and flushing them as one real glDrawArrays() call - the engine's
+// other rendering still uses real immediate mode for attribute 0 elsewhere
+// on desktop builds, which depends on it not having an enabled array bound,
+// so android_imm_end() always disables the arrays it enables before
+// returning.
+struct AndroidImmVertex {
+ float x, y, z;
+ float u, v;
+ float light;
+};
+
+// Arbitrarily-sized, but generous: the engine's polygons (room walls/
+// floors, sprites, screen-filling quads) are all small, hand-authored
+// shapes, never anywhere near this many vertices.
+static AndroidImmVertex s_immVerts[64];
+static int s_immVertCount;
+static GLint s_immTcAttrib;
+static GLint s_immLightAttrib;
+
+// tcAttrib < 0 means this draw has no texcoord attribute (flat/gouraud
+// polygons via opengl_draw_poly()) - matches draw_vertex()'s own
+// `tcAttrib >= 0` check below.
+static void android_imm_begin(GLint tcAttrib, GLint lightAttrib) {
+ s_immVertCount = 0;
+ s_immTcAttrib = tcAttrib;
+ s_immLightAttrib = lightAttrib;
+}
+
+static void android_imm_vertex(float x, float y, float z, float u, float v, float light) {
+ if (s_immVertCount >= (int)(sizeof(s_immVerts) / sizeof(s_immVerts[0]))) {
+ WARN("android_imm_vertex: dropping vertex past the %d-vertex limit", s_immVertCount);
+ return;
+ }
+ AndroidImmVertex &vert = s_immVerts[s_immVertCount++];
+ vert.x = x;
+ vert.y = y;
+ vert.z = z;
+ vert.u = u;
+ vert.v = v;
+ vert.light = light;
+}
+
+static void android_imm_end() {
+ if (s_immVertCount < 3)
+ return;
+ glEnableVertexAttribArray(0);
+ if (s_immTcAttrib >= 0)
+ glEnableVertexAttribArray(s_immTcAttrib);
+ glEnableVertexAttribArray(s_immLightAttrib);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(AndroidImmVertex), &s_immVerts[0].x);
+ if (s_immTcAttrib >= 0)
+ glVertexAttribPointer(s_immTcAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(AndroidImmVertex),
+ &s_immVerts[0].u);
+ glVertexAttribPointer(s_immLightAttrib, 1, GL_FLOAT, GL_FALSE, sizeof(AndroidImmVertex),
+ &s_immVerts[0].light);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, s_immVertCount);
+ glDisableVertexAttribArray(0);
+ if (s_immTcAttrib >= 0)
+ glDisableVertexAttribArray(s_immTcAttrib);
+ glDisableVertexAttribArray(s_immLightAttrib);
+}
+
+// Same underlying bug as android_imm_*() above, for opengl_draw_star():
+// opengl_begin_stars()/opengl_draw_star()/opengl_end_stars() draw up to
+// NUM_STARS (rendtool.c) individual GL_POINTS between one begin/end pair,
+// each with its own per-star brightness via glVertexAttrib1f(lightAttrib,
+// ...)/glVertex3f() immediate mode - under gl4es that made every star on
+// screen render at whatever brightness was set for the *last* one. Shaped
+// differently enough from android_imm_*() above (GL_POINTS instead of
+// GL_TRIANGLE_STRIP, far more vertices, no texcoord) to warrant its own
+// small buffer rather than overloading that one.
+static AndroidImmVertex s_starVerts[1000]; // NUM_STARS, GameSrc/rendtool.c
+static int s_starVertCount;
+static GLint s_starLightAttrib;
+
+static void android_stars_begin(GLint lightAttrib) {
+ s_starVertCount = 0;
+ s_starLightAttrib = lightAttrib;
+}
+
+static void android_stars_vertex(float x, float y, float z, float light) {
+ if (s_starVertCount >= (int)(sizeof(s_starVerts) / sizeof(s_starVerts[0]))) {
+ WARN("android_stars_vertex: dropping star past the %d-star limit", s_starVertCount);
+ return;
+ }
+ AndroidImmVertex &vert = s_starVerts[s_starVertCount++];
+ vert.x = x;
+ vert.y = y;
+ vert.z = z;
+ vert.light = light;
+}
+
+static void android_stars_end() {
+ if (s_starVertCount == 0)
+ return;
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(s_starLightAttrib);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(AndroidImmVertex), &s_starVerts[0].x);
+ glVertexAttribPointer(s_starLightAttrib, 1, GL_FLOAT, GL_FALSE, sizeof(AndroidImmVertex),
+ &s_starVerts[0].light);
+ glDrawArrays(GL_POINTS, 0, s_starVertCount);
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(s_starLightAttrib);
+}
+
// Shared by opengl_swap_and_restore()'s UI-overlay blit and
// android_composite_software_frame() below - draws an SDL_Surface as a
// fullscreen textured quad via gl4es. SDL's own renderer can't be used
@@ -537,42 +676,15 @@
set_blend_mode(blend);
- // Real per-vertex arrays, not glBegin/glVertexAttrib/glVertex3f
- // immediate mode: glVertexAttrib*() is GLES2's *constant*-attribute
- // API - without an enabled vertex array it sets one value for the
- // whole draw call, not a fresh value per vertex. gl4es's immediate-mode
- // emulation only reproduces desktop GL's per-vertex-capture behavior
- // for attribute 0 (position, driven directly by glVertex3f), not for
- // custom attributes like this shader's texcoords/light.
- //
// V is flipped (1 at the bottom, 0 at the top): GL texture v=0
// addresses the first row of data passed to glTexImage2D, but uiRgba
// (an SDL surface) stores its rows top-down.
- struct QuadVertex {
- float x, y, z;
- float u, v;
- float light;
- };
- static const QuadVertex quadVerts[4] = {
- {1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f},
- {1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
- {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- };
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(tcAttrib);
- glEnableVertexAttribArray(lightAttrib);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QuadVertex), &quadVerts[0].x);
- glVertexAttribPointer(tcAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(QuadVertex), &quadVerts[0].u);
- glVertexAttribPointer(lightAttrib, 1, GL_FLOAT, GL_FALSE, sizeof(QuadVertex),
- &quadVerts[0].light);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- // The engine's other rendering uses glBegin/glVertexAttrib/glVertex3f
- // immediate mode for attribute 0, which depends on it not having an
- // enabled array bound.
- glDisableVertexAttribArray(0);
- glDisableVertexAttribArray(tcAttrib);
- glDisableVertexAttribArray(lightAttrib);
+ android_imm_begin(tcAttrib, lightAttrib);
+ android_imm_vertex(1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f);
+ android_imm_vertex(1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+ android_imm_vertex(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+ android_imm_vertex(-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+ android_imm_end();
// glFinish(), not glFlush(): xr_swapchain_release() (called by our
// caller right after this returns) hands the image to the OpenXR
// runtime for cross-process consumption, which requires the GPU write
@@ -642,6 +754,16 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#ifdef __ANDROID__
+ // Real per-vertex arrays, not glBegin/glVertexAttrib/glVertex3f
+ // immediate mode - see android_imm_begin()'s comment above for why.
+ android_imm_begin(tcAttrib, lightAttrib);
+ android_imm_vertex(1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+ android_imm_vertex(1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f);
+ android_imm_vertex(-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+ android_imm_vertex(-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+ android_imm_end();
+#else
glBegin(GL_TRIANGLE_STRIP);
glVertexAttrib2f(tcAttrib, 1.0f, 0.0f);
glVertexAttrib1f(lightAttrib, 1.0f);
@@ -656,6 +778,7 @@
glVertexAttrib1f(lightAttrib, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();
+#endif
// Finish drawing the 3d view
glFlush();
@@ -709,7 +832,10 @@
render_width = width;
render_height = height;
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
int lw, lh;
SDL_RenderGetLogicalSize(renderer, &lw, &lh);
@@ -729,7 +855,10 @@
}
static bool opengl_cache_texture(CachedTexture toCache, grs_bitmap *bm) {
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
// GL_UNPACK_ROW_LENGTH must describe the buffer actually passed to
// glTexImage2D() below (toCache.converted->pixels, a separately
@@ -771,7 +900,10 @@
DEBUG("Clearing OpenGL texture cache.");
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
for (auto iter = texturesByBitsPtr.begin(); iter != texturesByBitsPtr.end();) {
// don't free locked surfaces
@@ -896,10 +1028,16 @@
light = 1.0f - (clut - grd_screen->ltab) / 4096.0f;
}
+#ifdef __ANDROID__
+ (void)tcAttrib; // captured by android_imm_begin() instead - see its comment above
+ android_imm_vertex(vertex.x / 65536.0f, vertex.y / 65536.0f, -vertex.z / 65536.0f,
+ vertex.uv.u / 256.0f, vertex.uv.v / 256.0f, light);
+#else
if (tcAttrib >= 0)
glVertexAttrib2f(tcAttrib, vertex.uv.u / 256.0, vertex.uv.v / 256.0);
glVertexAttrib1f(lightAttrib, light);
glVertex3f(vertex.x / 65536.0f, vertex.y / 65536.0f, -vertex.z / 65536.0f);
+#endif
}
int opengl_draw_tmap(int n, g3s_phandle *vp, grs_bitmap *bm) { return opengl_light_tmap(n, vp, bm); }
@@ -910,7 +1048,10 @@
return CLIP_ALL;
}
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
set_blend_mode(bm->flags & BMF_TRANS);
glUseProgram(textureShaderProgram.shaderProgram);
@@ -928,13 +1069,21 @@
glUniformMatrix4fv(textureShaderProgram.uniView, 1, false, ViewMatrix);
glUniformMatrix4fv(textureShaderProgram.uniProj, 1, false, ProjectionMatrix);
+#ifdef __ANDROID__
+ android_imm_begin(tcAttrib, lightAttrib);
+#else
glBegin(GL_TRIANGLE_STRIP);
+#endif
draw_vertex(*(vp[1]), tcAttrib, lightAttrib);
draw_vertex(*(vp[0]), tcAttrib, lightAttrib);
draw_vertex(*(vp[2]), tcAttrib, lightAttrib);
if (n > 3)
draw_vertex(*(vp[3]), tcAttrib, lightAttrib);
+#ifdef __ANDROID__
+ android_imm_end();
+#else
glEnd();
+#endif
return CLIP_NONE;
}
@@ -949,7 +1098,10 @@
return CLIP_ALL;
}
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
set_blend_mode(bm->flags & BMF_TRANS);
glUseProgram(textureShaderProgram.shaderProgram);
@@ -976,6 +1128,14 @@
glUniform1i(textureShaderProgram.uniMutant, (bm->type == BMT_TLUC8) || (bm->flags == BMF_TLUC8));
+#ifdef __ANDROID__
+ android_imm_begin(tcAttrib, lightAttrib);
+ android_imm_vertex(convx(vpl[1]->x), convy(vpl[1]->y), 0.0f, 1.0f, 0.0f, light);
+ android_imm_vertex(convx(vpl[0]->x), convy(vpl[0]->y), 0.0f, 0.0f, 0.0f, light);
+ android_imm_vertex(convx(vpl[2]->x), convy(vpl[2]->y), 0.0f, 1.0f, 1.0f, light);
+ android_imm_vertex(convx(vpl[3]->x), convy(vpl[3]->y), 0.0f, 0.0f, 1.0f, light);
+ android_imm_end();
+#else
glBegin(GL_TRIANGLE_STRIP);
glVertexAttrib2f(tcAttrib, 1.0f, 0.0f);
glVertexAttrib1f(lightAttrib, light);
@@ -990,6 +1150,7 @@
glVertexAttrib1f(lightAttrib, light);
glVertex3f(convx(vpl[3]->x), convy(vpl[3]->y), 0.0f);
glEnd();
+#endif
glUniform1i(textureShaderProgram.uniMutant, false);
@@ -1007,7 +1168,10 @@
return CLIP_ALL;
}
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
glUseProgram(colorShaderProgram.shaderProgram);
glUniformMatrix4fv(colorShaderProgram.uniView, 1, false, ViewMatrix);
@@ -1064,7 +1228,11 @@
GLint lightAttrib = colorShaderProgram.lightAttrib;
long a = 0, b = n_verts - 1;
+#ifdef __ANDROID__
+ android_imm_begin(-1, lightAttrib);
+#else
glBegin(GL_TRIANGLE_STRIP);
+#endif
while (true) {
draw_vertex(*(p[a]), -1, lightAttrib);
if (a++ == b)
@@ -1073,7 +1241,11 @@
if (b-- == a)
break;
}
+#ifdef __ANDROID__
+ android_imm_end();
+#else
glEnd();
+#endif
return CLIP_NONE;
}
@@ -1085,7 +1257,10 @@
}
void opengl_begin_stars() {
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
+#endif
// Bind the star shader before setting the point size: on Android,
// questshock_glPointSize() (see the __ANDROID__ block above) needs
@@ -1108,11 +1283,19 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+#ifdef __ANDROID__
+ android_stars_begin(starShaderProgram.lightAttrib);
+#else
glBegin(GL_POINTS);
+#endif
}
void opengl_end_stars() {
+#ifdef __ANDROID__
+ android_stars_end();
+#else
glEnd();
+#endif
// Turn off the stencil test and blending
opengl_set_stencil(0x00);
@@ -1120,9 +1303,11 @@
}
int opengl_draw_star(fix star_x, fix star_y, int c, bool anti_alias) {
+#ifndef __ANDROID__
+ // See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
-
GLint lightAttrib = starShaderProgram.lightAttrib;
+#endif
float x = fix_float(star_x);
float y = fix_float(star_y);
@@ -1142,8 +1327,12 @@
int color = (std_color_base + std_color_range - 1 - c);
color = (255 * color) / (std_color_range + 1);
+#ifdef __ANDROID__
+ android_stars_vertex(x, y, -0.25f, color / 255.0f);
+#else
glVertexAttrib1f(lightAttrib, color / 255.0f);
glVertex3f(x, y, -0.25f);
+#endif
return CLIP_NONE;
}
@@ -0,0 +1,45 @@
--- a/src/GameSrc/frsetup.c
+++ b/src/GameSrc/frsetup.c
@@ -635,7 +635,27 @@
uchar old_cam_type;
int detail;
+#ifdef __ANDROID__
+ // should_opengl_swap() (unlike use_opengl(), see its own
+ // FR_PICKUPM_MASK|FR_HACKCAM_MASK exclusion just below and the
+ // matching one used for the STEREO_SUPPORT path in fr_send_view()
+ // below) doesn't know which _fr context is currently being prepared -
+ // it's a frame-level check, also used by Shock.c's SDLDraw() to pick
+ // the frame's overall compositing path. render_hack_cameras() (see
+ // render.c) calls fr_rend() - and so this function - a second time per
+ // real frame for each active hack-camera monitor, rendering into a
+ // private software (FR_DOUBLEB_MASK) canvas rather than the actual
+ // GL-backed screen. Without this exclusion, opengl_start_frame() runs
+ // again mid-frame for that render even though its own polygon draw
+ // calls correctly stay on the software path (use_opengl() already
+ // excludes them) - re-entering the OpenXR swapchain/framebuffer setup
+ // a second time before the first call's frame has ended. Not known to
+ // be exercised on desktop (no OpenXR swapchain there), so this fix is
+ // kept Android-only rather than changing should_opengl_swap() itself.
+ if (should_opengl_swap() && !(_fr_curflags & (FR_PICKUPM_MASK | FR_HACKCAM_MASK))) {
+#else
if(should_opengl_swap()) {
+#endif
opengl_start_frame();
}
@@ -823,7 +843,14 @@
g3_end_frame();
+#ifdef __ANDROID__
+ // Mirrors the same fix in fr_start_view() above - see its comment.
+ // opengl_start_frame()/opengl_end_frame() must stay paired per real
+ // GL frame, so this exclusion has to match that one exactly.
+ if (should_opengl_swap() && !(_fr_curflags & (FR_PICKUPM_MASK | FR_HACKCAM_MASK))) {
+#else
if(should_opengl_swap()) {
+#endif
opengl_end_frame();
}
@@ -0,0 +1,34 @@
--- a/src/MacSrc/OpenGL.cc
+++ b/src/MacSrc/OpenGL.cc
@@ -455,10 +455,30 @@
#ifndef __ANDROID__
// See opengl_resize()'s comment above.
SDL_GL_MakeCurrent(window, context);
-#endif
// Done rendering to the frame buffer, reset back to normal
BindFrameBuffer(nullptr);
+#else
+ // BindFrameBuffer(nullptr) (glBindFramebuffer/glBindRenderbuffer to id
+ // 0) means "the real window surface" - on desktop that's SDL's actual
+ // GL window, but this app's real presentation target is never that
+ // SDLSurface's own EGL surface at all - it's the OpenXR swapchain's
+ // per-image FBOs, set up separately in xr_swapchain.c. Whatever
+ // framebuffer/renderbuffer 0 actually resolves to for gl4es in this
+ // configuration, binding it here reliably left gl4es reporting a
+ // persistent GL_INVALID_OPERATION (1282) - confirmed by bisecting
+ // through this whole render path with per-call checkpoints, all clean
+ // right up until "after opengl_end_frame", the one immediately after
+ // this exact call.
+ //
+ // The bind is also functionally dead on Android regardless of that:
+ // by the time anything next draws, Shock.c's SDLDraw() has already
+ // run xr_frame_begin() -> xr_swapchain_acquire(), which rebinds to
+ // that frame's real swapchain FBO before opengl_swap_and_restore()
+ // (the only thing that draws before the next opengl_start_frame()'s
+ // own BindFrameBuffer(&backupBuffer)) runs - so skipping it changes
+ // nothing about what actually gets rendered where.
+#endif
palette_dirty = false;
}
@@ -0,0 +1,54 @@
--- a/src/MacSrc/Shock.c
+++ b/src/MacSrc/Shock.c
@@ -31,6 +31,7 @@
#include <SDL.h>
#ifdef __ANDROID__
+#include "qs_config.h"
#include "xr_session.h"
#endif
@@ -109,6 +110,15 @@
LoadHotkeyKeybinds();
LoadMoveKeybinds();
+#ifdef __ANDROID__
+ // Persistent, human-editable JSON config (questshock.config.json) - see
+ // qs_config.h/CONFIG.md. After prefs.txt is loaded (above) so this file
+ // can override it, before init_all() below so there's no live-vs-
+ // restart distinction to worry about yet - every field just takes full
+ // effect as part of this same startup.
+ qs_config_load_startup();
+#endif
+
// Process some startup arguments
bool show_splash = !CheckArgument("-nosplash");
--- a/src/Libraries/INPUT/Source/sdl_events.c
+++ b/src/Libraries/INPUT/Source/sdl_events.c
@@ -29,6 +29,10 @@
#include <SDL.h>
#include <OpenGL.h>
+#ifdef __ANDROID__
+#include "qs_config.h"
+#endif
+
extern SDL_Window *window;
extern SDL_Renderer *renderer;
@@ -481,6 +485,14 @@
SDL_Event ev;
while (SDL_PollEvent(&ev)) {
+#ifdef __ANDROID__
+ // Custom event types qs_config_request_save()/_load() enqueue from
+ // the "Save Configuration"/"Load Configuration" menu buttons (see
+ // qs_config.h) - handled here, on this thread, rather than directly
+ // from those JNI calls (which run on Android's UI thread).
+ if (qs_config_handle_event(&ev))
+ continue;
+#endif
switch (ev.type) {
case SDL_QUIT:
// a bit hacky at this place, but this would allow exiting the game via the window's [x] button
@@ -0,0 +1,30 @@
--- a/src/GameSrc/mainloop.c
+++ b/src/GameSrc/mainloop.c
@@ -57,6 +57,10 @@
#include "tools.h"
#include "wrapper.h"
+#ifdef __ANDROID__
+#include "qs_config.h"
+#endif
+
// how is the game doing, anyway, set to true at end of time
uchar cit_success = FALSE;
@@ -103,6 +107,16 @@
_last_mode = *cmode;
(*exit_modes[_last_mode])();
*cmode = _new_mode;
+#ifdef __ANDROID__
+ // Notifies qs_config.c of every loop-mode transition so it can pick
+ // between the "Initial Screen" and "Game Screen" virtual-screen
+ // presets - see qs_config.h/CONFIG.md. Called synchronously, directly,
+ // on this thread (mainloop()'s own) - unlike the UI-thread-triggered
+ // config actions elsewhere in qs_config.c, this doesn't need the
+ // cross-thread SDL-event dance since it already originates on the
+ // right thread.
+ qs_screen_profile_notify_loop_mode(*cmode);
+#endif
_static_change = 0;
if (*cmode >= 0)
(*enter_modes[*cmode])();
@@ -0,0 +1,42 @@
--- a/src/GameSrc/cutsloop.c
+++ b/src/GameSrc/cutsloop.c
@@ -292,11 +292,38 @@
+#ifdef __ANDROID__
+// The intro (cutscene 0) ships in one file per language - localized
+// voice-over - each holding the same resource id (cutscene_anims[0]), so
+// opening the current language's file instead is all it takes. The death
+// and ending cutscenes only have one version.
+static char *intro_files_by_language[3] =
+{
+ "res/data/svgaintr.res", // English
+ "res/data/svfrintr.res", // French
+ "res/data/svgeintr.res" // German
+};
+
+static int open_cutscene_file(int id)
+{
+ if (id == 0 && which_lang > 0 && which_lang < 3)
+ {
+ int handle = ResOpenFile(intro_files_by_language[(int)which_lang]);
+ if (handle > 0)
+ return handle;
+ // Not installed for this language - fall back to English below.
+ }
+ return ResOpenFile(cutscene_files[id]);
+}
+#else
+#define open_cutscene_file(id) ResOpenFile(cutscene_files[id])
+#endif
+
short play_cutscene(int id, bool show_credits)
{
MacTuneKillCurrentTheme();
- cutscene_filehandle = ResOpenFile(cutscene_files[id]);
+ cutscene_filehandle = open_cutscene_file(id);
if (cutscene_filehandle <= 0) {
// If we failed to play the cutscene, go to setup / credits.
_new_mode = SETUP_LOOP;
@@ -0,0 +1,13 @@
--- a/src/GameSrc/mouselook.c
+++ b/src/GameSrc/mouselook.c
@@ -121,3 +121,10 @@
get_mouselook_vel(&mvelx, &mvely);
}
}
+
+#ifdef __ANDROID__
+// Whether the player is currently in cyberspace; read by the Android
+// controller input code (android/app/src/main/cpp/xr_input.c) to switch
+// between the normal and cyberspace action sets.
+int qs_in_cyberspace(void) { return global_fullmap != NULL && global_fullmap->cyber; }
+#endif
@@ -0,0 +1,110 @@
--- a/src/GameSrc/movekeys.c
+++ b/src/GameSrc/movekeys.c
@@ -44,6 +44,12 @@
extern bool gKeypadOverride;
uchar parse_motion_key(ushort code, short *cnum, short *cval);
+#ifdef __ANDROID__
+// Set every frame by android/app/src/main/cpp/xr_input.c.
+float qs_cyber_pitch_scale = 1.0f;
+float qs_cyber_bank_scale = 1.0f;
+#endif
+
uchar parse_motion_key_cyber(ushort code, short *cnum, short *cval);
void init_motion_polling(void);
@@ -173,6 +179,20 @@
*cnum = -1;
*cval = 0;
+#ifdef __ANDROID__
+ // Pitch and bank strength, scaled by the controller thumbstick's
+ // deflection (see android/app/src/main/cpp/xr_input.c); 1.0 for a key.
+ short pitchMax = (short)(CONTROL_MAX_VAL * qs_cyber_pitch_scale + 0.5f);
+ short bankMax = (short)(CONTROL_MAX_VAL * qs_cyber_bank_scale + 0.5f);
+ if (pitchMax < 1)
+ pitchMax = 1;
+ if (bankMax < 1)
+ bankMax = 1;
+#else
+ short pitchMax = CONTROL_MAX_VAL;
+ short bankMax = CONTROL_MAX_VAL;
+#endif
+
while (MoveCyberKeybinds[i].code != 255) {
if (code == MoveCyberKeybinds[i].code) {
move = MoveCyberKeybinds[i].move;
@@ -189,22 +209,22 @@
case M_CLIMB:
*cnum = CONTROL_YVEL;
- *cval = -CONTROL_MAX_VAL;
+ *cval = -pitchMax;
break;
case M_BANKLEFT:
*cnum = CONTROL_XYROT;
- *cval = -CONTROL_MAX_VAL;
+ *cval = -bankMax;
break;
case M_BANKRIGHT:
*cnum = CONTROL_XYROT;
- *cval = CONTROL_MAX_VAL;
+ *cval = bankMax;
break;
case M_DIVE:
*cnum = CONTROL_YVEL;
- *cval = CONTROL_MAX_VAL;
+ *cval = pitchMax;
break;
case M_ROLLRIGHT:
@@ -219,38 +239,38 @@
case M_CLIMBLEFT:
*cnum = CONTROL_YVEL;
- *cval = -CONTROL_MAX_VAL;
+ *cval = -pitchMax;
if (abs(poll_controls[*cnum]) < abs(*cval))
poll_controls[*cnum] = *cval;
*cnum = CONTROL_XYROT;
- *cval = -CONTROL_MAX_VAL;
+ *cval = -bankMax;
break;
case M_CLIMBRIGHT:
*cnum = CONTROL_YVEL;
- *cval = -CONTROL_MAX_VAL;
+ *cval = -pitchMax;
if (abs(poll_controls[*cnum]) < abs(*cval))
poll_controls[*cnum] = *cval;
*cnum = CONTROL_XYROT;
- *cval = CONTROL_MAX_VAL;
+ *cval = bankMax;
break;
case M_DIVERIGHT:
*cnum = CONTROL_YVEL;
- *cval = CONTROL_MAX_VAL;
+ *cval = pitchMax;
if (abs(poll_controls[*cnum]) < abs(*cval))
poll_controls[*cnum] = *cval;
*cnum = CONTROL_XYROT;
- *cval = CONTROL_MAX_VAL;
+ *cval = bankMax;
break;
case M_DIVELEFT:
*cnum = CONTROL_YVEL;
- *cval = CONTROL_MAX_VAL;
+ *cval = pitchMax;
if (abs(poll_controls[*cnum]) < abs(*cval))
poll_controls[*cnum] = *cval;
*cnum = CONTROL_XYROT;
- *cval = -CONTROL_MAX_VAL;
+ *cval = -bankMax;
break;
default:
// Unhandled movement. What I gonna do?
@@ -0,0 +1,74 @@
--- a/src/GameSrc/hkeyfunc.c
+++ b/src/GameSrc/hkeyfunc.c
@@ -1465,3 +1465,71 @@
#pragma enable_message(202)
#endif // NOT_YET
+
+#ifdef __ANDROID__
+// Tops up parts of the player's state; android/app/src/main/cpp/qs_config.c
+// calls it once per frame with the "unlimited" cheats that are switched on.
+// `what` is a bitmask: 1 health, 2 energy, 4 ammo, 8 items (the same values as
+// QS_CHEAT_MASK_* in qs_config.c). Only conventional guns use ammo: beam and
+// melee weapons keep heat in the same field, so they are left alone (beams draw
+// on energy). Spare ammo clips, grenades and drugs are only refilled for kinds
+// the player already holds, so the cheat never creates items.
+void qs_cheat_refill(int what) {
+ const int kAmmoFloor = 99;
+ const int kItemFloor = 99;
+ uchar vitalsChanged = FALSE;
+ uchar inventoryChanged = FALSE;
+
+ if (player_struct.dead)
+ return;
+ if ((what & 1) && player_struct.hit_points < PLAYER_MAX_HP) {
+ player_struct.hit_points = PLAYER_MAX_HP;
+ vitalsChanged = TRUE;
+ }
+ if ((what & 1) && player_struct.cspace_hp < PLAYER_MAX_HP) {
+ player_struct.cspace_hp = PLAYER_MAX_HP;
+ vitalsChanged = TRUE;
+ }
+ if ((what & 2) && player_struct.energy < 255) {
+ player_struct.energy = 255;
+ vitalsChanged = TRUE;
+ }
+ if (vitalsChanged)
+ chg_set_flg(VITALS_UPDATE);
+
+ if (what & 4) {
+ for (int i = 0; i < NUM_WEAPON_SLOTS; i++) {
+ weapon_slot *slot = &player_struct.weapons[i];
+ if (slot->type != EMPTY_WEAPON_SLOT && slot->type <= GUN_SUBCLASS_SPECIAL &&
+ slot->ammo < kAmmoFloor) {
+ slot->ammo = kAmmoFloor;
+ inventoryChanged = TRUE;
+ }
+ }
+ for (int i = 0; i < NUM_AMMO_TYPES; i++) {
+ if (player_struct.cartridges[i] > 0 && player_struct.cartridges[i] < kItemFloor) {
+ player_struct.cartridges[i] = kItemFloor;
+ inventoryChanged = TRUE;
+ }
+ }
+ }
+ if (what & 8) {
+ for (int i = 0; i < NUM_GRENADEZ; i++) {
+ if (player_struct.grenades[i] > 0 && player_struct.grenades[i] < kItemFloor) {
+ player_struct.grenades[i] = kItemFloor;
+ inventoryChanged = TRUE;
+ }
+ }
+ for (int i = 0; i < NUM_DRUGZ; i++) {
+ if (player_struct.drugs[i] > 0 && player_struct.drugs[i] < kItemFloor) {
+ player_struct.drugs[i] = kItemFloor;
+ inventoryChanged = TRUE;
+ }
+ }
+ }
+ if (inventoryChanged) {
+ chg_set_flg(INVENTORY_UPDATE);
+ mfd_force_update();
+ }
+}
+#endif
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# Forces a fully fresh native build - works around stageEngine sometimes
# wrongly reporting UP-TO-DATE after android/engine-patches/ or
# android/gl4es-patches/ changes (see gradle_stage_engine_stale_cache memory
# note). Run from anywhere. Needs JAVA_HOME set to a JDK 17+; defaults to
# Android Studio's bundled JDK if found.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
if [ -z "${JAVA_HOME:-}" ]; then
if [ -d /opt/android-studio/jbr ]; then
export JAVA_HOME=/opt/android-studio/jbr
else
echo "JAVA_HOME not set and no JDK found at /opt/android-studio/jbr - export it yourself" >&2
exit 1
fi
fi
./gradlew --stop
rm -rf \
../build/android-engine \
../build/android-gl4es \
../build/android-prebuilt \
app/.cxx \
app/build
echo "Done - next Gradle build/Run will rebuild from scratch."
@@ -0,0 +1,47 @@
diff -ru a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt 2026-07-31 13:25:14.739711912 +0200
+++ b/CMakeLists.txt 2026-07-31 13:25:29.283619378 +0200
@@ -2,11 +2,22 @@
project(gl4es LANGUAGES C)
+# questshock: on Android this project is add_subdirectory()'d straight into
+# the engine's own CMake configure (see android/engine-patches/
+# 02-android-opengl-es.patch), not built standalone - CMAKE_SOURCE_DIR then
+# points at the *outer* project's root, not here, so writing there would
+# scatter build output outside this project entirely. Leaving these unset
+# for Android just falls back to CMake's normal per-target build-tree
+# output, which AGP's own native-build packaging finds regardless of path;
+# link_directories() is also unneeded there since the GL/EGL targets link
+# each other by CMake target name, not by search path.
+if(NOT ANDROID)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
+endif()
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
option(PYRA "Set to ON if targeting an Dragonbox Pyra device" ${PYRA})
diff -ru a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt 2026-07-31 13:25:14.747711861 +0200
+++ b/src/CMakeLists.txt 2026-07-31 13:25:44.043526054 +0200
@@ -220,7 +220,16 @@
target_link_libraries(GL ${log-lib})
endif()
- if(CMAKE_SHARED_LIBRARY_SUFFIX MATCHES ".so")
+ # questshock: on Android, AGP's native-build packaging only bundles a
+ # jniLibs .so whose *filename* literally ends in ".so" (and the dynamic
+ # linker resolves NEEDED entries by embedded SONAME, which CMake derives
+ # from this same filename) - versioning it to "libGL.so.1" like the
+ # desktop build does would need a separate patchelf rename step, which
+ # only build-image's Docker environment could guarantee has this tool.
+ # Skipping the override on Android instead so CMake's own default
+ # SHARED library naming (plain "libGL.so", correct SONAME included)
+ # already comes out right with no extra step.
+ if(CMAKE_SHARED_LIBRARY_SUFFIX MATCHES ".so" AND NOT ANDROID)
set_target_properties(GL PROPERTIES SUFFIX ".so.1")
endif()
install(TARGETS GL
+12
View File
@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: ptitSeb
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: paypal.me/0ptitSeb
+11
View File
@@ -0,0 +1,11 @@
.gdb_history
.vscode/
CMakeFiles/
lib/
Makefile
CMakeCache.txt
CTestTestfile.cmake
cmake_install.cmake
spec/yml/gles-1.1-full.yml
/build/
/tests/*.png
+20
View File
@@ -0,0 +1,20 @@
language: c
sudo: false
dist: buster
compiler:
- gcc
#Build steps
before_script:
- mkdir build
- cd build
- cmake .. -DODROID=1
script:
- make
#after_script:
# - sudo apt-get install apitrace-gl-frontend=5\* imagemagick xvfb -y
# - cd ../tests
# - xvfb-run ./tests.sh ../lib
+104
View File
@@ -0,0 +1,104 @@
LOCAL_PATH := $(call my-dir)
###########################
#
# GL static library
#
###########################
include $(CLEAR_VARS)
LOCAL_MODULE := GL
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) -DBCMHOST
LOCAL_SRC_FILES := \
src/gl/arbconverter.c \
src/gl/arbgenerator.c \
src/gl/arbhelper.c \
src/gl/arbparser.c \
src/gl/array.c \
src/gl/blend.c \
src/gl/blit.c \
src/gl/buffers.c \
src/gl/build_info.c \
src/gl/debug.c \
src/gl/decompress.c \
src/gl/depth.c \
src/gl/directstate.c \
src/gl/drawing.c \
src/gl/enable.c \
src/gl/envvars.c \
src/gl/eval.c \
src/gl/face.c \
src/gl/fog.c \
src/gl/fpe.c \
src/gl/fpe_cache.c \
src/gl/fpe_shader.c \
src/gl/framebuffers.c \
src/gl/gl_lookup.c \
src/gl/getter.c \
src/gl/gl4es.c \
src/gl/glstate.c \
src/gl/hint.c \
src/gl/init.c \
src/gl/light.c \
src/gl/line.c \
src/gl/list.c \
src/gl/listdraw.c \
src/gl/listrl.c \
src/gl/loader.c \
src/gl/logs.c \
src/gl/matrix.c \
src/gl/matvec.c \
src/gl/oldprogram.c \
src/gl/pixel.c \
src/gl/planes.c \
src/gl/pointsprite.c \
src/gl/preproc.c \
src/gl/program.c \
src/gl/queries.c \
src/gl/raster.c \
src/gl/render.c \
src/gl/samplers.c \
src/gl/shader.c \
src/gl/shaderconv.c \
src/gl/shader_hacks.c \
src/gl/stack.c \
src/gl/stencil.c \
src/gl/string_utils.c \
src/gl/stubs.c \
src/gl/texenv.c \
src/gl/texgen.c \
src/gl/texture.c \
src/gl/texture_compressed.c \
src/gl/texture_params.c \
src/gl/texture_read.c \
src/gl/texture_3d.c \
src/gl/uniform.c \
src/gl/vertexattrib.c \
src/gl/wrap/gl4eswraps.c \
src/gl/wrap/gles.c \
src/gl/wrap/glstub.c \
src/gl/math/matheval.c \
src/glx/hardext.c \
src/glx/glx.c \
src/glx/lookup.c \
src/glx/gbm.c \
src/glx/streaming.c \
LOCAL_CFLAGS += -g -std=gnu99 -funwind-tables -O3 -fvisibility=hidden -include include/android_debug.h
LOCAL_CFLAGS += -DNOX11
LOCAL_CFLAGS += -DNO_GBM
#LOCAL_CFLAGS += -DNO_INIT_CONSTRUCTOR
LOCAL_CFLAGS += -DDEFAULT_ES=2
//TODO: maybe temporary?
LOCAL_CFLAGS += -Wno-typedef-redefinition -Wno-dangling-else
LOCAL_LDLIBS := -llog
#building as a static lib
LOCAL_CFLAGS += -DSTATICLIB
include $(BUILD_STATIC_LIBRARY)
+184
View File
@@ -0,0 +1,184 @@
Version history
----
##### v1.1.6
* Improve glGetError() handling
* Improve LIBGL_FB=3 handling
* Added some ShaderHacks
* Better Renderbuffer handling
* Fixed many issues with VAO and VBO
* Improved ARB shader support
* optimized some format conversion
* Improve mipmap handling
* Improve Android support
* Added sampler handling
* Improve texture format handling
* some fixes to a few matrix computation
* Added support for a new platform: Windows (thx to @yjh-styx)
* Added some more extension to GLES2 backend
##### v1.1.4
* Fixed some regression, and foobillard++ is working fine now
* Set default GL version to 2.1 (instead of 2.0) for GLES2.0 backend
* Added ARB_vertex_program and ARB_fragment_program
* Improved fpe with more compatibility fixes
* Improved Handling of DXTc textures
* Improve handling of partially mipmap'd textures
* Added PYRA Profile
* Added support for Texture LOD access in Fragment Shaders
* Increased maximum Texture Unit support to 16 (from 8)
* Added support for program without Vertex Shader
* Some fixes for program that switch GLX Context frequently.
* Fixes and improvements in fpe_shaders (less array access)
* Added support for Clipping Plane in custom shaders (help OpenMW water reflection)
* Added support for multiple FBO attachement (if hardware support it)
##### v1.1.2
* Improved a bit the merger (wich merge subsequent `glBegin(...)`/`glEnd()`) efficiency
* Removed LIBGL_BEGINEND=2 (that was not working correctly, and it complexify the code too much)
* Added some Direct Access function (from EXT_direct_access)
* Fixes and Improvements on depth (and depth_Stencil) Texture handling
* Handling of GL_BGRA color size in VA (for HumandRessourceMachine)
* Some fixes to fpe_shader (for Neverwinter Night)
* Rework of Header structure (from @rajdakin)
* Better test, using "make test" (from @rajdakin, still using apitrace for replay)
* Added PSA: Precompiled Shader Archive, to store (and fast retrieve) FPE shader (and avoid some pauses when complex FPE shaders are computed)
* Numerous optimization and changes in Batch mode.
* Fixes to GL_BGRA handling
* Improvement in texture format handling, to limit number of conversions
* Added handling of VBO. Real VBO are used (in GLES2+ only) for GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
* Added VBO when processing glList (only in GLES2+)
* Added a few more GL3.x functions (like glTexStorage). No real GL3.0 support yet
* Can now use GBM/DRM, using LIBGL_FB=4. Still WIP, but now it start to work (thanks to @icecream95)
* Preliminary Emscripten support (thanks to @CecilHarvey)
* AmigaOS4 support is now live (thanks to @kas1e)
* Some fixes to texture handling, when uploading (or modifying) a texture in a multi-texture context
* Small optimization some of the FPE Generated program (many fragment shaders that do texturing)
* Added support to glGetProgramBinary extension
* GL4ES has a logo now :) !
* AmigaOS4 is now fully supported! And SDK (with libs and samples) is available on os4depot
* Emscripten is now supported! A first example of a game using gl4es in a web build can be found [here](http://ptitseb.github.io/stuntcarremake/) with [Stunt Car Remake](https://github.com/ptitSeb/stuntcarremake)
##### v1.1.0
* Default backend is now GLES2 (but not on Pandora, still GLES1.1 for compatibility reasons)
* Added LIBGL_SHADERNOGLES to remove the GLES part of shaders (if any).
* Various RPi improvements, mainly in the context creation.
* Various AmigaOS4 improvement and workaround (but still in a beta state)
* Various improvement in GLX function, with a more accurate way to emulate GLXFBConfig
* Improved the way eglSurface are created in glx.c, to avoid try to create 2 on the same window (EGL doesn't allow that)
* Added LIBGL_GLXRECYCLE to not delete eglSurface and recycle them
* Added tracking of Framebuffers Object and Renderbuffers Objects
* Added (real) support for Float and Half-float Texture (including has attachement to FBO, emulating it if not supported in Hardware)
* Added support for Depth Stencil texture when attached to an FBO
* Added LIBGL_FBO=WxH for all platform
* Fixed some issue when resized textures attached to an FBO
* Added LIBGL_NODEPTHTEX to avoid using Depth Texture when available (using renderbuffer can be faster)
* Added support for Depth Texture when attached to an FBO (if supported by Hardware)
* Fixes some isue with blitting of FBO when size of Main Framebuffer changed
* Added option LIBGL_LOGSHADERERROR to get Shader compiler log and error
* Added support for (emulated) Hardware Instancing
* Added support for GL_ARB_draw_elements_base_vertex
##### v1.0.8
* Fixes and improvments to avoid unnecessary GLES state changes
* Fixes some memory issues with glBitmap
* Fixes to FPE (when using multitexture and GL_COMBINE)
* Added some TexEnv extension for GLES2 backend
* Fixes to Batch / Merger on GL_POLYGON primitives
* Fixes to LineStipple
* Pandora only: Fixed use of Texture Streaming on GLES2 backend
##### v1.0.6
* Factorised "Blit" function, and implemented `glBlitFramebuffer`
* Optimized `glBitmap`
* Added (limited) direct support to `GL_UNSIGNED_INT` for `glDrawElements` for hardware that support it
* Improved (a lot) `glBegin`/`glEnd` merger
* Added Anisotropic filtering support, for hardware that support it.
* Changed `LIBGL_BATCH`. It will now try to merge small (parametrable) subsequent `glDrawXXXX`
* Changed (simplified) the way texture "0" is handled
* Improvement to `glDrawArrays` and `glDrawElement`, with less copy of data
* WIP AmigaOS4 support (and BigEndian architecture)
* Improved NPOT support for "Limited NPOT" hardware
* Lots of FPE fixes
* Improve the way multi glX Context are handled
* Added basic pre-proc (only handle comments for now)
* Small optimization on when using `glDrawArrays` with GL_QUADS
* Improvement to GL_RENDER
* Improvement to line stipple
* Improvement to glPolygonMode(GL_LINE)
##### v1.0.4
* FPE is now usable. Most function are implemented
* ShaderConv in now usable. Basic GL 2 shader are supported
* Refactored Texture cache and handling, for better Tex1D/Tex3D/TexRectangle handling
##### v1.0.2
* Added GLES2 backend infrastructure
* Begin GLES2 backend
* Infrastructure for FPE (Fixed Pipeline Emulator)
* Basic and Crude Shader convertor
* Added blit function for GLES2 backend
* Added some OpenGL Builtin VAs and Uniforms
##### 1.0.0
* Removed old ES2 defines (ES2 will be dynamic later)
##### 0.9.8
* Added TravisCI build on github
* Added some optimization when to discard call to glBindTexture if useless (same texture) between 2 glBegin/glEnd blocks
* Stubbed glGet with GL_DRAW_BUFFER
* Improvement to Raster operations
* Factorised Blit function (only 1 function for that now)
* Tracking ShadeModel
* Tracking TexEnv
##### 0.9.7
* Tracking Clip Planes
* Refactor Blitting function, and use glDrawTex extension if present
* Restructured README and split in several files
* Some improvments and fixes to LIBGL_BEGINEND=2 mode
* Some improvments to some LIBGL_SHRINK mode
* Proper support for DOT3 extension
* Some fixes to Read/Draw Buffer handling
* Some fix with the PixMap glX context creation
##### 0.9.6
* Some fixes in GL_TEXTURE_RECTANGLE_ARB handling
* Some other fixes in texture handling (unpack and glList related)
* Some fix with the PBuffer glX context creation
* Tracking of glFog
* Exposed glBlendEquation if supported
* New LIBGL_AVOID16BITS parameter to prefer 32bits texture (useful on ODroid)
* Some optimisations in texture conversion
##### 0.9.5
* Added some optimizations for sequential glBegin/glEnd blocks, with a switch to control them
* Fixed many issue with Lights introduced with 0.9.4
* Fixed Android build introduced with 0.9.4
##### 0.9.4
* Fixed some extended functions (like glBlendFuncSeparate) not working inside list (fixing some issues with Batch mode)
* Added back GL_TEXTURE_RECTANGLE_ARB handling (and using npot texture, even limited, if available)
* Added tracking of Lights and Materials
* Fixed (Added in fact) support for Multisampling on the GLX Context creation (a bit hacky, but seems to works)
* Added LIBGL_NODOWNSAMPLING and associated Hint
* Try to implement some caching on VAO to avoid some memcpy in renderlist (with a way to disable it just in case)
##### 0.9.3
* Added support for Cube Mapping (with hardware support)
* Improved Texture state tracking
* Added LIBGL_NOTEXMAT env. var. switch for Texture Matrix handling
* Added GL_EXT_vertex_array_bgra (and NEONinzed some loop)
* Finished GL_EXT_direct_state_access extension
* Mangled glX function (to be able to use apitrace to capture GL frames)
* Return some values in glXQueryServerString, coherent with glXGetClientString
##### 0.9.2
* All matrix are tracked now
* Texture Matrix are 100% handled by gl4es. GLES Hardware keep an Identity matrix (TexCoord are transformed if needed). This allows a better handling of NPOT texture on hardware that doesn't support Full NPOT (fixed movies being horizontally shifted in openmw with LIBGL_NPOT=1 for example)
##### 0.9.1
* Added gl4es specifics glHint capabilities. If the extension GL_GL4ES_hint is present, than a few Hint are accessible. Look in include/gl4eshint.h for the list.
##### 0.9.0
* New name: gl4es
+300
View File
@@ -0,0 +1,300 @@
cmake_minimum_required(VERSION 2.8.12)
project(gl4es LANGUAGES C)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
option(PYRA "Set to ON if targeting an Dragonbox Pyra device" ${PYRA})
option(BCMHOST "Set to ON if targeting an RPi(2) device" ${BCMHOST})
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
option(GOA_CLONE "Set to ON if targeting GO Advance clones, like RG351p/v, Gameforce Chi, RGB10..." ${GOA_CLONE})
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
option(CHIP "Set to ON if targeting an C.H.I.P. device" ${CHIP})
option(AMIGAOS4 "Set to ON if targeting an AmigaOS4/Warp3D platform (activate NOEGL and NOX11)" ${AMIGAOS4})
option(NOX11 "Set to ON to not use X11 (creation of context has to be done outside gl4es)" ${NOX11})
option(NOEGL "Set to ON to not use EGL (all functions are taken in GLES library)" ${NOEGL})
option(STATICLIB "Set to ON to build a static version of gl4es" ${STATICLIB})
option(GBM "Set to ON to not build GBM interface" ${GBM})
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
option(USE_CLOCK "Set to ON to use clock_gettime instead of gttimeofday for LIBGL_FPS" ${USE_CLOCK})
option(NO_LOADER "disable library loader (useful for static library with NOEGL, NOX11, use include/gl4esinit.h)" ${NO_LOADER})
option(NO_INIT_CONSTRUCTOR "disable automatic initialization (useful for static library, use include/gl4esinit.h)" ${NO_INIT_CONSTRUCTOR})
option(USE_ANDROID_LOG "Set to ON to use Android log instead of stdio" ${USE_ANDROID_LOG})
option(EGL_WRAPPER "Set to ON to build EGL wrapper" ${EGL_WRAPPER})
option(GLX_STUBS "Set to ON to build GLX function stubs" ${GLX_STUBS})
include(CheckSymbolExists)
check_symbol_exists(backtrace "execinfo.h" HAS_BACKTRACE)
if (HAS_BACKTRACE)
add_definitions(-DHAS_BACKTRACE)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "MSYS")
set(NOX11 ON)
set(NO_GBM ON)
set(WIN32_PLATFORM ON)
if(CMAKE_C_COMPILER_ID MATCHES "MSVC" OR "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
set(WIN32_MSVC ON) #msvc or icl or clang-cl
endif()
endif()
# Pandora
if(PANDORA)
add_definitions(-DPANDORA)
add_definitions(-DTEXSTREAM)
add_definitions(-mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -fsingle-precision-constant -ffast-math)
set(NO_GBM ON)
endif()
if((NOT GBM) OR PANDORA)
set(NO_GBM ON)
else()
set(NO_GBM OFF)
endif()
if(NOT DEFAULT_ES)
if(PANDORA)
set(DEFAULT_ES 1)
else()
set(DEFAULT_ES 2)
endif()
endif()
if(STATICLIB)
add_definitions(-DSTATICLIB)
endif(STATICLIB)
# Pyra
if(PYRA)
add_definitions(-DPYRA)
set(USE_CLOCK ON)
#add_definitions(-DTEXSTREAM)
add_definitions(-mcpu=cortex-a15 -mfpu=neon-vfpv4 -mfloat-abi=hard -ftree-vectorize -fsingle-precision-constant -ffast-math)
set(NO_GBM ON)
endif()
# Raspberry PI
if(BCMHOST)
include_directories(/opt/vc/include /opt/vc/include/interface/vcos/pthreads /opt/vc/include/interface/vmcs_host/linux)
link_directories(/opt/vc/lib)
add_definitions(-DBCMHOST)
endif()
# ODROID
if(ODROID)
add_definitions(-DODROID)
endif()
# GOA_CLONE
if(GOA_CLONE)
add_definitions(-DGOA_CLONE)
add_definitions(-mcpu=cortex-a35 -mfpu=neon-vfpv3 -march=armv8-a+crc+simd+crypto -mfloat-abi=hard -ftree-vectorize -fsingle-precision-constant -ffast-math)
set(EGL_WRAPPER ON)
set(GLX_STUBS ON)
endif()
# Android
if(ANDROID)
add_definitions(-DANDROID)
add_definitions(-DNOX11 -DNO_GBM -DDEFAULT_ES=2)
endif()
if(USE_ANDROID_LOG)
add_definitions(-DUSE_ANDROID_LOG)
find_library(log-lib log)
endif()
#PocketCHIP
if(CHIP)
add_definitions(-DCHIP)
add_definitions(-mcpu=cortex-a8 -mfpu=neon -mfloat-abi=hard -ftree-vectorize -fsingle-precision-constant -ffast-math)
endif()
# AmigaOS4
if(AMIGAOS4)
set(CMAKE_C_COMPILER "ppc-amigaos-gcc")
set(CMAKE_CXX_COMPILER "ppc-amigaos-g++")
set(CMAKE_LINKER "ppc-amigaos-ld")
set(CMAKE_AR "ppc-amigaos-ar")
set(CMAKE_RANLIB "ppc-amigaos-ranlib")
add_definitions(-DAMIGAOS4)
set(NOX11 ON)
set(NOEGL ON)
set(NO_GBM ON)
set(CMAKE_C_FLAGS_DEBUG "-O1 -gstabs")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gstabs")
endif()
#NOX11
if(NOX11)
add_definitions(-DEGL_NO_X11)
add_definitions(-DNOX11)
endif()
#NOEGL
if(NOEGL)
add_definitions(-DNOEGL)
add_definitions(-DNOX11)
endif()
if(NOT NO_GBM)
find_package(PkgConfig REQUIRED)
pkg_check_modules(KMSDRM REQUIRED libdrm gbm egl)
link_directories(${KMSDRM_LIBRARY_DIRS})
include_directories(${KMSDRM_INCLUDE_DIRS})
endif()
if(NO_GBM)
add_definitions(-DNO_GBM)
endif()
#NOX11
if(USE_CLOCK)
add_definitions(-DUSE_CLOCK)
endif()
if(NO_LOADER)
add_definitions(-DNO_LOADER)
endif()
if(NO_INIT_CONSTRUCTOR)
add_definitions(-DNO_INIT_CONSTRUCTOR)
endif()
if(GLX_STUBS)
add_definitions(-DGLX_STUBS)
endif()
#DEFAULT_ES=2
if(DEFAULT_ES EQUAL 2)
add_definitions(-DDEFAULT_ES=2)
endif()
if(DEFAULT_ES EQUAL 1)
add_definitions(-DDEFAULT_ES=1)
endif()
if(USE_CCACHE)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif()
endif()
link_directories(${CMAKE_SOURCE_DIR}/lib)
if(NOT WIN32_MSVC)
add_definitions(-std=gnu11 -funwind-tables)
if(NOT WIN32_PLATFORM)
add_definitions(-fvisibility=hidden)
else()
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--exclude-all-symbols,--kill-at")
endif()
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
add_definitions(-Wno-deprecated-declarations) #strdup
add_definitions(-Wno-unused-function -Wno-unused-variable -Wno-dangling-else)
add_definitions(-Wno-implicit-const-int-float-conversion)
add_definitions(-Wno-visibility)
else()
if(CMAKE_C_COMPILER_ID MATCHES "Intel")
add_definitions(-wd1786 -wd589 -wd537 -wd118 -wd2722)
else()
add_definitions(-wd4996 -wd4244 -wd4267 -wd4098 -wd4018)
endif()
add_definitions("-Dinline=__inline" "-D__func__=__FUNCTION__") # for VC<=13
endif()
if (CMAKE_CC_COMPILER_ID MATCHES "Clang" OR CMAKE_SYSTEM_NAME MATCHES "Emscripten")
add_definitions(-Wno-pointer-sign -Wno-dangling-else)
endif()
include_directories(include)
add_subdirectory(src)
enable_testing()
macro(create_test test_name test_filename calls_count tolerance)
if (${ARGC} EQUAL 5)
add_test(${test_name}
${CMAKE_COMMAND}
-D LIBRARY_FOLDER=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
-D TESTS_DIRECTORY=${CMAKE_SOURCE_DIR}/tests
-D TEST_FILENAME=${test_filename}
-D CALLS=${calls_count}
-D TOLERANCE=${tolerance}
-D EXTRACT_RANGE=${ARGV4}
-P ${CMAKE_SOURCE_DIR}/test.cmake)
elseif (${ARGC} EQUAL 6)
if (${ARGV4} STREQUAL "NOEXTRACT_RANGE")
add_test(${test_name}
${CMAKE_COMMAND}
-D LIBRARY_FOLDER=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
-D TESTS_DIRECTORY=${CMAKE_SOURCE_DIR}/tests
-D TEST_FILENAME=${test_filename}
-D CALLS=${calls_count}
-D TOLERANCE_GLES1=${tolerance}
-D TOLERANCE_GLES2=${ARGV5}
-P ${CMAKE_SOURCE_DIR}/test.cmake)
else (${ARGV4} STREQUAL "NOEXTRACT_RANGE")
add_test(${test_name}
${CMAKE_COMMAND}
-D LIBRARY_FOLDER=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
-D TESTS_DIRECTORY=${CMAKE_SOURCE_DIR}/tests
-D TEST_FILENAME=${test_filename}
-D CALLS=${calls_count}
-D TOLERANCE_GLES1=${tolerance}
-D TOLERANCE_GLES2=${ARGV5}
-D EXTRACT_RANGE=${ARGV4}
-P ${CMAKE_SOURCE_DIR}/test.cmake)
endif (${ARGV4} STREQUAL "NOEXTRACT_RANGE")
else (${ARGC} EQUAL 5)
add_test(${test_name}
${CMAKE_COMMAND}
-D LIBRARY_FOLDER=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
-D TESTS_DIRECTORY=${CMAKE_SOURCE_DIR}/tests
-D TEST_FILENAME=${test_filename}
-D CALLS=${calls_count}
-D TOLERANCE=${tolerance}
-P ${CMAKE_SOURCE_DIR}/test.cmake)
endif (${ARGC} EQUAL 5)
endmacro(create_test)
macro(create_test_GLES test_name GLES test_filename calls_count tolerance)
if (${ARGC} EQUAL 5)
add_test(${test_name}_GLES${GLES}
${CMAKE_COMMAND}
-D LIBRARY_FOLDER=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
-D TESTS_DIRECTORY=${CMAKE_SOURCE_DIR}/tests
-D TEST_FILENAME=${test_filename}
-D CALLS=${calls_count}
-D TOLERANCE=${tolerance}
-D EXTRACT_RANGE=${ARGV4}
-D GLES_FORCED=${GLES}
-P ${CMAKE_SOURCE_DIR}/test.cmake)
else (${ARGC} EQUAL 5)
add_test(${test_name}_GLES${GLES}
${CMAKE_COMMAND}
-D LIBRARY_FOLDER=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
-D TESTS_DIRECTORY=${CMAKE_SOURCE_DIR}/tests
-D TEST_FILENAME=${test_filename}
-D CALLS=${calls_count}
-D TOLERANCE=${tolerance}
-D GLES_FORCED=${GLES}
-P ${CMAKE_SOURCE_DIR}/test.cmake)
endif (${ARGC} EQUAL 5)
endmacro(create_test_GLES)
create_test(GLXgears glxgears "0000008203" 25 "NOEXTRACT_RANGE" 700)
create_test(StuntCarRacer stuntcarracer "0000118817" 20 "638x478+1+1")
create_test(Neverball neverball "0000078750" 20 "798x478+1+1" 200)
create_test(FoobillardPlus foobillardplus "0000014748" 50 "798x478+1+1" 60)
create_test(Descent3 descent3 "0000284192" 20 "638x478+1+1")
create_test(PointSprite pointsprite "0000248810" 20)
#create_test_GLES(Neverball 2 neverball "0000078750" 200 "798x478+1+1")
create_test_GLES(OpenRA 2 openra "0000031249" 20 "638x478+1+1")
create_test_GLES(GLSL_lighting 2 glsl_lighting "0000505393" 20)
+133
View File
@@ -0,0 +1,133 @@
Compiling
====
It's better to define the CMake Build type, preferably `RelWithDebInfo`, that define a Release build (so with some optimizations) but with debug info (so gdb Backtrace shows infos).
*Pandora*
---
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
*Raspberry Pi*
---
If your are using legacy driver (non-mesa ones)
`mkdir build; cd build; cmake .. -DBCMHOST=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
For Mesa VC4 driver, use the ODROID profile.
*ODroid*
---
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
*Tinker Board 1/1S or RK3288*
---
use ODROID profile.
*OrangePI*
---
use ODROID profile.
*CHIP machines*
---
`mkdir build; cd build; cmake .. -DCHIP=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
*Emscripten*
---
`mkdir build; cd build; emcmake cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DNOX11=ON -DNOEGL=ON -DSTATICLIB=ON; make`
*Android*
---
An Android.mk is provided that should compile with an NDK
*iOS*
---
```
mkdir build
cd build
cmake .. -G Xcode -DCMAKE_TOOLCHAIN_FILE={where ios.toolchain.cmake is located} -DNOX11=ON -DNOEGL=ON -DSTATICLIB=ON -DPLATFORM=OS
cmake --build . --config Release --target GL
```
Use with [ios-cmake](https://github.com/leetal/ios-cmake)
*Custom build*
---
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
You can avoid the use of X11 with `NOX11=1` and EGL with `NOEGL=1`, but then, you will need to create the EGL Context yourself (or using SDL for example). Be sure to synchronize the context you create with the Backend you use. By default GLES 1.1 backend is used. To used GLES2 by default, use `DEFAULT_ES=2`
You can use USE_CLOCK to use `clock_gettime(...)` instead of `gettimeofday(...)` for LIBGL_FPS. It can be more precise on some platform. Add `-DUSE_CLOCK=ON`
You can use cmake and mix command line argument to custom build your version of GL4ES. For example, for a generic ARM with NEON platform, not using X11 or EGL, defaulting to GLES2 backend, enabling RPi, and using clock_gettime, you would do:
`mkdir build; cd build; cmake .. -DBCMHOST=1 -DNOEGL=1 -DNOX11=1 -DDEFAULT_ES=2 -DUSE_CLOCK=ON -DCMAKE_C_FLAGS="-marm -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard" -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
----
Testing
====
A few tests are included.
They can be launched with `tests/tests.sh`
You will need apitrace and imagemagick for them to run. (on debian and friend, it's `sudo apt install apitrace-gl-frontend imagemagick`)
The tests use a pre-recorded GL trace that is replayed, then a specific frame is captured and compared to a reference picture.
Because each renderer may render slightly differently, there are some fuzz in the comparison, so only significant changes will be detected.
For now, 2 tests are done, one with glxgears (basic testing, using mostly glBegin / glEnd) and stuntcarracer (with more GL stuff, textures and lighting).
----
Per-platform
====
## OpenPandora
This is the main developpement platform for now. GL4ES works on all 3 models (CC, Rebirth and Gigahertz), and with all driver version.
For the SGX Driver version that doesn't support X11 Windowed mode (i.e. there is no `/usr/lib/libpvrPVR2D_X11WSEGL.so` library in the firmware), you need to use one of the framebuffer output: `LIBGL_FB=1` is the fastest, but you may need `LIBGL_FB=2` if you need 32bits framebuffer, or `LIBGL_FB=3` if you need GL in a Window (but it will be slow, as each frame has to be blitted back in the X11 windows).
On the Pandora, the special `LIBGL_GAMMA` can be used also, to boost gamma at load, using firmware command to change LCD gamma.
## ODroid
GL4ES works well on ODroid. I can test on XU4 model, but it has been reported to work on all model, including 64bits version.
On ODroid, the EGL context can be created with SRGB attribute, by using `LIBGL_SRGB=1`, for a nice boost in the gamma (supported on most ODroid).
## OrangePI
GL4ES works on OrangePI using ODROID profile. GLES Hardware is MALI and is similar to ODroid in many way. I don't own any OrangePI but I have seen many success in compiling and using the lib.
## C.H.I.P.
GL4ES should work on CHIP and PocketCHIP. Framebuffers mode will probably not work, with only `LIBGL_FB=3` mode that seems to work fine, and with adequate performances (there is probably no slow blit, as the driver handle directly the GL->X11 blit).
Also, on the CHIP, you will probably need to do `sudo apt-get install chip-mali-userspace` to be sure the GLES driver of the CHIP is present.
## RaspberryPI
GL4ES works on RaspberryPI, on both legacy driver and mesa opensourced ones.
For Legacy driver, the Framebuffer mode should work on this plateform. It seems `LIBGL_FB=3` gives good result and should be used in most cases. `LIBGL_FB=1` try to use `DispManX` for more speed. Be aware that if you use X-less config, many SDL version dedicated to DispManX do not handle GL context creation. So trying to create a GL context with this version of SDL will fail, but GL4ES is never called, so I cannot "fix" that (the fix would be inside SDL/DispManX driver).
## Android
On Android build of GL4ES, no X11 function are called. So most `glX` function are not defined. That means that the GL context (in fact a GLES1.1 context) has to be created by other apps (mainly SDL or SDL2).
On Android version 4.0 and earlier, there is a bug that prevent dlopen to be called inside dlopen (see [here](http://grokbase.com/t/gg/android-ndk/124bdvscqx/block-with-calling-dlopen-and-dlclose)).
GL4ES use a "library constructor" to initialize itself a load, and that constructor do some dlopen (to load EGL and GLES libraries), so it will trigger that bug.
If you are targeting a wide range of device, you should probably activate the workaround:
1. Modify [Android.mk](Android.mk) to uncomment `#LOCAL_CFLAGS += -DNO_INIT_CONSTRUCTOR` near the end of the file, to prevent the use of the library constructor.
2. In your code, call `void initialize_gl4es()` as soon as possible after loading GL4ES, and before using any GL function.
To try the GLES2 backend, you can compile gl4es with ES2 by default (so you don't have to mess with env. variable). Simply uncomment `#LOCAL_CFLAGS += -DDEFAULT_ES=2`, and create the GL Context as GLES2.
## Emscripten
In your code, call `void initialize_gl4es()` as soon as possible after loading GL4ES, and before using any GL function.
Use `-s FULL_ES2=1 -I[directory where GL4ES source code is located]/gl4es/include -lGL` when compiling your program for Emscripten.
## iOS
In your code, call `void initialize_gl4es()` as soon as possible after loading GLES context, and before using any GL function. If you use EAGLContext, call it immediately after `[EAGLContext setCurrentContext:context]`.
+390
View File
@@ -0,0 +1,390 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="GL4ES" />
<Option pch_mode="0" />
<Option compiler="gcc" />
<Build>
<Target title="Linux Static">
<Option output="./libGL4ES.a" prefix_auto="0" extension_auto="0" />
<Option working_dir="" />
<Option type="2" />
<Option compiler="gcc" />
<Option projectResourceIncludeDirsRelation="1" />
</Target>
<Target title="Linux Dynamic">
<Option output="./libGL.so" prefix_auto="0" extension_auto="0" />
<Option type="3" />
<Option compiler="gcc" />
<Option projectResourceIncludeDirsRelation="1" />
</Target>
<Target title="Amiga Dynamic">
<Option output="./libGL.so" prefix_auto="0" extension_auto="0" />
<Option type="3" />
<Option compiler="gcc" />
<Option projectResourceIncludeDirsRelation="1" />
</Target>
</Build>
<VirtualTargets>
<Add alias="All" targets="Linux Static;" />
</VirtualTargets>
<Compiler>
<Add option="-DNO_GBM" />
<Add directory="/home/Dev/libs/game/Irrlicht-SVN/include" />
<Add directory="include" />
</Compiler>
<Linker>
<Add directory="/home/Dev/libs/game/Irrlicht-SVN/lib/Linux" />
</Linker>
<Unit filename="include/EGL/egl.h" />
<Unit filename="include/EGL/eglext.h" />
<Unit filename="include/EGL/eglplatform.h" />
<Unit filename="include/GL/gl.h" />
<Unit filename="include/GL/gl_mangle.h" />
<Unit filename="include/GL/glext.h" />
<Unit filename="include/GL/glu.h" />
<Unit filename="include/GL/glu_mangle.h" />
<Unit filename="include/GL/glx.h" />
<Unit filename="include/GL/glx_mangle.h" />
<Unit filename="include/GL/glxext.h" />
<Unit filename="include/GL/internal/dri_interface.h" />
<Unit filename="include/GLES/egl.h" />
<Unit filename="include/GLES/gl.h" />
<Unit filename="include/GLES/gl2.h" />
<Unit filename="include/GLES/gl2ext.h" />
<Unit filename="include/GLES/gl2platform.h" />
<Unit filename="include/GLES/gl3.h" />
<Unit filename="include/GLES/gl3ext.h" />
<Unit filename="include/GLES/gl3platform.h" />
<Unit filename="include/GLES/glext.h" />
<Unit filename="include/GLES/glplatform.h" />
<Unit filename="include/KHR/khrplatform.h" />
<Unit filename="include/android_debug.h" />
<Unit filename="include/gl4eshint.h" />
<Unit filename="include/gl4esinit.h" />
<Unit filename="include/khash.h" />
<Unit filename="src/agl/agl.c">
<Option compilerVar="CC" />
<Option target="Amiga Dynamic" />
</Unit>
<Unit filename="src/agl/agl.h">
<Option target="Amiga Dynamic" />
</Unit>
<Unit filename="src/agl/amigaos.c">
<Option compilerVar="CC" />
<Option target="Amiga Dynamic" />
</Unit>
<Unit filename="src/agl/amigaos.h">
<Option target="Amiga Dynamic" />
</Unit>
<Unit filename="src/agl/lookup.c">
<Option compilerVar="CC" />
<Option target="Amiga Dynamic" />
</Unit>
<Unit filename="src/gl/arbconverter.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/arbconverter.h" />
<Unit filename="src/gl/arbgenerator.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/arbgenerator.h" />
<Unit filename="src/gl/arbhelper.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/arbhelper.h" />
<Unit filename="src/gl/arbparser.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/arbparser.h" />
<Unit filename="src/gl/array.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/array.h" />
<Unit filename="src/gl/attributes.h" />
<Unit filename="src/gl/blend.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/blend.h" />
<Unit filename="src/gl/blit.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/blit.h" />
<Unit filename="src/gl/buffers.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/buffers.h" />
<Unit filename="src/gl/build_info.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/build_info.h" />
<Unit filename="src/gl/const.h" />
<Unit filename="src/gl/debug.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/debug.h" />
<Unit filename="src/gl/decompress.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/decompress.h" />
<Unit filename="src/gl/depth.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/depth.h" />
<Unit filename="src/gl/directstate.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/directstate.h" />
<Unit filename="src/gl/drawing.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/enable.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/enum_info.h" />
<Unit filename="src/gl/envvars.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/envvars.h" />
<Unit filename="src/gl/eval.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/eval.h" />
<Unit filename="src/gl/face.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/face.h" />
<Unit filename="src/gl/fog.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/fog.h" />
<Unit filename="src/gl/fpe.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/fpe.h" />
<Unit filename="src/gl/fpe_cache.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/fpe_cache.h" />
<Unit filename="src/gl/fpe_shader.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/fpe_shader.h" />
<Unit filename="src/gl/framebuffers.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/framebuffers.h" />
<Unit filename="src/gl/getter.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/gl4es.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/gl4es.h" />
<Unit filename="src/gl/gl_lookup.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/gl_lookup.h" />
<Unit filename="src/gl/glcase.h" />
<Unit filename="src/gl/gles.h" />
<Unit filename="src/gl/glesfuncs.inc" />
<Unit filename="src/gl/glstate.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/glstate.h" />
<Unit filename="src/gl/hint.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/hint.h" />
<Unit filename="src/gl/init.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/init.h" />
<Unit filename="src/gl/light.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/light.h" />
<Unit filename="src/gl/line.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/line.h" />
<Unit filename="src/gl/list.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/list.h" />
<Unit filename="src/gl/listdraw.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/listrl.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/loader.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/loader.h" />
<Unit filename="src/gl/logs.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/logs.h" />
<Unit filename="src/gl/math/eval.h" />
<Unit filename="src/gl/math/matheval.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/matrix.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/matrix.h" />
<Unit filename="src/gl/matvec.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/matvec.h" />
<Unit filename="src/gl/oldprogram.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/oldprogram.h" />
<Unit filename="src/gl/pixel.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/pixel.h" />
<Unit filename="src/gl/planes.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/planes.h" />
<Unit filename="src/gl/pointsprite.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/pointsprite.h" />
<Unit filename="src/gl/preproc.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/preproc.h" />
<Unit filename="src/gl/program.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/program.h" />
<Unit filename="src/gl/queries.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/queries.h" />
<Unit filename="src/gl/raster.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/raster.h" />
<Unit filename="src/gl/render.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/render.h" />
<Unit filename="src/gl/samplers.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/samplers.h" />
<Unit filename="src/gl/shader.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/shader.h" />
<Unit filename="src/gl/shader_hacks.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/shader_hacks.h" />
<Unit filename="src/gl/shaderconv.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/shaderconv.h" />
<Unit filename="src/gl/stack.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/stack.h" />
<Unit filename="src/gl/state.h" />
<Unit filename="src/gl/stb_dxt_104.h" />
<Unit filename="src/gl/stencil.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/stencil.h" />
<Unit filename="src/gl/string_utils.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/string_utils.h" />
<Unit filename="src/gl/stubs.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/texenv.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/texenv.h" />
<Unit filename="src/gl/texgen.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/texgen.h" />
<Unit filename="src/gl/texture.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/texture.h" />
<Unit filename="src/gl/texture_3d.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/texture_compressed.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/texture_params.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/texture_read.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/uniform.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/uniform.h" />
<Unit filename="src/gl/vertexattrib.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/vertexattrib.h" />
<Unit filename="src/gl/wrap/gl4es.h" />
<Unit filename="src/gl/wrap/gl4eswraps.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/wrap/gles.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/wrap/gles.h" />
<Unit filename="src/gl/wrap/glstub.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/gl/wrap/skips.h" />
<Unit filename="src/gl/wrap/stub.h" />
<Unit filename="src/glx/drmfunc.h" />
<Unit filename="src/glx/gbm.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/gbmfunc.h" />
<Unit filename="src/glx/glx.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/glx.h" />
<Unit filename="src/glx/glx_gbm.h" />
<Unit filename="src/glx/glx_stubs.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/hardext.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/hardext.h" />
<Unit filename="src/glx/lookup.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/rpi.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/rpi.h" />
<Unit filename="src/glx/streaming.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/streaming.h" />
<Unit filename="src/glx/utils.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/glx/utils.h" />
<Extensions />
</Project>
</CodeBlocks_project_file>
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2016-2018 Sebastien Chevalier
Copyright (c) 2013-2016 Ryan Hileman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+61
View File
@@ -0,0 +1,61 @@
GL4ES - OpenGL for GLES Hardware
====
Many OpenGL software already works with GL4ES.
![foobillards++](refs/foobillardplus.0000014748.png)
Complex OpenGL 1.5 games, like Foobillard++, that uses cascaded display list, line stipple and TexGen works fine. Here running on the OpenPandora. It will work with both GLES1.1 and GLES2.0 backend. Most OpenGL 1.x games will runs.
[![Play on Youtube](https://img.youtube.com/vi/75FYb60L7zw/0.jpg)](https://www.youtube.com/watch?v=75FYb60L7zw)
The limit is an hardware one: GLES1.1 and GLES2.0 hardware do not allow reading Depth buffer, so some games that use it (like AssaultCube) for game play wont run correctly. Some FPS are using it just for cosmetics (Lens flare) and run fine without, like Serious Sam (both First and Second Encounter), here on the OpenPandora again.
![AssaultCube on Android](media/assaultcube.jpg)
AssaultCube an Android also use gl4es for the rendering
[![Play on Youtube](https://img.youtube.com/vi/kJPb2jYiBoM/0.jpg)](https://www.youtube.com/watch?v=kJPb2jYiBoM)
More complex program, like Blender, can also run.
![MineCraft](media/minecraft.png)
But also Minecraft, here on an ODroid in this old video.
![OpenRA](refs/openra.0000031249.png)
On the OpenGL 2.0, side using GLES2.0 backend, OpenRA can run on the Pandora.
And OpenGL 2.x opens a lot of doors. Many commercial games run just fine on gl4es.
[![Play on Youtube](https://img.youtube.com/vi/VUoeHWuwlMU/0.jpg)](https://www.youtube.com/watch?v=VUoeHWuwlMU)
Here some FNA games, running on an ODroid XU4 (using method described [there](https://magazine.odroid.com/article/playing-modern-fna-games-on-the-odroid-platform/)). That video show just a few, and even more can be make to run.
[![Play on Youtube](https://img.youtube.com/vi/B4YN37z3-ws/0.jpg)](https://www.youtube.com/watch?v=B4YN37z3-ws)
And with [Box86](https://github.com/ptitSeb/box86), even more commercial games can run, like here NeverWinter Night on an ODroid XU4
GL4ES also now works on some other platform, like AmigaOS4 (so BigEndian platform)
[![Play on Youtube](https://img.youtube.com/vi/hQVabA_ReoQ/0.jpg)](https://www.youtube.com/watch?v=hQVabA_ReoQ)
Here running Foobillard++
Or even in a web browser (that support WebGL): try it with Stunt Car Remake [here](http://ptitseb.github.io/stuntcarremake/)
Another web browser example: Serious Sam Engine, try it [here](https://martinmullins.github.io/ssam/) (initial 80MB game files download).
[source repo](https://github.com/martinmullins/Serious-Engine)
[![Gif of Serious Engine](https://github.com/martinmullins/ssam/blob/main/ssam.gif?raw=true)](https://martinmullins.github.io/ssam/)
Neverball in a browser also use gl4es for rendering: [neverball in a browser](https://neverball.github.io/)
About performances: while gl4es is a wrapper, there are many caching and works done in gl4es to avoid slowdown and bottleneck. While those optimization are useless in highly optimized engine, like the Quake3 engine, on other engine and games, gl4es can be (much) faster than straight GLES conversion (especially if there are a lot of `glBegin(...)`/`glEnd()` drawing commands). On an x86 VM, gl4es running on GLES can be faster than direct OpenGL use on some games!
Now GL4ES can also use VBO, either when the software use it, or automatically when using glList, giving sometimes a nice boost (the boost depend on the Platform and game)
+95
View File
@@ -0,0 +1,95 @@
![logo](gl4es.png "gl4es logo")
GL4ES - OpenGL for GLES Hardware
====
![gl4es build status](https://api.travis-ci.org/ptitSeb/gl4es.png "gl4es build status")
This is a library provide OpenGL 2.x functionality for GLES2.0 accelerated Hardware (and of course also support OpenGL 1.5 function, sometimes better than when using GLES 1.1 backend)
There is also support for GLES 1.1 Hardware, emulating OpenGL 1.5, and some OpenGL 2.x+ extensions.
GL4ES is known to work on many platform: OpenPandora, ODroid, RaspberryPI (2 and 3 at least), PocketCHIP, "otherfruit"PI (like the OrangePI), Android, iOS, x86 and x86_64 Linux (tested using mesa-egl). There is also some WIP support for AmigaOS4, using experimental GLES2 driver for Warp3D.
This library is based on glshim (https://github.com/lunixbochs/glshim) but as now evolved far from it, with different feature set and objectives. Go check this lib if you need things like RemoteGL or TinyGLES (for software rendering).
The focus is on compatibility and speed with a wide selection of game and software.
It has been tested successfully of a large selection of games and software, including: Minecraft, OpenMW, SeriousSam (both First and Second Encounters), RVGL (ReVolt GL), TSMC (The Secret Maryo Chronicles), TORCS, SpeedDreams, GL-117, Foobillard(plus), half life 1&2, Blender 2.68 to name just a few. I have also some success with Linux port of XNA games, using either MonoGame or FNA.
Most function of OpenGL up to 1.5 are supported, with some notable exceptions:
* Reading of Depth or Stencil buffer will not work
* GL_FEEDBACK mode is not implemented
* No Accum emulation
Some known general limitations:
* GL_SELECT as some limitation in its implementation (for example, current Depth buffer or bounded texture are not taken into account, also custom vertex shader will not work here)
* NPOT texture are supported, but not with GL_REPEAT / GL_MIRRORED, only GL_CLAMP will work properly (unless the GLES Hardware support NPOT)
* Multiple Color attachment on Framebuffer are not supported
* OcclusionQuery is implemented, but with a 0 bits precision
* Probably many other things
Status of the GLES2 backend
* The FPE (Fixed Pipeline Emulator) has most OpenGL 1.5 drawing call implemented
* The Shader Conversion is really crude, so only simple shaders will work (especially, the implicit conversion float <-> int is not handled)
* ARB_program are supported (converted on-the-fly to glsl shaders)
* Lighting support double-side and color separation
* FogCoord are supported, along with secondary color
* An ES2 context should be usable (useful for SDL2)
* OpenGL 2.x games that have been tested include: OpenRA, GZDoom, Danger from the Deep, SuperTuxKart 0.8.1, Hammerwatch, OpenMW, half life 2, many FNA & MonoGames games (FEZ, Towerfall Ascension, Stardew Valley, Dust, Owlboy, and many other), even some Unity3D games (Teslagrad, Colin McRea Rally remake and other)...
* glxgears works, but FlatShade is not implemented (and will probably never be), so it's slightly different than using GLES1.1 or actual GL hardware
* GL_TEXTURE_1D, GL_TEXTURE_3D and GL_TEXTURE_RECTANGLE_ARB are not yet supported in shaders (they are supported in fixed pipeline functions), and texture 3D are just a single 2D layer for now.
* Program that link only a GL_FRAGMENT or GL_VERTEX shader are not supported yet.
* Some VBO are used.
Status of the GLES1.1 backend
* Framebuffer use FRAMEBUFFER_OES extension (that must be present in the GLES 1.1 stack)
* Lighting doesn't support double-side or color separation
* FogCoord or Secondary colors are not supported
* GL_TEXTURE_3D are just a single 2D layer (the 1st layer).
* VBO are supported, but they are emulated, even if VBO if supported in GLES1.1 driver
If you use gl4es in your project (as a static or dynamic link), please mention gl4es in you readme / about / whatever.
----
Compiling
----
How to compile and per-platform specific comment can be found [here](COMPILE.md)
----
GLU
----
Standard GLU do works without any issues. You can find a version [here](https://github.com/ptitSeb/GLU) if you need one.
----
Installation
----
Put lib/libGL.so.1 in your `LD_LIBRARY_PATH`.
Beware that GL4ES is meant to replace any libGL you can have on your system (like Mesa for example)
----
Usage
----
There are many environment variable to control gl4es behavior, also usable at runtime using `glHint(...)`.
See [here](USAGE.md) for all variables and what they do.
----
Media (what is working already)
----
Some screenshot and youtube links of stuffs that works [here](MEDIA.md)
----
Version history
----
The change log is [here](CHANGELOG.md)
+387
View File
@@ -0,0 +1,387 @@
Usage
----
There are many environment variables to control gl4es behavior. All are numeric, except LIBGL_VERSION that take a string, LIBGL_FBO that takes a 2d size (WxH), and both LIBGL_EGL and LIBGL_GLES that take path/filename.
You can also change many of this variable at runtime using the `glHint(...)` function. See [gl4eshint.h](include/gl4eshint.h) for the list of #define to use in this function.
##### LIBGL_FB
Controls the Framebuffer output
* 0 : Default, using standard x11 rendering
* 1 : Use Framebuffer output (x11 bypassed, only fullscreen)
* 2 : Use Framebuffer, but also an intermediary FBO
* 3 : Use PBuffer, allowing x11 (and windowed) rendering even if driver doesn't support it
##### LIBGL_FBONOALPHA
In case of LIBGL_FB=2, control if FBO is RGBA or RGB
* 0 : Default, use RGBA
* 1 : Use RGB for FBO
##### LIBGL_ES
Controls the version of GLES to use
* 0 : Default, using GLES 2.0 backend (unless built with DEFAULT_ES 1) (not on Pandora, still GLES 1.1 backend by default)
* 1 : Use GLES 1.1 backend
* 2 : Use GLES 2.0 backend
##### LIBGL_GL
Controls the version of OpenGL exposed
* 0 : Default, expose OpenGL 1.5 when using GLES1.1 or OpenGL 2.1 when using GLES2.0
* 10..14: Export OpenGL 1.0-1.4
* 15: Expose OpenGL 1.5 (default for GLES 1.1 backend)
* 20: Expose OpenGL 2.0
* 21: Expose OpenGL 2.1 (default for GLES 2.0 backend)
##### LIBGL_XREFRESH
Debug helper in specific cases
* 0 : Default, nothing special
* 1 : xrefresh will be called on cleanup
##### LIBGL_STACKTRACE
Automatic Backtrace log
* 0 : Default, nothing special
* 1 : stacktrace will be printed on crash
##### LIBGL_FPS
Print current FPS to the console
* 0 : Defaut, don't measure or printf FPS
* 1 : Print FPS (on stdout) every second
##### LIBGL_VSYNC
VSync control
* 0 : Default, nothing special
* 1 : vsync enabled
##### LIBGL_RECYCLEFBO
Recycling FBO special case (don't delete a created FBO, but recycle it if needed)
* 0 : Default, nothing special
* 1 : Recycling of FBO enabled
##### LIBGL_MIPMAP
Handling of Manual and Automatic MIPMAP
* 0 : Default, nothing special
* 1 : AutoMipMap forced
* 2 : guess AutoMipMap (based on manual mipmaping on textures)
* 3 : ignore MipMap (mipmap creation / use entirely disabled)
* 4 : ignore AutoMipMap on non-squared textures
* 5 : calculate all sub-mipmap one time when uploading level 1
##### LIBGL_FORCENPOT
Forcing NPOT (Non-Power of Two) Texture size.
* 0 : Default, nothing special
* 1 : If hardware only support Limited NPOT, then disabling MIPMAP (i.e. LIBGL_MIPMAP=3), so all texture can be NPOT.
If Hardware support full NPOT, do nothing special. Useful for GLES2 backend where limited NPOT is always supported.
##### LIBGL_TEXCOPY
Make a local copy of every texture for easy glGetTexImage2D
* 0 : Default, nothing special
* 1 : Texture copy enabled
##### LIBGL_SHRINK
Texture shrinking control
* 0 : Default, nothing special
* 1 : everything / 2 (using original algorithm for size reduction, all other shrink mode use a refined algorithm)
* 2 : only textures which one size > 512 are / 2
* 3 : only textures which one size > 256 are / 2
* 4 : only textures which one size > 256 are / 2, and the one > 1024 are / 4
* 5 : only textures which one size > 256 are resized to 256 (if possible, because only /2 and /4 exists), but empty texture are not shrunken
* 6 : only textures which one size > 128 are / 2, those >= 512 are resized to 256 (if possible, because only /2 and /4 exists), but empty texture are not shrunken
* 7 : only textures which one size > 512 are / 2, but empty texture are not shrunken
* 8 : advertise a max texture size *4, but every texture which one size > 2048 are shrunken to 2048
* 9 : advertise a max texture size *4, but every texture which one size > 4096 are / 4 and the one > 512 are / 2, but empty texture are not shrunken
* 10: advertise a max texture size *4, but every texture which one size > 2048 are / 4 and the one > 512 are / 2, but empty texture are not shrunken
* 11: advertise a max texture size *2, but every texture with one dimension > max texture size will get shrunken to max texture size
##### LIBGL_TEXDUMP
Texture dump
* 0 : Default, nothing special
* 1 : Texture dump enabled
##### LIBGL_ALPHAHACK
Experimental: enable Alpha test only when using texture that contains an alpha channel
* 0 : Default, nothing special
* 1 : Alpha Hack enabled
##### LIBGL_NODOWNSAMPLING
Texture downsampling control (deprecated, use LIBGL_AVOID16BITS instead)
* 0 : Default, DXTc texture are downsampled to 16bits
* 1 : DXTc texture are left as 32bits RGBA
##### LIBGL_STREAM
PANDORA only: enable Texture Streaming (works only on RGB textures)
* 0 : Default, nothing special
* 1 : Enabled on empty RGB textures
* 2 : Enabled on all RGB textures
##### LIBGL_COPY
Removed (Controlled the glCopyTex(Sub)Image2D hack, it's now automatic, depending on how compatible is the read framebuffer)
##### LIBGL_NOLUMALPHA
Control the availability of the LUMINANCE_ALPHA format (can be buggy on Pandora model CC)
* 0 : Default,GL_LUMINANCE_ALPHA is available and used if needed
* 1 : GL_LUMINANCE_ALPHA hardware support disabled (a GL_RGBA texture will be used instead)
##### LIBGL_BLENDHACK
Experimental: Change Blend GL_SRC_ALPHA, GL_ONE to GL_ONE, GL_ONE
* 0 : Default, nothing special
* 1 : Change Blend GL_SRC_ALPHA, GL_ONE to GL_ONE, GL_ONE (can be usefull for Xash3D engine)
##### LIBGL_BLENDCOLOR
Hack: Export a (faked) glBlendColor
* 0 : Default, don't expose gBlendColor
* 1 : Exposed the function (if no hardware support, faked function will be used)
##### LIBGL_VERSION
Hack: Control the glGetString version. Override version string (should be in the form of "1.x")
##### LIBGL_BATCH
This has been changed with v1.0.5.
Now BATCH simply try to merge subsequent glDrawXXXXX (glDrawArrays, glDrawElements...). It only try to merge if arrays is between MINBATCH and MAXBATCH (inclusive)
The Batching stop when there is a change of GL State, but also if an Array of more then 100*N is encountered.
* 0 : Default: don't try to merge glDrawXXXXX
* N : Any number: try to merger arrays, 1st must be between 0 and 100*N
* MIN-MAX : 2 number separated by minus, to try merge arrays that are between MIN and MAX vertices
##### LIBGL_NOERROR
Hack: glGetError() always return GL_NOERROR
* 0 : Default, glGetError behave as it should
* 1 : glGetError never fail.
##### LIBGL_GAMMA
Pandora Hack: Set a Gamma value (in decimal formal, 1.0 means no gamma boost)
* X.Y : Use X.Y as gamma when creating context (typical value can be 1.6 or 2.0)
##### LIBGL_SRGB
ODROID Hack: Enable sRGB Surface (so Gamma corrected), if Hardware support it
* 0 : Default, don't try to use sRGB surface
* 1 : Enable sRGB Surface (but support will be tested first, must have EGL_KHR_gl_colorspace extension)
##### LIBGL_FASTMATH
Hack: Activate some Fast Math in processor/co-processor
* 0 : Default, nothing special
* 1 : On OpenPandora and CHIP, activate "RunFast" on Cortex-A8 (mode default NaN, flush-to-zero)
: Not implemented on other platforms (will do nothing)
##### LIBGL_SILENTSTUB
Debug: Hide or Show the Sub / Not found message
* 0 : The messages for Stub or absent function are printed
* 1 : Default, don't print the STUB or glXGetProcAddress glXXXXX not found message
##### LIBGL_NOBANNER
Show/Hide initial text
* 0 : Default, print starting message
* 1 : Silent: no LIBGL message at start (combine with LIBGL_SILENTSTUB for more silence)
##### LIBGL_NPOT
Expose NPOT (Non Power of Two) Support
* 0 : Default, expose the extension that are available by the GLES backend
* 1 : Expose limited NPOT extension
* 2 : Expose GL_ARB_texture_non_power_of_two extension
##### LIBGL_GLQUERIES
Expose glQueries functions
* 0 : Don't expose the function (fake one will be used if called)
* 1 : Default, expose fake functions (always answer 0)
##### LIBGL_NOTEXMAT
Handling of Texture Matrix
* 0 : Default, perform handling internally (better handling of NPOT texture on all hardware)
* 1 : Let the driver handle texmat (can be faster in some cases, but NPOT texture may be broken)
##### LIBGL_NOTEST
Initial Hardware test
* 0 : Default, perform initial hardware testing (using a PBuffer)
* 1 : Do not perform test (no extensions tested or used)
##### LIBGL_NOVAOCACHE
VAO Caching
* 0 : Default, try to cache vao to avoid memcpy in render list
* 1 : Don't cache VAO
##### LIBGL_VABGRA
Vertex Array BGRA extension
* 0 : Default, GL_ARB_vertex_array_bgra not exposed (still emulated)
* 1 : Extension exposed may be faster in some cases (Arx Libertatis mainly)
##### LIBGL_BEGINEND
Merge of subsequent glBegin/glEnd blocks (will be non-effective if BATCH mode is used)
* 0 : Don't try to merge
* 1 : Try to merge, even if there is a glColor / glNormal in between (default)
##### LIBGL_AVOID16BITS
Try to avoid 16bits textures
* 0 : Default on ImgTec hardware, use 16bits texture if it can avoid a conversion or for DXTc textures
* 1 : Default on all other hardware, Use 32bits texture unless specifically requested (using internalformat)
##### LIBGL_AVOID24BITS
Try to avoid 24bits textures (i.e. GL_RGB)
* 0 : Default, use 24bits texture when it's possible
* 1 : Force 32bits textures when GL_RGB is asked (as internal or not). Not recommended, as it may break some blend functions (especially on GLES 1.1 backend). Does not impact 16bits formats.
##### LIBGL_FORCE16BITS
Try to use 16bits textures
* 0 : Default, don't force 16bits texture
* 1 : Use 16bits texture instead of 32bits (i.e. use RGBA4 instead of RGBA8 and RGB5 instead of RGB8)
##### LIBGL_POTFRAMEBUFFER
Use only Power Of Two dimension for Framebuffer
* 0 : Default, use NPOT dimension if supported
* 1 : Force Framebuffer to be created with POT dimension (not advised on GLES2 backend)
##### LIBGL_NOBGRA
Ignore BGRA Texture hardware extension
* 0 : Default, use BGRA extension if possible
* 1 : Ignore BGRA extension, even if supported by GLES hardware
##### LIBGL_NOTEXRECT
Don't expose Texture rectangle extension (GL_ARB_texture_rectangle)
* 0 : Default, the extension is listed
* 1 : Don't expose the extension (it's not supported in shaders yet)
##### LIBGL_NOHIGHP
Usage of highp precision in fragment shader (ES2 backend only)
* 0 : Default, use highp if available
* 1 : Disable usage of highp in Fragment shaders
##### LIBGL_COMMENTS
Comments in shaders are kept (also for generated shaders by fpe_shaders)
* 0 : Default, no comments in shaders sent to GLES Hardware
* 1 : Comments are left in Shaders sent to GLES Hardware
##### LIBGL_DEFAULTWRAP
Hack to define default WRAP mode for texture
* 0 : Default wrap mode is GL_REPEAT (normal OpenGL behavour): default on NPOT hardware
* 1 : Default wrap mode is GL_CLAMP_TO_EDGE: default on limited NPOT or non-NPOT hardware
* 2 : Default wrap mode is GL_CLAMP_TO_EDGE, enforced (not advised)
##### LIBGL_FBOUNBIND
Workaround on FBO where a bond texture is used for drawing
* 0 : Disabled (Default for all other configuration)
* 1 : Enabled (Default on ARM and PowerVR hardware)
##### LIBGL_FBOFORCETEX
For the Color Attachment 0 to be a Texture2D (even if program attachs a Renderbuffer) => may speedup glBlitFramebuffer if used
* 0 : Don't force (allow Renderbuffer to be used on color attachments)
* 1 : Default: For Color Attachment 0 of FBO to be a texture
##### LIBGL_BLITFULLSCREEN
Hack to trigger a SwapBuffers when a Full Framebuffer Blit on default FBO is done
* 0 : Don't force
* 1 : Default: Activate the hack (usefull with Wine/D3D)
##### LIBGL_NOARBPROGRAM
Don't expose ARB Program extensions (GL_ARB_vertex_program, GL_ARB_fragment_program and GL_EXT_program_parameters)
* 0 : Default: expose the ARB Program extensions
* 1 : Don't expose the extensions
##### LIBGL_FBO
Hack: define custom dimension for FBO (only used with LIBGL_FBO=2)
* WxH : Define FBO of WxH size (ex: LIBGL_FBO=1280x720)
##### LIBGL_NOTEXARRAY
Hack to force using discrete Texture instead of Array in all shader
* 0 : Default: Array of texture is used in shaders (not in FPE generated ones)
* 1 : Individual texture are forced in shaders (shaders may fail to compile if array are accessed by indice)
##### LIBGL_LOGSHADERERROR
Log to the console Shader Compile error, with initial and ShaderConv'd source of the shader
* 0 : Default, don't log
* 1 : Log Shader Compilation Errors
##### LIBGL_SHADERNOGLES
Don't use GL_ES part in shaders
* 0 : Default, let GL_ES part in shader
* 1 : Remove the GL_ES part in shader (useful for Löve for example)
##### LIBGL_NODEPTHTEX
Disable the use of Depth texture
* 0 : Default, Use Depth Texture if supported by Hardware
* 1 : Disable the use of Depth Texture (renderbuffer will be used in FBO)
##### LIBGL_FLOAT
Expose support for FLOAT and HALF_FLOAT Texture support (and has attachment to FBO)
* 0 : Don't exposed, even if supported in hardware
* 1 : Default, exposed what is supported by hardware
* 2 : Force exposed, even if no supported (will be emulated has GL_UNSIGNED_BYTE if not supported)
##### LIBGL_GLXRECYCLE
Recycle EGLSurface per Drawable, instead of destroying them
* 0 : Default, don't recycle
* 1 : Don't destroy EGLSurface, per reused them per drawable (can fix EGL_BAD_ALLOC error). EGLSurface are never destroyed in this mode for now.
##### LIBGL_NOCLEAN
Debug: don't clean GLContext when they are destroy
* 0 : Default, clean GLContext
* 1 : Don't clean GLContext
##### LIBGL_EGL
Define EGL lib to use. Default folder are the standard one for dynamic library loading (LD_LIBRARY_PATH and friend) plus "/opt/vc/lib/", /usr/local/lib/" and "/usr/lib/".
* by default try to use libbrcmEGL and libEGL
* filename: try to load from the defaults folder (don't forget to use complete filename, with ".so" extension). If not found/loaded, default one will be tried.
* /path/to/filename: try to use exact path/filename. If not found/loaded, default one will be tried.
##### LIBGL_GLES
Define GLES(2) lib to use. Default folder are the standard one for dynamic library loading (LD_LIBRARY_PATH and friend) plus "/opt/vc/lib/", /usr/local/lib/" and "/usr/lib/". Be sure to point to correct GLES library depending on wich GLES backend you are using.
* by default try to use libGLESv1_CM, libGLES_CM or libbrcmGLESv1_CM for GLES1.1 and libGLESv2_CM, libGLESv2 or libbrcmGLESv2 for GLES2 backend
* filename: try to load from the defaults folder (don't forget to use complete filename, with ".so" extension). If not found/loaded, default one will be tried.
* /path/to/filename: try to use exact path/filename. If not found/loaded, default one will be tried.
##### LIBGL_DBGSHADERCONV
Log to the console all shaders before and after conversion
* 0 : Default: don't log anything
* 1 : Log Vertex Shader
* 2 : Log Framegent Shader
* 4 : Log Shaders before going to Shaderconv
* 8 : Log Shaders after going to Shaderconv
Note that you can combine (logical or state. So 14 will be only Fragment shader before and after shaderconv)
Note also that if neither Fragment and Vertex are defined, both will be selected. Same for Before and After.
At last, the value "1" will be changed to "15", to log everything.
##### LIBGL_NOPSA
Disable the use of the Precompiled Shader Archive
* 0 : Default: use (and save) the PSA (it's saved on $HOME/.gl4es.psa on linux)
* 1 : Don't use PSA.
##### LIBGL_PSA_FOLDER
Set a custom path for Precompile Shader Archive
* XXXXX : set that path. Archive will be saved at XXXXX/.gl4es.psa
##### LIBGL_USEVBO
Usage of VBO in certain cases. Only for GLES2+. The 2 and 3 mode are experimental and will probably be slower anyway.
* 0 : Disable the use of VBO.
* 1 : Default: Use VBO when possible (for Arrays VBO or glList)
* 2 : Use VBO when possible (and also on `glLockArrays`).
* 3 : Use VBO when possible (and special case on `glLockArrays` for idTech3 engine games).
##### LIBGL_NOES2COMPAT
Don't expose GLX_EXT_create_context_es2_profile extension
* 0 : Extension is there
* 1 : Don't expose the extension: for SDL2, use it with SDL_VIDEO_GL_DRIVER and SDL_VIDEO_EGL_DRIVER to use GLESv2 driver directly
##### LIBGL_NOINTOVLHACK
Disable the hack in shader converter to define overloaded function with int
* 0 : Default: use the hack
* 1 : Don't use it (some driver / PVRCapture don't like it much).
##### LIBGL_GLXNATIVE
Disable the filtering of GLXConfig by NATIVE_TYPE
* 0 : Default, GLX_X_NATIVE_TYPE attribute are taken into account
* 1 : Don't filter GLXConfig by GLX_X_NATIVE_TYPE
##### LIBGL_NOSHADERLOD
Disable GL_EXT_shader_texture_lod
* 0 : Default, use the extension if present
* 1 : Disable the use of the extension (using crude fallback)
##### LIBGL_NORMALIZE
Force normals to be normliazed in FPE
* 0 : Default, don't force normalizations
* 1 : Force normalization on normals on FPE, even when it's disabled (workaround for a bug that prevent colors on Minecraft 1.16+)
###### LIBGL_BLITFB0
Blit to FB 0 force a SwapBuffer
* 0 : Default, don't force a SwapBuffer when glBlitFramebuffer to draw fb0 is used (unless the full FB0 if blitted)
* 1 : Force a SwapBuffer each time glBlitFramebuffer on FB0 is used (can help some windowed Wine games)
###### LIBGL_DEEPBIND
Use RTLD_DEEPBIND when loading EGL and GLES library
* 0 : Default except on PYRA, use RTLD_DEEPBIND when loading EGL/GLES libraries
* 1 : Default only on PYRA, don't use RTLD_DEEPBIND when loading EGL/GLES libraries
+2
View File
@@ -0,0 +1,2 @@
theme: jekyll-theme-hacker
title: GL4ES - The OpenGL driver for GLES Hardware
+84
View File
@@ -0,0 +1,84 @@
/**********************************************************************
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
* Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful but, except
* as otherwise stated in writing, without any warranty; without even the
* implied warranty of merchantability or fitness for a particular purpose.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
* Contact Information:
* Imagination Technologies Ltd. <gpl-support@imgtec.com>
* Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
*
******************************************************************************/
#ifndef __BC_CAT_H__
#define __BC_CAT_H__
#include <linux/ioctl.h>
#define BC_FOURCC(a,b,c,d) \
((unsigned long) ((a) | (b)<<8 | (c)<<16 | (d)<<24))
#define BC_PIX_FMT_NV12 BC_FOURCC('N', 'V', '1', '2') /*YUV 4:2:0*/
#define BC_PIX_FMT_UYVY BC_FOURCC('U', 'Y', 'V', 'Y') /*YUV 4:2:2*/
#define BC_PIX_FMT_YUYV BC_FOURCC('Y', 'U', 'Y', 'V') /*YUV 4:2:2*/
#define BC_PIX_FMT_RGB565 BC_FOURCC('R', 'G', 'B', 'P') /*RGB 5:6:5*/
enum BC_memory {
BC_MEMORY_MMAP = 1,
BC_MEMORY_USERPTR = 2,
};
typedef struct BCIO_package_TAG {
int input;
int output;
}BCIO_package;
/*
* the following types are tested for fourcc in struct bc_buf_params_t
* NV12
* UYVY
* RGB565 - not tested yet
* YUYV
*/
typedef struct bc_buf_params {
int count; /*number of buffers, [in/out]*/
int width; /*buffer width in pixel, multiple of 8 or 32*/
int height; /*buffer height in pixel*/
unsigned int fourcc; /*buffer pixel format*/
enum BC_memory type;
} bc_buf_params_t;
typedef struct bc_buf_ptr {
unsigned int index;
int size;
unsigned long pa;
} bc_buf_ptr_t;
#define BCIO_GID 'g'
#define BC_IOWR(INDEX) _IOWR(BCIO_GID, INDEX, BCIO_package)
#define BCIOGET_BUFFERCOUNT BC_IOWR(0) /*obsolete, since BCIOREQ_BUFFERS
return the number of buffers*/
#define BCIOGET_BUFFERPHYADDR BC_IOWR(1) /*get physical address by index*/
#define BCIOGET_BUFFERIDX BC_IOWR(2) /*get index by physical address*/
#define BCIOREQ_BUFFERS BC_IOWR(3)
#define BCIOSET_BUFFERPHYADDR BC_IOWR(4)
#endif
+5
View File
@@ -0,0 +1,5 @@
gl4es for Debian
---------------
-- licheng <shiptux@gmail.com> Fri, 30 Jul 2021 14:53:15 +0800
+7
View File
@@ -0,0 +1,7 @@
gl4es for Debian
---------------
-- licheng <shiptux@gmail.com> Fri, 30 Jul 2021 14:53:15 +0800
+5
View File
@@ -0,0 +1,5 @@
gl4es (1.1.4-1) unstable; urgency=medium
* Initial release
-- licheng <shiptux@gmail.com> Fri, 30 Jul 2021 14:53:15 +0800
+1
View File
@@ -0,0 +1 @@
11
+29
View File
@@ -0,0 +1,29 @@
Source: gl4es
Section: libs
Priority: optional
Maintainer: licheng <shiptux@gmail.com>
Build-Depends: debhelper (>= 11),cmake,libx11-dev
Standards-Version: 4.1.3
Homepage: https://github.com/ptitSeb/gl4es
Package: libgl4es
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Multi-arch: no
Description: GL4ES - OpenGL for GLES Hardware
This is a library provide OpenGL 2.x functionality for GLES2.0 accelerated Hardware
(and of course also support OpenGL 1.5 function, so metimes better than when using
GLES 1.1 backend) There is also support for GLES 1.1 Hardware, emulating OpenGL 1.5,
and some OpenGL 2.x + extensions.
This package contains the shared libraries.
Package: libgl4es-dev
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Multi-arch: no
Description: GL4ES - OpenGL for GLES Hardware
This is a headers provide OpenGL 2.x functionality for GLES2.0 accelerated Hardware
(and of course also support OpenGL 1.5 function, so metimes better than when using
GLES 1.1 backend) There is also support for GLES 1.1 Hardware, emulating OpenGL 1.5,
and some OpenGL 2.x + extensions.
This package contains the development files.
+46
View File
@@ -0,0 +1,46 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: gl4es
Source: https://github.com/ptitSeb/gl4es
Files: *
Copyright: Copyright (c) 2016-2018 Sebastien Chevalier
Copyright (c) 2013-2016 Ryan Hileman
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Files: debian/*
Copyright: 2021 licheng <shiptux@gmail.com>
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
@@ -0,0 +1,3 @@
include/gl4esinit.h usr/include/gl4es/
include/gl4eshint.h usr/include/gl4es/
@@ -0,0 +1,2 @@
lib/libGL.so.1 usr/lib/gl4es/
@@ -0,0 +1,13 @@
fix lintian error
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,6 +6,9 @@
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
+set(CMAKE_SKIP_INSTALL_RPATH ON)
+set(CMAKE_SKIP_RPATH ON)
+
link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
+1
View File
@@ -0,0 +1 @@
fix_lintian_error
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_test:
# Disable auto tests at build time
:
override_dh_auto_clean:
dh_auto_clean
rm -f lib/*.so*
+1
View File
@@ -0,0 +1 @@
3.0 (quilt)
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

+361
View File
@@ -0,0 +1,361 @@
#ifndef __egl_h_
#define __egl_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright (c) 2013-2017 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/*
** This header is generated from the Khronos EGL XML API Registry.
** The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
** http://www.khronos.org/registry/egl
**
** Khronos $Git commit SHA1: cb927ca98d $ on $Git commit date: 2019-08-08 01:05:38 -0700 $
*/
#include <EGL/eglplatform.h>
#ifndef EGL_EGL_PROTOTYPES
#define EGL_EGL_PROTOTYPES 1
#endif
/* Generated on date 20190808 */
/* Generated C header for:
* API: egl
* Versions considered: .*
* Versions emitted: .*
* Default extensions included: None
* Additional extensions included: _nomatch_^
* Extensions removed: _nomatch_^
*/
#ifndef EGL_VERSION_1_0
#define EGL_VERSION_1_0 1
typedef unsigned int EGLBoolean;
typedef void *EGLDisplay;
#include <KHR/khrplatform.h>
#include <EGL/eglplatform.h>
typedef void *EGLConfig;
typedef void *EGLSurface;
typedef void *EGLContext;
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
#define EGL_ALPHA_SIZE 0x3021
#define EGL_BAD_ACCESS 0x3002
#define EGL_BAD_ALLOC 0x3003
#define EGL_BAD_ATTRIBUTE 0x3004
#define EGL_BAD_CONFIG 0x3005
#define EGL_BAD_CONTEXT 0x3006
#define EGL_BAD_CURRENT_SURFACE 0x3007
#define EGL_BAD_DISPLAY 0x3008
#define EGL_BAD_MATCH 0x3009
#define EGL_BAD_NATIVE_PIXMAP 0x300A
#define EGL_BAD_NATIVE_WINDOW 0x300B
#define EGL_BAD_PARAMETER 0x300C
#define EGL_BAD_SURFACE 0x300D
#define EGL_BLUE_SIZE 0x3022
#define EGL_BUFFER_SIZE 0x3020
#define EGL_CONFIG_CAVEAT 0x3027
#define EGL_CONFIG_ID 0x3028
#define EGL_CORE_NATIVE_ENGINE 0x305B
#define EGL_DEPTH_SIZE 0x3025
#define EGL_DONT_CARE EGL_CAST(EGLint,-1)
#define EGL_DRAW 0x3059
#define EGL_EXTENSIONS 0x3055
#define EGL_FALSE 0
#define EGL_GREEN_SIZE 0x3023
#define EGL_HEIGHT 0x3056
#define EGL_LARGEST_PBUFFER 0x3058
#define EGL_LEVEL 0x3029
#define EGL_MAX_PBUFFER_HEIGHT 0x302A
#define EGL_MAX_PBUFFER_PIXELS 0x302B
#define EGL_MAX_PBUFFER_WIDTH 0x302C
#define EGL_NATIVE_RENDERABLE 0x302D
#define EGL_NATIVE_VISUAL_ID 0x302E
#define EGL_NATIVE_VISUAL_TYPE 0x302F
#define EGL_NONE 0x3038
#define EGL_NON_CONFORMANT_CONFIG 0x3051
#define EGL_NOT_INITIALIZED 0x3001
#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)
#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)
#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
#define EGL_PBUFFER_BIT 0x0001
#define EGL_PIXMAP_BIT 0x0002
#define EGL_READ 0x305A
#define EGL_RED_SIZE 0x3024
#define EGL_SAMPLES 0x3031
#define EGL_SAMPLE_BUFFERS 0x3032
#define EGL_SLOW_CONFIG 0x3050
#define EGL_STENCIL_SIZE 0x3026
#define EGL_SUCCESS 0x3000
#define EGL_SURFACE_TYPE 0x3033
#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
#define EGL_TRANSPARENT_RED_VALUE 0x3037
#define EGL_TRANSPARENT_RGB 0x3052
#define EGL_TRANSPARENT_TYPE 0x3034
#define EGL_TRUE 1
#define EGL_VENDOR 0x3053
#define EGL_VERSION 0x3054
#define EGL_WIDTH 0x3057
#define EGL_WINDOW_BIT 0x0004
typedef EGLBoolean (EGLAPIENTRYP PFNEGLCHOOSECONFIGPROC) (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOPYBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
typedef EGLContext (EGLAPIENTRYP PFNEGLCREATECONTEXTPROC) (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERSURFACEPROC) (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGATTRIBPROC) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGSPROC) (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETCURRENTDISPLAYPROC) (void);
typedef EGLSurface (EGLAPIENTRYP PFNEGLGETCURRENTSURFACEPROC) (EGLint readdraw);
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDISPLAYPROC) (EGLNativeDisplayType display_id);
typedef EGLint (EGLAPIENTRYP PFNEGLGETERRORPROC) (void);
typedef __eglMustCastToProperFunctionPointerType (EGLAPIENTRYP PFNEGLGETPROCADDRESSPROC) (const char *procname);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLINITIALIZEPROC) (EGLDisplay dpy, EGLint *major, EGLint *minor);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLMAKECURRENTPROC) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLTERMINATEPROC) (EGLDisplay dpy);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITGLPROC) (void);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITNATIVEPROC) (EGLint engine);
#if EGL_EGL_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
EGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);
EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);
EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);
EGLAPI EGLint EGLAPIENTRY eglGetError (void);
EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);
EGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
EGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);
EGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);
EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);
EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);
#endif
#endif /* EGL_VERSION_1_0 */
#ifndef EGL_VERSION_1_1
#define EGL_VERSION_1_1 1
#define EGL_BACK_BUFFER 0x3084
#define EGL_BIND_TO_TEXTURE_RGB 0x3039
#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
#define EGL_CONTEXT_LOST 0x300E
#define EGL_MIN_SWAP_INTERVAL 0x303B
#define EGL_MAX_SWAP_INTERVAL 0x303C
#define EGL_MIPMAP_TEXTURE 0x3082
#define EGL_MIPMAP_LEVEL 0x3083
#define EGL_NO_TEXTURE 0x305C
#define EGL_TEXTURE_2D 0x305F
#define EGL_TEXTURE_FORMAT 0x3080
#define EGL_TEXTURE_RGB 0x305D
#define EGL_TEXTURE_RGBA 0x305E
#define EGL_TEXTURE_TARGET 0x3081
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDTEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSURFACEATTRIBPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPINTERVALPROC) (EGLDisplay dpy, EGLint interval);
#if EGL_EGL_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);
#endif
#endif /* EGL_VERSION_1_1 */
#ifndef EGL_VERSION_1_2
#define EGL_VERSION_1_2 1
typedef unsigned int EGLenum;
typedef void *EGLClientBuffer;
#define EGL_ALPHA_FORMAT 0x3088
#define EGL_ALPHA_FORMAT_NONPRE 0x308B
#define EGL_ALPHA_FORMAT_PRE 0x308C
#define EGL_ALPHA_MASK_SIZE 0x303E
#define EGL_BUFFER_PRESERVED 0x3094
#define EGL_BUFFER_DESTROYED 0x3095
#define EGL_CLIENT_APIS 0x308D
#define EGL_COLORSPACE 0x3087
#define EGL_COLORSPACE_sRGB 0x3089
#define EGL_COLORSPACE_LINEAR 0x308A
#define EGL_COLOR_BUFFER_TYPE 0x303F
#define EGL_CONTEXT_CLIENT_TYPE 0x3097
#define EGL_DISPLAY_SCALING 10000
#define EGL_HORIZONTAL_RESOLUTION 0x3090
#define EGL_LUMINANCE_BUFFER 0x308F
#define EGL_LUMINANCE_SIZE 0x303D
#define EGL_OPENGL_ES_BIT 0x0001
#define EGL_OPENVG_BIT 0x0002
#define EGL_OPENGL_ES_API 0x30A0
#define EGL_OPENVG_API 0x30A1
#define EGL_OPENVG_IMAGE 0x3096
#define EGL_PIXEL_ASPECT_RATIO 0x3092
#define EGL_RENDERABLE_TYPE 0x3040
#define EGL_RENDER_BUFFER 0x3086
#define EGL_RGB_BUFFER 0x308E
#define EGL_SINGLE_BUFFER 0x3085
#define EGL_SWAP_BEHAVIOR 0x3093
#define EGL_UNKNOWN EGL_CAST(EGLint,-1)
#define EGL_VERTICAL_RESOLUTION 0x3091
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDAPIPROC) (EGLenum api);
typedef EGLenum (EGLAPIENTRYP PFNEGLQUERYAPIPROC) (void);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETHREADPROC) (void);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITCLIENTPROC) (void);
#if EGL_EGL_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);
EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);
EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);
EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);
#endif
#endif /* EGL_VERSION_1_2 */
#ifndef EGL_VERSION_1_3
#define EGL_VERSION_1_3 1
#define EGL_CONFORMANT 0x3042
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
#define EGL_MATCH_NATIVE_PIXMAP 0x3041
#define EGL_OPENGL_ES2_BIT 0x0004
#define EGL_VG_ALPHA_FORMAT 0x3088
#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
#define EGL_VG_COLORSPACE 0x3087
#define EGL_VG_COLORSPACE_sRGB 0x3089
#define EGL_VG_COLORSPACE_LINEAR 0x308A
#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
#endif /* EGL_VERSION_1_3 */
#ifndef EGL_VERSION_1_4
#define EGL_VERSION_1_4 1
#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
#define EGL_MULTISAMPLE_RESOLVE 0x3099
#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
#define EGL_OPENGL_API 0x30A2
#define EGL_OPENGL_BIT 0x0008
#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
typedef EGLContext (EGLAPIENTRYP PFNEGLGETCURRENTCONTEXTPROC) (void);
#if EGL_EGL_PROTOTYPES
EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
#endif
#endif /* EGL_VERSION_1_4 */
#ifndef EGL_VERSION_1_5
#define EGL_VERSION_1_5 1
typedef void *EGLSync;
typedef intptr_t EGLAttrib;
typedef khronos_utime_nanoseconds_t EGLTime;
typedef void *EGLImage;
#define EGL_CONTEXT_MAJOR_VERSION 0x3098
#define EGL_CONTEXT_MINOR_VERSION 0x30FB
#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
#define EGL_NO_RESET_NOTIFICATION 0x31BE
#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
#define EGL_OPENGL_ES3_BIT 0x00000040
#define EGL_CL_EVENT_HANDLE 0x309C
#define EGL_SYNC_CL_EVENT 0x30FE
#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
#define EGL_SYNC_TYPE 0x30F7
#define EGL_SYNC_STATUS 0x30F1
#define EGL_SYNC_CONDITION 0x30F8
#define EGL_SIGNALED 0x30F2
#define EGL_UNSIGNALED 0x30F3
#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
#define EGL_FOREVER 0xFFFFFFFFFFFFFFFFull
#define EGL_TIMEOUT_EXPIRED 0x30F5
#define EGL_CONDITION_SATISFIED 0x30F6
#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
#define EGL_SYNC_FENCE 0x30F9
#define EGL_GL_COLORSPACE 0x309D
#define EGL_GL_COLORSPACE_SRGB 0x3089
#define EGL_GL_COLORSPACE_LINEAR 0x308A
#define EGL_GL_RENDERBUFFER 0x30B9
#define EGL_GL_TEXTURE_2D 0x30B1
#define EGL_GL_TEXTURE_LEVEL 0x30BC
#define EGL_GL_TEXTURE_3D 0x30B2
#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
#define EGL_IMAGE_PRESERVED 0x30D2
#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)
typedef EGLSync (EGLAPIENTRYP PFNEGLCREATESYNCPROC) (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCPROC) (EGLDisplay dpy, EGLSync sync);
typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBPROC) (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
typedef EGLImage (EGLAPIENTRYP PFNEGLCREATEIMAGEPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEPROC) (EGLDisplay dpy, EGLImage image);
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYPROC) (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags);
#if EGL_EGL_PROTOTYPES
EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
EGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image);
EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
EGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);
#endif
#endif /* EGL_VERSION_1_5 */
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
+182
View File
@@ -0,0 +1,182 @@
#ifndef __eglplatform_h_
#define __eglplatform_h_
/*
** Copyright (c) 2007-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Platform-specific types and definitions for egl.h
* $Revision: 30994 $ on $Date: 2015-04-30 13:36:48 -0700 (Thu, 30 Apr 2015) $
*
* Adopters may modify khrplatform.h and this file to suit their platform.
* You are encouraged to submit all modifications to the Khronos group so that
* they can be included in future versions of this file. Please submit changes
* by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
* by filing a bug against product "EGL" component "Registry".
*/
#include <KHR/khrplatform.h>
/* Macros used in EGL function prototype declarations.
*
* EGL functions should be prototyped as:
*
* EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
* typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
*
* KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
*/
#ifndef EGLAPI
#define EGLAPI KHRONOS_APICALL
#endif
#ifndef EGLAPIENTRY
#define EGLAPIENTRY KHRONOS_APIENTRY
#endif
#define EGLAPIENTRYP EGLAPIENTRY*
#if defined(MESA_EGL_NO_X11_HEADERS) && !defined(EGL_NO_X11)
#warning "`MESA_EGL_NO_X11_HEADERS` is deprecated, and doesn't work with the unmodified Khronos header"
#warning "Please use `EGL_NO_X11` instead, as `MESA_EGL_NO_X11_HEADERS` will be removed soon"
#define EGL_NO_X11
#endif
/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
* are aliases of window-system-dependent types, such as X Display * or
* Windows Device Context. They must be defined in platform-specific
* code below. The EGL-prefixed versions of Native*Type are the same
* types, renamed in EGL 1.3 so all types in the API start with "EGL".
*
* Khronos STRONGLY RECOMMENDS that you use the default definitions
* provided below, since these changes affect both binary and source
* portability of applications using EGL running on different EGL
* implementations.
*/
#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
typedef HDC EGLNativeDisplayType;
typedef HBITMAP EGLNativePixmapType;
typedef HWND EGLNativeWindowType;
#elif defined(__EMSCRIPTEN__)
typedef int EGLNativeDisplayType;
typedef int EGLNativePixmapType;
typedef int EGLNativeWindowType;
#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
typedef int EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
#elif defined(WL_EGL_PLATFORM)
typedef struct wl_display *EGLNativeDisplayType;
typedef struct wl_egl_pixmap *EGLNativePixmapType;
typedef struct wl_egl_window *EGLNativeWindowType;
#elif defined(__GBM__)
typedef struct gbm_device *EGLNativeDisplayType;
typedef struct gbm_bo *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
#elif defined(__ANDROID__) || defined(ANDROID)
struct ANativeWindow;
struct egl_native_pixmap_t;
typedef void* EGLNativeDisplayType;
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef struct ANativeWindow* EGLNativeWindowType;
#elif defined(USE_OZONE)
typedef intptr_t EGLNativeDisplayType;
typedef intptr_t EGLNativePixmapType;
typedef intptr_t EGLNativeWindowType;
#elif defined(__unix__) && defined(EGL_NO_X11)
typedef void *EGLNativeDisplayType;
typedef khronos_uintptr_t EGLNativePixmapType;
typedef khronos_uintptr_t EGLNativeWindowType;
#elif defined(__unix__) || defined(USE_X11)
/* X11 (tentative) */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
typedef Display *EGLNativeDisplayType;
typedef Pixmap EGLNativePixmapType;
typedef Window EGLNativeWindowType;
#elif defined(__APPLE__)
typedef int EGLNativeDisplayType;
typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
#elif defined(__HAIKU__)
#include <kernel/image.h>
typedef void *EGLNativeDisplayType;
typedef khronos_uintptr_t EGLNativePixmapType;
typedef khronos_uintptr_t EGLNativeWindowType;
#else
#error "Platform not recognized"
#endif
/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
typedef EGLNativeDisplayType NativeDisplayType;
typedef EGLNativePixmapType NativePixmapType;
typedef EGLNativeWindowType NativeWindowType;
/* Define EGLint. This must be a signed integral type large enough to contain
* all legal attribute names and values passed into and out of EGL, whether
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
* handle, or other. While in general a 32-bit integer will suffice, if
* handles are 64 bit types, then EGLint should be defined as a signed 64-bit
* integer type.
*/
typedef khronos_int32_t EGLint;
/* C++ / C typecast macros for special EGL handle values */
#if defined(__cplusplus)
#define EGL_CAST(type, value) (static_cast<type>(value))
#else
#define EGL_CAST(type, value) ((type) (value))
#endif
#endif /* __eglplatform_h */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+353
View File
@@ -0,0 +1,353 @@
/*
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice including the dates of first publication and
* either this permission notice or a reference to
* http://oss.sgi.com/projects/FreeB/
* shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of Silicon Graphics, Inc.
* shall not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization from
* Silicon Graphics, Inc.
*/
#ifndef __glu_h__
#define __glu_h__
#if defined(USE_MGL_NAMESPACE)
#include "glu_mangle.h"
#endif
#include <GL/gl.h>
#ifndef GLAPIENTRY
#if defined(_MSC_VER) || defined(__MINGW32__)
#define GLAPIENTRY __stdcall
#else
#define GLAPIENTRY
#endif
#endif
#ifndef GLAPIENTRYP
#define GLAPIENTRYP GLAPIENTRY *
#endif
#if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GLU32)
# undef GLAPI
# define GLAPI __declspec(dllexport)
#elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL)
/* tag specifying we're building for DLL runtime support */
# undef GLAPI
# define GLAPI __declspec(dllimport)
#elif !defined(GLAPI)
/* for use with static link lib build of Win32 edition only */
# define GLAPI extern
#endif /* _STATIC_MESA support */
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************/
/* Extensions */
#define GLU_EXT_object_space_tess 1
#define GLU_EXT_nurbs_tessellator 1
/* Boolean */
#define GLU_FALSE 0
#define GLU_TRUE 1
/* Version */
#define GLU_VERSION_1_1 1
#define GLU_VERSION_1_2 1
#define GLU_VERSION_1_3 1
/* StringName */
#define GLU_VERSION 100800
#define GLU_EXTENSIONS 100801
/* ErrorCode */
#define GLU_INVALID_ENUM 100900
#define GLU_INVALID_VALUE 100901
#define GLU_OUT_OF_MEMORY 100902
#define GLU_INCOMPATIBLE_GL_VERSION 100903
#define GLU_INVALID_OPERATION 100904
/* NurbsDisplay */
/* GLU_FILL */
#define GLU_OUTLINE_POLYGON 100240
#define GLU_OUTLINE_PATCH 100241
/* NurbsCallback */
#define GLU_NURBS_ERROR 100103
#define GLU_ERROR 100103
#define GLU_NURBS_BEGIN 100164
#define GLU_NURBS_BEGIN_EXT 100164
#define GLU_NURBS_VERTEX 100165
#define GLU_NURBS_VERTEX_EXT 100165
#define GLU_NURBS_NORMAL 100166
#define GLU_NURBS_NORMAL_EXT 100166
#define GLU_NURBS_COLOR 100167
#define GLU_NURBS_COLOR_EXT 100167
#define GLU_NURBS_TEXTURE_COORD 100168
#define GLU_NURBS_TEX_COORD_EXT 100168
#define GLU_NURBS_END 100169
#define GLU_NURBS_END_EXT 100169
#define GLU_NURBS_BEGIN_DATA 100170
#define GLU_NURBS_BEGIN_DATA_EXT 100170
#define GLU_NURBS_VERTEX_DATA 100171
#define GLU_NURBS_VERTEX_DATA_EXT 100171
#define GLU_NURBS_NORMAL_DATA 100172
#define GLU_NURBS_NORMAL_DATA_EXT 100172
#define GLU_NURBS_COLOR_DATA 100173
#define GLU_NURBS_COLOR_DATA_EXT 100173
#define GLU_NURBS_TEXTURE_COORD_DATA 100174
#define GLU_NURBS_TEX_COORD_DATA_EXT 100174
#define GLU_NURBS_END_DATA 100175
#define GLU_NURBS_END_DATA_EXT 100175
/* NurbsError */
#define GLU_NURBS_ERROR1 100251
#define GLU_NURBS_ERROR2 100252
#define GLU_NURBS_ERROR3 100253
#define GLU_NURBS_ERROR4 100254
#define GLU_NURBS_ERROR5 100255
#define GLU_NURBS_ERROR6 100256
#define GLU_NURBS_ERROR7 100257
#define GLU_NURBS_ERROR8 100258
#define GLU_NURBS_ERROR9 100259
#define GLU_NURBS_ERROR10 100260
#define GLU_NURBS_ERROR11 100261
#define GLU_NURBS_ERROR12 100262
#define GLU_NURBS_ERROR13 100263
#define GLU_NURBS_ERROR14 100264
#define GLU_NURBS_ERROR15 100265
#define GLU_NURBS_ERROR16 100266
#define GLU_NURBS_ERROR17 100267
#define GLU_NURBS_ERROR18 100268
#define GLU_NURBS_ERROR19 100269
#define GLU_NURBS_ERROR20 100270
#define GLU_NURBS_ERROR21 100271
#define GLU_NURBS_ERROR22 100272
#define GLU_NURBS_ERROR23 100273
#define GLU_NURBS_ERROR24 100274
#define GLU_NURBS_ERROR25 100275
#define GLU_NURBS_ERROR26 100276
#define GLU_NURBS_ERROR27 100277
#define GLU_NURBS_ERROR28 100278
#define GLU_NURBS_ERROR29 100279
#define GLU_NURBS_ERROR30 100280
#define GLU_NURBS_ERROR31 100281
#define GLU_NURBS_ERROR32 100282
#define GLU_NURBS_ERROR33 100283
#define GLU_NURBS_ERROR34 100284
#define GLU_NURBS_ERROR35 100285
#define GLU_NURBS_ERROR36 100286
#define GLU_NURBS_ERROR37 100287
/* NurbsProperty */
#define GLU_AUTO_LOAD_MATRIX 100200
#define GLU_CULLING 100201
#define GLU_SAMPLING_TOLERANCE 100203
#define GLU_DISPLAY_MODE 100204
#define GLU_PARAMETRIC_TOLERANCE 100202
#define GLU_SAMPLING_METHOD 100205
#define GLU_U_STEP 100206
#define GLU_V_STEP 100207
#define GLU_NURBS_MODE 100160
#define GLU_NURBS_MODE_EXT 100160
#define GLU_NURBS_TESSELLATOR 100161
#define GLU_NURBS_TESSELLATOR_EXT 100161
#define GLU_NURBS_RENDERER 100162
#define GLU_NURBS_RENDERER_EXT 100162
/* NurbsSampling */
#define GLU_OBJECT_PARAMETRIC_ERROR 100208
#define GLU_OBJECT_PARAMETRIC_ERROR_EXT 100208
#define GLU_OBJECT_PATH_LENGTH 100209
#define GLU_OBJECT_PATH_LENGTH_EXT 100209
#define GLU_PATH_LENGTH 100215
#define GLU_PARAMETRIC_ERROR 100216
#define GLU_DOMAIN_DISTANCE 100217
/* NurbsTrim */
#define GLU_MAP1_TRIM_2 100210
#define GLU_MAP1_TRIM_3 100211
/* QuadricDrawStyle */
#define GLU_POINT 100010
#define GLU_LINE 100011
#define GLU_FILL 100012
#define GLU_SILHOUETTE 100013
/* QuadricCallback */
/* GLU_ERROR */
/* QuadricNormal */
#define GLU_SMOOTH 100000
#define GLU_FLAT 100001
#define GLU_NONE 100002
/* QuadricOrientation */
#define GLU_OUTSIDE 100020
#define GLU_INSIDE 100021
/* TessCallback */
#define GLU_TESS_BEGIN 100100
#define GLU_BEGIN 100100
#define GLU_TESS_VERTEX 100101
#define GLU_VERTEX 100101
#define GLU_TESS_END 100102
#define GLU_END 100102
#define GLU_TESS_ERROR 100103
#define GLU_TESS_EDGE_FLAG 100104
#define GLU_EDGE_FLAG 100104
#define GLU_TESS_COMBINE 100105
#define GLU_TESS_BEGIN_DATA 100106
#define GLU_TESS_VERTEX_DATA 100107
#define GLU_TESS_END_DATA 100108
#define GLU_TESS_ERROR_DATA 100109
#define GLU_TESS_EDGE_FLAG_DATA 100110
#define GLU_TESS_COMBINE_DATA 100111
/* TessContour */
#define GLU_CW 100120
#define GLU_CCW 100121
#define GLU_INTERIOR 100122
#define GLU_EXTERIOR 100123
#define GLU_UNKNOWN 100124
/* TessProperty */
#define GLU_TESS_WINDING_RULE 100140
#define GLU_TESS_BOUNDARY_ONLY 100141
#define GLU_TESS_TOLERANCE 100142
/* TessError */
#define GLU_TESS_ERROR1 100151
#define GLU_TESS_ERROR2 100152
#define GLU_TESS_ERROR3 100153
#define GLU_TESS_ERROR4 100154
#define GLU_TESS_ERROR5 100155
#define GLU_TESS_ERROR6 100156
#define GLU_TESS_ERROR7 100157
#define GLU_TESS_ERROR8 100158
#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
#define GLU_TESS_MISSING_END_POLYGON 100153
#define GLU_TESS_MISSING_END_CONTOUR 100154
#define GLU_TESS_COORD_TOO_LARGE 100155
#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
/* TessWinding */
#define GLU_TESS_WINDING_ODD 100130
#define GLU_TESS_WINDING_NONZERO 100131
#define GLU_TESS_WINDING_POSITIVE 100132
#define GLU_TESS_WINDING_NEGATIVE 100133
#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
/*************************************************************/
#ifdef __cplusplus
class GLUnurbs;
class GLUquadric;
class GLUtesselator;
#else
typedef struct GLUnurbs GLUnurbs;
typedef struct GLUquadric GLUquadric;
typedef struct GLUtesselator GLUtesselator;
#endif
typedef GLUnurbs GLUnurbsObj;
typedef GLUquadric GLUquadricObj;
typedef GLUtesselator GLUtesselatorObj;
typedef GLUtesselator GLUtriangulatorObj;
#define GLU_TESS_MAX_COORD 1.0e150
/* Internal convenience typedefs */
typedef void (GLAPIENTRYP _GLUfuncptr)(void);
GLAPI void GLAPIENTRY gluBeginCurve (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluBeginPolygon (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluBeginSurface (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluBeginTrim (GLUnurbs* nurb);
GLAPI GLint GLAPIENTRY gluBuild1DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild2DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
GLAPI GLint GLAPIENTRY gluBuild3DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
GLAPI GLboolean GLAPIENTRY gluCheckExtension (const GLubyte *extName, const GLubyte *extString);
GLAPI void GLAPIENTRY gluCylinder (GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks);
GLAPI void GLAPIENTRY gluDeleteNurbsRenderer (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluDeleteQuadric (GLUquadric* quad);
GLAPI void GLAPIENTRY gluDeleteTess (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops);
GLAPI void GLAPIENTRY gluEndCurve (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluEndPolygon (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluEndSurface (GLUnurbs* nurb);
GLAPI void GLAPIENTRY gluEndTrim (GLUnurbs* nurb);
GLAPI const GLubyte * GLAPIENTRY gluErrorString (GLenum error);
GLAPI void GLAPIENTRY gluGetNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat* data);
GLAPI const GLubyte * GLAPIENTRY gluGetString (GLenum name);
GLAPI void GLAPIENTRY gluGetTessProperty (GLUtesselator* tess, GLenum which, GLdouble* data);
GLAPI void GLAPIENTRY gluLoadSamplingMatrices (GLUnurbs* nurb, const GLfloat *model, const GLfloat *perspective, const GLint *view);
GLAPI void GLAPIENTRY gluLookAt (GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ);
GLAPI GLUnurbs* GLAPIENTRY gluNewNurbsRenderer (void);
GLAPI GLUquadric* GLAPIENTRY gluNewQuadric (void);
GLAPI GLUtesselator* GLAPIENTRY gluNewTess (void);
GLAPI void GLAPIENTRY gluNextContour (GLUtesselator* tess, GLenum type);
GLAPI void GLAPIENTRY gluNurbsCallback (GLUnurbs* nurb, GLenum which, _GLUfuncptr CallBackFunc);
GLAPI void GLAPIENTRY gluNurbsCallbackData (GLUnurbs* nurb, GLvoid* userData);
GLAPI void GLAPIENTRY gluNurbsCallbackDataEXT (GLUnurbs* nurb, GLvoid* userData);
GLAPI void GLAPIENTRY gluNurbsCurve (GLUnurbs* nurb, GLint knotCount, GLfloat *knots, GLint stride, GLfloat *control, GLint order, GLenum type);
GLAPI void GLAPIENTRY gluNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat value);
GLAPI void GLAPIENTRY gluNurbsSurface (GLUnurbs* nurb, GLint sKnotCount, GLfloat* sKnots, GLint tKnotCount, GLfloat* tKnots, GLint sStride, GLint tStride, GLfloat* control, GLint sOrder, GLint tOrder, GLenum type);
GLAPI void GLAPIENTRY gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
GLAPI void GLAPIENTRY gluPartialDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops, GLdouble start, GLdouble sweep);
GLAPI void GLAPIENTRY gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
GLAPI void GLAPIENTRY gluPickMatrix (GLdouble x, GLdouble y, GLdouble delX, GLdouble delY, GLint *viewport);
GLAPI GLint GLAPIENTRY gluProject (GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* winX, GLdouble* winY, GLdouble* winZ);
GLAPI void GLAPIENTRY gluPwlCurve (GLUnurbs* nurb, GLint count, GLfloat* data, GLint stride, GLenum type);
GLAPI void GLAPIENTRY gluQuadricCallback (GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);
GLAPI void GLAPIENTRY gluQuadricDrawStyle (GLUquadric* quad, GLenum draw);
GLAPI void GLAPIENTRY gluQuadricNormals (GLUquadric* quad, GLenum normal);
GLAPI void GLAPIENTRY gluQuadricOrientation (GLUquadric* quad, GLenum orientation);
GLAPI void GLAPIENTRY gluQuadricTexture (GLUquadric* quad, GLboolean texture);
GLAPI GLint GLAPIENTRY gluScaleImage (GLenum format, GLsizei wIn, GLsizei hIn, GLenum typeIn, const void *dataIn, GLsizei wOut, GLsizei hOut, GLenum typeOut, GLvoid* dataOut);
GLAPI void GLAPIENTRY gluSphere (GLUquadric* quad, GLdouble radius, GLint slices, GLint stacks);
GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ);
GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data);
GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data);
GLAPI GLint GLAPIENTRY gluUnProject (GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* objX, GLdouble* objY, GLdouble* objZ);
GLAPI GLint GLAPIENTRY gluUnProject4 (GLdouble winX, GLdouble winY, GLdouble winZ, GLdouble clipW, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble nearVal, GLdouble farVal, GLdouble* objX, GLdouble* objY, GLdouble* objZ, GLdouble* objW);
#ifdef __cplusplus
}
#endif
#endif /* __glu_h__ */
+86
View File
@@ -0,0 +1,86 @@
/*
* Mesa 3-D graphics library
* Version: 3.0
* Copyright (C) 1995-1998 Brian Paul
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef GLU_MANGLE_H
#define GLU_MANGLE_H
#define gluLookAt mgluLookAt
#define gluOrtho2D mgluOrtho2D
#define gluPerspective mgluPerspective
#define gluPickMatrix mgluPickMatrix
#define gluProject mgluProject
#define gluUnProject mgluUnProject
#define gluErrorString mgluErrorString
#define gluScaleImage mgluScaleImage
#define gluBuild1DMipmaps mgluBuild1DMipmaps
#define gluBuild2DMipmaps mgluBuild2DMipmaps
#define gluNewQuadric mgluNewQuadric
#define gluDeleteQuadric mgluDeleteQuadric
#define gluQuadricDrawStyle mgluQuadricDrawStyle
#define gluQuadricOrientation mgluQuadricOrientation
#define gluQuadricNormals mgluQuadricNormals
#define gluQuadricTexture mgluQuadricTexture
#define gluQuadricCallback mgluQuadricCallback
#define gluCylinder mgluCylinder
#define gluSphere mgluSphere
#define gluDisk mgluDisk
#define gluPartialDisk mgluPartialDisk
#define gluNewNurbsRenderer mgluNewNurbsRenderer
#define gluDeleteNurbsRenderer mgluDeleteNurbsRenderer
#define gluLoadSamplingMatrices mgluLoadSamplingMatrices
#define gluNurbsProperty mgluNurbsProperty
#define gluGetNurbsProperty mgluGetNurbsProperty
#define gluBeginCurve mgluBeginCurve
#define gluEndCurve mgluEndCurve
#define gluNurbsCurve mgluNurbsCurve
#define gluBeginSurface mgluBeginSurface
#define gluEndSurface mgluEndSurface
#define gluNurbsSurface mgluNurbsSurface
#define gluBeginTrim mgluBeginTrim
#define gluEndTrim mgluEndTrim
#define gluPwlCurve mgluPwlCurve
#define gluNurbsCallback mgluNurbsCallback
#define gluNewTess mgluNewTess
#define gluDeleteTess mgluDeleteTess
#define gluTessBeginPolygon mgluTessBeginPolygon
#define gluTessBeginContour mgluTessBeginContour
#define gluTessVertex mgluTessVertex
#define gluTessEndPolygon mgluTessEndPolygon
#define gluTessEndContour mgluTessEndContour
#define gluTessProperty mgluTessProperty
#define gluTessNormal mgluTessNormal
#define gluTessCallback mgluTessCallback
#define gluGetTessProperty mgluGetTessProperty
#define gluBeginPolygon mgluBeginPolygon
#define gluNextContour mgluNextContour
#define gluEndPolygon mgluEndPolygon
#define gluGetString mgluGetString
#define gluBuild1DMipmapLevels mgluBuild1DMipmapLevels
#define gluBuild2DMipmapLevels mgluBuild2DMipmapLevels
#define gluBuild3DMipmapLevels mgluBuild3DMipmapLevels
#define gluBuild3DMipmaps mgluBuild3DMipmaps
#define gluCheckExtension mgluCheckExtension
#define gluUnProject4 mgluUnProject4
#define gluNurbsCallbackData mgluNurbsCallbackData
#define gluNurbsCallbackDataEXT mgluNurbsCallbackDataEXT
#endif
+528
View File
@@ -0,0 +1,528 @@
/*
* Mesa 3-D graphics library
* Version: 6.5
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef GLX_H
#define GLX_H
#ifdef __VMS
#include <GL/vms_x_fix.h>
# ifdef __cplusplus
/* VMS Xlib.h gives problems with C++.
* this avoids a bunch of trivial warnings */
#pragma message disable nosimpint
#endif
#endif
#ifndef NOX11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#endif // NOX11
#ifdef __VMS
# ifdef __cplusplus
#pragma message enable nosimpint
#endif
#endif
#include <GL/gl.h>
#if defined(USE_MGL_NAMESPACE)
#include "glx_mangle.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define GLX_VERSION_1_1 1
#define GLX_VERSION_1_2 1
#define GLX_VERSION_1_3 1
#define GLX_VERSION_1_4 1
#define GLX_EXTENSION_NAME "GLX"
/*
* Tokens for glXChooseVisual and glXGetConfig:
*/
#define GLX_USE_GL 1
#define GLX_BUFFER_SIZE 2
#define GLX_LEVEL 3
#define GLX_RGBA 4
#define GLX_DOUBLEBUFFER 5
#define GLX_STEREO 6
#define GLX_AUX_BUFFERS 7
#define GLX_RED_SIZE 8
#define GLX_GREEN_SIZE 9
#define GLX_BLUE_SIZE 10
#define GLX_ALPHA_SIZE 11
#define GLX_DEPTH_SIZE 12
#define GLX_STENCIL_SIZE 13
#define GLX_ACCUM_RED_SIZE 14
#define GLX_ACCUM_GREEN_SIZE 15
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_ALPHA_SIZE 17
/*
* Error codes returned by glXGetConfig:
*/
#define GLX_BAD_SCREEN 1
#define GLX_BAD_ATTRIBUTE 2
#define GLX_NO_EXTENSION 3
#define GLX_BAD_VISUAL 4
#define GLX_BAD_CONTEXT 5
#define GLX_BAD_VALUE 6
#define GLX_BAD_ENUM 7
/*
* GLX 1.1 and later:
*/
#define GLX_VENDOR 1
#define GLX_VERSION 2
#define GLX_EXTENSIONS 3
/*
* GLX 1.3 and later:
*/
#define GLX_CONFIG_CAVEAT 0x20
#define GLX_DONT_CARE 0xFFFFFFFF
#define GLX_X_VISUAL_TYPE 0x22
#define GLX_TRANSPARENT_TYPE 0x23
#define GLX_TRANSPARENT_INDEX_VALUE 0x24
#define GLX_TRANSPARENT_RED_VALUE 0x25
#define GLX_TRANSPARENT_GREEN_VALUE 0x26
#define GLX_TRANSPARENT_BLUE_VALUE 0x27
#define GLX_TRANSPARENT_ALPHA_VALUE 0x28
#define GLX_WINDOW_BIT 0x00000001
#define GLX_PIXMAP_BIT 0x00000002
#define GLX_PBUFFER_BIT 0x00000004
#define GLX_AUX_BUFFERS_BIT 0x00000010
#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001
#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002
#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008
#define GLX_DEPTH_BUFFER_BIT 0x00000020
#define GLX_STENCIL_BUFFER_BIT 0x00000040
#define GLX_ACCUM_BUFFER_BIT 0x00000080
#define GLX_NONE 0x8000
#define GLX_SLOW_CONFIG 0x8001
#define GLX_TRUE_COLOR 0x8002
#define GLX_DIRECT_COLOR 0x8003
#define GLX_PSEUDO_COLOR 0x8004
#define GLX_STATIC_COLOR 0x8005
#define GLX_GRAY_SCALE 0x8006
#define GLX_STATIC_GRAY 0x8007
#define GLX_TRANSPARENT_RGB 0x8008
#define GLX_TRANSPARENT_INDEX 0x8009
#define GLX_VISUAL_ID 0x800B
#define GLX_SCREEN 0x800C
#define GLX_NON_CONFORMANT_CONFIG 0x800D
#define GLX_DRAWABLE_TYPE 0x8010
#define GLX_RENDER_TYPE 0x8011
#define GLX_X_RENDERABLE 0x8012
#define GLX_FBCONFIG_ID 0x8013
#define GLX_RGBA_TYPE 0x8014
#define GLX_COLOR_INDEX_TYPE 0x8015
#define GLX_MAX_PBUFFER_WIDTH 0x8016
#define GLX_MAX_PBUFFER_HEIGHT 0x8017
#define GLX_MAX_PBUFFER_PIXELS 0x8018
#define GLX_PRESERVED_CONTENTS 0x801B
#define GLX_LARGEST_PBUFFER 0x801C
#define GLX_WIDTH 0x801D
#define GLX_HEIGHT 0x801E
#define GLX_EVENT_MASK 0x801F
#define GLX_DAMAGED 0x8020
#define GLX_SAVED 0x8021
#define GLX_WINDOW 0x8022
#define GLX_PBUFFER 0x8023
#define GLX_PBUFFER_HEIGHT 0x8040
#define GLX_PBUFFER_WIDTH 0x8041
#define GLX_RGBA_BIT 0x00000001
#define GLX_COLOR_INDEX_BIT 0x00000002
#define GLX_PBUFFER_CLOBBER_MASK 0x08000000
/*
* GLX 1.4 and later:
*/
#define GLX_SAMPLE_BUFFERS 0x186a0 /*100000*/
#define GLX_SAMPLES 0x186a1 /*100001*/
typedef struct __GLXcontextRec *GLXContext;
typedef XID GLXPixmap;
typedef XID GLXDrawable;
/* GLX 1.3 and later */
typedef struct __GLXFBConfigRec *GLXFBConfig;
typedef XID GLXFBConfigID;
typedef XID GLXContextID;
typedef XID GLXWindow;
typedef XID GLXPbuffer;
/*
** Events.
** __GLX_NUMBER_EVENTS is set to 17 to account for the BufferClobberSGIX
** event - this helps initialization if the server supports the pbuffer
** extension and the client doesn't.
*/
#define GLX_PbufferClobber 0
#define GLX_BufferSwapComplete 1
#define __GLX_NUMBER_EVENTS 17
extern XVisualInfo* glXChooseVisual( Display *dpy, int screen,
int *attribList );
extern GLXContext glXCreateContext( Display *dpy, XVisualInfo *vis,
GLXContext shareList, Bool direct );
extern void glXDestroyContext( Display *dpy, GLXContext ctx );
extern Bool glXMakeCurrent( Display *dpy, GLXDrawable drawable,
GLXContext ctx);
extern void glXCopyContext( Display *dpy, GLXContext src, GLXContext dst,
unsigned long mask );
extern void glXSwapBuffers( Display *dpy, GLXDrawable drawable );
extern GLXPixmap glXCreateGLXPixmap( Display *dpy, XVisualInfo *visual,
Pixmap pixmap );
extern void glXDestroyGLXPixmap( Display *dpy, GLXPixmap pixmap );
extern Bool glXQueryExtension( Display *dpy, int *errorb, int *event );
extern Bool glXQueryVersion( Display *dpy, int *maj, int *min );
extern Bool glXIsDirect( Display *dpy, GLXContext ctx );
extern int glXGetConfig( Display *dpy, XVisualInfo *visual,
int attrib, int *value );
extern GLXContext glXGetCurrentContext( void );
extern GLXDrawable glXGetCurrentDrawable( void );
extern void glXWaitGL( void );
extern void glXWaitX( void );
extern void glXUseXFont( Font font, int first, int count, int list );
/* GLX 1.1 and later */
extern const char *glXQueryExtensionsString( Display *dpy, int screen );
extern const char *glXQueryServerString( Display *dpy, int screen, int name );
extern const char *glXGetClientString( Display *dpy, int name );
/* GLX 1.2 and later */
extern Display *glXGetCurrentDisplay( void );
/* GLX 1.3 and later */
extern GLXFBConfig *glXChooseFBConfig( Display *dpy, int screen,
const int *attribList, int *nitems );
extern int glXGetFBConfigAttrib( Display *dpy, GLXFBConfig config,
int attribute, int *value );
extern GLXFBConfig *glXGetFBConfigs( Display *dpy, int screen,
int *nelements );
extern XVisualInfo *glXGetVisualFromFBConfig( Display *dpy,
GLXFBConfig config );
extern GLXWindow glXCreateWindow( Display *dpy, GLXFBConfig config,
Window win, const int *attribList );
extern void glXDestroyWindow( Display *dpy, GLXWindow window );
extern GLXPixmap glXCreatePixmap( Display *dpy, GLXFBConfig config,
Pixmap pixmap, const int *attribList );
extern void glXDestroyPixmap( Display *dpy, GLXPixmap pixmap );
extern GLXPbuffer glXCreatePbuffer( Display *dpy, GLXFBConfig config,
const int *attribList );
extern void glXDestroyPbuffer( Display *dpy, GLXPbuffer pbuf );
extern void glXQueryDrawable( Display *dpy, GLXDrawable draw, int attribute,
unsigned int *value );
extern GLXContext glXCreateNewContext( Display *dpy, GLXFBConfig config,
int renderType, GLXContext shareList,
Bool direct );
extern Bool glXMakeContextCurrent( Display *dpy, GLXDrawable draw,
GLXDrawable read, GLXContext ctx );
extern GLXDrawable glXGetCurrentReadDrawable( void );
extern int glXQueryContext( Display *dpy, GLXContext ctx, int attribute,
int *value );
extern void glXSelectEvent( Display *dpy, GLXDrawable drawable,
unsigned long mask );
extern void glXGetSelectedEvent( Display *dpy, GLXDrawable drawable,
unsigned long *mask );
/* GLX 1.3 function pointer typedefs */
typedef GLXFBConfig * (* PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements);
typedef GLXFBConfig * (* PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
typedef int (* PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value);
typedef XVisualInfo * (* PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);
typedef GLXWindow (* PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
typedef void (* PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win);
typedef GLXPixmap (* PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
typedef void (* PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap);
typedef GLXPbuffer (* PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list);
typedef void (* PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf);
typedef void (* PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
typedef GLXContext (* PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
typedef Bool (* PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
typedef GLXDrawable (* PFNGLXGETCURRENTREADDRAWABLEPROC) (void);
typedef Display * (* PFNGLXGETCURRENTDISPLAYPROC) (void);
typedef int (* PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value);
typedef void (* PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask);
typedef void (* PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
/*
* ARB 2. GLX_ARB_get_proc_address
*/
#ifndef GLX_ARB_get_proc_address
#define GLX_ARB_get_proc_address 1
typedef void (*__GLXextFuncPtr)(void);
extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *);
#endif /* GLX_ARB_get_proc_address */
/* GLX 1.4 and later */
extern void (*glXGetProcAddress(const GLubyte *procname))( void );
/* GLX 1.4 function pointer typedefs */
typedef __GLXextFuncPtr (* PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName);
#ifndef GLX_GLXEXT_LEGACY
#include <GL/glxext.h>
#endif /* GLX_GLXEXT_LEGACY */
/**
** The following aren't in glxext.h yet.
**/
/*
* ???. GLX_NV_vertex_array_range
*/
#ifndef GLX_NV_vertex_array_range
#define GLX_NV_vertex_array_range
extern void *glXAllocateMemoryNV(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
extern void glXFreeMemoryNV(GLvoid *pointer);
typedef void * ( * PFNGLXALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
typedef void ( * PFNGLXFREEMEMORYNVPROC) (GLvoid *pointer);
#endif /* GLX_NV_vertex_array_range */
/*
* ARB ?. GLX_ARB_render_texture
* XXX This was never finalized!
*/
#ifndef GLX_ARB_render_texture
#define GLX_ARB_render_texture 1
extern Bool glXBindTexImageARB(Display *dpy, GLXPbuffer pbuffer, int buffer);
extern Bool glXReleaseTexImageARB(Display *dpy, GLXPbuffer pbuffer, int buffer);
extern Bool glXDrawableAttribARB(Display *dpy, GLXDrawable draw, const int *attribList);
#endif /* GLX_ARB_render_texture */
/*
* Remove this when glxext.h is updated.
*/
#ifndef GLX_NV_float_buffer
#define GLX_NV_float_buffer 1
#define GLX_FLOAT_COMPONENTS_NV 0x20B0
#endif /* GLX_NV_float_buffer */
/*
* #?. GLX_MESA_swap_frame_usage
*/
#ifndef GLX_MESA_swap_frame_usage
#define GLX_MESA_swap_frame_usage 1
extern int glXGetFrameUsageMESA(Display *dpy, GLXDrawable drawable, float *usage);
extern int glXBeginFrameTrackingMESA(Display *dpy, GLXDrawable drawable);
extern int glXEndFrameTrackingMESA(Display *dpy, GLXDrawable drawable);
extern int glXQueryFrameTrackingMESA(Display *dpy, GLXDrawable drawable, int64_t *swapCount, int64_t *missedFrames, float *lastMissedUsage);
typedef int (*PFNGLXGETFRAMEUSAGEMESAPROC) (Display *dpy, GLXDrawable drawable, float *usage);
typedef int (*PFNGLXBEGINFRAMETRACKINGMESAPROC)(Display *dpy, GLXDrawable drawable);
typedef int (*PFNGLXENDFRAMETRACKINGMESAPROC)(Display *dpy, GLXDrawable drawable);
typedef int (*PFNGLXQUERYFRAMETRACKINGMESAPROC)(Display *dpy, GLXDrawable drawable, int64_t *swapCount, int64_t *missedFrames, float *lastMissedUsage);
#endif /* GLX_MESA_swap_frame_usage */
/*
* #?. GLX_MESA_swap_control
*/
#ifndef GLX_MESA_swap_control
#define GLX_MESA_swap_control 1
extern int glXSwapIntervalMESA(unsigned int interval);
extern int glXGetSwapIntervalMESA(void);
typedef int (*PFNGLXSWAPINTERVALMESAPROC)(unsigned int interval);
typedef int (*PFNGLXGETSWAPINTERVALMESAPROC)(void);
#endif /* GLX_MESA_swap_control */
/*
* #?. GLX_EXT_texture_from_pixmap
* XXX not finished?
*/
#ifndef GLX_EXT_texture_from_pixmap
#define GLX_EXT_texture_from_pixmap 1
#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
#define GLX_Y_INVERTED_EXT 0x20D4
#define GLX_TEXTURE_FORMAT_EXT 0x20D5
#define GLX_TEXTURE_TARGET_EXT 0x20D6
#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
#define GLX_TEXTURE_1D_BIT_EXT 0x00000001
#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
#define GLX_TEXTURE_1D_EXT 0x20DB
#define GLX_TEXTURE_2D_EXT 0x20DC
#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
#define GLX_FRONT_LEFT_EXT 0x20DE
#define GLX_FRONT_RIGHT_EXT 0x20DF
#define GLX_BACK_LEFT_EXT 0x20E0
#define GLX_BACK_RIGHT_EXT 0x20E1
#define GLX_FRONT_EXT GLX_FRONT_LEFT_EXT
#define GLX_BACK_EXT GLX_BACK_LEFT_EXT
#define GLX_AUX0_EXT 0x20E2
#define GLX_AUX1_EXT 0x20E3
#define GLX_AUX2_EXT 0x20E4
#define GLX_AUX3_EXT 0x20E5
#define GLX_AUX4_EXT 0x20E6
#define GLX_AUX5_EXT 0x20E7
#define GLX_AUX6_EXT 0x20E8
#define GLX_AUX7_EXT 0x20E9
#define GLX_AUX8_EXT 0x20EA
#define GLX_AUX9_EXT 0x20EB
extern void glXBindTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
extern void glXReleaseTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer);
#endif /* GLX_EXT_texture_from_pixmap */
/*** Should these go here, or in another header? */
/*
** GLX Events
*/
typedef struct {
int event_type; /* GLX_DAMAGED or GLX_SAVED */
int draw_type; /* GLX_WINDOW or GLX_PBUFFER */
unsigned long serial; /* # of last request processed by server */
Bool send_event; /* true if this came for SendEvent request */
Display *display; /* display the event was read from */
GLXDrawable drawable; /* XID of Drawable */
unsigned int buffer_mask; /* mask indicating which buffers are affected */
unsigned int aux_buffer; /* which aux buffer was affected */
int x, y;
int width, height;
int count; /* if nonzero, at least this many more */
} GLXPbufferClobberEvent;
typedef struct {
int type;
unsigned long serial; /* # of last request processed by server */
Bool send_event; /* true if this came from a SendEvent request */
Display *display; /* Display the event was read from */
GLXDrawable drawable; /* drawable on which event was requested in event mask */
int event_type;
int64_t ust;
int64_t msc;
int64_t sbc;
} GLXBufferSwapComplete;
typedef union __GLXEvent {
GLXPbufferClobberEvent glxpbufferclobber;
GLXBufferSwapComplete glxbufferswapcomplete;
long pad[24];
} GLXEvent;
#ifdef __cplusplus
}
#endif
#endif
+82
View File
@@ -0,0 +1,82 @@
/*
* Mesa 3-D graphics library
* Version: 6.5
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef GLX_MANGLE_H
#define GLX_MANGLE_H
#define glXChooseVisual mglXChooseVisual
#define glXCreateContext mglXCreateContext
#define glXDestroyContext mglXDestroyContext
#define glXMakeCurrent mglXMakeCurrent
#define glXCopyContext mglXCopyContext
#define glXSwapBuffers mglXSwapBuffers
#define glXCreateGLXPixmap mglXCreateGLXPixmap
#define glXDestroyGLXPixmap mglXDestroyGLXPixmap
#define glXQueryExtension mglXQueryExtension
#define glXQueryVersion mglXQueryVersion
#define glXIsDirect mglXIsDirect
#define glXGetConfig mglXGetConfig
#define glXGetCurrentContext mglXGetCurrentContext
#define glXGetCurrentDrawable mglXGetCurrentDrawable
#define glXWaitGL mglXWaitGL
#define glXWaitX mglXWaitX
#define glXUseXFont mglXUseXFont
#define glXQueryExtensionsString mglXQueryExtensionsString
#define glXQueryServerString mglXQueryServerString
#define glXGetClientString mglXGetClientString
#define glXCreateGLXPixmapMESA mglXCreateGLXPixmapMESA
#define glXReleaseBuffersMESA mglXReleaseBuffersMESA
#define glXCopySubBufferMESA mglXCopySubBufferMESA
#define glXGetVideoSyncSGI mglXGetVideoSyncSGI
#define glXWaitVideoSyncSGI mglXWaitVideoSyncSGI
/* GLX 1.2 */
#define glXGetCurrentDisplay mglXGetCurrentDisplay
/* GLX 1.3 */
#define glXChooseFBConfig mglXChooseFBConfig
#define glXGetFBConfigAttrib mglXGetFBConfigAttrib
#define glXGetFBConfigs mglXGetFBConfigs
#define glXGetVisualFromFBConfig mglXGetVisualFromFBConfig
#define glXCreateWindow mglXCreateWindow
#define glXDestroyWindow mglXDestroyWindow
#define glXCreatePixmap mglXCreatePixmap
#define glXDestroyPixmap mglXDestroyPixmap
#define glXCreatePbuffer mglXCreatePbuffer
#define glXDestroyPbuffer mglXDestroyPbuffer
#define glXQueryDrawable mglXQueryDrawable
#define glXCreateNewContext mglXCreateNewContext
#define glXMakeContextCurrent mglXMakeContextCurrent
#define glXGetCurrentReadDrawable mglXGetCurrentReadDrawable
#define glXQueryContext mglXQueryContext
#define glXSelectEvent mglXSelectEvent
#define glXGetSelectedEvent mglXGetSelectedEvent
/* GLX 1.4 */
#define glXGetProcAddress mglXGetProcAddress
#define glXGetProcAddressARB mglXGetProcAddressARB
#endif
+993
View File
@@ -0,0 +1,993 @@
#ifndef __glxext_h_
#define __glxext_h_
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright (c) 2007-2010 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Function declaration macros - to move into glplatform.h */
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#endif
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
#ifndef GLAPI
#define GLAPI extern
#endif
/*************************************************************/
/* Header file version number, required by OpenGL ABI for Linux */
/* glxext.h last updated 2010/08/06 */
/* Current version at http://www.opengl.org/registry/ */
#define GLX_GLXEXT_VERSION 32
#ifndef GLX_VERSION_1_3
#define GLX_WINDOW_BIT 0x00000001
#define GLX_PIXMAP_BIT 0x00000002
#define GLX_PBUFFER_BIT 0x00000004
#define GLX_RGBA_BIT 0x00000001
#define GLX_COLOR_INDEX_BIT 0x00000002
#define GLX_PBUFFER_CLOBBER_MASK 0x08000000
#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001
#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002
#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008
#define GLX_AUX_BUFFERS_BIT 0x00000010
#define GLX_DEPTH_BUFFER_BIT 0x00000020
#define GLX_STENCIL_BUFFER_BIT 0x00000040
#define GLX_ACCUM_BUFFER_BIT 0x00000080
#define GLX_CONFIG_CAVEAT 0x20
#define GLX_X_VISUAL_TYPE 0x22
#define GLX_TRANSPARENT_TYPE 0x23
#define GLX_TRANSPARENT_INDEX_VALUE 0x24
#define GLX_TRANSPARENT_RED_VALUE 0x25
#define GLX_TRANSPARENT_GREEN_VALUE 0x26
#define GLX_TRANSPARENT_BLUE_VALUE 0x27
#define GLX_TRANSPARENT_ALPHA_VALUE 0x28
#define GLX_DONT_CARE 0xFFFFFFFF
#define GLX_NONE 0x8000
#define GLX_SLOW_CONFIG 0x8001
#define GLX_TRUE_COLOR 0x8002
#define GLX_DIRECT_COLOR 0x8003
#define GLX_PSEUDO_COLOR 0x8004
#define GLX_STATIC_COLOR 0x8005
#define GLX_GRAY_SCALE 0x8006
#define GLX_STATIC_GRAY 0x8007
#define GLX_TRANSPARENT_RGB 0x8008
#define GLX_TRANSPARENT_INDEX 0x8009
#define GLX_VISUAL_ID 0x800B
#define GLX_SCREEN 0x800C
#define GLX_NON_CONFORMANT_CONFIG 0x800D
#define GLX_DRAWABLE_TYPE 0x8010
#define GLX_RENDER_TYPE 0x8011
#define GLX_X_RENDERABLE 0x8012
#define GLX_FBCONFIG_ID 0x8013
#define GLX_RGBA_TYPE 0x8014
#define GLX_COLOR_INDEX_TYPE 0x8015
#define GLX_MAX_PBUFFER_WIDTH 0x8016
#define GLX_MAX_PBUFFER_HEIGHT 0x8017
#define GLX_MAX_PBUFFER_PIXELS 0x8018
#define GLX_PRESERVED_CONTENTS 0x801B
#define GLX_LARGEST_PBUFFER 0x801C
#define GLX_WIDTH 0x801D
#define GLX_HEIGHT 0x801E
#define GLX_EVENT_MASK 0x801F
#define GLX_DAMAGED 0x8020
#define GLX_SAVED 0x8021
#define GLX_WINDOW 0x8022
#define GLX_PBUFFER 0x8023
#define GLX_PBUFFER_HEIGHT 0x8040
#define GLX_PBUFFER_WIDTH 0x8041
#endif
#ifndef GLX_VERSION_1_4
#define GLX_SAMPLE_BUFFERS 100000
#define GLX_SAMPLES 100001
#endif
#ifndef GLX_ARB_get_proc_address
#endif
#ifndef GLX_ARB_multisample
#define GLX_SAMPLE_BUFFERS_ARB 100000
#define GLX_SAMPLES_ARB 100001
#endif
#ifndef GLX_ARB_vertex_buffer_object
#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095
#endif
#ifndef GLX_ARB_fbconfig_float
#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9
#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004
#endif
#ifndef GLX_ARB_framebuffer_sRGB
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
#endif
#ifndef GLX_ARB_create_context
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#endif
#ifndef GLX_ARB_create_context_profile
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#endif
#ifndef GLX_ARB_create_context_robustness
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
#endif
#ifndef GLX_SGIS_multisample
#define GLX_SAMPLE_BUFFERS_SGIS 100000
#define GLX_SAMPLES_SGIS 100001
#endif
#ifndef GLX_EXT_visual_info
#define GLX_X_VISUAL_TYPE_EXT 0x22
#define GLX_TRANSPARENT_TYPE_EXT 0x23
#define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24
#define GLX_TRANSPARENT_RED_VALUE_EXT 0x25
#define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26
#define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27
#define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28
#define GLX_NONE_EXT 0x8000
#define GLX_TRUE_COLOR_EXT 0x8002
#define GLX_DIRECT_COLOR_EXT 0x8003
#define GLX_PSEUDO_COLOR_EXT 0x8004
#define GLX_STATIC_COLOR_EXT 0x8005
#define GLX_GRAY_SCALE_EXT 0x8006
#define GLX_STATIC_GRAY_EXT 0x8007
#define GLX_TRANSPARENT_RGB_EXT 0x8008
#define GLX_TRANSPARENT_INDEX_EXT 0x8009
#endif
#ifndef GLX_SGI_swap_control
#endif
#ifndef GLX_SGI_video_sync
#endif
#ifndef GLX_SGI_make_current_read
#endif
#ifndef GLX_SGIX_video_source
#endif
#ifndef GLX_EXT_visual_rating
#define GLX_VISUAL_CAVEAT_EXT 0x20
#define GLX_SLOW_VISUAL_EXT 0x8001
#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
/* reuse GLX_NONE_EXT */
#endif
#ifndef GLX_EXT_import_context
#define GLX_SHARE_CONTEXT_EXT 0x800A
#define GLX_VISUAL_ID_EXT 0x800B
#define GLX_SCREEN_EXT 0x800C
#endif
#ifndef GLX_SGIX_fbconfig
#define GLX_WINDOW_BIT_SGIX 0x00000001
#define GLX_PIXMAP_BIT_SGIX 0x00000002
#define GLX_RGBA_BIT_SGIX 0x00000001
#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002
#define GLX_DRAWABLE_TYPE_SGIX 0x8010
#define GLX_RENDER_TYPE_SGIX 0x8011
#define GLX_X_RENDERABLE_SGIX 0x8012
#define GLX_FBCONFIG_ID_SGIX 0x8013
#define GLX_RGBA_TYPE_SGIX 0x8014
#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015
/* reuse GLX_SCREEN_EXT */
#endif
#ifndef GLX_SGIX_pbuffer
#define GLX_PBUFFER_BIT_SGIX 0x00000004
#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000
#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001
#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002
#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008
#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010
#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020
#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040
#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080
#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100
#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016
#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017
#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018
#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019
#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A
#define GLX_PRESERVED_CONTENTS_SGIX 0x801B
#define GLX_LARGEST_PBUFFER_SGIX 0x801C
#define GLX_WIDTH_SGIX 0x801D
#define GLX_HEIGHT_SGIX 0x801E
#define GLX_EVENT_MASK_SGIX 0x801F
#define GLX_DAMAGED_SGIX 0x8020
#define GLX_SAVED_SGIX 0x8021
#define GLX_WINDOW_SGIX 0x8022
#define GLX_PBUFFER_SGIX 0x8023
#endif
#ifndef GLX_SGI_cushion
#endif
#ifndef GLX_SGIX_video_resize
#define GLX_SYNC_FRAME_SGIX 0x00000000
#define GLX_SYNC_SWAP_SGIX 0x00000001
#endif
#ifndef GLX_SGIX_dmbuffer
#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024
#endif
#ifndef GLX_SGIX_swap_group
#endif
#ifndef GLX_SGIX_swap_barrier
#endif
#ifndef GLX_SGIS_blended_overlay
#define GLX_BLENDED_RGBA_SGIS 0x8025
#endif
#ifndef GLX_SGIS_shared_multisample
#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026
#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027
#endif
#ifndef GLX_SUN_get_transparent_index
#endif
#ifndef GLX_3DFX_multisample
#define GLX_SAMPLE_BUFFERS_3DFX 0x8050
#define GLX_SAMPLES_3DFX 0x8051
#endif
#ifndef GLX_MESA_copy_sub_buffer
#endif
#ifndef GLX_MESA_pixmap_colormap
#endif
#ifndef GLX_MESA_release_buffers
#endif
#ifndef GLX_MESA_set_3dfx_mode
#define GLX_3DFX_WINDOW_MODE_MESA 0x1
#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2
#endif
#ifndef GLX_SGIX_visual_select_group
#define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028
#endif
#ifndef GLX_OML_swap_method
#define GLX_SWAP_METHOD_OML 0x8060
#define GLX_SWAP_EXCHANGE_OML 0x8061
#define GLX_SWAP_COPY_OML 0x8062
#define GLX_SWAP_UNDEFINED_OML 0x8063
#endif
#ifndef GLX_OML_sync_control
#endif
#ifndef GLX_NV_float_buffer
#define GLX_FLOAT_COMPONENTS_NV 0x20B0
#endif
#ifndef GLX_SGIX_hyperpipe
#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80
#define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91
#define GLX_BAD_HYPERPIPE_SGIX 92
#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001
#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002
#define GLX_PIPE_RECT_SGIX 0x00000001
#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002
#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003
#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004
#define GLX_HYPERPIPE_ID_SGIX 0x8030
#endif
#ifndef GLX_MESA_agp_offset
#endif
#ifndef GLX_EXT_fbconfig_packed_float
#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1
#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008
#endif
#ifndef GLX_EXT_framebuffer_sRGB
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2
#endif
#ifndef GLX_EXT_texture_from_pixmap
#define GLX_TEXTURE_1D_BIT_EXT 0x00000001
#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
#define GLX_Y_INVERTED_EXT 0x20D4
#define GLX_TEXTURE_FORMAT_EXT 0x20D5
#define GLX_TEXTURE_TARGET_EXT 0x20D6
#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
#define GLX_TEXTURE_1D_EXT 0x20DB
#define GLX_TEXTURE_2D_EXT 0x20DC
#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
#define GLX_FRONT_LEFT_EXT 0x20DE
#define GLX_FRONT_RIGHT_EXT 0x20DF
#define GLX_BACK_LEFT_EXT 0x20E0
#define GLX_BACK_RIGHT_EXT 0x20E1
#define GLX_FRONT_EXT GLX_FRONT_LEFT_EXT
#define GLX_BACK_EXT GLX_BACK_LEFT_EXT
#define GLX_AUX0_EXT 0x20E2
#define GLX_AUX1_EXT 0x20E3
#define GLX_AUX2_EXT 0x20E4
#define GLX_AUX3_EXT 0x20E5
#define GLX_AUX4_EXT 0x20E6
#define GLX_AUX5_EXT 0x20E7
#define GLX_AUX6_EXT 0x20E8
#define GLX_AUX7_EXT 0x20E9
#define GLX_AUX8_EXT 0x20EA
#define GLX_AUX9_EXT 0x20EB
#endif
#ifndef GLX_NV_present_video
#define GLX_NUM_VIDEO_SLOTS_NV 0x20F0
#endif
#ifndef GLX_NV_video_out
#define GLX_VIDEO_OUT_COLOR_NV 0x20C3
#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4
#define GLX_VIDEO_OUT_DEPTH_NV 0x20C5
#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6
#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7
#define GLX_VIDEO_OUT_FRAME_NV 0x20C8
#define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9
#define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA
#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB
#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC
#endif
#ifndef GLX_NV_swap_group
#endif
#ifndef GLX_NV_video_capture
#define GLX_DEVICE_ID_NV 0x20CD
#define GLX_UNIQUE_ID_NV 0x20CE
#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF
#endif
#ifndef GLX_EXT_swap_control
#define GLX_SWAP_INTERVAL_EXT 0x20F1
#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
#endif
#ifndef GLX_NV_copy_image
#endif
#ifndef GLX_INTEL_swap_event
#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000
#define GLX_EXCHANGE_COMPLETE_INTEL 0x8180
#define GLX_COPY_COMPLETE_INTEL 0x8181
#define GLX_FLIP_COMPLETE_INTEL 0x8182
#endif
#ifndef GLX_NV_multisample_coverage
#define GLX_COVERAGE_SAMPLES_NV 100001
#define GLX_COLOR_SAMPLES_NV 0x20B3
#endif
#ifndef GLX_AMD_gpu_association
#define GLX_GPU_VENDOR_AMD 0x1F00
#define GLX_GPU_RENDERER_STRING_AMD 0x1F01
#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02
#define GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2
#define GLX_GPU_RAM_AMD 0x21A3
#define GLX_GPU_CLOCK_AMD 0x21A4
#define GLX_GPU_NUM_PIPES_AMD 0x21A5
#define GLX_GPU_NUM_SIMD_AMD 0x21A6
#define GLX_GPU_NUM_RB_AMD 0x21A7
#define GLX_GPU_NUM_SPI_AMD 0x21A8
#endif
#ifndef GLX_EXT_create_context_es2_profile
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#endif
/*************************************************************/
#ifndef GLX_ARB_get_proc_address
typedef void (*__GLXextFuncPtr)(void);
#endif
#ifndef GLX_SGIX_video_source
typedef XID GLXVideoSourceSGIX;
#endif
#ifndef GLX_SGIX_fbconfig
typedef XID GLXFBConfigIDSGIX;
typedef struct __GLXFBConfigRec *GLXFBConfigSGIX;
#endif
#ifndef GLX_SGIX_pbuffer
typedef XID GLXPbufferSGIX;
typedef struct {
int type;
unsigned long serial; /* # of last request processed by server */
Bool send_event; /* true if this came for SendEvent request */
Display *display; /* display the event was read from */
GLXDrawable drawable; /* i.d. of Drawable */
int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */
int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */
unsigned int mask; /* mask indicating which buffers are affected*/
int x, y;
int width, height;
int count; /* if nonzero, at least this many more */
} GLXBufferClobberEventSGIX;
#endif
#ifndef GLX_NV_video_output
typedef unsigned int GLXVideoDeviceNV;
#endif
#ifndef GLX_NV_video_capture
typedef XID GLXVideoCaptureDeviceNV;
#endif
#ifndef GLEXT_64_TYPES_DEFINED
/* This code block is duplicated in glext.h, so must be protected */
#define GLEXT_64_TYPES_DEFINED
/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
/* (as used in the GLX_OML_sync_control extension). */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <inttypes.h>
#elif defined(__sun__) || defined(__digital__)
#include <inttypes.h>
#if defined(__STDC__)
#if defined(__arch64__) || defined(_LP64)
typedef long int int64_t;
typedef unsigned long int uint64_t;
#else
typedef long long int int64_t;
typedef unsigned long long int uint64_t;
#endif /* __arch64__ */
#endif /* __STDC__ */
#elif defined( __VMS ) || defined(__sgi)
#include <inttypes.h>
#elif defined(__SCO__) || defined(__USLC__)
#include <stdint.h>
#elif defined(__UNIXOS2__) || defined(__SOL64__)
typedef long int int32_t;
typedef long long int int64_t;
typedef unsigned long long int uint64_t;
#elif defined(_WIN32) && defined(__GNUC__)
#include <stdint.h>
#elif defined(_WIN32)
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <inttypes.h> /* Fallback option */
#endif
#endif
#ifndef GLX_VERSION_1_3
#define GLX_VERSION_1_3 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern GLXFBConfig * glXGetFBConfigs (Display *dpy, int screen, int *nelements);
extern GLXFBConfig * glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements);
extern int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value);
extern XVisualInfo * glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config);
extern GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
extern void glXDestroyWindow (Display *dpy, GLXWindow win);
extern GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
extern void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap);
extern GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list);
extern void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf);
extern void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
extern GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
extern Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
extern GLXDrawable glXGetCurrentReadDrawable (void);
extern Display * glXGetCurrentDisplay (void);
extern int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value);
extern void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask);
extern void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef GLXFBConfig * ( * PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements);
typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
typedef int ( * PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value);
typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);
typedef GLXWindow ( * PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
typedef void ( * PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win);
typedef GLXPixmap ( * PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
typedef void ( * PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap);
typedef GLXPbuffer ( * PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list);
typedef void ( * PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf);
typedef void ( * PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
typedef GLXContext ( * PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
typedef Bool ( * PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLEPROC) (void);
typedef Display * ( * PFNGLXGETCURRENTDISPLAYPROC) (void);
typedef int ( * PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value);
typedef void ( * PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask);
typedef void ( * PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
#endif
#ifndef GLX_VERSION_1_4
#define GLX_VERSION_1_4 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern __GLXextFuncPtr glXGetProcAddress (const GLubyte *procName);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName);
#endif
#ifndef GLX_ARB_get_proc_address
#define GLX_ARB_get_proc_address 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName);
#endif
#ifndef GLX_ARB_multisample
#define GLX_ARB_multisample 1
#endif
#ifndef GLX_ARB_fbconfig_float
#define GLX_ARB_fbconfig_float 1
#endif
#ifndef GLX_ARB_framebuffer_sRGB
#define GLX_ARB_framebuffer_sRGB 1
#endif
#ifndef GLX_ARB_create_context
#define GLX_ARB_create_context 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef GLXContext ( * PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
#endif
#ifndef GLX_ARB_create_context_profile
#define GLX_ARB_create_context_profile 1
#endif
#ifndef GLX_ARB_create_context_robustness
#define GLX_ARB_create_context_robustness 1
#endif
#ifndef GLX_SGIS_multisample
#define GLX_SGIS_multisample 1
#endif
#ifndef GLX_EXT_visual_info
#define GLX_EXT_visual_info 1
#endif
#ifndef GLX_SGI_swap_control
#define GLX_SGI_swap_control 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern int glXSwapIntervalSGI (int interval);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval);
#endif
#ifndef GLX_SGI_video_sync
#define GLX_SGI_video_sync 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern int glXGetVideoSyncSGI (unsigned int *count);
extern int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef int ( * PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count);
typedef int ( * PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count);
#endif
#ifndef GLX_SGI_make_current_read
#define GLX_SGI_make_current_read 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
extern GLXDrawable glXGetCurrentReadDrawableSGI (void);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Bool ( * PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void);
#endif
#ifndef GLX_SGIX_video_source
#define GLX_SGIX_video_source 1
#ifdef _VL_H
#ifdef GLX_GLXEXT_PROTOTYPES
extern GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
extern void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef GLXVideoSourceSGIX ( * PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
typedef void ( * PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource);
#endif /* _VL_H */
#endif
#ifndef GLX_EXT_visual_rating
#define GLX_EXT_visual_rating 1
#endif
#ifndef GLX_EXT_import_context
#define GLX_EXT_import_context 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern Display * glXGetCurrentDisplayEXT (void);
extern int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value);
extern GLXContextID glXGetContextIDEXT (const GLXContext context);
extern GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID);
extern void glXFreeContextEXT (Display *dpy, GLXContext context);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Display * ( * PFNGLXGETCURRENTDISPLAYEXTPROC) (void);
typedef int ( * PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value);
typedef GLXContextID ( * PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context);
typedef GLXContext ( * PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID);
typedef void ( * PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context);
#endif
#ifndef GLX_SGIX_fbconfig
#define GLX_SGIX_fbconfig 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
extern GLXFBConfigSGIX * glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements);
extern GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
extern GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
extern XVisualInfo * glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config);
extern GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef int ( * PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
typedef GLXFBConfigSGIX * ( * PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements);
typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
typedef GLXContext ( * PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config);
typedef GLXFBConfigSGIX ( * PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis);
#endif
#ifndef GLX_SGIX_pbuffer
#define GLX_SGIX_pbuffer 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
extern void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf);
extern int glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
extern void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask);
extern void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef GLXPbufferSGIX ( * PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
typedef void ( * PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf);
typedef int ( * PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
typedef void ( * PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask);
typedef void ( * PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask);
#endif
#ifndef GLX_SGI_cushion
#define GLX_SGI_cushion 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern void glXCushionSGI (Display *dpy, Window window, float cushion);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef void ( * PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion);
#endif
#ifndef GLX_SGIX_video_resize
#define GLX_SGIX_video_resize 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window);
extern int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h);
extern int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
extern int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
extern int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef int ( * PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window);
typedef int ( * PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h);
typedef int ( * PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
typedef int ( * PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
typedef int ( * PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype);
#endif
#ifndef GLX_SGIX_dmbuffer
#define GLX_SGIX_dmbuffer 1
#ifdef _DM_BUFFER_H_
#ifdef GLX_GLXEXT_PROTOTYPES
extern Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Bool ( * PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
#endif /* _DM_BUFFER_H_ */
#endif
#ifndef GLX_SGIX_swap_group
#define GLX_SGIX_swap_group 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef void ( * PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member);
#endif
#ifndef GLX_SGIX_swap_barrier
#define GLX_SGIX_swap_barrier 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier);
extern Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef void ( * PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier);
typedef Bool ( * PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max);
#endif
#ifndef GLX_SUN_get_transparent_index
#define GLX_SUN_get_transparent_index 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Status ( * PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex);
#endif
#ifndef GLX_MESA_copy_sub_buffer
#define GLX_MESA_copy_sub_buffer 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef void ( * PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
#endif
#ifndef GLX_MESA_pixmap_colormap
#define GLX_MESA_pixmap_colormap 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
#endif
#ifndef GLX_MESA_release_buffers
#define GLX_MESA_release_buffers 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Bool ( * PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable);
#endif
#ifndef GLX_MESA_set_3dfx_mode
#define GLX_MESA_set_3dfx_mode 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern Bool glXSet3DfxModeMESA (int mode);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Bool ( * PFNGLXSET3DFXMODEMESAPROC) (int mode);
#endif
#ifndef GLX_SGIX_visual_select_group
#define GLX_SGIX_visual_select_group 1
#endif
#ifndef GLX_OML_swap_method
#define GLX_OML_swap_method 1
#endif
#ifndef GLX_OML_sync_control
#define GLX_OML_sync_control 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
extern Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
extern int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
extern Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
extern Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Bool ( * PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
typedef int64_t ( * PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
typedef Bool ( * PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
typedef Bool ( * PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
#endif
#ifndef GLX_NV_float_buffer
#define GLX_NV_float_buffer 1
#endif
#ifndef GLX_SGIX_hyperpipe
#define GLX_SGIX_hyperpipe 1
typedef struct {
char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX];
int networkId;
} GLXHyperpipeNetworkSGIX;
typedef struct {
char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX];
int channel;
unsigned int
participationType;
int timeSlice;
} GLXHyperpipeConfigSGIX;
typedef struct {
char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX];
int srcXOrigin, srcYOrigin, srcWidth, srcHeight;
int destXOrigin, destYOrigin, destWidth, destHeight;
} GLXPipeRect;
typedef struct {
char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX];
int XOrigin, YOrigin, maxHeight, maxWidth;
} GLXPipeRectLimits;
#ifdef GLX_GLXEXT_PROTOTYPES
extern GLXHyperpipeNetworkSGIX * glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes);
extern int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
extern GLXHyperpipeConfigSGIX * glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes);
extern int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId);
extern int glXBindHyperpipeSGIX (Display *dpy, int hpId);
extern int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
extern int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
extern int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef GLXHyperpipeNetworkSGIX * ( * PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes);
typedef int ( * PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
typedef GLXHyperpipeConfigSGIX * ( * PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes);
typedef int ( * PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId);
typedef int ( * PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId);
typedef int ( * PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
typedef int ( * PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
typedef int ( * PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
#endif
#ifndef GLX_MESA_agp_offset
#define GLX_MESA_agp_offset 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern unsigned int glXGetAGPOffsetMESA (const void *pointer);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef unsigned int ( * PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer);
#endif
#ifndef GLX_EXT_fbconfig_packed_float
#define GLX_EXT_fbconfig_packed_float 1
#endif
#ifndef GLX_EXT_framebuffer_sRGB
#define GLX_EXT_framebuffer_sRGB 1
#endif
#ifndef GLX_EXT_texture_from_pixmap
#define GLX_EXT_texture_from_pixmap 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
extern void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef void ( * PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
typedef void ( * PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer);
#endif
#ifndef GLX_NV_present_video
#define GLX_NV_present_video 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern unsigned int * glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements);
extern int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef unsigned int * ( * PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements);
typedef int ( * PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
#endif
#ifndef GLX_NV_video_output
#define GLX_NV_video_output 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
extern int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
extern int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
extern int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf);
extern int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
extern int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef int ( * PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
typedef int ( * PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
typedef int ( * PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
typedef int ( * PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf);
typedef int ( * PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
typedef int ( * PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
#endif
#ifndef GLX_NV_swap_group
#define GLX_NV_swap_group 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group);
extern Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier);
extern Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
extern Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
extern Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count);
extern Bool glXResetFrameCountNV (Display *dpy, int screen);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef Bool ( * PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group);
typedef Bool ( * PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier);
typedef Bool ( * PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
typedef Bool ( * PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
typedef Bool ( * PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count);
typedef Bool ( * PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen);
#endif
#ifndef GLX_NV_video_capture
#define GLX_NV_video_capture 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
extern GLXVideoCaptureDeviceNV * glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements);
extern void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
extern int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
extern void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef int ( * PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
typedef GLXVideoCaptureDeviceNV * ( * PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements);
typedef void ( * PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
typedef int ( * PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
typedef void ( * PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
#endif
#ifndef GLX_EXT_swap_control
#define GLX_EXT_swap_control 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern int glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef int ( * PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval);
#endif
#ifndef GLX_NV_copy_image
#define GLX_NV_copy_image 1
#ifdef GLX_GLXEXT_PROTOTYPES
extern void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
#endif /* GLX_GLXEXT_PROTOTYPES */
typedef void ( * PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
#endif
#ifndef GLX_INTEL_swap_event
#define GLX_INTEL_swap_event 1
#endif
#ifndef GLX_NV_multisample_coverage
#define GLX_NV_multisample_coverage 1
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,862 @@
/*
* Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2007-2008 Red Hat, Inc.
* (C) Copyright IBM Corporation 2004
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* \file dri_interface.h
*
* This file contains all the types and functions that define the interface
* between a DRI driver and driver loader. Currently, the most common driver
* loader is the XFree86 libGL.so. However, other loaders do exist, and in
* the future the server-side libglx.a will also be a loader.
*
* \author Kevin E. Martin <kevin@precisioninsight.com>
* \author Ian Romanick <idr@us.ibm.com>
* \author Kristian Høgsberg <krh@redhat.com>
*/
#ifndef DRI_INTERFACE_H
#define DRI_INTERFACE_H
/* For archs with no drm.h */
#if defined(__APPLE__) || defined(__CYGWIN__) || defined(__GNU__)
#ifndef __NOT_HAVE_DRM_H
#define __NOT_HAVE_DRM_H
#endif
#endif
#ifndef __NOT_HAVE_DRM_H
#include <drm.h>
#else
typedef unsigned int drm_context_t;
typedef unsigned int drm_drawable_t;
typedef struct drm_clip_rect drm_clip_rect_t;
#endif
/**
* \name DRI interface structures
*
* The following structures define the interface between the GLX client
* side library and the DRI (direct rendering infrastructure).
*/
/*@{*/
typedef struct __DRIdisplayRec __DRIdisplay;
typedef struct __DRIscreenRec __DRIscreen;
typedef struct __DRIcontextRec __DRIcontext;
typedef struct __DRIdrawableRec __DRIdrawable;
typedef struct __DRIconfigRec __DRIconfig;
typedef struct __DRIframebufferRec __DRIframebuffer;
typedef struct __DRIversionRec __DRIversion;
typedef struct __DRIcoreExtensionRec __DRIcoreExtension;
typedef struct __DRIextensionRec __DRIextension;
typedef struct __DRIcopySubBufferExtensionRec __DRIcopySubBufferExtension;
typedef struct __DRIswapControlExtensionRec __DRIswapControlExtension;
typedef struct __DRIframeTrackingExtensionRec __DRIframeTrackingExtension;
typedef struct __DRImediaStreamCounterExtensionRec __DRImediaStreamCounterExtension;
typedef struct __DRItexOffsetExtensionRec __DRItexOffsetExtension;
typedef struct __DRItexBufferExtensionRec __DRItexBufferExtension;
typedef struct __DRIlegacyExtensionRec __DRIlegacyExtension;
typedef struct __DRIswrastExtensionRec __DRIswrastExtension;
typedef struct __DRIbufferRec __DRIbuffer;
typedef struct __DRIdri2ExtensionRec __DRIdri2Extension;
typedef struct __DRIdri2LoaderExtensionRec __DRIdri2LoaderExtension;
typedef struct __DRI2flushExtensionRec __DRI2flushExtension;
/*@}*/
/**
* Extension struct. Drivers 'inherit' from this struct by embedding
* it as the first element in the extension struct.
*
* We never break API in for a DRI extension. If we need to change
* the way things work in a non-backwards compatible manner, we
* introduce a new extension. During a transition period, we can
* leave both the old and the new extension in the driver, which
* allows us to move to the new interface without having to update the
* loader(s) in lock step.
*
* However, we can add entry points to an extension over time as long
* as we don't break the old ones. As we add entry points to an
* extension, we increase the version number. The corresponding
* #define can be used to guard code that accesses the new entry
* points at compile time and the version field in the extension
* struct can be used at run-time to determine how to use the
* extension.
*/
struct __DRIextensionRec {
const char *name;
int version;
};
/**
* The first set of extension are the screen extensions, returned by
* __DRIcore::getExtensions(). This entry point will return a list of
* extensions and the loader can use the ones it knows about by
* casting them to more specific extensions and advertising any GLX
* extensions the DRI extensions enables.
*/
/**
* Used by drivers to indicate support for setting the read drawable.
*/
#define __DRI_READ_DRAWABLE "DRI_ReadDrawable"
#define __DRI_READ_DRAWABLE_VERSION 1
/**
* Used by drivers that implement the GLX_MESA_copy_sub_buffer extension.
*/
#define __DRI_COPY_SUB_BUFFER "DRI_CopySubBuffer"
#define __DRI_COPY_SUB_BUFFER_VERSION 1
struct __DRIcopySubBufferExtensionRec {
__DRIextension base;
void (*copySubBuffer)(__DRIdrawable *drawable, int x, int y, int w, int h);
};
/**
* Used by drivers that implement the GLX_SGI_swap_control or
* GLX_MESA_swap_control extension.
*/
#define __DRI_SWAP_CONTROL "DRI_SwapControl"
#define __DRI_SWAP_CONTROL_VERSION 1
struct __DRIswapControlExtensionRec {
__DRIextension base;
void (*setSwapInterval)(__DRIdrawable *drawable, unsigned int inteval);
unsigned int (*getSwapInterval)(__DRIdrawable *drawable);
};
/**
* Used by drivers that implement the GLX_MESA_swap_frame_usage extension.
*/
#define __DRI_FRAME_TRACKING "DRI_FrameTracking"
#define __DRI_FRAME_TRACKING_VERSION 1
struct __DRIframeTrackingExtensionRec {
__DRIextension base;
/**
* Enable or disable frame usage tracking.
*
* \since Internal API version 20030317.
*/
int (*frameTracking)(__DRIdrawable *drawable, GLboolean enable);
/**
* Retrieve frame usage information.
*
* \since Internal API version 20030317.
*/
int (*queryFrameTracking)(__DRIdrawable *drawable,
int64_t * sbc, int64_t * missedFrames,
float * lastMissedUsage, float * usage);
};
/**
* Used by drivers that implement the GLX_SGI_video_sync extension.
*/
#define __DRI_MEDIA_STREAM_COUNTER "DRI_MediaStreamCounter"
#define __DRI_MEDIA_STREAM_COUNTER_VERSION 1
struct __DRImediaStreamCounterExtensionRec {
__DRIextension base;
/**
* Wait for the MSC to equal target_msc, or, if that has already passed,
* the next time (MSC % divisor) is equal to remainder. If divisor is
* zero, the function will return as soon as MSC is greater than or equal
* to target_msc.
*/
int (*waitForMSC)(__DRIdrawable *drawable,
int64_t target_msc, int64_t divisor, int64_t remainder,
int64_t * msc, int64_t * sbc);
/**
* Get the number of vertical refreshes since some point in time before
* this function was first called (i.e., system start up).
*/
int (*getDrawableMSC)(__DRIscreen *screen, __DRIdrawable *drawable,
int64_t *msc);
};
#define __DRI_TEX_OFFSET "DRI_TexOffset"
#define __DRI_TEX_OFFSET_VERSION 1
struct __DRItexOffsetExtensionRec {
__DRIextension base;
/**
* Method to override base texture image with a driver specific 'offset'.
* The depth passed in allows e.g. to ignore the alpha channel of texture
* images where the non-alpha components don't occupy a whole texel.
*
* For GLX_EXT_texture_from_pixmap with AIGLX.
*/
void (*setTexOffset)(__DRIcontext *pDRICtx, GLint texname,
unsigned long long offset, GLint depth, GLuint pitch);
};
/* Valid values for format in the setTexBuffer2 function below. These
* values match the GLX tokens for compatibility reasons, but we
* define them here since the DRI interface can't depend on GLX. */
#define __DRI_TEXTURE_FORMAT_NONE 0x20D8
#define __DRI_TEXTURE_FORMAT_RGB 0x20D9
#define __DRI_TEXTURE_FORMAT_RGBA 0x20DA
#define __DRI_TEX_BUFFER "DRI_TexBuffer"
#define __DRI_TEX_BUFFER_VERSION 2
struct __DRItexBufferExtensionRec {
__DRIextension base;
/**
* Method to override base texture image with the contents of a
* __DRIdrawable.
*
* For GLX_EXT_texture_from_pixmap with AIGLX. Deprecated in favor of
* setTexBuffer2 in version 2 of this interface
*/
void (*setTexBuffer)(__DRIcontext *pDRICtx,
GLint target,
__DRIdrawable *pDraw);
/**
* Method to override base texture image with the contents of a
* __DRIdrawable, including the required texture format attribute.
*
* For GLX_EXT_texture_from_pixmap with AIGLX.
*/
void (*setTexBuffer2)(__DRIcontext *pDRICtx,
GLint target,
GLint format,
__DRIdrawable *pDraw);
};
/**
* Used by drivers that implement DRI2
*/
#define __DRI2_FLUSH "DRI2_Flush"
#define __DRI2_FLUSH_VERSION 3
struct __DRI2flushExtensionRec {
__DRIextension base;
void (*flush)(__DRIdrawable *drawable);
/**
* Ask the driver to call getBuffers/getBuffersWithFormat before
* it starts rendering again.
*
* \param drawable the drawable to invalidate
*
* \since 3
*/
void (*invalidate)(__DRIdrawable *drawable);
};
/**
* XML document describing the configuration options supported by the
* driver.
*/
extern const char __driConfigOptions[];
/*@}*/
/**
* The following extensions describe loader features that the DRI
* driver can make use of. Some of these are mandatory, such as the
* getDrawableInfo extension for DRI and the DRI Loader extensions for
* DRI2, while others are optional, and if present allow the driver to
* expose certain features. The loader pass in a NULL terminated
* array of these extensions to the driver in the createNewScreen
* constructor.
*/
typedef struct __DRIgetDrawableInfoExtensionRec __DRIgetDrawableInfoExtension;
typedef struct __DRIsystemTimeExtensionRec __DRIsystemTimeExtension;
typedef struct __DRIdamageExtensionRec __DRIdamageExtension;
typedef struct __DRIloaderExtensionRec __DRIloaderExtension;
typedef struct __DRIswrastLoaderExtensionRec __DRIswrastLoaderExtension;
/**
* Callback to getDrawableInfo protocol
*/
#define __DRI_GET_DRAWABLE_INFO "DRI_GetDrawableInfo"
#define __DRI_GET_DRAWABLE_INFO_VERSION 1
struct __DRIgetDrawableInfoExtensionRec {
__DRIextension base;
/**
* This function is used to get information about the position, size, and
* clip rects of a drawable.
*/
GLboolean (* getDrawableInfo) ( __DRIdrawable *drawable,
unsigned int * index, unsigned int * stamp,
int * x, int * y, int * width, int * height,
int * numClipRects, drm_clip_rect_t ** pClipRects,
int * backX, int * backY,
int * numBackClipRects, drm_clip_rect_t ** pBackClipRects,
void *loaderPrivate);
};
/**
* Callback to get system time for media stream counter extensions.
*/
#define __DRI_SYSTEM_TIME "DRI_SystemTime"
#define __DRI_SYSTEM_TIME_VERSION 1
struct __DRIsystemTimeExtensionRec {
__DRIextension base;
/**
* Get the 64-bit unadjusted system time (UST).
*/
int (*getUST)(int64_t * ust);
/**
* Get the media stream counter (MSC) rate.
*
* Matching the definition in GLX_OML_sync_control, this function returns
* the rate of the "media stream counter". In practical terms, this is
* the frame refresh rate of the display.
*/
GLboolean (*getMSCRate)(__DRIdrawable *draw,
int32_t * numerator, int32_t * denominator,
void *loaderPrivate);
};
/**
* Damage reporting
*/
#define __DRI_DAMAGE "DRI_Damage"
#define __DRI_DAMAGE_VERSION 1
struct __DRIdamageExtensionRec {
__DRIextension base;
/**
* Reports areas of the given drawable which have been modified by the
* driver.
*
* \param drawable which the drawing was done to.
* \param rects rectangles affected, with the drawable origin as the
* origin.
* \param x X offset of the drawable within the screen (used in the
* front_buffer case)
* \param y Y offset of the drawable within the screen.
* \param front_buffer boolean flag for whether the drawing to the
* drawable was actually done directly to the front buffer (instead
* of backing storage, for example)
* \param loaderPrivate the data passed in at createNewDrawable time
*/
void (*reportDamage)(__DRIdrawable *draw,
int x, int y,
drm_clip_rect_t *rects, int num_rects,
GLboolean front_buffer,
void *loaderPrivate);
};
#define __DRI_SWRAST_IMAGE_OP_DRAW 1
#define __DRI_SWRAST_IMAGE_OP_CLEAR 2
#define __DRI_SWRAST_IMAGE_OP_SWAP 3
/**
* SWRast Loader extension.
*/
#define __DRI_SWRAST_LOADER "DRI_SWRastLoader"
#define __DRI_SWRAST_LOADER_VERSION 1
struct __DRIswrastLoaderExtensionRec {
__DRIextension base;
/*
* Drawable position and size
*/
void (*getDrawableInfo)(__DRIdrawable *drawable,
int *x, int *y, int *width, int *height,
void *loaderPrivate);
/**
* Put image to drawable
*/
void (*putImage)(__DRIdrawable *drawable, int op,
int x, int y, int width, int height,
char *data, void *loaderPrivate);
/**
* Get image from readable
*/
void (*getImage)(__DRIdrawable *readable,
int x, int y, int width, int height,
char *data, void *loaderPrivate);
};
/**
* Invalidate loader extension. The presence of this extension
* indicates to the DRI driver that the loader will call invalidate in
* the __DRI2_FLUSH extension, whenever the needs to query for new
* buffers. This means that the DRI driver can drop the polling in
* glViewport().
*
* The extension doesn't provide any functionality, it's only use to
* indicate to the driver that it can use the new semantics. A DRI
* driver can use this to switch between the different semantics or
* just refuse to initialize if this extension isn't present.
*/
#define __DRI_USE_INVALIDATE "DRI_UseInvalidate"
#define __DRI_USE_INVALIDATE_VERSION 1
typedef struct __DRIuseInvalidateExtensionRec __DRIuseInvalidateExtension;
struct __DRIuseInvalidateExtensionRec {
__DRIextension base;
};
/**
* The remaining extensions describe driver extensions, immediately
* available interfaces provided by the driver. To start using the
* driver, dlsym() for the __DRI_DRIVER_EXTENSIONS symbol and look for
* the extension you need in the array.
*/
#define __DRI_DRIVER_EXTENSIONS "__driDriverExtensions"
/**
* Tokens for __DRIconfig attribs. A number of attributes defined by
* GLX or EGL standards are not in the table, as they must be provided
* by the loader. For example, FBConfig ID or visual ID, drawable type.
*/
#define __DRI_ATTRIB_BUFFER_SIZE 1
#define __DRI_ATTRIB_LEVEL 2
#define __DRI_ATTRIB_RED_SIZE 3
#define __DRI_ATTRIB_GREEN_SIZE 4
#define __DRI_ATTRIB_BLUE_SIZE 5
#define __DRI_ATTRIB_LUMINANCE_SIZE 6
#define __DRI_ATTRIB_ALPHA_SIZE 7
#define __DRI_ATTRIB_ALPHA_MASK_SIZE 8
#define __DRI_ATTRIB_DEPTH_SIZE 9
#define __DRI_ATTRIB_STENCIL_SIZE 10
#define __DRI_ATTRIB_ACCUM_RED_SIZE 11
#define __DRI_ATTRIB_ACCUM_GREEN_SIZE 12
#define __DRI_ATTRIB_ACCUM_BLUE_SIZE 13
#define __DRI_ATTRIB_ACCUM_ALPHA_SIZE 14
#define __DRI_ATTRIB_SAMPLE_BUFFERS 15
#define __DRI_ATTRIB_SAMPLES 16
#define __DRI_ATTRIB_RENDER_TYPE 17
#define __DRI_ATTRIB_CONFIG_CAVEAT 18
#define __DRI_ATTRIB_CONFORMANT 19
#define __DRI_ATTRIB_DOUBLE_BUFFER 20
#define __DRI_ATTRIB_STEREO 21
#define __DRI_ATTRIB_AUX_BUFFERS 22
#define __DRI_ATTRIB_TRANSPARENT_TYPE 23
#define __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE 24
#define __DRI_ATTRIB_TRANSPARENT_RED_VALUE 25
#define __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE 26
#define __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE 27
#define __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE 28
#define __DRI_ATTRIB_FLOAT_MODE 29
#define __DRI_ATTRIB_RED_MASK 30
#define __DRI_ATTRIB_GREEN_MASK 31
#define __DRI_ATTRIB_BLUE_MASK 32
#define __DRI_ATTRIB_ALPHA_MASK 33
#define __DRI_ATTRIB_MAX_PBUFFER_WIDTH 34
#define __DRI_ATTRIB_MAX_PBUFFER_HEIGHT 35
#define __DRI_ATTRIB_MAX_PBUFFER_PIXELS 36
#define __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH 37
#define __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT 38
#define __DRI_ATTRIB_VISUAL_SELECT_GROUP 39
#define __DRI_ATTRIB_SWAP_METHOD 40
#define __DRI_ATTRIB_MAX_SWAP_INTERVAL 41
#define __DRI_ATTRIB_MIN_SWAP_INTERVAL 42
#define __DRI_ATTRIB_BIND_TO_TEXTURE_RGB 43
#define __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA 44
#define __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE 45
#define __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS 46
#define __DRI_ATTRIB_YINVERTED 47
/* __DRI_ATTRIB_RENDER_TYPE */
#define __DRI_ATTRIB_RGBA_BIT 0x01
#define __DRI_ATTRIB_COLOR_INDEX_BIT 0x02
#define __DRI_ATTRIB_LUMINANCE_BIT 0x04
/* __DRI_ATTRIB_CONFIG_CAVEAT */
#define __DRI_ATTRIB_SLOW_BIT 0x01
#define __DRI_ATTRIB_NON_CONFORMANT_CONFIG 0x02
/* __DRI_ATTRIB_TRANSPARENT_TYPE */
#define __DRI_ATTRIB_TRANSPARENT_RGB 0x00
#define __DRI_ATTRIB_TRANSPARENT_INDEX 0x01
/* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */
#define __DRI_ATTRIB_TEXTURE_1D_BIT 0x01
#define __DRI_ATTRIB_TEXTURE_2D_BIT 0x02
#define __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT 0x04
/**
* This extension defines the core DRI functionality.
*/
#define __DRI_CORE "DRI_Core"
#define __DRI_CORE_VERSION 1
struct __DRIcoreExtensionRec {
__DRIextension base;
__DRIscreen *(*createNewScreen)(int screen, int fd,
unsigned int sarea_handle,
const __DRIextension **extensions,
const __DRIconfig ***driverConfigs,
void *loaderPrivate);
void (*destroyScreen)(__DRIscreen *screen);
const __DRIextension **(*getExtensions)(__DRIscreen *screen);
int (*getConfigAttrib)(const __DRIconfig *config,
unsigned int attrib,
unsigned int *value);
int (*indexConfigAttrib)(const __DRIconfig *config, int index,
unsigned int *attrib, unsigned int *value);
__DRIdrawable *(*createNewDrawable)(__DRIscreen *screen,
const __DRIconfig *config,
unsigned int drawable_id,
unsigned int head,
void *loaderPrivate);
void (*destroyDrawable)(__DRIdrawable *drawable);
void (*swapBuffers)(__DRIdrawable *drawable);
__DRIcontext *(*createNewContext)(__DRIscreen *screen,
const __DRIconfig *config,
__DRIcontext *shared,
void *loaderPrivate);
int (*copyContext)(__DRIcontext *dest,
__DRIcontext *src,
unsigned long mask);
void (*destroyContext)(__DRIcontext *context);
int (*bindContext)(__DRIcontext *ctx,
__DRIdrawable *pdraw,
__DRIdrawable *pread);
int (*unbindContext)(__DRIcontext *ctx);
};
/**
* Stored version of some component (i.e., server-side DRI module, kernel-side
* DRM, etc.).
*
* \todo
* There are several data structures that explicitly store a major version,
* minor version, and patch level. These structures should be modified to
* have a \c __DRIversionRec instead.
*/
struct __DRIversionRec {
int major; /**< Major version number. */
int minor; /**< Minor version number. */
int patch; /**< Patch-level. */
};
/**
* Framebuffer information record. Used by libGL to communicate information
* about the framebuffer to the driver's \c __driCreateNewScreen function.
*
* In XFree86, most of this information is derrived from data returned by
* calling \c XF86DRIGetDeviceInfo.
*
* \sa XF86DRIGetDeviceInfo __DRIdisplayRec::createNewScreen
* __driUtilCreateNewScreen CallCreateNewScreen
*
* \bug This structure could be better named.
*/
struct __DRIframebufferRec {
unsigned char *base; /**< Framebuffer base address in the CPU's
* address space. This value is calculated by
* calling \c drmMap on the framebuffer handle
* returned by \c XF86DRIGetDeviceInfo (or a
* similar function).
*/
int size; /**< Framebuffer size, in bytes. */
int stride; /**< Number of bytes from one line to the next. */
int width; /**< Pixel width of the framebuffer. */
int height; /**< Pixel height of the framebuffer. */
int dev_priv_size; /**< Size of the driver's dev-priv structure. */
void *dev_priv; /**< Pointer to the driver's dev-priv structure. */
};
/**
* This extension provides alternative screen, drawable and context
* constructors for legacy DRI functionality. This is used in
* conjunction with the core extension.
*/
#define __DRI_LEGACY "DRI_Legacy"
#define __DRI_LEGACY_VERSION 1
struct __DRIlegacyExtensionRec {
__DRIextension base;
__DRIscreen *(*createNewScreen)(int screen,
const __DRIversion *ddx_version,
const __DRIversion *dri_version,
const __DRIversion *drm_version,
const __DRIframebuffer *frame_buffer,
void *pSAREA, int fd,
const __DRIextension **extensions,
const __DRIconfig ***driver_configs,
void *loaderPrivate);
__DRIdrawable *(*createNewDrawable)(__DRIscreen *screen,
const __DRIconfig *config,
drm_drawable_t hwDrawable,
int renderType, const int *attrs,
void *loaderPrivate);
__DRIcontext *(*createNewContext)(__DRIscreen *screen,
const __DRIconfig *config,
int render_type,
__DRIcontext *shared,
drm_context_t hwContext,
void *loaderPrivate);
};
/**
* This extension provides alternative screen, drawable and context
* constructors for swrast DRI functionality. This is used in
* conjunction with the core extension.
*/
#define __DRI_SWRAST "DRI_SWRast"
#define __DRI_SWRAST_VERSION 1
struct __DRIswrastExtensionRec {
__DRIextension base;
__DRIscreen *(*createNewScreen)(int screen,
const __DRIextension **extensions,
const __DRIconfig ***driver_configs,
void *loaderPrivate);
__DRIdrawable *(*createNewDrawable)(__DRIscreen *screen,
const __DRIconfig *config,
void *loaderPrivate);
};
/**
* DRI2 Loader extension.
*/
#define __DRI_BUFFER_FRONT_LEFT 0
#define __DRI_BUFFER_BACK_LEFT 1
#define __DRI_BUFFER_FRONT_RIGHT 2
#define __DRI_BUFFER_BACK_RIGHT 3
#define __DRI_BUFFER_DEPTH 4
#define __DRI_BUFFER_STENCIL 5
#define __DRI_BUFFER_ACCUM 6
#define __DRI_BUFFER_FAKE_FRONT_LEFT 7
#define __DRI_BUFFER_FAKE_FRONT_RIGHT 8
#define __DRI_BUFFER_DEPTH_STENCIL 9 /**< Only available with DRI2 1.1 */
struct __DRIbufferRec {
unsigned int attachment;
unsigned int name;
unsigned int pitch;
unsigned int cpp;
unsigned int flags;
};
#define __DRI_DRI2_LOADER "DRI_DRI2Loader"
#define __DRI_DRI2_LOADER_VERSION 3
struct __DRIdri2LoaderExtensionRec {
__DRIextension base;
__DRIbuffer *(*getBuffers)(__DRIdrawable *driDrawable,
int *width, int *height,
unsigned int *attachments, int count,
int *out_count, void *loaderPrivate);
/**
* Flush pending front-buffer rendering
*
* Any rendering that has been performed to the
* \c __DRI_BUFFER_FAKE_FRONT_LEFT will be flushed to the
* \c __DRI_BUFFER_FRONT_LEFT.
*
* \param driDrawable Drawable whose front-buffer is to be flushed
* \param loaderPrivate Loader's private data that was previously passed
* into __DRIdri2ExtensionRec::createNewDrawable
*/
void (*flushFrontBuffer)(__DRIdrawable *driDrawable, void *loaderPrivate);
/**
* Get list of buffers from the server
*
* Gets a list of buffer for the specified set of attachments. Unlike
* \c ::getBuffers, this function takes a list of attachments paired with
* opaque \c unsigned \c int value describing the format of the buffer.
* It is the responsibility of the caller to know what the service that
* allocates the buffers will expect to receive for the format.
*
* \param driDrawable Drawable whose buffers are being queried.
* \param width Output where the width of the buffers is stored.
* \param height Output where the height of the buffers is stored.
* \param attachments List of pairs of attachment ID and opaque format
* requested for the drawable.
* \param count Number of attachment / format pairs stored in
* \c attachments.
* \param loaderPrivate Loader's private data that was previously passed
* into __DRIdri2ExtensionRec::createNewDrawable.
*/
__DRIbuffer *(*getBuffersWithFormat)(__DRIdrawable *driDrawable,
int *width, int *height,
unsigned int *attachments, int count,
int *out_count, void *loaderPrivate);
};
/**
* This extension provides alternative screen, drawable and context
* constructors for DRI2.
*/
#define __DRI_DRI2 "DRI_DRI2"
#define __DRI_DRI2_VERSION 2
#define __DRI_API_OPENGL 0
#define __DRI_API_GLES 1
#define __DRI_API_GLES2 2
struct __DRIdri2ExtensionRec {
__DRIextension base;
__DRIscreen *(*createNewScreen)(int screen, int fd,
const __DRIextension **extensions,
const __DRIconfig ***driver_configs,
void *loaderPrivate);
__DRIdrawable *(*createNewDrawable)(__DRIscreen *screen,
const __DRIconfig *config,
void *loaderPrivate);
__DRIcontext *(*createNewContext)(__DRIscreen *screen,
const __DRIconfig *config,
__DRIcontext *shared,
void *loaderPrivate);
/* Since version 2 */
unsigned int (*getAPIMask)(__DRIscreen *screen);
__DRIcontext *(*createNewContextForAPI)(__DRIscreen *screen,
int api,
const __DRIconfig *config,
__DRIcontext *shared,
void *data);
};
/**
* This extension provides functionality to enable various EGLImage
* extensions.
*/
#define __DRI_IMAGE "DRI_IMAGE"
#define __DRI_IMAGE_VERSION 1
/**
* These formats correspond to the similarly named MESA_FORMAT_*
* tokens, except in the native endian of the CPU. For example, on
* little endian __DRI_IMAGE_FORMAT_XRGB8888 corresponds to
* MESA_FORMAT_XRGB8888, but MESA_FORMAT_XRGB8888_REV on big endian.
*/
#define __DRI_IMAGE_FORMAT_RGB565 0x1001
#define __DRI_IMAGE_FORMAT_XRGB8888 0x1002
#define __DRI_IMAGE_FORMAT_ARGB8888 0x1003
#define __DRI_IMAGE_USE_SHARE 0x0001
#define __DRI_IMAGE_USE_SCANOUT 0x0002
/**
* queryImage attributes
*/
#define __DRI_IMAGE_ATTRIB_STRIDE 0x2000
#define __DRI_IMAGE_ATTRIB_HANDLE 0x2001
#define __DRI_IMAGE_ATTRIB_NAME 0x2002
typedef struct __DRIimageRec __DRIimage;
typedef struct __DRIimageExtensionRec __DRIimageExtension;
struct __DRIimageExtensionRec {
__DRIextension base;
__DRIimage *(*createImageFromName)(__DRIscreen *screen,
int width, int height, int format,
int name, int pitch,
void *loaderPrivate);
__DRIimage *(*createImageFromRenderbuffer)(__DRIcontext *context,
int renderbuffer,
void *loaderPrivate);
void (*destroyImage)(__DRIimage *image);
__DRIimage *(*createImage)(__DRIscreen *screen,
int width, int height, int format,
unsigned int use,
void *loaderPrivate);
GLboolean (*queryImage)(__DRIimage *image, int attrib, int *value);
};
/**
* This extension must be implemented by the loader and passed to the
* driver at screen creation time. The EGLImage entry points in the
* various client APIs take opaque EGLImage handles and use this
* extension to map them to a __DRIimage. At version 1, this
* extensions allows mapping EGLImage pointers to __DRIimage pointers,
* but future versions could support other EGLImage-like, opaque types
* with new lookup functions.
*/
#define __DRI_IMAGE_LOOKUP "DRI_IMAGE_LOOKUP"
#define __DRI_IMAGE_LOOKUP_VERSION 1
typedef struct __DRIimageLookupExtensionRec __DRIimageLookupExtension;
struct __DRIimageLookupExtensionRec {
__DRIextension base;
__DRIimage *(*lookupEGLImage)(__DRIscreen *screen, void *image,
void *loaderPrivate);
};
/**
* This extension allows for common DRI2 options
*/
#define __DRI2_CONFIG_QUERY "DRI_CONFIG_QUERY"
#define __DRI2_CONFIG_QUERY_VERSION 1
typedef struct __DRI2configQueryExtensionRec __DRI2configQueryExtension;
struct __DRI2configQueryExtensionRec {
__DRIextension base;
int (*configQueryb)(__DRIscreen *screen, const char *var, GLboolean *val);
int (*configQueryi)(__DRIscreen *screen, const char *var, GLint *val);
int (*configQueryf)(__DRIscreen *screen, const char *var, GLfloat *val);
};
#endif
+15
View File
@@ -0,0 +1,15 @@
/*
* Skeleton egl.h to provide compatibility for early GLES 1.0
* applications. Several early implementations included gl.h
* in egl.h leading applications to include only egl.h
*
* $Revision: 6252 $ on $Date:: 2008-08-06 16:35:08 -0700 #$
*/
#ifndef __legacy_egl_h_
#define __legacy_egl_h_
#include <EGL/egl.h>
#include <GLES/gl.h>
#endif /* __legacy_egl_h_ */
+770
View File
@@ -0,0 +1,770 @@
#ifndef __gl_h_
#define __gl_h_
/* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */
#include <GLES/glplatform.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This document is licensed under the SGI Free Software B License Version
* 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
*/
typedef void GLvoid;
typedef char GLchar;
typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef khronos_int8_t GLbyte;
typedef short GLshort;
typedef int GLint;
typedef int GLsizei;
typedef khronos_uint8_t GLubyte;
typedef unsigned short GLushort;
typedef unsigned int GLuint;
typedef khronos_float_t GLfloat;
typedef khronos_float_t GLclampf;
typedef khronos_int32_t GLfixed;
typedef khronos_int32_t GLclampx;
typedef khronos_intptr_t GLintptr;
typedef khronos_ssize_t GLsizeiptr;
/*************************************************************/
/* OpenGL ES core versions */
#define GL_VERSION_ES_CM_1_0 1
#define GL_VERSION_ES_CL_1_0 1
#define GL_VERSION_ES_CM_1_1 1
#define GL_VERSION_ES_CL_1_1 1
/* ClearBufferMask */
#define GL_DEPTH_BUFFER_BIT 0x00000100
#define GL_STENCIL_BUFFER_BIT 0x00000400
#define GL_COLOR_BUFFER_BIT 0x00004000
/* Boolean */
#define GL_FALSE 0
#define GL_TRUE 1
/* BeginMode */
#define GL_POINTS 0x0000
#define GL_LINES 0x0001
#define GL_LINE_LOOP 0x0002
#define GL_LINE_STRIP 0x0003
#define GL_TRIANGLES 0x0004
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
/* AlphaFunction */
#define GL_NEVER 0x0200
#define GL_LESS 0x0201
#define GL_EQUAL 0x0202
#define GL_LEQUAL 0x0203
#define GL_GREATER 0x0204
#define GL_NOTEQUAL 0x0205
#define GL_GEQUAL 0x0206
#define GL_ALWAYS 0x0207
/* BlendingFactorDest */
#define GL_ZERO 0
#define GL_ONE 1
#define GL_SRC_COLOR 0x0300
#define GL_ONE_MINUS_SRC_COLOR 0x0301
#define GL_SRC_ALPHA 0x0302
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_DST_ALPHA 0x0304
#define GL_ONE_MINUS_DST_ALPHA 0x0305
/* BlendingFactorSrc */
/* GL_ZERO */
/* GL_ONE */
#define GL_DST_COLOR 0x0306
#define GL_ONE_MINUS_DST_COLOR 0x0307
#define GL_SRC_ALPHA_SATURATE 0x0308
/* GL_SRC_ALPHA */
/* GL_ONE_MINUS_SRC_ALPHA */
/* GL_DST_ALPHA */
/* GL_ONE_MINUS_DST_ALPHA */
/* ClipPlaneName */
#define GL_CLIP_PLANE0 0x3000
#define GL_CLIP_PLANE1 0x3001
#define GL_CLIP_PLANE2 0x3002
#define GL_CLIP_PLANE3 0x3003
#define GL_CLIP_PLANE4 0x3004
#define GL_CLIP_PLANE5 0x3005
/* ColorMaterialFace */
/* GL_FRONT_AND_BACK */
/* ColorMaterialParameter */
/* GL_AMBIENT_AND_DIFFUSE */
/* ColorPointerType */
/* GL_UNSIGNED_BYTE */
/* GL_FLOAT */
/* GL_FIXED */
/* CullFaceMode */
#define GL_FRONT 0x0404
#define GL_BACK 0x0405
#define GL_FRONT_AND_BACK 0x0408
/* DepthFunction */
/* GL_NEVER */
/* GL_LESS */
/* GL_EQUAL */
/* GL_LEQUAL */
/* GL_GREATER */
/* GL_NOTEQUAL */
/* GL_GEQUAL */
/* GL_ALWAYS */
/* EnableCap */
#define GL_FOG 0x0B60
#define GL_LIGHTING 0x0B50
#define GL_TEXTURE_2D 0x0DE1
#define GL_CULL_FACE 0x0B44
#define GL_ALPHA_TEST 0x0BC0
#define GL_BLEND 0x0BE2
#define GL_COLOR_LOGIC_OP 0x0BF2
#define GL_DITHER 0x0BD0
#define GL_STENCIL_TEST 0x0B90
#define GL_DEPTH_TEST 0x0B71
/* GL_LIGHT0 */
/* GL_LIGHT1 */
/* GL_LIGHT2 */
/* GL_LIGHT3 */
/* GL_LIGHT4 */
/* GL_LIGHT5 */
/* GL_LIGHT6 */
/* GL_LIGHT7 */
#define GL_POINT_SMOOTH 0x0B10
#define GL_LINE_SMOOTH 0x0B20
#define GL_SCISSOR_TEST 0x0C11
#define GL_COLOR_MATERIAL 0x0B57
#define GL_NORMALIZE 0x0BA1
#define GL_RESCALE_NORMAL 0x803A
#define GL_POLYGON_OFFSET_FILL 0x8037
#define GL_VERTEX_ARRAY 0x8074
#define GL_NORMAL_ARRAY 0x8075
#define GL_COLOR_ARRAY 0x8076
#define GL_TEXTURE_COORD_ARRAY 0x8078
#define GL_MULTISAMPLE 0x809D
#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
#define GL_SAMPLE_COVERAGE 0x80A0
/* ErrorCode */
#define GL_NO_ERROR 0
#define GL_INVALID_ENUM 0x0500
#define GL_INVALID_VALUE 0x0501
#define GL_INVALID_OPERATION 0x0502
#define GL_STACK_OVERFLOW 0x0503
#define GL_STACK_UNDERFLOW 0x0504
#define GL_OUT_OF_MEMORY 0x0505
/* FogMode */
/* GL_LINEAR */
#define GL_EXP 0x0800
#define GL_EXP2 0x0801
/* FogParameter */
#define GL_FOG_DENSITY 0x0B62
#define GL_FOG_START 0x0B63
#define GL_FOG_END 0x0B64
#define GL_FOG_MODE 0x0B65
#define GL_FOG_COLOR 0x0B66
/* FrontFaceDirection */
#define GL_CW 0x0900
#define GL_CCW 0x0901
/* GetPName */
#define GL_CURRENT_COLOR 0x0B00
#define GL_CURRENT_NORMAL 0x0B02
#define GL_CURRENT_TEXTURE_COORDS 0x0B03
#define GL_POINT_SIZE 0x0B11
#define GL_POINT_SIZE_MIN 0x8126
#define GL_POINT_SIZE_MAX 0x8127
#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
#define GL_POINT_DISTANCE_ATTENUATION 0x8129
#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
#define GL_LINE_WIDTH 0x0B21
#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
#define GL_CULL_FACE_MODE 0x0B45
#define GL_FRONT_FACE 0x0B46
#define GL_SHADE_MODEL 0x0B54
#define GL_DEPTH_RANGE 0x0B70
#define GL_DEPTH_WRITEMASK 0x0B72
#define GL_DEPTH_CLEAR_VALUE 0x0B73
#define GL_DEPTH_FUNC 0x0B74
#define GL_STENCIL_CLEAR_VALUE 0x0B91
#define GL_STENCIL_FUNC 0x0B92
#define GL_STENCIL_VALUE_MASK 0x0B93
#define GL_STENCIL_FAIL 0x0B94
#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
#define GL_STENCIL_REF 0x0B97
#define GL_STENCIL_WRITEMASK 0x0B98
#define GL_MATRIX_MODE 0x0BA0
#define GL_VIEWPORT 0x0BA2
#define GL_MODELVIEW_STACK_DEPTH 0x0BA3
#define GL_PROJECTION_STACK_DEPTH 0x0BA4
#define GL_TEXTURE_STACK_DEPTH 0x0BA5
#define GL_MODELVIEW_MATRIX 0x0BA6
#define GL_PROJECTION_MATRIX 0x0BA7
#define GL_TEXTURE_MATRIX 0x0BA8
#define GL_ALPHA_TEST_FUNC 0x0BC1
#define GL_ALPHA_TEST_REF 0x0BC2
#define GL_BLEND_DST 0x0BE0
#define GL_BLEND_SRC 0x0BE1
#define GL_LOGIC_OP_MODE 0x0BF0
#define GL_SCISSOR_BOX 0x0C10
#define GL_SCISSOR_TEST 0x0C11
#define GL_COLOR_CLEAR_VALUE 0x0C22
#define GL_COLOR_WRITEMASK 0x0C23
#define GL_UNPACK_ALIGNMENT 0x0CF5
#define GL_PACK_ALIGNMENT 0x0D05
#define GL_MAX_LIGHTS 0x0D31
#define GL_MAX_CLIP_PLANES 0x0D32
#define GL_MAX_TEXTURE_SIZE 0x0D33
#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
#define GL_MAX_VIEWPORT_DIMS 0x0D3A
#define GL_MAX_TEXTURE_UNITS 0x84E2
#define GL_SUBPIXEL_BITS 0x0D50
#define GL_RED_BITS 0x0D52
#define GL_GREEN_BITS 0x0D53
#define GL_BLUE_BITS 0x0D54
#define GL_ALPHA_BITS 0x0D55
#define GL_DEPTH_BITS 0x0D56
#define GL_STENCIL_BITS 0x0D57
#define GL_POLYGON_OFFSET_UNITS 0x2A00
#define GL_POLYGON_OFFSET_FILL 0x8037
#define GL_POLYGON_OFFSET_FACTOR 0x8038
#define GL_TEXTURE_BINDING_2D 0x8069
#define GL_VERTEX_ARRAY_SIZE 0x807A
#define GL_VERTEX_ARRAY_TYPE 0x807B
#define GL_VERTEX_ARRAY_STRIDE 0x807C
#define GL_NORMAL_ARRAY_TYPE 0x807E
#define GL_NORMAL_ARRAY_STRIDE 0x807F
#define GL_COLOR_ARRAY_SIZE 0x8081
#define GL_COLOR_ARRAY_TYPE 0x8082
#define GL_COLOR_ARRAY_STRIDE 0x8083
#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088
#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089
#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A
#define GL_VERTEX_ARRAY_POINTER 0x808E
#define GL_NORMAL_ARRAY_POINTER 0x808F
#define GL_COLOR_ARRAY_POINTER 0x8090
#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092
#define GL_SAMPLE_BUFFERS 0x80A8
#define GL_SAMPLES 0x80A9
#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
/* GetTextureParameter */
/* GL_TEXTURE_MAG_FILTER */
/* GL_TEXTURE_MIN_FILTER */
/* GL_TEXTURE_WRAP_S */
/* GL_TEXTURE_WRAP_T */
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
/* HintMode */
#define GL_DONT_CARE 0x1100
#define GL_FASTEST 0x1101
#define GL_NICEST 0x1102
/* HintTarget */
#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
#define GL_POINT_SMOOTH_HINT 0x0C51
#define GL_LINE_SMOOTH_HINT 0x0C52
#define GL_FOG_HINT 0x0C54
#define GL_GENERATE_MIPMAP_HINT 0x8192
/* LightModelParameter */
#define GL_LIGHT_MODEL_AMBIENT 0x0B53
#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
/* LightParameter */
#define GL_AMBIENT 0x1200
#define GL_DIFFUSE 0x1201
#define GL_SPECULAR 0x1202
#define GL_POSITION 0x1203
#define GL_SPOT_DIRECTION 0x1204
#define GL_SPOT_EXPONENT 0x1205
#define GL_SPOT_CUTOFF 0x1206
#define GL_CONSTANT_ATTENUATION 0x1207
#define GL_LINEAR_ATTENUATION 0x1208
#define GL_QUADRATIC_ATTENUATION 0x1209
/* DataType */
#define GL_BYTE 0x1400
#define GL_UNSIGNED_BYTE 0x1401
#define GL_SHORT 0x1402
#define GL_UNSIGNED_SHORT 0x1403
#define GL_FLOAT 0x1406
#define GL_FIXED 0x140C
/* LogicOp */
#define GL_CLEAR 0x1500
#define GL_AND 0x1501
#define GL_AND_REVERSE 0x1502
#define GL_COPY 0x1503
#define GL_AND_INVERTED 0x1504
#define GL_NOOP 0x1505
#define GL_XOR 0x1506
#define GL_OR 0x1507
#define GL_NOR 0x1508
#define GL_EQUIV 0x1509
#define GL_INVERT 0x150A
#define GL_OR_REVERSE 0x150B
#define GL_COPY_INVERTED 0x150C
#define GL_OR_INVERTED 0x150D
#define GL_NAND 0x150E
#define GL_SET 0x150F
/* MaterialFace */
/* GL_FRONT_AND_BACK */
/* MaterialParameter */
#define GL_EMISSION 0x1600
#define GL_SHININESS 0x1601
#define GL_AMBIENT_AND_DIFFUSE 0x1602
/* GL_AMBIENT */
/* GL_DIFFUSE */
/* GL_SPECULAR */
/* MatrixMode */
#define GL_MODELVIEW 0x1700
#define GL_PROJECTION 0x1701
#define GL_TEXTURE 0x1702
/* NormalPointerType */
/* GL_BYTE */
/* GL_SHORT */
/* GL_FLOAT */
/* GL_FIXED */
/* PixelFormat */
#define GL_ALPHA 0x1906
#define GL_RGB 0x1907
#define GL_RGBA 0x1908
#define GL_LUMINANCE 0x1909
#define GL_LUMINANCE_ALPHA 0x190A
/* PixelStoreParameter */
#define GL_UNPACK_ALIGNMENT 0x0CF5
#define GL_PACK_ALIGNMENT 0x0D05
/* PixelType */
/* GL_UNSIGNED_BYTE */
#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
#define GL_UNSIGNED_SHORT_5_6_5 0x8363
/* ShadingModel */
#define GL_FLAT 0x1D00
#define GL_SMOOTH 0x1D01
/* StencilFunction */
/* GL_NEVER */
/* GL_LESS */
/* GL_EQUAL */
/* GL_LEQUAL */
/* GL_GREATER */
/* GL_NOTEQUAL */
/* GL_GEQUAL */
/* GL_ALWAYS */
/* StencilOp */
/* GL_ZERO */
#define GL_KEEP 0x1E00
#define GL_REPLACE 0x1E01
#define GL_INCR 0x1E02
#define GL_DECR 0x1E03
/* GL_INVERT */
/* StringName */
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
/* TexCoordPointerType */
/* GL_SHORT */
/* GL_FLOAT */
/* GL_FIXED */
/* GL_BYTE */
/* TextureEnvMode */
#define GL_MODULATE 0x2100
#define GL_DECAL 0x2101
/* GL_BLEND */
#define GL_ADD 0x0104
/* GL_REPLACE */
/* TextureEnvParameter */
#define GL_TEXTURE_ENV_MODE 0x2200
#define GL_TEXTURE_ENV_COLOR 0x2201
/* TextureEnvTarget */
#define GL_TEXTURE_ENV 0x2300
/* TextureMagFilter */
#define GL_NEAREST 0x2600
#define GL_LINEAR 0x2601
/* TextureMinFilter */
/* GL_NEAREST */
/* GL_LINEAR */
#define GL_NEAREST_MIPMAP_NEAREST 0x2700
#define GL_LINEAR_MIPMAP_NEAREST 0x2701
#define GL_NEAREST_MIPMAP_LINEAR 0x2702
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
/* TextureParameterName */
#define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801
#define GL_TEXTURE_WRAP_S 0x2802
#define GL_TEXTURE_WRAP_T 0x2803
#define GL_GENERATE_MIPMAP 0x8191
/* TextureTarget */
/* GL_TEXTURE_2D */
/* TextureUnit */
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
#define GL_TEXTURE3 0x84C3
#define GL_TEXTURE4 0x84C4
#define GL_TEXTURE5 0x84C5
#define GL_TEXTURE6 0x84C6
#define GL_TEXTURE7 0x84C7
#define GL_TEXTURE8 0x84C8
#define GL_TEXTURE9 0x84C9
#define GL_TEXTURE10 0x84CA
#define GL_TEXTURE11 0x84CB
#define GL_TEXTURE12 0x84CC
#define GL_TEXTURE13 0x84CD
#define GL_TEXTURE14 0x84CE
#define GL_TEXTURE15 0x84CF
#define GL_TEXTURE16 0x84D0
#define GL_TEXTURE17 0x84D1
#define GL_TEXTURE18 0x84D2
#define GL_TEXTURE19 0x84D3
#define GL_TEXTURE20 0x84D4
#define GL_TEXTURE21 0x84D5
#define GL_TEXTURE22 0x84D6
#define GL_TEXTURE23 0x84D7
#define GL_TEXTURE24 0x84D8
#define GL_TEXTURE25 0x84D9
#define GL_TEXTURE26 0x84DA
#define GL_TEXTURE27 0x84DB
#define GL_TEXTURE28 0x84DC
#define GL_TEXTURE29 0x84DD
#define GL_TEXTURE30 0x84DE
#define GL_TEXTURE31 0x84DF
#define GL_ACTIVE_TEXTURE 0x84E0
#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1
/* TextureWrapMode */
#define GL_REPEAT 0x2901
#define GL_CLAMP_TO_EDGE 0x812F
/* VertexPointerType */
/* GL_SHORT */
/* GL_FLOAT */
/* GL_FIXED */
/* GL_BYTE */
/* LightName */
#define GL_LIGHT0 0x4000
#define GL_LIGHT1 0x4001
#define GL_LIGHT2 0x4002
#define GL_LIGHT3 0x4003
#define GL_LIGHT4 0x4004
#define GL_LIGHT5 0x4005
#define GL_LIGHT6 0x4006
#define GL_LIGHT7 0x4007
/* Buffer Objects */
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
#define GL_STATIC_DRAW 0x88E4
#define GL_DYNAMIC_DRAW 0x88E8
#define GL_BUFFER_SIZE 0x8764
#define GL_BUFFER_USAGE 0x8765
/* Texture combine + dot3 */
#define GL_SUBTRACT 0x84E7
#define GL_COMBINE 0x8570
#define GL_COMBINE_RGB 0x8571
#define GL_COMBINE_ALPHA 0x8572
#define GL_RGB_SCALE 0x8573
#define GL_ADD_SIGNED 0x8574
#define GL_INTERPOLATE 0x8575
#define GL_CONSTANT 0x8576
#define GL_PRIMARY_COLOR 0x8577
#define GL_PREVIOUS 0x8578
#define GL_OPERAND0_RGB 0x8590
#define GL_OPERAND1_RGB 0x8591
#define GL_OPERAND2_RGB 0x8592
#define GL_OPERAND0_ALPHA 0x8598
#define GL_OPERAND1_ALPHA 0x8599
#define GL_OPERAND2_ALPHA 0x859A
#define GL_ALPHA_SCALE 0x0D1C
#define GL_SRC0_RGB 0x8580
#define GL_SRC1_RGB 0x8581
#define GL_SRC2_RGB 0x8582
#define GL_SRC0_ALPHA 0x8588
#define GL_SRC1_ALPHA 0x8589
#define GL_SRC2_ALPHA 0x858A
#define GL_DOT3_RGB 0x86AE
#define GL_DOT3_RGBA 0x86AF
/*------------------------------------------------------------------------*
* required OES extension tokens
*------------------------------------------------------------------------*/
/* OES_read_format */
#ifndef GL_OES_read_format
#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
#endif
/* GL_OES_compressed_paletted_texture */
#ifndef GL_OES_compressed_paletted_texture
#define GL_PALETTE4_RGB8_OES 0x8B90
#define GL_PALETTE4_RGBA8_OES 0x8B91
#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
#define GL_PALETTE4_RGBA4_OES 0x8B93
#define GL_PALETTE4_RGB5_A1_OES 0x8B94
#define GL_PALETTE8_RGB8_OES 0x8B95
#define GL_PALETTE8_RGBA8_OES 0x8B96
#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
#define GL_PALETTE8_RGBA4_OES 0x8B98
#define GL_PALETTE8_RGB5_A1_OES 0x8B99
#endif
/* OES_point_size_array */
#ifndef GL_OES_point_size_array
#define GL_POINT_SIZE_ARRAY_OES 0x8B9C
#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A
#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B
#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C
#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F
#endif
/* GL_OES_point_sprite */
#ifndef GL_OES_point_sprite
#define GL_POINT_SPRITE_OES 0x8861
#define GL_COORD_REPLACE_OES 0x8862
#endif
/*************************************************************/
/* Available only in Common profile */
GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
GL_API void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
GL_API void GL_APIENTRY glClearDepthf (GLclampf depth);
GL_API void GL_APIENTRY glClipPlanef (GLenum plane, const GLfloat *equation);
GL_API void GL_APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
GL_API void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
GL_API void GL_APIENTRY glFogf (GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glFogfv (GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
GL_API void GL_APIENTRY glGetClipPlanef (GLenum pname, GLfloat eqn[4]);
GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params);
GL_API void GL_APIENTRY glLightModelf (GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glLineWidth (GLfloat width);
GL_API void GL_APIENTRY glLoadMatrixf (const GLfloat *m);
GL_API void GL_APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glMultMatrixf (const GLfloat *m);
GL_API void GL_APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
GL_API void GL_APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
GL_API void GL_APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
GL_API void GL_APIENTRY glPointParameterf (GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glPointSize (GLfloat size);
GL_API void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
GL_API void GL_APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
GL_API void GL_APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z);
GL_API void GL_APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
GL_API void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
GL_API void GL_APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);
/* Available in both Common and Common-Lite profiles */
GL_API void GL_APIENTRY glActiveTexture (GLenum texture);
GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLclampx ref);
GL_API void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
GL_API void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
GL_API void GL_APIENTRY glClear (GLbitfield mask);
GL_API void GL_APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
GL_API void GL_APIENTRY glClearDepthx (GLclampx depth);
GL_API void GL_APIENTRY glClearStencil (GLint s);
GL_API void GL_APIENTRY glClientActiveTexture (GLenum texture);
GL_API void GL_APIENTRY glClipPlanex (GLenum plane, const GLfixed *equation);
GL_API void GL_APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
GL_API void GL_APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
GL_API void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
GL_API void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
GL_API void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
GL_API void GL_APIENTRY glCullFace (GLenum mode);
GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
GL_API void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
GL_API void GL_APIENTRY glDepthFunc (GLenum func);
GL_API void GL_APIENTRY glDepthMask (GLboolean flag);
GL_API void GL_APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar);
GL_API void GL_APIENTRY glDisable (GLenum cap);
GL_API void GL_APIENTRY glDisableClientState (GLenum array);
GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
GL_API void GL_APIENTRY glEnable (GLenum cap);
GL_API void GL_APIENTRY glEnableClientState (GLenum array);
GL_API void GL_APIENTRY glFinish (void);
GL_API void GL_APIENTRY glFlush (void);
GL_API void GL_APIENTRY glFogx (GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glFrontFace (GLenum mode);
GL_API void GL_APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *params);
GL_API void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
GL_API void GL_APIENTRY glGetClipPlanex (GLenum pname, GLfixed eqn[4]);
GL_API void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
GL_API void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures);
GL_API GLenum GL_APIENTRY glGetError (void);
GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params);
GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glGetPointerv (GLenum pname, GLvoid **params);
GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name);
GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params);
GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params);
GL_API void GL_APIENTRY glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params);
GL_API void GL_APIENTRY glHint (GLenum target, GLenum mode);
GL_API GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
GL_API GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
GL_API GLboolean GL_APIENTRY glIsTexture (GLuint texture);
GL_API void GL_APIENTRY glLightModelx (GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glLineWidthx (GLfixed width);
GL_API void GL_APIENTRY glLoadIdentity (void);
GL_API void GL_APIENTRY glLoadMatrixx (const GLfixed *m);
GL_API void GL_APIENTRY glLogicOp (GLenum opcode);
GL_API void GL_APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glMatrixMode (GLenum mode);
GL_API void GL_APIENTRY glMultMatrixx (const GLfixed *m);
GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
GL_API void GL_APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz);
GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
GL_API void GL_APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
GL_API void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
GL_API void GL_APIENTRY glPointParameterx (GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glPointParameterxv (GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glPointSizex (GLfixed size);
GL_API void GL_APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units);
GL_API void GL_APIENTRY glPopMatrix (void);
GL_API void GL_APIENTRY glPushMatrix (void);
GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
GL_API void GL_APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
GL_API void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
GL_API void GL_APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert);
GL_API void GL_APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z);
GL_API void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
GL_API void GL_APIENTRY glShadeModel (GLenum mode);
GL_API void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
GL_API void GL_APIENTRY glStencilMask (GLuint mask);
GL_API void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
GL_API void GL_APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param);
GL_API void GL_APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params);
GL_API void GL_APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
GL_API void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
GL_API void GL_APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param);
GL_API void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
GL_API void GL_APIENTRY glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params);
GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
GL_API void GL_APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z);
GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
GL_API void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
/*------------------------------------------------------------------------*
* Required OES extension functions
*------------------------------------------------------------------------*/
/* GL_OES_read_format */
#ifndef GL_OES_read_format
#define GL_OES_read_format 1
#endif
/* GL_OES_compressed_paletted_texture */
#ifndef GL_OES_compressed_paletted_texture
#define GL_OES_compressed_paletted_texture 1
#endif
/* GL_OES_point_size_array */
#ifndef GL_OES_point_size_array
#define GL_OES_point_size_array 1
GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer);
#endif
/* GL_OES_point_sprite */
#ifndef GL_OES_point_sprite
#define GL_OES_point_sprite 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* __gl_h_ */
+620
View File
@@ -0,0 +1,620 @@
#ifndef __gl2_h_
#define __gl2_h_
/* $Revision: 16803 $ on $Date:: 2012-02-02 09:49:18 -0800 #$ */
#include <GLES2/gl2platform.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This document is licensed under the SGI Free Software B License Version
* 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
*/
/*-------------------------------------------------------------------------
* Data type definitions
*-----------------------------------------------------------------------*/
typedef void GLvoid;
typedef char GLchar;
typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef khronos_int8_t GLbyte;
typedef short GLshort;
typedef int GLint;
typedef int GLsizei;
typedef khronos_uint8_t GLubyte;
typedef unsigned short GLushort;
typedef unsigned int GLuint;
typedef khronos_float_t GLfloat;
typedef khronos_float_t GLclampf;
typedef khronos_int32_t GLfixed;
/* GL types for handling large vertex buffer objects */
typedef khronos_intptr_t GLintptr;
typedef khronos_ssize_t GLsizeiptr;
/* OpenGL ES core versions */
#define GL_ES_VERSION_2_0 1
/* ClearBufferMask */
#define GL_DEPTH_BUFFER_BIT 0x00000100
#define GL_STENCIL_BUFFER_BIT 0x00000400
#define GL_COLOR_BUFFER_BIT 0x00004000
/* Boolean */
#define GL_FALSE 0
#define GL_TRUE 1
/* BeginMode */
#define GL_POINTS 0x0000
#define GL_LINES 0x0001
#define GL_LINE_LOOP 0x0002
#define GL_LINE_STRIP 0x0003
#define GL_TRIANGLES 0x0004
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
/* AlphaFunction (not supported in ES20) */
/* GL_NEVER */
/* GL_LESS */
/* GL_EQUAL */
/* GL_LEQUAL */
/* GL_GREATER */
/* GL_NOTEQUAL */
/* GL_GEQUAL */
/* GL_ALWAYS */
/* BlendingFactorDest */
#define GL_ZERO 0
#define GL_ONE 1
#define GL_SRC_COLOR 0x0300
#define GL_ONE_MINUS_SRC_COLOR 0x0301
#define GL_SRC_ALPHA 0x0302
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_DST_ALPHA 0x0304
#define GL_ONE_MINUS_DST_ALPHA 0x0305
/* BlendingFactorSrc */
/* GL_ZERO */
/* GL_ONE */
#define GL_DST_COLOR 0x0306
#define GL_ONE_MINUS_DST_COLOR 0x0307
#define GL_SRC_ALPHA_SATURATE 0x0308
/* GL_SRC_ALPHA */
/* GL_ONE_MINUS_SRC_ALPHA */
/* GL_DST_ALPHA */
/* GL_ONE_MINUS_DST_ALPHA */
/* BlendEquationSeparate */
#define GL_FUNC_ADD 0x8006
#define GL_BLEND_EQUATION 0x8009
#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
#define GL_BLEND_EQUATION_ALPHA 0x883D
/* BlendSubtract */
#define GL_FUNC_SUBTRACT 0x800A
#define GL_FUNC_REVERSE_SUBTRACT 0x800B
/* Separate Blend Functions */
#define GL_BLEND_DST_RGB 0x80C8
#define GL_BLEND_SRC_RGB 0x80C9
#define GL_BLEND_DST_ALPHA 0x80CA
#define GL_BLEND_SRC_ALPHA 0x80CB
#define GL_CONSTANT_COLOR 0x8001
#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
#define GL_CONSTANT_ALPHA 0x8003
#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
#define GL_BLEND_COLOR 0x8005
/* Buffer Objects */
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
#define GL_STREAM_DRAW 0x88E0
#define GL_STATIC_DRAW 0x88E4
#define GL_DYNAMIC_DRAW 0x88E8
#define GL_BUFFER_SIZE 0x8764
#define GL_BUFFER_USAGE 0x8765
#define GL_CURRENT_VERTEX_ATTRIB 0x8626
/* CullFaceMode */
#define GL_FRONT 0x0404
#define GL_BACK 0x0405
#define GL_FRONT_AND_BACK 0x0408
/* DepthFunction */
/* GL_NEVER */
/* GL_LESS */
/* GL_EQUAL */
/* GL_LEQUAL */
/* GL_GREATER */
/* GL_NOTEQUAL */
/* GL_GEQUAL */
/* GL_ALWAYS */
/* EnableCap */
#define GL_TEXTURE_2D 0x0DE1
#define GL_CULL_FACE 0x0B44
#define GL_BLEND 0x0BE2
#define GL_DITHER 0x0BD0
#define GL_STENCIL_TEST 0x0B90
#define GL_DEPTH_TEST 0x0B71
#define GL_SCISSOR_TEST 0x0C11
#define GL_POLYGON_OFFSET_FILL 0x8037
#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
#define GL_SAMPLE_COVERAGE 0x80A0
/* ErrorCode */
#define GL_NO_ERROR 0
#define GL_INVALID_ENUM 0x0500
#define GL_INVALID_VALUE 0x0501
#define GL_INVALID_OPERATION 0x0502
#define GL_OUT_OF_MEMORY 0x0505
/* FrontFaceDirection */
#define GL_CW 0x0900
#define GL_CCW 0x0901
/* GetPName */
#define GL_LINE_WIDTH 0x0B21
#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
#define GL_CULL_FACE_MODE 0x0B45
#define GL_FRONT_FACE 0x0B46
#define GL_DEPTH_RANGE 0x0B70
#define GL_DEPTH_WRITEMASK 0x0B72
#define GL_DEPTH_CLEAR_VALUE 0x0B73
#define GL_DEPTH_FUNC 0x0B74
#define GL_STENCIL_CLEAR_VALUE 0x0B91
#define GL_STENCIL_FUNC 0x0B92
#define GL_STENCIL_FAIL 0x0B94
#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
#define GL_STENCIL_REF 0x0B97
#define GL_STENCIL_VALUE_MASK 0x0B93
#define GL_STENCIL_WRITEMASK 0x0B98
#define GL_STENCIL_BACK_FUNC 0x8800
#define GL_STENCIL_BACK_FAIL 0x8801
#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
#define GL_STENCIL_BACK_REF 0x8CA3
#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
#define GL_VIEWPORT 0x0BA2
#define GL_SCISSOR_BOX 0x0C10
/* GL_SCISSOR_TEST */
#define GL_COLOR_CLEAR_VALUE 0x0C22
#define GL_COLOR_WRITEMASK 0x0C23
#define GL_UNPACK_ALIGNMENT 0x0CF5
#define GL_PACK_ALIGNMENT 0x0D05
#define GL_MAX_TEXTURE_SIZE 0x0D33
#define GL_MAX_VIEWPORT_DIMS 0x0D3A
#define GL_SUBPIXEL_BITS 0x0D50
#define GL_RED_BITS 0x0D52
#define GL_GREEN_BITS 0x0D53
#define GL_BLUE_BITS 0x0D54
#define GL_ALPHA_BITS 0x0D55
#define GL_DEPTH_BITS 0x0D56
#define GL_STENCIL_BITS 0x0D57
#define GL_POLYGON_OFFSET_UNITS 0x2A00
/* GL_POLYGON_OFFSET_FILL */
#define GL_POLYGON_OFFSET_FACTOR 0x8038
#define GL_TEXTURE_BINDING_2D 0x8069
#define GL_SAMPLE_BUFFERS 0x80A8
#define GL_SAMPLES 0x80A9
#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
/* GetTextureParameter */
/* GL_TEXTURE_MAG_FILTER */
/* GL_TEXTURE_MIN_FILTER */
/* GL_TEXTURE_WRAP_S */
/* GL_TEXTURE_WRAP_T */
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
/* HintMode */
#define GL_DONT_CARE 0x1100
#define GL_FASTEST 0x1101
#define GL_NICEST 0x1102
/* HintTarget */
#define GL_GENERATE_MIPMAP_HINT 0x8192
/* DataType */
#define GL_BYTE 0x1400
#define GL_UNSIGNED_BYTE 0x1401
#define GL_SHORT 0x1402
#define GL_UNSIGNED_SHORT 0x1403
#define GL_INT 0x1404
#define GL_UNSIGNED_INT 0x1405
#define GL_FLOAT 0x1406
#define GL_FIXED 0x140C
/* PixelFormat */
#define GL_DEPTH_COMPONENT 0x1902
#define GL_ALPHA 0x1906
#define GL_RGB 0x1907
#define GL_RGBA 0x1908
#define GL_LUMINANCE 0x1909
#define GL_LUMINANCE_ALPHA 0x190A
/* PixelType */
/* GL_UNSIGNED_BYTE */
#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
#define GL_UNSIGNED_SHORT_5_6_5 0x8363
/* Shaders */
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_MAX_VERTEX_ATTRIBS 0x8869
#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
#define GL_MAX_VARYING_VECTORS 0x8DFC
#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
#define GL_SHADER_TYPE 0x8B4F
#define GL_DELETE_STATUS 0x8B80
#define GL_LINK_STATUS 0x8B82
#define GL_VALIDATE_STATUS 0x8B83
#define GL_ATTACHED_SHADERS 0x8B85
#define GL_ACTIVE_UNIFORMS 0x8B86
#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
#define GL_ACTIVE_ATTRIBUTES 0x8B89
#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
#define GL_CURRENT_PROGRAM 0x8B8D
/* StencilFunction */
#define GL_NEVER 0x0200
#define GL_LESS 0x0201
#define GL_EQUAL 0x0202
#define GL_LEQUAL 0x0203
#define GL_GREATER 0x0204
#define GL_NOTEQUAL 0x0205
#define GL_GEQUAL 0x0206
#define GL_ALWAYS 0x0207
/* StencilOp */
/* GL_ZERO */
#define GL_KEEP 0x1E00
#define GL_REPLACE 0x1E01
#define GL_INCR 0x1E02
#define GL_DECR 0x1E03
#define GL_INVERT 0x150A
#define GL_INCR_WRAP 0x8507
#define GL_DECR_WRAP 0x8508
/* StringName */
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
/* TextureMagFilter */
#define GL_NEAREST 0x2600
#define GL_LINEAR 0x2601
/* TextureMinFilter */
/* GL_NEAREST */
/* GL_LINEAR */
#define GL_NEAREST_MIPMAP_NEAREST 0x2700
#define GL_LINEAR_MIPMAP_NEAREST 0x2701
#define GL_NEAREST_MIPMAP_LINEAR 0x2702
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
/* TextureParameterName */
#define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801
#define GL_TEXTURE_WRAP_S 0x2802
#define GL_TEXTURE_WRAP_T 0x2803
/* TextureTarget */
/* GL_TEXTURE_2D */
#define GL_TEXTURE 0x1702
#define GL_TEXTURE_CUBE_MAP 0x8513
#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
/* TextureUnit */
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
#define GL_TEXTURE3 0x84C3
#define GL_TEXTURE4 0x84C4
#define GL_TEXTURE5 0x84C5
#define GL_TEXTURE6 0x84C6
#define GL_TEXTURE7 0x84C7
#define GL_TEXTURE8 0x84C8
#define GL_TEXTURE9 0x84C9
#define GL_TEXTURE10 0x84CA
#define GL_TEXTURE11 0x84CB
#define GL_TEXTURE12 0x84CC
#define GL_TEXTURE13 0x84CD
#define GL_TEXTURE14 0x84CE
#define GL_TEXTURE15 0x84CF
#define GL_TEXTURE16 0x84D0
#define GL_TEXTURE17 0x84D1
#define GL_TEXTURE18 0x84D2
#define GL_TEXTURE19 0x84D3
#define GL_TEXTURE20 0x84D4
#define GL_TEXTURE21 0x84D5
#define GL_TEXTURE22 0x84D6
#define GL_TEXTURE23 0x84D7
#define GL_TEXTURE24 0x84D8
#define GL_TEXTURE25 0x84D9
#define GL_TEXTURE26 0x84DA
#define GL_TEXTURE27 0x84DB
#define GL_TEXTURE28 0x84DC
#define GL_TEXTURE29 0x84DD
#define GL_TEXTURE30 0x84DE
#define GL_TEXTURE31 0x84DF
#define GL_ACTIVE_TEXTURE 0x84E0
/* TextureWrapMode */
#define GL_REPEAT 0x2901
#define GL_CLAMP_TO_EDGE 0x812F
#define GL_MIRRORED_REPEAT 0x8370
/* Uniform Types */
#define GL_FLOAT_VEC2 0x8B50
#define GL_FLOAT_VEC3 0x8B51
#define GL_FLOAT_VEC4 0x8B52
#define GL_INT_VEC2 0x8B53
#define GL_INT_VEC3 0x8B54
#define GL_INT_VEC4 0x8B55
#define GL_BOOL 0x8B56
#define GL_BOOL_VEC2 0x8B57
#define GL_BOOL_VEC3 0x8B58
#define GL_BOOL_VEC4 0x8B59
#define GL_FLOAT_MAT2 0x8B5A
#define GL_FLOAT_MAT3 0x8B5B
#define GL_FLOAT_MAT4 0x8B5C
#define GL_SAMPLER_2D 0x8B5E
#define GL_SAMPLER_CUBE 0x8B60
/* Vertex Arrays */
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
/* Read Format */
#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
/* Shader Source */
#define GL_COMPILE_STATUS 0x8B81
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_SHADER_SOURCE_LENGTH 0x8B88
#define GL_SHADER_COMPILER 0x8DFA
/* Shader Binary */
#define GL_SHADER_BINARY_FORMATS 0x8DF8
#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
/* Shader Precision-Specified Types */
#define GL_LOW_FLOAT 0x8DF0
#define GL_MEDIUM_FLOAT 0x8DF1
#define GL_HIGH_FLOAT 0x8DF2
#define GL_LOW_INT 0x8DF3
#define GL_MEDIUM_INT 0x8DF4
#define GL_HIGH_INT 0x8DF5
/* Framebuffer Object. */
#define GL_FRAMEBUFFER 0x8D40
#define GL_RENDERBUFFER 0x8D41
#define GL_RGBA4 0x8056
#define GL_RGB5_A1 0x8057
#define GL_RGB565 0x8D62
#define GL_DEPTH_COMPONENT16 0x81A5
#define GL_STENCIL_INDEX8 0x8D48
#define GL_RENDERBUFFER_WIDTH 0x8D42
#define GL_RENDERBUFFER_HEIGHT 0x8D43
#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
#define GL_RENDERBUFFER_RED_SIZE 0x8D50
#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
#define GL_COLOR_ATTACHMENT0 0x8CE0
#define GL_DEPTH_ATTACHMENT 0x8D00
#define GL_STENCIL_ATTACHMENT 0x8D20
#define GL_NONE 0
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
#define GL_FRAMEBUFFER_BINDING 0x8CA6
#define GL_RENDERBUFFER_BINDING 0x8CA7
#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
/*-------------------------------------------------------------------------
* GL core functions.
*-----------------------------------------------------------------------*/
GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
GL_APICALL void GL_APIENTRY glFinish (void);
GL_APICALL void GL_APIENTRY glFlush (void);
GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
GL_APICALL GLenum GL_APIENTRY glGetError (void);
GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
#ifdef __cplusplus
}
#endif
#endif /* __gl2_h_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,30 @@
#ifndef __gl2platform_h_
#define __gl2platform_h_
/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
/*
* This document is licensed under the SGI Free Software B License Version
* 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
*/
/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
*
* Adopters may modify khrplatform.h and this file to suit their platform.
* You are encouraged to submit all modifications to the Khronos group so that
* they can be included in future versions of this file. Please submit changes
* by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
* by filing a bug against product "OpenGL-ES" component "Registry".
*/
#include <KHR/khrplatform.h>
#ifndef GL_APICALL
#define GL_APICALL KHRONOS_APICALL
#endif
#ifndef GL_APIENTRY
#define GL_APIENTRY KHRONOS_APIENTRY
#endif
#endif /* __gl2platform_h_ */
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More