Files
leocad/common/lc_context.h
T
Leonardo Zide b69db29428 Replace custom Image buffers with QImage
Texture decoding and generated atlases previously used a custom packed-pixel
container alongside QImage, duplicating storage and image-processing code.
Use QImage throughout texture preparation and upload, remove Image and its
pixel-format enum, and store font and string masks in Alpha8 atlases.

Preserve power-of-two dimensions with smooth scaling and keep the existing
OpenGL formats, shaders, and CPU mipmap filtering. Handle padded scanlines,
restore the caller's unpack alignment on every upload return, and centralize
binding cleanup so failed uploads do not leave stale texture caches.

Validation: full application build and diff checks passed. OpenGL readback
checks covered RGB/RGBA/alpha data, padded and custom strides, generated and
supplied mipmaps, unpack-state restoration, and failure cleanup. All nine
grid mip levels matched the previous generator. Visual rendering was checked
by the user.
2026-10-12 19:24:44 -07:00

342 lines
8.5 KiB
C++

#pragma once
#include "lc_math.h"
#include "lc_mesh.h"
#include "lc_result.h"
class lcVertexBuffer
{
public:
constexpr lcVertexBuffer()
: Pointer(nullptr)
{
}
bool IsValid() const
{
return Pointer != nullptr;
}
union
{
GLuint Object;
void* Pointer;
};
};
class lcIndexBuffer
{
public:
constexpr lcIndexBuffer()
: Pointer(nullptr)
{
}
bool IsValid() const
{
return Pointer != nullptr;
}
union
{
GLuint Object;
void* Pointer;
};
};
enum class lcMaterialType
{
UnlitColor,
UnlitColorConditional,
UnlitTextureModulate,
TextSDF,
UnlitTextureDecal,
UnlitVertexColor,
UnlitViewSphere,
FakeLitColor,
FakeLitTextureDecal,
OutlineComposite,
Count
};
enum class lcProgramAttrib
{
Position,
Normal,
TexCoord,
Color,
Count,
ControlPoint1 = Position,
ControlPoint2 = Normal,
ControlPoint3 = TexCoord,
ControlPoint4 = Color
};
struct lcProgram
{
GLuint Object;
GLint WorldViewProjectionMatrixLocation;
GLint WorldMatrixLocation;
GLint MaterialColorLocation;
GLint LightPositionLocation;
GLint EyePositionLocation;
GLint HighlightParamsLocation;
GLint OutlineParamsLocation;
GLint TextHaloColorLocation;
};
enum class lcPolygonOffset
{
None,
Opaque,
Translucent
};
enum class lcDepthFunction
{
LessEqual,
Always
};
struct lcVertexAttribState
{
GLint Size = 0;
GLenum Type = 0;
GLboolean Normalized = 0;
bool Enabled = 0;
GLsizei Stride = 0;
const void* Pointer = nullptr;
GLuint VertexBufferObject = 0;
};
// Restores caller state after temporary rendering, including a caller with no current context.
class lcScopedGLContextState
{
public:
lcScopedGLContextState();
~lcScopedGLContextState();
lcScopedGLContextState(const lcScopedGLContextState&) = delete;
lcScopedGLContextState& operator=(const lcScopedGLContextState&) = delete;
private:
QOpenGLContext* mContext;
QSurface* mSurface;
GLint mDrawFramebuffer = 0;
GLint mReadFramebuffer = 0;
bool mSeparateFramebuffers = false;
};
class lcContext : public QOpenGLFunctions
{
public:
lcContext();
~lcContext();
lcContext(const lcContext&) = delete;
lcContext(lcContext&&) = delete;
lcContext& operator=(const lcContext&) = delete;
lcContext& operator=(lcContext&&) = delete;
static lcResult<void> InitializeRenderer(bool CreateRenderResources);
static void ShutdownRenderer();
static lcContext* GetGlobalOffscreenContext();
lcResult<void> CreateResources();
void DestroyResources();
void SetDefaultState();
void ClearResources();
void MakeCurrent();
QOpenGLContext* GetGLContext() const { return mContext; }
void SetGLContext(QOpenGLContext* GLContext, QOpenGLWidget* Widget);
void SetOffscreenContext();
bool IsOffscreen() const
{
return mWidget == nullptr;
}
void ClearColorAndDepth(const lcVector4& ClearColor);
void ClearDepth();
static bool SupportsMaterial(lcMaterialType MaterialType)
{
return mPrograms[static_cast<int>(MaterialType)].Object != 0;
}
static bool SupportsDefaultLights()
{
return SupportsMaterial(lcMaterialType::FakeLitColor) && SupportsMaterial(lcMaterialType::FakeLitTextureDecal);
}
static bool SupportsSelectionOutline();
int GetMaxTextureSize();
std::unique_ptr<QOpenGLFramebufferObject> CreateFramebuffer(int Width, int Height);
bool GenerateOutlineMasks(const lcScene& Scene, QOpenGLFramebufferObject& FullFramebuffer, QOpenGLFramebufferObject& VisibleFramebuffer);
void DrawOutline(QOpenGLFramebufferObject& FullFramebuffer, QOpenGLFramebufferObject& VisibleFramebuffer, float DeviceScale);
void SetWorldMatrix(const lcMatrix44& WorldMatrix)
{
mWorldMatrix = WorldMatrix;
mWorldMatrixDirty = true;
}
void SetViewMatrix(const lcMatrix44& ViewMatrix)
{
mViewMatrix = ViewMatrix;
mViewMatrixDirty = true;
mViewProjectionMatrixDirty = true;
}
void SetProjectionMatrix(const lcMatrix44& ProjectionMatrix)
{
mProjectionMatrix = ProjectionMatrix;
mProjectionMatrixDirty = true;
mViewProjectionMatrixDirty = true;
}
const lcMatrix44& GetProjectionMatrix()
{
return mProjectionMatrix;
}
void SetMaterial(lcMaterialType MaterialType);
void SetViewport(int x, int y, int Width, int Height);
void SetPolygonOffset(lcPolygonOffset PolygonOffset);
void SetDepthWrite(bool Enable);
void SetDepthFunction(lcDepthFunction DepthFunction);
void EnableDepthTest(bool Enable);
void EnableColorWrite(bool Enable);
void EnableColorBlend(bool Enable);
void EnableCullFace(bool Enable);
void SetLineWidth(float LineWidth);
void BindTexture2D(const lcTexture* Texture);
void BindTextureCubeMap(const lcTexture* Texture);
void ClearTexture2D();
void ClearTextureCubeMap();
bool UploadTexture(lcTexture* Texture);
void SetColor(const lcVector4& Color)
{
mColor = Color;
mColorDirty = true;
}
void SetTextHaloColor(const lcVector4& Color)
{
mTextHaloColor = Color;
mTextHaloColorDirty = true;
}
void SetHighlightParams(const lcVector4& HighlightPosition, const lcVector4& TextColor, const lcVector4& BackgroundColor, const lcVector4& HighlightColor)
{
mHighlightParams[0] = HighlightPosition;
mHighlightParams[1] = TextColor;
mHighlightParams[2] = BackgroundColor;
mHighlightParams[3] = HighlightColor;
mHighlightParamsDirty = true;
}
void SetOutlineParams(const lcVector4& PixelSizeRadiusOpacity, const lcVector4& SelectedColor, const lcVector4& FocusedColor)
{
mOutlineParams[0] = PixelSizeRadiusOpacity;
mOutlineParams[1] = SelectedColor;
mOutlineParams[2] = FocusedColor;
mOutlineParamsDirty = true;
}
void SetColor(float Red, float Green, float Blue, float Alpha);
void SetColorIndex(int ColorIndex);
void SetColorIndexTinted(int ColorIndex, const lcVector4& Tint, float Weight);
void SetColorIndexTinted(int ColorIndex, const lcVector4& Tint);
void SetEdgeColorIndex(int ColorIndex);
void SetEdgeColorIndexTinted(int ColorIndex, const lcVector4& Tint);
lcVertexBuffer CreateVertexBuffer(int Size, const void* Data);
void DestroyVertexBuffer(lcVertexBuffer& VertexBuffer);
lcIndexBuffer CreateIndexBuffer(int Size, const void* Data);
void DestroyIndexBuffer(lcIndexBuffer& IndexBuffer);
void ClearVertexBuffer();
void SetVertexBuffer(lcVertexBuffer VertexBuffer);
void SetVertexBufferPointer(const void* VertexBuffer);
void ClearIndexBuffer();
void SetIndexBuffer(lcIndexBuffer IndexBuffer);
void SetIndexBufferPointer(const void* IndexBuffer);
void SetVertexFormat(int BufferOffset, int PositionSize, int NormalSize, int TexCoordSize, int ColorSize, bool EnableNormals);
void SetVertexFormatPosition(int PositionSize);
void SetVertexFormatConditional(int BufferOffset);
void DrawPrimitives(GLenum Mode, GLint First, GLsizei Count);
void DrawIndexedPrimitives(GLenum Mode, GLsizei Count, GLenum Type, int Offset);
void BindMesh(const lcMesh* Mesh);
protected:
static lcResult<void> CreateOffscreenContext();
static void DestroyOffscreenContext();
lcResult<void> CreateShaderPrograms();
void UploadTextureImage(GLenum Target, int Level, GLenum Format, const QImage& Image);
void FlushState();
bool TryShareDepthAttachment(GLuint SourceFramebuffer, QOpenGLFramebufferObject& TargetFramebuffer);
void SetVertexAttribPointer(lcProgramAttrib Attrib, GLint Size, GLenum Type, GLboolean Normalized, GLsizei Stride, const void* Pointer);
void EnableVertexAttrib(lcProgramAttrib Attrib);
void DisableVertexAttrib(lcProgramAttrib Attrib);
QOpenGLWidget* mWidget = nullptr;
QOpenGLContext* mContext = nullptr;
GLuint mVertexBufferObject;
GLuint mIndexBufferObject;
const char* mVertexBufferPointer;
const char* mIndexBufferPointer;
lcMaterialType mMaterialType;
lcVertexAttribState mVertexAttribState[static_cast<int>(lcProgramAttrib::Count)];
GLuint mTexture2D;
GLuint mTextureCubeMap;
lcPolygonOffset mPolygonOffset;
bool mDepthWrite;
lcDepthFunction mDepthFunction;
bool mDepthTest;
bool mColorWrite;
bool mColorBlend;
bool mCullFace;
float mLineWidth;
lcVector4 mColor;
lcVector4 mTextHaloColor;
lcMatrix44 mWorldMatrix;
lcMatrix44 mViewMatrix;
lcMatrix44 mProjectionMatrix;
lcMatrix44 mViewProjectionMatrix;
lcVector4 mHighlightParams[4];
lcVector4 mOutlineParams[3];
bool mColorDirty;
bool mTextHaloColorDirty;
bool mWorldMatrixDirty;
bool mViewMatrixDirty;
bool mProjectionMatrixDirty;
bool mViewProjectionMatrixDirty;
bool mHighlightParamsDirty;
bool mOutlineParamsDirty;
static std::unique_ptr<QOpenGLContext> mOffscreenContext;
static std::unique_ptr<QOffscreenSurface> mOffscreenSurface;
static std::unique_ptr<lcContext> mGlobalOffscreenContext;
static bool mRenderResourcesCreated;
static lcProgram mPrograms[static_cast<int>(lcMaterialType::Count)];
Q_DECLARE_TR_FUNCTIONS(lcContext);
};