Files
t5de-renderer/adapter/engine.hpp
T
dhkatzandClaude Opus 5.5 05a7be5d41
CI / build (push) Successful in 1m31s
Ask the client for frames between its steps
The frame pacer repaints the client's 3D windows at the user's frame rate
(HKCU\Software\T5DE\Graphics\FrameRate: 30, the default, adds nothing; 60, 120,
240, 360; 0 uncapped), so the client draws frames between its 30-per-second
steps. Only when affordable: a window is asked once its last frame is drawn,
and only if its frames take under three quarters of the interval; uncapped,
the client is left idle a third of a frame between frames. The engine's stats
now log frames per second.

The extra frames show the same scene for now.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 20:38:31 -07:00

100 lines
5.7 KiB
C++

#pragma once
// The adapter's engine: what the client draws with. Everything is recorded for the renderer process, which draws the
// 3D view and the render targets it makes. The client's own Direct3D renderer gets state and resources too (as a
// fallback, and for reading textures back), but while the renderer process covers the whole view, the client's
// renderer skips its frames' clears and draws. When the renderer process doesn't cover it (it failed, or shows only
// part of the view, for comparing) the client's renderer draws everything, from the next frame on.
#include <windows.h>
#include <cstdint>
#include <memory>
#include "recorder.hpp"
#include "t5de/imvu/render_engine.hpp"
namespace t5de {
class Engine final : public imvu::PiRenderEngine {
public:
// recorder may be inactive (no renderer process); window is the 3D window drawn into (frame_pacer.hpp), or null.
Engine(imvu::SharedPtr<imvu::PiRenderEngine> inner, std::shared_ptr<Recorder> recorder, HWND window);
~Engine() override;
void resizeFrameBuffer(imvu::Vec2i size) override;
void enable2dFrameBuffer() override;
void clear(std::uint32_t flags, imvu::Color color) override;
void setProjection(imvu::Vec2i viewport, const imvu::Mat4f& projection) override;
void setModelSpace(const imvu::Transform& model) override;
void setViewSpace(const imvu::Transform& view) override;
void setTextures(imvu::PiRenderTexture* texture0, imvu::PiRenderTexture* texture1) override;
void setDepthTestingOn(bool on) override;
void setDepthWritingOn(bool on) override;
void setBlendMode(imvu::RenderBlendMode mode) override;
void setAlphaTestingOn(bool on) override;
void setAlphaTestValue(float value) override;
void setBlendingOn(bool on) override;
void setBackFaceCullingOn(bool on) override;
void setNormalInvertingOn(bool on) override;
void setLightingOn(bool on) override;
void setLightProperties(std::uint32_t index, const imvu::LightProperties& light) override;
void setFogOn(bool on) override;
void setFogAttributes(float start, float end, imvu::Color color) override;
void setTextureTransformMatrixIdentity(std::uint32_t stage) override;
void setTextureTransformMatrix(std::uint32_t stage, const imvu::TextureTransform& transform) override;
void setEnvironmentAmbient(imvu::Color color) override;
imvu::PiRenderTexture* newRenderTexture(const imvu::Pixmap& pixmap, std::uint32_t flags) override;
imvu::PiInternalIndexBuffer* newIndexBuffer(std::uint32_t count, const std::uint16_t* indices) override;
imvu::PiInternalVertexBuffer* newStaticVertexBuffer(const void* data, std::uint32_t stride,
std::uint32_t elementSize,
std::uint32_t elementCount) override;
imvu::PiInternalVertexBuffer* newDynamicVertexBuffer(std::uint32_t elementSize,
std::uint32_t elementCount) override;
imvu::SharedPtr<imvu::PiPixmapRenderTarget> newPixmapRenderTarget(imvu::Vec2i size) override;
imvu::SharedPtr<imvu::PiTextureRenderTarget> newTextureRenderTarget(imvu::Vec2i size) override;
void beginRendering(imvu::PiRenderTarget* target) override;
void endRendering() override;
void drawTriangles(imvu::PiInternalIndexBuffer* indices, imvu::PiInternalVertexBuffer* positions,
imvu::PiInternalVertexBuffer* normals, imvu::PiInternalVertexBuffer* texCoords,
imvu::PiInternalVertexBuffer* colors) override;
void drawLine(imvu::Vec3f from, imvu::Vec3f to, imvu::Color color) override;
void drawPointSprites(const imvu::PointSpriteVector& sprites) override;
void drawTrianglesFromMemory(std::uint32_t vertexCount, std::uint32_t indexCount, const std::uint16_t* indices,
const imvu::VertexAttributeArray<imvu::Vec3f>& positions,
const imvu::VertexAttributeArray<imvu::Vec3f>& normals,
const imvu::VertexAttributeArray<imvu::Vec2f>& texCoords,
const imvu::VertexAttributeArray<imvu::Color>& colors) override;
private:
void setState(protocol::State state, std::uint32_t value);
// Whether the client's renderer should draw this frame's clears and draws.
[[nodiscard]] bool innerDraws() const { return !takenOver_; }
imvu::SharedPtr<imvu::PiRenderEngine> inner_;
std::shared_ptr<Recorder> recorder_;
HWND window_;
std::uint64_t frames_ = 0;
bool takenOver_ = false; // this frame is drawn by the renderer process only
imvu::PiRenderTarget* ourTarget_ = nullptr; // this frame's render target, if it's one of ours
int foreignLogged_ = 0; // diagnostics: textures the client renderer made, render targets
// Diagnostics: what the client draws, summed over 300 frames and logged (the first few times).
struct Stats {
std::uint32_t triangles = 0; // drawTriangles with our buffers
std::uint32_t foreignTriangles = 0; // drawTriangles with buffers that aren't ours (not drawn)
std::uint32_t indexed = 0; // drawTrianglesFromMemory with indices
std::uint32_t unindexed = 0; // drawTrianglesFromMemory without
std::uint32_t sprites = 0;
std::uint32_t lines = 0;
std::uint32_t flat = 0; // setProjection with an orthographic projection (2D)
};
Stats stats_;
LARGE_INTEGER statsStart_{}; // when the stats' 300 frames started
LARGE_INTEGER frameStart_{}; // when the current frame began
bool windowFrame_ = false; // the current frame is drawn into the window
int statsLogged_ = 0;
};
} // namespace t5de