Particles (point sprites) are drawn as instanced camera-facing squares sized like Direct3D 9's. Fog is by depth buffer value, as Direct3D 9 does with IMVU's projections. At most one frame is queued for display, frames carry the adapter's timestamp so the renderer process logs the delay to presenting, and the log's lines from several processes no longer mix. Co-Authored-By: Claude Opus 5.5 <[email protected]>
125 lines
4.8 KiB
C++
125 lines
4.8 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 <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);
|
|
|
|
// 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_;
|
|
|
|
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
|