The studio renderer replaces geometry submission while GoldSrc owns the surrounding model draw. Start with the architecture guide and diagrams for engine integration, scene order, materials, and preview; use the diagnostics guide for runtime inspection. The Russian translations are linked from those documents.
StudioInterceptStatepatches the studio API before the client copies it. Keep the installed interceptor entry points callable after shutdown and forward them to the original API: the client retains its copied pointers.- Defer independent packets only in the opaque and transparent entity traversals, preserving their existing list order. Capture bones, matrices, lighting, raster inputs, materials and the result of
StudioSetupSkinwhile the original entity and forced flags are current. Submission must not read a live entity or shared pose. - Preparation is keyed by model draw serial, header and entity. Share the bone capture and texture-header resolution across body parts, but never across different poses. Capture into reused storage must initialize every consumed field, including normal-pass shell color.
StudioRendererowns the renderer-threadStudioPosePool. Capture one complete immutable 6144-byte palette per model draw key and share handles across packets and effects. Packet copies/moves do not copy palette values. Reset releases free slots and detaches retained ones; preview/effects handles survive reset or owner destruction until their last release. Keep handle operations on the renderer owner thread.- Keep the complete captured pose for authored shader compatibility. Size a builtin bone upload from the captured bone count, not a live header that may have changed.
- Scratch storage is shared with material texture loading. Borrow submission arrays only
for packets that use only built-in rendering and have sufficient space. Packets containing
a material whose program differs from
studio_legacyneed owned arrays. Pending draws must not retain pointers into a scoped scratch allocation. - Recycle mesh-vector capacity only after submission ends, within the queue's retained budget. Queue reset must release the retained storage.
- Preserve packet, pass and authored mesh order, including additive meshes; equal-depth surfaces can depend on it. Group only adjacent compatible entries. Restore packet blend and depth-write settings for each group before applying its mesh overrides.
- Group only equal consumed mesh/material inputs. In ordinary submission, matching programs do not establish compatibility or permit skipping the next packet's program bind, uniforms or bone upload. The submit renderer uses MultiDraw for one range too; monitoring's Single classifies range count. Rigid union instancing batches only adjacent single-mesh packets with proven rigid geometry and exact captured shared state. It prepares the builtin shader, separate geometry VAO, and submission-owned instance VBO before packet publication. A batch applies its shared uniforms/state once and uploads the ordered run once; ordinary fallback retains the complete per-packet program/uniform/bone contract. Union submission preserves packet and primitive order and requires primitive restart disabled. Current renderer passes do not permit active transform feedback or primitive-count queries; timing queries remain supported. Rendering owners issue GL calls and own their CPU/GPU scopes; diagnostics receive numeric results and never submit geometry.
- Drain before sprite, brush, alias, stock fallback/shadow, studio debug drawing, triangle Begin, actual studio event callbacks, resource mutation and each entity pass end. End transparent deferral before fixed-function cleanup and client transparent triangles. Pause deferral throughout event callbacks. No studio shader may stay active during arbitrary client preparation.
- Engine remap textures can change contents. Keep models with Remap*/DM_Base.bmp skins immediate, and retain r_studio_queue 0 for custom raw-GL studio callbacks without barriers.
- Preserve rejection handling: queued geometry from the rejected submission must not also render through the engine, and later body parts must not re-arm an abandoned model draw.
material/ groups material documents, catalogs, textures, editing, server bindings, coverage, and shared effect-material semantics. model/ groups Studio model identity, metadata/material resolution, geometry, and submodel integration. effects/ groups effect orchestration, targets, passes, bounds, and their integration adapter. Renderer composition, StudioMaterialRuntime, submission, device/shader infrastructure, capture, diagnostics, and this guide stay at the renderer root; graphics/preview remains a peer subsystem.
-
StudioModelCacheowns copied model-name/header/session identity and composesStudioGeometrywithStudioModelMaterials. Geometry owns the static buffer pair, VAO, mesh ranges, and bone bounds; materials owns metadata, texture/skin tables, documents, and generation-dependent resolution. The converter and bounded owned readers live inncl_studio. Metadata preparation and material lookup require no GL; valid metadata remains visible after geometry failure, while metadata failure exposes no authoring entry. -
Session forgetting advances generation and invalidates borrowed header tokens and sorted name snapshots without GL calls. Selective model retirement preserves unrelated metadata and preview capacity accounting. Drain valid packets before header replacement, model reload, or existing-slot reuse; discard pending references before model-session teardown or filtered unload. A reused name and header address in another session cannot establish GPU identity. Device loss invalidates GPU preparation and the non-owning recent-entry pointer while retaining CPU metadata for the current model session.
Models_Clearrequires the queue already empty.Models_ReleaseGeometryrequires pending, queued, and preview-captured references to be discarded; it preserves model entries, metadata, materials, and session identity for lazy GPU preparation. The authoring preview close boundary composes that eviction with its target/picking release and material-image cleanup, and preserves independent Wavefront scenes and preview admission accounting. -
Pass the actual texture-owner model into metadata/material preparation and retain its copied bounded name as a dependency identity alongside the header token. Companion retirement invalidates dependent texture/material readiness while preserving independent main metadata and GPU geometry. Every authoring getter requires complete metadata/texture readiness. During nested loading, selective interception invalidation preserves unrelated current lighting and inputs; publish the complete draw key after the callback and recheck the draw serial before consuming borrowed pointers.
-
Use
StudioSetupSkinto capture base-skin selection. Player remapping and forced chrome depend on engine state; replay the captured binding and synchronize engine bookkeeping. -
Base skins use texture unit 0. Material samplers start at
kFirstMaterialUnit, currently 3; units 1 and 2 belong to the engine's lightmap/detail binding bookkeeping.StudioBindings.howns this layout, including the touched-unit count used by broad GL scopes and previews. Enumerate samplers from the manifest and bind every declared active sampler for each group. -
MaterialManifestspublishes only matching embedded shader pairs with validated renderer contracts.StudioProgramContractowns coverage/effect semantic roles; consumers use checked enrollment and manifest defaults.ServerMaterialsowns network authorization and materializes zero overrides for restricted activations, including omitted positive defaults. -
MaterialSyncSystemowns wire snapshots and registry translation;ServerMaterialsowns indexed per-entity synchronized owners, copied requests, resolved candidates, and complete params. Parameter replacement resets only that owner's candidates from immutable cached presets plus synchronized policy. Admission reserves console textures first, then descending owner IDs and request order, up to 16 distinct case-insensitive textures. Retain excluded candidates for later promotion; admission changes must not reconstruct other owners' materials. Query pointers are call-local; queued meshes own copied values. Synchronized removal must never call entity-wide ClearBindings. -
StudioGlSubmissioncaches only its own applied raster and base unit-0 binding values within Begin/End. Reset the cache at each boundary and release; packet setup and masked/additive overrides must update the same values. Material samplers use their reserved units and return to unit 0. Keep the captured binder for actual base changes and unconditional caller restoration so engine binding/palette bookkeeping stays synchronized. Ordinary submission preserves every packet's program bind, uniforms, matrices, and bones. -
Keep explicit GL save/restore and the boundary's binding conventions together. Studio, radar and text have different state ownership; a local binding cache cannot assume what another renderer left active. Follow the parent engine rules for context lifetime.
-
RendererResourcescomposesRenderDevice,ShaderManager,MaterialManifestCatalog, andMaterialTextureCachein dependency order.StudioRendererresolves their references once and constructsStudioMaterialRuntime(ShaderManager&, MaterialManifestCatalog&, MaterialTextureCache&, performance::PerformanceMonitor&)before supplying it toStudioGlSubmission. Owners outlive the runtime; construction performs no GL work. Registered owners unregister and forget names during destruction; live deletion requires explicitClearwith the owning context current. Shader/source compilation, image loading, localization, and diagnostics use explicit cold backends. Cache hits use concrete methods without backend dispatch or allocation; shader and image lookups retain the direct native-context check. Shader clearing requires pending, queued, and preview-captured references to be discarded first. Production lifecycle callers own this barrier before clearing the concrete shader owner; the shader integration adapter only forwards the clear operation. Program generations are nonzero, and borrowed programs remain valid until their owner generation changes. Keep engine gamma conversion and captured-skin binding inStudioRenderer; the runtime owns descriptor strings, borrowed references, configuration revisions, and normalized gamma values.StudioShaderInterface.howns the uniform order, shade values/defines, gamma dimensions, and built-in descriptor. -
RendererStateborrows the uniqueRendererResourcesroot and constructsMaterialDocumentStore,ServerMaterials,StudioModelCache, andMaterialEditorin dependency order. Its production composition owns the coldMaterialGameFilesbackend before the store. Game initialization binds the mod directory used for writes. The store centralizes model/editor document reads, writes, parsing diagnostics, and bounded server preset reads; the server owner supplies its 1 MiB limit without limiting ordinary documents. Each cache receives concrete device, document, catalog, shader-generation, and server-generation owners.StudioRendererbinds model/server references once and calls them directly during preparation.BindingForreceives the live network-state condition from that boundary. A model preparation operation receives its resource barrier explicitly and invokes it only before actual stale-entry replacement. Cache hits perform no barrier callback or extra lookup.StudioGeometryandGpuBufferuse their supplied device for registration and native-context checks. Destruction forgets names and unregisters; explicit release owns live GL deletion. -
MaterialEditorreceives the concrete model, server-material, shader, manifest, and document owners. It owns aMaterialEditSessionvalue with model/entity selection, copied texture materials, and parameter-preview rollback snapshots. The exportedrender::MaterialEditInterfacereturns that same editor instance fromRendererState. Cold API methods supply the current connection-state predicate to source operations so each subsequent texture observes reentrant loading/reset.StudioRendererbinds a direct const session reference once and supplies authoring availability at the draw boundary. Override lookup reads only owned entries, with no virtual call, allocation, catalog lookup, or file access. Save merges selected entries through the injected store and callsStudioModelCache::ReloadDocumentsonly after successful persistence. Preserve the typed read status: a failed native open must checkFS_FileExistsand reportReadFailedwhen the document exists; onlyNotFoundpermits creating a document; read or size failures must leave the authored document and model cache unchanged. Native persistence writes a unique temporary file in the destination directory, checks write, flush, and close, then replaces the destination with one checked platform operation. Failures remove temporary output and preserve the destination. -
ClientStringRegistryowns a bounded table of 2048 strings and constructs without engine calls or message registration. Thecl_string_registryintegration adapter parses messages, registers commands, and explains capacity failure before disconnecting.engine.cppsupplies the unique registry and server-material owners toMaterialSyncSystem. The handler copies all registry values before preset-loading calls, distinguishes full material replacement from complete parameter replacement, publishes wire snapshots only after replacement succeeds, and removes the previous owner only after successful migration.CL_ClearClientStateclears the renderer session/borrowed work, synchronized owners, string registry, then server materials. -
Prepared bindings belong to each concrete pass/interaction or stable material-program entry and refresh at the supplied shader generation boundary. Coverage upload receives numeric scalar, transform, viewport/time, and sampler locations directly. Material records retain the accepted owner-lifetime manifest and schema-ordered locations; queued and preview-captured meshes borrow those records alongside program pointers. The runtime outlives every packet, and shader resource barriers drain or discard packets before invalidation. Draw/upload paths must not resolve uniform or block names or find binding records through a catalog. Edited material values remain packet-owned.
-
Cached program pointers and configuration require shader generation checks. Configuration also checks the gamma revision; a reused GL program name after reload does not retain the deleted object's uniforms or block bindings. Resolve all material/default textures and neutral images before selecting material units, then bind every declared active sampler. Bind the captured skin after material upload to repair engine unit-0 bookkeeping.
-
The stock shadow consumes CPU-transformed vertices. It cannot use a GPU-only pose without a corresponding implementation of its geometry source.
-
Material coverage computes visibility without discarding fragments. Complete implicit-gradient texture sampling and derivative operations before coverage or masked-alpha discard in color, picking, and effect passes. Keep masked-alpha sampling outside fragment-dependent short-circuit expressions.
-
StudioEffectsowns per-view entity snapshots, retained masks, statistics, targets, and passes. Deferred capture owns packet values and shares immutable poses; replay never reads live engine entities. Preserve first-accepted entity order and part order within each entity. Snapshot final scene depth once, capture/composite one entity at a time, and reapply capture/fullscreen state at each transition. Resource barriers materialize pending captures in every open view before borrowed resources change, without early composition. Mutable skins capture immediately; materialize pending captures before unsafe callbacks. Queue-disabled paths also capture immediately unless the renderer explicitly controls the preview inputs. Cancellation discards pending references before external callbacks or resource invalidation.studio_effects.h/.cppis the thin production integration adapter. -
Ordinary EndView may borrow shared capture depth only for pending entities without materialized masks; clear their final union ROI once before all parts and finish composition before reusing depth. Keep the borrowed texture out of entity snapshots. Match explicit object-depth storage kind and samples in pool reuse. Retained barriers, immediate capture, and late parts own independent depth. Object-depth addressing is separate from cropped color addressing. Preserve main-pass depth interpolation coordinates and caller GL scopes.
-
Keep pool and scratch ownership private in
StudioEffectTargets; pass concrete target,ShaderManager, andMaterialCoverageRuntimereferences toStudioEffectPasses. Preserve mask-growth color/depth copies and the512 * 1024retained mask-pixel budget. Mask rectangles describe logical content; allocation capacity is separate. Retained-pool admission counts capacity pixels, and capture and postprocessing must exclude padding from visibility. During streaming, admit the completed working mask first and limit free capacity to the larger of the retained budget and that mask's capacity; apply the retained budget at view completion. -
effects::ProjectBoundsand material capability helpers remain stateless. Preserve scalar rounding, near-plane/full-viewport fallback, and nonfinite semantics when vectorizing bounds projection. -
Construct coverage and effects in
RendererStateafter the resource owners. Coverage selects an accepted manifest once per operation; pure semantic helpers receive it explicitly. Cache fixed effect programs, including failures, by the concrete shader manager generation. Register every effects owner with its supplied device during construction and unregister from that same device during destruction. Destruction only forgets names. Explicit liveClearrequires the tracked current context; loss forgets every view, pool, and scratch name without GL. Local owners must release live resources explicitly before destruction. -
render::previewowns explicit scene, interaction, target, native-model, and asset dependencies. Compose the bindings/backend/repository/model renderer and scene inRendererState; keep resolved pointers and late studio-table binding at initialization adapters. Picking captures complete owned packets through a direct optional interaction pointer and retains identity scratch. Cache fixed pick/outline results, including failures, by the supplied shader generation. Return model/header identity only as a synchronous preparation output, revalidate after native loading and metadata work, and never retain it between draws. Register and unregister resources with their supplied device; destruction forgets names and explicit clear proves the native context. Authoring close discards queue/picking references before geometry and image release, retaining independent scenes and admission accounting. Restore patched preview callbacks before engine providers expire. Studio flush/pause/discard integration remains the concrete studio-owner composition boundary.
Select affected engine-free tests, build engine_mini, and check affected consumers under the parent rules when changing behavior. Converter changes also follow ncl_studio/AGENTS.md. A mocked MultiDraw test can establish API-call accounting but cannot prove ordering, skin remapping or GL appearance. Use the existing dump and A/B commands for developer-run runtime observations; do not launch the game. Engine-free capture and offscreen GL tests complement the scheduling tests; they do not establish installed-engine appearance or speedup. Documentation-only edits need link, source and formatting checks, not a rebuild.
RendererState constructs RendererLifecycle with its actual device, shader, texture, model, editor, capture, studio, interceptor, effects, scene-preview, and test-quad owners. GetLifecycle() is the integration accessor. The coordinator owns explicit map, connection, context, and terminal phases. Queue discard precedes session invalidation or resource mutation. Device_IsContextCurrent() proves a non-null stored native identity matches the current identity and GL entry points are initialized; Device_IsContextAlive is only stored state. Release owned programs, submission bones, geometry, textures, effects, preview targets, and text atlases before device invalidation. Loss notifies owners with the device unavailable, forgets names without GL, and retains model-session CPU metadata. Same-context preparation preserves resources when entry points are ready and retries failed preparation. Terminal state is permanent; standalone draw shutdown permits later adoption. Keep shader warmup/debug policy and stock forwarding in their adapters.
StudioRenderer owns synchronous pending preparation, the material runtime, concrete GL submission, queue, and preview-input stack. StudioInterceptState passes the original API, captured identity/lighting/serial, and a live synchronous serial source as operation inputs; queued packets retain neither the source nor live entities. Preview native bindings/backend/repository precede the renderer, and preview-model rendering and ScenePreview follow it. All internal preview flush/pause/discard operations use the supplied renderer. Keep ABI owner selection only in the process-lifetime trampolines.
Queue and picking mesh storage have separate 1 MiB retained payload budgets, including nested material capacities. Retirement clears program, material_bindings, and texture identities. Keep pending mesh_count private, use it for skin lookup and rejection rollback, and trim before every packet consumer. Reset, close, loss, and cancellation release retained storage. Complete material snapshots remain owned; shape changes and restricted-policy tails can allocate, and accounting adds a retirement walk. No total heap cap or measured speedup is implied.
RenderCaptureSession receives actual cvar owners at Begin and restores exact strings through its cold native backend before engine-provider retirement. StudioDiagnostics owns dump/watch state and its numeric StudioPhaseCapture. Phase capture preserves native view/pass boundaries and receives no packet, entity, or model pointers. The adapter exports stopped recordings outside the measured loop. The dump/watch owner and receives engine bindings plus explicit path/time inputs. TestQuad receives its device and shader manager, releases explicitly before device invalidation, and never deletes GL resources in its destructor. Lifecycle external backend is limited to existing performance and Windows text/surface integrations. RendererState receives the stable concrete monitor and mapper directly. Geometry, coverage/material runtime, StudioRenderer, interception, and GL submission use supplied owners; the native shader backend binds its monitor at construction. StudioRenderer owns the nesting depth shared with its interceptor and sink. Independent owners must retain independent measurements. PerformanceRuntime receives the completed device/lifecycle owners at native Bind and never participates in renderer draw construction.
Prepare image dependencies before packet publication. FlushPending must move the complete trimmed pending packet into local ownership and reset its builder before any cold load. TextureLoadGuard is synchronous and must never retain caller serial references in pending or queued work. Check cancellation immediately after the native texture callback, before GL or engine-pointer access, and do not cache canceled loads. Main/coverage/effects/picking consume fixed image IDs and an explicitly prepared accepted manifest; their loops do not load images or consult the catalog. Check the packet's texture revision once at consumer entry. Preserve ordinary missing/default/neutral semantics, including coverage maps optimized out of the color program.
Keep full GL snapshots and exact native-context validation at actual cold loading boundaries. Warmed packet preparation reads direct epochs and the device's established identity; it adds neither GL snapshots nor repeated native-context queries. Preview scopes stop flush/resume and following models after cancellation. Context-aware GL restoration skips a lost/replaced device while live session reset remains distinct. StudioModelCache replacement barriers snapshot mutation epoch and stop with failure before touching held entries or input pointers after nested invalidation.
Preview entry Flush, model preparation, and queue pause may prepare cold images. Capture cancellation before those operations and check it before borrowed model access or GL setup. Cancel the exact effects-view identity on a canceled preview; preserve enclosing views and never composite canceled masks. Balance every successful preview target Begin through presentation or cancellation; cancellation restores caller bindings only while the owning native context is current and always ends target activity. Clear must not reuse view identities.