@@ -264,11 +264,12 @@ and the `get_*`/`is_*` callback contract). Move any custom drawing onto those
264264supported entry points, or draw with your own modern-OpenGL code.
265265====
266266
267- The immediate-mode drawing helpers used by the old renderer remain available for
268- compatibility (`linuxcnc.draw_lines`, `linuxcnc.line9`, `linuxcnc.draw_dwells`,
269- `linuxcnc.positionlogger.call()`); they are unused by the in-tree GUIs, which
270- bake geometry to VBOs and upload the backplot from `positionlogger.points()`,
271- but still work for out-of-tree tools under a legacy/compatibility context.
267+ The immediate-mode drawing helpers of the old renderer (`linuxcnc.draw_lines`,
268+ `linuxcnc.line9`, `linuxcnc.draw_dwells`, `linuxcnc.positionlogger.call()`) are
269+ retired. They keep their names, signatures and argument checking so that
270+ out-of-tree callers still import and run, but they draw nothing and raise a
271+ `DeprecationWarning` on first use. The in-tree GUIs bake geometry to VBOs and
272+ upload the backplot from `positionlogger.points()`.
272273
273274=== Notes for integrators and driver authors
274275
@@ -298,6 +299,74 @@ but still work for out-of-tree tools under a legacy/compatibility context.
298299 drawing; only its camera consumes the (now GL-free) explicit matrices from
299300 `glnav`.
300301
302+ === The program is built in C++ during the parse
303+
304+ `gcode.parse` no longer drives the preview through per-move Python callbacks.
305+ For a canon that subclasses `gcode.RendererCanon` - `rs274.glcanon.GLCanon` is
306+ one, so every in-tree preview is - the whole program is built in C++
307+ (`GCodeRenderer`, `src/emc/rs274ngc/gcode_renderer.{hh,cc}`): the
308+ g92/rotation/g5x transform, arc segmentation, rigid taps, `(AXIS,hide)`
309+ suppression, the vertices per drawn plane, the extents, the path lengths and
310+ the dwell and tool-change records. The finished program is handed over once,
311+ at the end of the parse, as a `gcode.PreviewGeometry` through the canon's
312+ `adopt_geometry()`. A parse reads two more things off such a canon:
313+ `program_geometry` (the GEOMETRY strings and the rotation offsets) and
314+ `arcdivision`, which defaults to 64 and is read once at parse start. Every
315+ parse starts from a zero transform with nothing drawn; where the machine stands
316+ arrives as the caller's initcode (a `G53 G0` per axis), which the
317+ leading-traverse drop repositions on rather than draws. A `RendererCanon`
318+ subclass without a callable `adopt_geometry` is a `TypeError` from
319+ `gcode.parse`, not a silent fall back to callbacks.
320+
321+ The per-event canon protocol is unchanged for every other canon:
322+ `rs274.interpret.PrintCanon`, the interpreter tests and out-of-tree users of
323+ `gcode.parse` still receive `straight_feed`, `arc_feed`, `next_line` and the
324+ rest exactly as before, and `rs274.interpret.Translated` /
325+ `ArcsToSegmentsMixin` remain for them. The `gcode` module itself was rewritten
326+ on pybind11; its functions keep their names and signatures. One behaviour
327+ change: `gcode.linecode()` snapshots the running parse, and raises
328+ `ValueError` when no parse is in progress.
329+
330+ [WARNING]
331+ .BREAKING: out-of-tree canons that subclass `rs274.glcanon.GLCanon`
332+ ====
333+ On a rendered parse the interpreter forwards only `next_line` (on the handful
334+ of lines that still forward, not once per line), `comment`, `message`,
335+ `change_tool`, `check_abort`, the `get_*` queries and `parameter_file`.
336+ Consequently:
337+
338+ * *Overrides of the per-move methods are never called.* `straight_traverse`,
339+ `straight_feed`, `straight_probe`, `arc_feed`, `straight_arcsegments`,
340+ `rigid_tap`, `dwell`, `user_defined_function`, `set_g5x_offset`,
341+ `set_g92_offset`, `set_xy_rotation`, `tool_offset`, `set_plane`,
342+ `select_plane`, `set_feed_rate` and `set_spindle_rate` no longer exist on
343+ `GLCanon`, and a subclass that defines them is not called back. Read the
344+ finished program from `canon.program_geometry` instead.
345+ * *`next_line` is not a per-line tick.* A progress bar overrides
346+ `renderer_progress(lineno)`, which fires on the parser's 100 ms tick and
347+ before each forwarded callback. AXIS and QtVCP show `(AXIS,notify)` /
348+ `(PREVIEW,notify)` messages by checking once more after `load_preview`
349+ returns, since no `next_line` follows the comment.
350+ * *Parse-state attributes are gone.* `lo`, `first_move`, `xo`..`wo`,
351+ `suppress`, `in_arc`, `plane`, `feedrate`, `g5x_index`, `g5x_offset_*`,
352+ `g92_offset_*`, `rotation_xy`, `rotation_sin`, `rotation_cos` and
353+ `rotate_and_translate()`. `GLCanon` no longer mixes in `Translated` or
354+ `ArcsToSegmentsMixin`; the renderer keeps its own copy of the offsets, the
355+ rotation, the plane and the feed rate and forwards none of them. Nothing in
356+ the tree reads them - the DROs read the status channel.
357+ * *The per-move lists are gone.* `traverse`, `feed`, `arcfeed`, `moves`,
358+ `move_cats` and `preview_zero_rxy` raise `AttributeError` on read, naming
359+ the replacement: the program record's `positions()`/`lines`/`kinds`,
360+ `g0_length`/`g1_length`/`run_time()` and `extents_zero_rxy`.
361+ * *`tool_list` and `dwells` fill at the end of the parse* (in
362+ `adopt_geometry`) rather than growing during it. `dwells` keeps its column
363+ order and raw machine coordinates.
364+ * *Still honoured:* `arcdivision` (set from `[DISPLAY]ARCDIVISION`), the
365+ `comment` vocabulary (`stop`, `notify`, the foam Z levels; `hide`/`show` are
366+ counted in C++ from the same text), and `change_tool`, which the interpreter
367+ still needs for a G43 after an M6.
368+ ====
369+
301370=== How the preview is put together
302371
303372The drawing itself lives in `lib/python/rs274/glcanon_scene.py`, in four tiers.
@@ -337,18 +406,18 @@ the offset frame the offsets progressively build.
337406Parts read a `FrameContext` - an explicit, enumerated list of machine, view and
338407renderer state, built once per frame by `GlCanonDraw` - rather than the widget
339408itself. That is what lets them be tested without a window: build a context by
340- hand, call `part.draw(ctx)`, and assert on the vertices it emitted. See
341- `tests/glcanon-scene/`.
409+ hand, call `part.draw(ctx)`, and assert on the vertices it emitted.
342410
343411Click-to-select is not a part - it draws nothing to the screen. `Picker` renders
344412the *same* program geometry into an offscreen framebuffer with line numbers
345413encoded as colour and resolves the nearest hit; `GlCanonDraw.select(x, y)`
346414delegates to it. It shares one `ProgramGeometry` with the drawing part, so the
347415pickable geometry and the drawn geometry cannot drift apart.
348416
349- Setting `GLCANON_SCENE_DEBUG=1` logs which parts the scene drew and which it
350- skipped whenever that split changes, and reports depth/blend state a part left
351- behind.
417+ Setting `GLCANON_DEBUG=1`, the preview's one verbosity switch, raises the
418+ `rs274` logger to DEBUG, checks `glGetError` after each pass, logs which parts
419+ the scene drew and which it skipped whenever that split changes, and reports
420+ depth/blend state a part left behind.
352421
353422
354423== New HAL components
0 commit comments