Metadata-Version: 2.4
Name: OpenGLContext
Version: 3.0.0a1
Summary: Demonstration and testing contexts for PyOpenGL/OpenGL-ctypes
Author-email: "Mike C. Fletcher" <mcfletch@vrplumber.com>
License-Expression: BSD-3-Clause
Project-URL: Homepage, http://pyopengl.sourceforge.net/context/
Project-URL: Documentation, http://pyopengl.sourceforge.net/context/documentation.html
Project-URL: Repository, https://github.com/mcfletch/openglcontext
Keywords: PyOpenGL,OpenGL,Context,OpenGLContext,render,3D,TrueType,text,VRML,VRML97,scenegraph
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
Classifier: Intended Audience :: Developers
Classifier: Environment :: X11 Applications
Classifier: Environment :: Win32 (MS Windows)
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: license.txt
Requires-Dist: numpy>=2.0
Requires-Dist: omi_audio>=0.1.0a1
Requires-Dist: omi_physics>=0.2.2
Requires-Dist: pillow
Requires-Dist: PyOpenGL>=4.0.0a1
Requires-Dist: PyOpenGL-accelerate>=4.0.0a1
Requires-Dist: PyVRML97>=2.3.4b1
Requires-Dist: PyVRML97-accelerate>=2.3.4b1
Requires-Dist: pydispatcher
Requires-Dist: TTFQuery>=2.0.1a1
Requires-Dist: simpleparse>=3.0.0a3
Requires-Dist: pygltflib>=1.16
Provides-Extra: wx
Requires-Dist: wxPython>=4.0; extra == "wx"
Provides-Extra: pygame
Requires-Dist: pygame>=2.0; extra == "pygame"
Provides-Extra: glfw
Requires-Dist: glfw>=2.0; extra == "glfw"
Provides-Extra: gltf
Provides-Extra: draco
Requires-Dist: DracoPy>=1.4; extra == "draco"
Provides-Extra: audio
Requires-Dist: omi_audio[playback]; extra == "audio"
Provides-Extra: accelerate
Provides-Extra: all
Requires-Dist: OpenGLContext[accelerate,audio,draco,glfw,gltf,pygame,wx]; extra == "all"
Provides-Extra: dev
Requires-Dist: OpenGLContext[all]; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: pytest-html; extra == "dev"
Requires-Dist: pytest-timeout; extra == "dev"
Requires-Dist: psutil; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Dynamic: license-file

# OpenGLContext 3.0.0a1

OpenGLContext renders 3D scenes with PyOpenGL, in a window belonging to
whichever GUI toolkit your application already uses. It loads glTF 2.0 and
VRML97 worlds, draws them through a core-profile pipeline with physically based
materials, and lets you walk around inside them with game-style physics and
positional audio.

The primary focus of the library has always been to provide a way to create
simple demos and tests for the PyOpenGL library. With the 3.0 release
OpenGLContext is closer to a game engine than a demonstration library.
It is still the primary suite of test cases run to verify PyOpenGL 
behaviour, but it is also a relatively broad framework on which you can
create your own demos or tools.

## What it does

- **Renders into five GUI toolkits** — GLFW (recommended for core-profile and
  PBR rendering), GLUT, Pygame, wxPython and Qt/PySide — owning the window or
  embedded as one canvas in a larger application. Backends are plug-ins, so an
  application can register its own.

- **Loads scenes** — glTF 2.0 and GLB with animation, skinning and morph
  targets; VRML97; Wavefront OBJ; and streamed 3D Tiles datasets, from a file or
  over the network. PK3 files with a [secondary package](https://github.com/mcfletch/twig-bb).

- **Draws them** — physically based materials, image-based lighting, shadows,
  transmission and bloom, particle effects, fog, TrueType text, and instancing
  that collapses repeated shapes into a single draw.

- **Lets you interact** — click to pick objects in the scene, move through it in
  examine, fly, walk or first-person mode, respond to mouse, keyboard and timer
  events, and put panels, widgets and a settings screen over the top.

- **Game-style physics** — rigid bodies, collision, joints and gravity zones,
  and a character who walks on the terrain you can see.

- **Game-style positional audio** — sounds placed in the scene and heard from
  where the listener stands.

- **Viewer Application** — `oglc-view model.glb`. With embedded links to sample
  content you can browse through the embedded UI.

## Install

Needs Python 3.10+ and a platform with Desktop OpenGL 3.3+

```sh
pip install "OpenGLContext[glfw,draco,audio]"
oglc-view model.glb
```

or, with uv:

```sh
uv run --with "OpenGLContext[glfw,draco,audio]" oglc-view
```

Extras add optional pieces: `audio` for sound you can hear, `draco` for
Draco-compressed glTF, `pygame` and `wx` for those backends, `all` for
everything.

## Documentation

[docs/documentation.html](docs/documentation.html) is the index — installation,
tutorials, and a page per feature. [docs/structure.html](docs/structure.html)
describes how the pieces fit together.

## Development

The 3.0.0 release of OpenGLContext makes use of Large Language models
during the development process. A few of the stand-in models for weapons
were also generated via LLMs.

## Releasing

[.github/workflows/release.yml](.github/workflows/release.yml) runs on every push
to `main`. It compares `__version__` in
[OpenGLContext/\_\_init\_\_.py](OpenGLContext/__init__.py) against PyPI: if that
version is already published the run stops there, and if it is new the sdist and
wheel are built, checked and uploaded. **Bumping the version is what cuts a
release**; a push that leaves it alone does nothing.

Three checks stand between the build and the upload — `twine check --strict` on
the metadata, `scripts/check_release_artifact.py` on both artifacts, and a
comparison of the built filenames against the version that was looked up.

The test suite is not among them. It renders real frames and wants a live GL
context, which a stock runner does not have, so **run it locally and confirm it
is green before bumping the version**:

```bash
python -m pytest tests/
python scripts/check_release_artifact.py --source-root . dist/*.whl dist/*.tar.gz
```

Uploading uses PyPI trusted publishing, so no API token is stored anywhere. It
needs a publisher registered on the PyPI project for this repository with
workflow `release.yml` and **the environment field left blank**: the OIDC claim
carries no environment, and a publisher that names one will not match.

## Changelog

### 3.0.0a1

The major version marks the removals at the end of this entry: several
sub-packages and the visitor-based renderer are gone, so code that imported them
needs changing. Everything else here is additive.

- **glTF 2.0**, as a loader package (`loaders/gltf/`) and the format the viewer
  leads with: `.gltf`/`.glb`, local or over http(s), with animation, skinning,
  morph targets, sparse accessors, computed tangents and the
  `KHR_materials_*`/`KHR_texture_transform`/unlit/specular-glossiness family.
  `KHR_draco_mesh_compression` decodes when the optional `DracoPy` is installed.
  See `docs/gltf.html`.

- **Physically-based rendering** — a metallic/roughness uber-shader and PBR
  render pass, `PBRMaterial`, image-based lighting (analytic or a runtime probe,
  with Radiance `.hdr` panoramas), screen-space transmission and emissive bloom.
  `docs/pbr.html`, `docs/ubershader.html`.

- **Shadow maps**, per-light, with cascades for directional lights and an
  fps-adaptive cascade count. Replaces the removed stencil-volume path.
  `docs/shadows.html`.

- **Instanced rendering**, automatic: the pass batches shapes that share geometry
  and a compatible appearance into one `glDrawElementsInstanced`, for VRML
  `USE`/`DEF`, shared glTF meshes and `EXT_mesh_gpu_instancing` alike.
  `docs/instancing.html`.

- **One viewer, `oglc-view`**, for glTF, VRML97, OBJ and 3D Tiles: format is
  chosen from the source by a registered `SceneAdapter`, so a third party adds a
  format without touching the viewer. It carries a launch menu, a model library,
  and settings and controls screens. `oglc-vrml`, `oglc-gltf` and `oglc-tiles`
  are deprecated aliases for it. `docs/viewer.html`.

- **An overlay UI** (`ui/`) — panels, widgets, layout and a skin, drawn in one
  batched call, with a settings screen generated from a node's own fields, a
  console and a key-bindings editor. `docs/overlayui.html`.

- **Rigid-body physics and character movement** — collision, gravity, joints and
  gravity zones through the `omi_physics` package, first-person and examine
  navigation, declared movement modes, and a terrain-walking mode.
  `docs/physics.html`, `docs/navigation.html`.

- **Terrain and 3D Tiles** — an OGC 3D Tiles streaming runtime with
  screen-space-error LOD, async paging and eviction; splat-textured heightfield
  terrain; and instanced vegetation. `docs/terrain.html`.

- **Spatial audio** — VRML97's `Sound` and `AudioClip` play, alongside glTF's
  `KHR_audio_emitter`, through the `omi_audio` package. `docs/audio.html`.

- **Particle systems**, **fog**, and a **HUD/debug overlay** with frame timing and
  loop instrumentation. `docs/particles.html`, `docs/hud.html`.

- **Untrusted assets are contained.** A document that names external resources —
  a glTF's buffers, images and audio, a 3D Tiles tileset's content and nested
  tilesets — may only reach what its own origin permits: same-origin http(s) for
  a document fetched over the network (re-checked on every redirect hop), and the
  document's own directory for one loaded from disk. Every fetched resource is
  size-capped, and the download cache is per-user rather than in shared
  system temp. The policy lives in one module, `loaders/resolver.py`.

- **Packaging modernised** — `pyproject.toml` with PEP 639 licence metadata, and
  `scripts/check_release_artifact.py`, which refuses an artifact carrying files
  the source tree no longer has.

- glTF audio codec extensions. A `KHR_audio_emitter` source may offer the same
  sound in Ogg Vorbis through `OMI_audio_ogg_vorbis`, keeping its own MP3 as the
  fallback; the Vorbis is decoded and preferred. Which OMI extensions are
  supported at all is tabulated in `docs/gltf.html`; the codec rules are in
  `docs/audio.html`.

- Removed code that nothing reached any more. None of the five GUI backends is
  affected.

  - `browser` sub-package — the unfinished wxPython "browser" shell and the
    VPython-compatible `visual` API (never finished past prototype, see the
    2.0.0c1 note below). The one piece anything outside it used,
    `appdatadirectory()`, is now `OpenGLContext.userpaths`. The `oglc-visual`
    script goes with it.

  - `shadow` sub-package — stencil shadow volumes, which required the
    fixed-function pipeline and an infinite-perspective projection. Dynamic
    shadows are shadow maps (see `docs/shadows.html`); the `vrml_view_shadow`
    script goes with it.

  - `scenegraph.tree` — the volumetric/space-colonization tree. Shipped
    vegetation is instanced glTF with impostors.

  - The visitor-based multi-pass renderer — `RenderPass`, `VisitingRenderPass`,
    `Opaque`/`Transparent`/`SelectRenderPass`, `OverallPass`, `PassSet` and
    `RenderVisitor`. Rendering has gone through the flat pass
    (`passes/_flat.py`) for some time; these were reachable only from the two
    sub-packages removed above. `renderpass.py` now just selects a flat pass,
    `rendervisitor.py` just binds the active `Viewpoint`, and `visitor.py` is
    the `find()` traversal. `docs/renderprocess.html`, which documented the
    removed system, is withdrawn.

  - `DisplayListCompiler` / `DisplayListRenderer` — unreachable: the
    compiler-selection weighting always preferred `ArrayGeometryCompiler` (1.0
    over 0.9), so no `IndexedFaceSet` has compiled to a display list in a long
    time. Display lists themselves remain, for the bitmap font providers that
    use them.

  - `scenegraph.nurbsshader` (superseded by `nurbstess`, which is the one wired
    into `nurbs.py`), `move.fps` (superseded by `move.modes.FPSMode`),
    `passes.flat`, `events.tkevents` and `events.fxevents` (no Tk or FOX
    context exists to reach them).

- `DisplayList.__del__` no longer reports an error when its context has already
  gone away; there is nothing to release in that case.

### 2.0.0c1 -> 2.1.0a1

- PyOpenGL 3.x compatibility

- Support for Numpy

- PyVRML97 project split back out into separate project

- A few more tests/demos

- Register and look up node-types explicitly using plug-in framework.

- Register and look up context-types explicitly using plug-in framework.

- Expose scripts for `vrml_view` and `choosecontext`.

### 2.0.0b1 -> 2.0.0c1

Refactoring and code cleanup:

- Major scripts moved to the `bin` subdirectory.

- Contexts now have classmethods for their "main" functions.

- Scripts to choose the default context class and font.

- Application data directory now hidden on non-Win32 platforms
  (`.OpenGLContext` instead of `OpenGLContext`).

- Mechanism for specifying context attributes (size, depth, buffer type,
  etceteras). See the `contextdefinition.ContextDefinition` Node-class for
  details.

- Default `getScenegraph` implementation of `getattr(self,'sg',None)`.

- Force flush before swap buffers (attempt to compensate for rendering
  artefacts on Linux).

Non-standard `MouseOver` node for constructing buttons.

- PyGame interactivity fixes

  - Work on making the PyGame interactions, particularly keyboard repeats, act
    in the same way as the keyboard interactions under wxPython and GLUT

- `wxTestingContext` icons

  - wxPython testing context now has icons set for the frame so that it isn't
    showing the (ugly) default windows icons.

- A few more tests/demos

  - `wx_with_controls.py` — demo of wxPython context + interacting control
    outside the context

  - `arbwindowpos.py` — ARB extension for pixel-level positioning of bitmap
    position within the rendering window

- Resources directory w/ OpenGLContext icons for easy import

- Dispatcher module completely factored out into the SourceForge pydispatcher
  project.

- Switched `registerCallback` to using class-methods, switched demo to using
  those methods to allow non-context-dependent registration of mouse events.

- Refactoring of mouse-based events, addition of code to allow "captured" and
  "bubbling" events (parent recieves events before/after children and can
  cancel further propagation).

- Bug Fixes:

  - Try `ImageTexture` stub when PIL not available

  - Workaround for strange bug with wxPython where the main thread appears as
    two different objects, depending on whether it's in a callback or not.

  - Test for bugs in PyOpenGL's feedback mode operation

- Additionally, some work has been done on the `browser` sub-package, but it is
  still not finished to even prototype stages yet. It may, however, be useful
  as a source of sample code to some people.

### 2.0.0a4 -> 2.0.0b1

- Optimization and accelerator modules:

  - The entire rendering pipeline has been noticeably sped up, with a number of
    key performance bottlenecks rewritten using C modules (which should compile
    on any Python+Numeric setup).

- Frustum Culling:

  - Bounding box calculation for common geometry types, including caching and
    automatic updating of bounding boxes.

  - Frustum extraction from model view matrix.

- Polygonal and Bitmap Text (TTF):

  - Use of (new) ttfquery package based on the fonttools package allows
    scanning for system fonts (or fonts in a given directory) and doing
    primitive face-name matching for those fonts. Uses direct extraction of
    font outlines for polygonal text.

  - Context customization point for setup

  - Eliminated `BitmapText` node, use `FontStyle.format ='bitmap'` instead.

- All rendering methods and functions are now given a "mode" argument, and
  generally pass that argument to the functions they call to provide access to
  the current renderpass, context, etc.

- GLE-based extrusion geometry types added

- Added object for managing initialized extensions for a given context

- Added some utility mechanisms for dealing with parametric equations of planes
  expressed as 4-item arrays.

- Switch to using Mip-mapped textures by default

- Polygon tessellation code reworked and generalized (used by the polygonal
  text engine, for instance).

- Added (disabled) code to use display lists instead of array geometry for
  rendering indexed face sets.

- Broke out vertex and polygon classes from IFS module

- wxPython context:

  - Added wants-chars style to work properly in panels

  - wxPython context should also be somewhat more stable, particularly when
    used with Python 2.2.3. Workarounds for Python 2.2.2 bugs are still in
    place, but they do not guarantee that no errors will occur, merely reduce
    the likelihood when using Python 2.2.2.

  - Added ability to provide an OpenGL `attribList` for `wxContext`.

- Bug Fixes (too many to list everything):

  - Textures and display-lists in particular have significant bug fixes checked
    in. Many of these were simply making the objects context-specific. Also
    caught strange bug where display list creation is returning 0 rather than
    raising exceptions.

  - Textured transparent geometry (i.e. geometry whose textures have Alpha
    channels) are now rendered during the transparent rendering pass, rather
    than the opaque rendering pass.

  - Fix for unlit textured geometry not showing white as base colour.

  - `TextureTransform` logic bug eliminated (was occasionally leaving the
    texture transform active).

  - The cache API is now easier to use, and hopefully will not be triggering
    Python 2.2.2 errors anymore.

  - Python 2.3 compatibility revisions

  - Removed premature optimisation which was eliminating USE'd transparent
    shapes even though the matrices were different.

  - Fix for `build_normalPerVertex` to properly build the normals (produces
    true smoothing, rather than the rather strange looking results of the
    previous version).

### 2.0.0a3 -> 2.0.0a4

- PROTOs:

  - Initial support for prototyped nodes added, which allows for loading a
    wider swath of VRML content. No support for EXTERNPROTO as-of-yet.

  - Refactored `vrml.vrml97.prototypes` into `vrml.route` and
    `vrml.vrml97.script` modules

- Events:

  - Partial rework of the mouse-events API to allow the events to be handled
    during the event-cascade, addition of support for event-cascade deferal of
    event processing to eventhandler mix-in and Context classes.

  - Addition of support in the event base class for tracking visited node/field
    combinations, calling of base-class initializer from the sub-class
    initializer's.

  - ROUTEs are now active for fields

  - IS mappings now work for PROTO fields (sub-class of ROUTE)

  - Introduction of `Event` class in the vrml package, should become the
    base-class for `OpenGLContext.events.event`

- Cleanup of bugs in `Shape`, `Switch` and `WGLFont` where corner-cases were
  not properly caught (e.g. no geometry, `whichChoice` out-of-bounds, no text
  on a line)

- `IndexedFaceSet`:

  - Reworked generation code extensively, now supports colour-per-face and
    normal-per-face modes of VRML97

  - Added a few sanity checks as well.

- `PixelTexture` node added.

- Preliminary `Cylinder` and `Cone` implementations.

- Stub implementations of `LOD`, `Inline` and `Billboard` nodes.

- Fix for transparent-geometry rendering (depth-buffer-testing enabled).

- Consolidated `vrml.node` and `vrml.vrml97.node` into `vrml.node`. Moved
  fieldtypes to `vrml` package instead of VRML97 package

- Made default testing-context preference-sequence wx, Pygame, then GLUT

- Made all Bindable types also act as Children, since they are present in the
  scenegraph hierarchy.

- Fix for parsing hexidecimal-encoded SFImage fields (as seen in
  `PixelTexture`s).

- Work-around for Python 2.2.2 calling of receiver methods in dispatcher.

- Considerably more robust `getField` implementation in `protofunctions`

### 2.0.0a2 -> 2.0.0a3

- Major Documentation updates (almost all doc-strings are updated in all
  modules).

- Loaders:

  - Fixed bug with local-file loading where a local-file combined with the url
    `../` would give a result of: `z:../` , we now create a file-path url in
    cases where a local-file is loaded.

  - Moved `vrml2pklgz` script to loaders module.

  - Re-added "dump" method to VRML97 loader.

- ViewPlatform:

  - Fix for the `straighten` method

  - Elimination of `distance` attribute

  - Switch to new-style classes

  - Loosening of the API for `setPosition` and `setOrientation`

  - Fix for bug in the "forward" method

  - Mix-in:

    - Eliminated `trackball` attribute and `unProject` method, commented out
      the unused slider interface

- Minor tweaks/optimisations to `vectorutilities`.

- Nodes:

  - Changed `Node.externalURL` back to a simple attribute value of the class
    (bug-fix)

  - Made `SFNode` and `MFNode` donate `rootSceneGraph` to children without them
    when values are set.

  - Eliminated unused `WeakMFNode` field-type

  - Fixed bug in `WeakField` implementation (returned a weak reference)

  - Added a `bound` field to `CubeBackground`.

  - Fixed inheritence for `WeakSFNode`, eliminated cube-background work-around
    for `rootSceneGraph` tracking.

  - Texture/ImageTexture:

    - Refactored PIL texture conversions

    - Fixed typo/copying bug in `Texture.__del__`

    - Fix for image loading (default `baseURI` re-instated), reduced levels on
      a number of log messages

  - Fix for cube-background render when last `glColor` set the color to black.

  - Added fields `Background` to shadow those in `CubeBackground` which prevent
    `ImageTexture` objects being linearised to VRML97 where they shouldn't be.

- Complete rework of the `field.Field` implementation to eliminate the seperate
  "fieldtype" objects in favour of making fieldtypes the actual type (class) of
  the field. [ MAJOR CHANGE ]

- Unused methods deleted from `OverallPass`

- Fixed bug in the `builtin( )` function, it would only properly report for
  Nodes before, instead of working for both Nodes or prototypes/classes.

- Events:

  - Eliminated use of Start and Stop Timer Events as parents for Pause and
    Resume events

  - `InternalTime`'s now generate `FractionalEvent`s in a few more places.

  - Moved the examine manager to the events package

  - `EventManger.registerCallback` raises `NotImplementedError` instead of
    `SystemError` if a sub-class doesn't implement the method.

  - Minor cleanup in `Event` and `EventHandler` classes

- Switch a few classes to being new-style classes.

- Testing Code:

  - `ambient_only` made a sub-class of the `vrml_view` test

  - Removed obsolete glut stencil buffer test script

### 2.0.0a1 -> 2.0.0a2

- Made `scenegraph.regDefName` de-register references to the object by it's
  previous `defName` if possible.

- Added PROTO name declaration to `BitmapText`

- Changed `NurbsTrimmedSurface` name to `TrimmedSurface` to follow the
  nurbs-extension naming scheme

- Added `standardPrototype` function to `loaders.vrml97` to allow for
  programmatic registry of standardPrototypes for the loader

- Documentation updates.

- A few setup and manifest changes.

- Added a texture-specific log to the `debug/logs` module.

- Addition of "root" protofunction for getting the root scenegraph for a node
  (doesn't currently support automatically setting the root field for children,
  however)

- Elimination of weakref dicts for implementating scenegraph, uses
  protofunctions instead

- Elimination of "DEF" and "PROTO" references in favour of
  `protofunctions.defName` and `protofunctions.protoName`

- Image and Texture Loading:

  - Initial support for loading textures across the network, basically it's the
    original VRML97 loader with a bit of refactoring to support both images and
    scenes.

  - Caching textures (only creating a single OpenGL texture if there are
    multiple `ImageTexture`s which use the same PIL image)

  - PIL paletted texture -> RGB

  - PIL resize of non-power-of-two textures

- IFS Tesellation — commented out debugging code when IFS runs out of vertex
  indices before it runs out of other indices, just considers itself done now
  (lets some malformed content load)

- `.cvsignore` files added throughout

- Added missing attribution for glprint test
