Particles: Direct3D 9's size limit evidently isn't the documented 64 pixels; unclamped (up to 2048) they match the client's renderer. A compare view shows the left half's scene over the right half, both renderers side by side; %TEMP%\t5de-renderer-view.txt switches views and %TEMP%\t5de-renderer-shaders\fixed_function.hlsl replaces the shaders while the client runs. The renderer process runs from a copy, so the program can be replaced meanwhile. The adapter recognizes only the textures and buffers it made (others reach the client renderer unchanged) and logs the others and render targets. Co-Authored-By: Claude Opus 5.5 <[email protected]>
130 lines
5.0 KiB
C++
130 lines
5.0 KiB
C++
#pragma once
|
|
// Carries out the command stream (include/t5de/protocol/commands.hpp) with Diligent, reproducing IMVU's Direct3D 9
|
|
// look (shaders/fixed_function.hlsl): the client's textures and buffers by id, its state as it sets it, a pipeline
|
|
// for each combination of states it draws with.
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <span>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
#include "EngineFactoryD3D11.h"
|
|
#include "RefCntAutoPtr.hpp"
|
|
#include "t5de/protocol/commands.hpp"
|
|
|
|
namespace t5de {
|
|
|
|
class Scene {
|
|
public:
|
|
Scene(Diligent::IRenderDevice* device, Diligent::IDeviceContext* context, Diligent::ISwapChain* swapChain);
|
|
|
|
// Carries out one frame's commands. offsetX is where the window starts within the client's 3D view; without draw,
|
|
// only the frame's changes are made (textures, buffers, state). True if the frame was drawn into the window (to
|
|
// present).
|
|
bool execute(std::span<const std::byte> commands, int offsetX, bool draw);
|
|
|
|
// Replaces the shaders' source (the built-in one by default): for trying changes while the client runs.
|
|
void setShaderSource(std::string source);
|
|
|
|
// When the adapter sent the last frame carried out (QueryPerformanceCounter).
|
|
[[nodiscard]] std::uint64_t lastSentAt() const { return lastSentAt_; }
|
|
|
|
private:
|
|
struct Texture {
|
|
Diligent::RefCntAutoPtr<Diligent::ITexture> texture;
|
|
std::uint32_t width = 0;
|
|
std::uint32_t height = 0;
|
|
std::uint32_t flags = 0;
|
|
};
|
|
|
|
struct Buffer {
|
|
Diligent::RefCntAutoPtr<Diligent::IBuffer> buffer;
|
|
protocol::BufferKind kind = protocol::BufferKind::Vertex;
|
|
std::uint32_t elementSize = 0;
|
|
std::uint32_t count = 0;
|
|
};
|
|
|
|
struct Pipeline {
|
|
Diligent::RefCntAutoPtr<Diligent::IPipelineState> state;
|
|
Diligent::RefCntAutoPtr<Diligent::IShaderResourceBinding> bindings;
|
|
Diligent::IShaderResourceVariable* texture0 = nullptr;
|
|
Diligent::IShaderResourceVariable* texture1 = nullptr;
|
|
};
|
|
|
|
struct Shaders {
|
|
Diligent::RefCntAutoPtr<Diligent::IShader> vertex;
|
|
Diligent::RefCntAutoPtr<Diligent::IShader> pixel;
|
|
};
|
|
|
|
// Mirrors the shader's constant buffer.
|
|
struct Constants {
|
|
float world[16];
|
|
float view[16];
|
|
float projection[16];
|
|
float texTransform0[8];
|
|
float texTransform1[8];
|
|
float ambient[4];
|
|
float lightColor[8][4];
|
|
float lightVector[8][4];
|
|
float fogColor[4];
|
|
float fog[4];
|
|
float flags[4];
|
|
float viewport[4];
|
|
};
|
|
|
|
// What a draw needs from the state, as set by the client.
|
|
struct State {
|
|
bool depthTest = true;
|
|
bool depthWrite = true;
|
|
bool blending = false;
|
|
std::uint32_t blendMode = 1;
|
|
bool culling = true;
|
|
bool normalInverting = false;
|
|
std::uint32_t texture0 = 0;
|
|
std::uint32_t texture1 = 0;
|
|
};
|
|
|
|
void createTexture(const protocol::Command& command);
|
|
void updateTexture(const protocol::Command& command);
|
|
void createBuffer(const protocol::Command& command);
|
|
void updateBuffer(const protocol::Command& command);
|
|
void setProjection(const protocol::SetProjection& projection);
|
|
void setState(const protocol::SetState& state);
|
|
void drawTriangles(const protocol::DrawTriangles& draw);
|
|
void drawArrays(const protocol::Command& command);
|
|
void drawPointSprites(const protocol::Command& command);
|
|
|
|
// Draws indexCount indices from index, with vertex streams (positions required, the others may be null).
|
|
void draw(Diligent::IBuffer* indices, std::uint32_t indexCount, Diligent::IBuffer* positions,
|
|
Diligent::IBuffer* normals, Diligent::IBuffer* texCoords, Diligent::IBuffer* colors);
|
|
// The pipeline for the current state, with these vertex streams and textures, for triangles or particles.
|
|
Pipeline* pipeline(std::uint32_t streams, std::uint32_t textures, bool sprites);
|
|
const Shaders& shaders(std::uint32_t streams, std::uint32_t textures, bool sprites);
|
|
// Picks the pipeline for the current state and sets it up for a draw: constants, textures. Null if it can't.
|
|
Pipeline* prepare(std::uint32_t streams, bool sprites);
|
|
Diligent::ITextureView* textureView(std::uint32_t id);
|
|
|
|
Diligent::RefCntAutoPtr<Diligent::IRenderDevice> device_;
|
|
Diligent::RefCntAutoPtr<Diligent::IDeviceContext> context_;
|
|
Diligent::RefCntAutoPtr<Diligent::ISwapChain> swapChain_;
|
|
Diligent::RefCntAutoPtr<Diligent::IBuffer> constantBuffer_;
|
|
Diligent::RefCntAutoPtr<Diligent::ISampler> samplers_[4]; // by wrap u (1) and wrap v (2)
|
|
|
|
std::unordered_map<std::uint32_t, Texture> textures_;
|
|
std::unordered_map<std::uint32_t, Buffer> buffers_;
|
|
std::unordered_map<std::uint32_t, Shaders> shaders_;
|
|
std::unordered_map<std::uint32_t, Pipeline> pipelines_;
|
|
std::string shaderSource_;
|
|
|
|
Constants constants_{};
|
|
State state_;
|
|
bool onscreen_ = false; // in a frame drawn into the window
|
|
bool draw_ = true;
|
|
std::uint64_t lastSentAt_ = 0;
|
|
int spritesLogged_ = 0;
|
|
int offsetX_ = 0;
|
|
};
|
|
|
|
} // namespace t5de
|