mirror of
https://github.com/YACReader/yacreader
synced 2026-03-01 10:22:58 -05:00
Add an initial rhi implementation that mimics the opengl implementation
This commit is contained in:
@ -1,7 +1,5 @@
|
||||
#include "opengl_checker.h"
|
||||
|
||||
#include "QsLog.h"
|
||||
|
||||
OpenGLChecker::OpenGLChecker()
|
||||
: compatibleOpenGLVersion(true)
|
||||
{
|
||||
|
||||
287
common/rhi/README.md
Normal file
287
common/rhi/README.md
Normal file
@ -0,0 +1,287 @@
|
||||
# YACReader Flow RHI Implementation
|
||||
|
||||
This directory contains the QRhiWidget-based implementation of the YACReader 3D cover flow, providing cross-platform 3D rendering support for Qt 6.7+.
|
||||
|
||||
## Overview
|
||||
|
||||
The RHI (Rendering Hardware Interface) implementation is a modern replacement for the OpenGL-based flow (`yacreader_flow_gl`) that:
|
||||
|
||||
- ✅ Supports **multiple graphics APIs**: Vulkan, Metal, Direct3D 11/12, OpenGL
|
||||
- ✅ Provides **native performance** on modern platforms (Metal on macOS, D3D on Windows)
|
||||
- ✅ Maintains **100% API compatibility** with the OpenGL version
|
||||
- ✅ Works seamlessly with **Qt 6.7+** while Qt5 continues using OpenGL
|
||||
- ✅ Enables **future-proof** rendering infrastructure
|
||||
|
||||
## Architecture
|
||||
|
||||
### Class Hierarchy
|
||||
|
||||
```
|
||||
QRhiWidget (Qt base class)
|
||||
└── YACReaderFlow3D (Base implementation)
|
||||
├── YACReaderComicFlow3D (File path-based loading for library)
|
||||
└── YACReaderPageFlow3D (Byte array-based loading for viewer)
|
||||
```
|
||||
|
||||
### Files
|
||||
|
||||
- **yacreader_flow_rhi.h** - Header with class definitions
|
||||
- **yacreader_flow_rhi.cpp** - Implementation
|
||||
- **shaders/** - GLSL 450 shaders and compiled .qsb files
|
||||
- **README.md** - This file
|
||||
|
||||
## Key Features
|
||||
|
||||
### Graphics Pipeline
|
||||
|
||||
The implementation uses:
|
||||
- **Instanced rendering** for efficient batch drawing
|
||||
- **Dual-pass rendering** (reflections + covers)
|
||||
- **MSAA** (4x by default) for anti-aliasing
|
||||
- **Depth testing** and back-face culling
|
||||
- **Alpha blending** for transparency
|
||||
|
||||
### Resource Management
|
||||
|
||||
QRhi resources managed:
|
||||
- `QRhiBuffer` for vertices, instance data, and uniforms
|
||||
- `QRhiTexture` for cover images, marks, and default texture
|
||||
- `QRhiSampler` for texture filtering
|
||||
- `QRhiGraphicsPipeline` for render state
|
||||
- `QRhiShaderResourceBindings` for uniform/texture bindings
|
||||
|
||||
### Shader System
|
||||
|
||||
Shaders are written in **GLSL 4.50** and compiled to `.qsb` format supporting:
|
||||
- OpenGL ES 2.0, 3.0
|
||||
- OpenGL 2.1, 3.0+
|
||||
- HLSL (Direct3D 11/12)
|
||||
- Metal Shading Language (macOS/iOS)
|
||||
|
||||
## Integration
|
||||
|
||||
### Qt5 vs Qt6 Selection
|
||||
|
||||
The build system automatically selects the appropriate implementation:
|
||||
|
||||
**Qt 5.x**: Uses `YACReaderFlowGL` (OpenGL-based)
|
||||
**Qt 6.0-6.6**: Uses `YACReaderFlowGL` (OpenGL-based)
|
||||
**Qt 6.7+**: Uses `YACReaderFlow3D` (RHI-based) if `YACREADER_USE_RHI` is defined
|
||||
|
||||
### Type Aliases
|
||||
|
||||
Applications use type aliases for seamless switching:
|
||||
|
||||
```cpp
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) && defined(YACREADER_USE_RHI)
|
||||
using YACReaderPageFlowImpl = YACReaderPageFlow3D;
|
||||
using YACReaderComicFlowImpl = YACReaderComicFlow3D;
|
||||
#else
|
||||
using YACReaderPageFlowImpl = YACReaderPageFlowGL;
|
||||
using YACReaderComicFlowImpl = YACReaderComicFlowGL;
|
||||
#endif
|
||||
```
|
||||
|
||||
### Example Usage (YACReader Viewer)
|
||||
|
||||
```cpp
|
||||
// goto_flow_gl.cpp
|
||||
flow = new YACReaderPageFlowImpl(this);
|
||||
flow->setShowMarks(false);
|
||||
flow->populate(numPages);
|
||||
connect(flow, &YACReaderPageFlowImpl::selected, this, &GoToFlowGL::goToPage);
|
||||
```
|
||||
|
||||
### Example Usage (YACReaderLibrary)
|
||||
|
||||
```cpp
|
||||
// comic_flow_widget.cpp
|
||||
flow = new YACReaderComicFlowImpl(parent);
|
||||
flow->setImagePaths(pathsList);
|
||||
connect(flow, &YACReaderComicFlowImpl::centerIndexChanged,
|
||||
this, &ComicFlowWidget::centerIndexChanged);
|
||||
```
|
||||
|
||||
## API Compatibility
|
||||
|
||||
All public methods from `YACReaderFlowGL` are preserved:
|
||||
|
||||
### Navigation
|
||||
- `showPrevious()`, `showNext()`
|
||||
- `setCurrentIndex(int)`, `setCenterIndex(unsigned int)`
|
||||
- `showSlide(int)`, `centerIndex()`
|
||||
|
||||
### Configuration
|
||||
- `setPreset(const Preset &)`
|
||||
- `setPerformance(Performance)`
|
||||
- `setFlowRightToLeft(bool)`
|
||||
- `setZoom(int)`, `setRotation(int)`
|
||||
- `setCF_RX/RY/RZ(int)`, `setCF_Y/Z(int)`
|
||||
- `setX_Distance(int)`, `setCenter_Distance(int)`, etc.
|
||||
|
||||
### Appearance
|
||||
- `setBackgroundColor(const QColor &)`
|
||||
- `setTextColor(const QColor &)`
|
||||
- `setShadingColor(const QColor &)`
|
||||
- `setShowMarks(bool)`, `setMarks(QVector<...>)`
|
||||
|
||||
### Content Management
|
||||
- `populate(int)`, `clear()`, `reset()`, `reload()`
|
||||
- `insert()`, `remove(int)`, `add(int)`, `replace()`
|
||||
- Subclass-specific: `setImagePaths()`, `resortCovers()`, etc.
|
||||
|
||||
## Building
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Qt 6.7 or later**
|
||||
2. **qsb tool** (Qt Shader Baker) in PATH
|
||||
3. **C++17 compiler**
|
||||
|
||||
### Compile Shaders
|
||||
|
||||
Before building YACReader, compile the shaders:
|
||||
|
||||
```bash
|
||||
cd common/rhi/shaders
|
||||
# Windows
|
||||
compile_shaders.bat
|
||||
|
||||
# Unix/macOS
|
||||
chmod +x compile_shaders.sh
|
||||
./compile_shaders.sh
|
||||
```
|
||||
|
||||
This generates `flow.vert.qsb` and `flow.frag.qsb` which are embedded via `shaders.qrc`.
|
||||
|
||||
### Build YACReader
|
||||
|
||||
The `.pro` files automatically include RHI sources for Qt 6.7+:
|
||||
|
||||
```bash
|
||||
qmake YACReader.pro
|
||||
make
|
||||
```
|
||||
|
||||
For Qt 5 builds, the OpenGL version is used automatically.
|
||||
|
||||
## Graphics API Selection
|
||||
|
||||
QRhiWidget auto-selects the best API per platform:
|
||||
|
||||
- **macOS/iOS**: Metal (native)
|
||||
- **Windows**: Direct3D 11 (default) or Direct3D 12
|
||||
- **Linux**: Vulkan or OpenGL
|
||||
- **Android**: OpenGL ES 3.0 or Vulkan
|
||||
|
||||
You can force a specific API via environment variables (for testing):
|
||||
|
||||
```bash
|
||||
# Force OpenGL
|
||||
export QSG_RHI_BACKEND=opengl
|
||||
|
||||
# Force Vulkan
|
||||
export QSG_RHI_BACKEND=vulkan
|
||||
|
||||
# Force Direct3D 11 (Windows)
|
||||
set QSG_RHI_BACKEND=d3d11
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
Performance tiers match the OpenGL version:
|
||||
|
||||
- **Low**: 8 covers loaded, 128px textures (page flow) / 200px (comic flow)
|
||||
- **Medium**: 10 covers, 196px / 256px textures
|
||||
- **High**: 12 covers, 256px / 320px textures
|
||||
- **Ultra High**: 14-16 covers, full resolution textures
|
||||
|
||||
Texture loading happens asynchronously via worker threads (`ImageLoader3D`, `ImageLoaderByteArray3D`).
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Validation Layers
|
||||
|
||||
For debugging graphics issues, enable validation:
|
||||
|
||||
```cpp
|
||||
flow->setDebugLayerEnabled(true); // Call before widget is shown
|
||||
```
|
||||
|
||||
This activates:
|
||||
- **Vulkan**: VK_LAYER_KHRONOS_validation
|
||||
- **Direct3D**: D3D11 debug layer
|
||||
- **Metal**: Metal API validation
|
||||
|
||||
### Check Active Graphics API
|
||||
|
||||
```cpp
|
||||
QRhi *rhi = flow->rhi();
|
||||
qDebug() << "Backend:" << rhi->backend();
|
||||
qDebug() << "Driver:" << rhi->driverInfo();
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Problem**: Shaders fail to load
|
||||
**Solution**: Ensure `.qsb` files are compiled and included in resources
|
||||
|
||||
**Problem**: Black screen on Qt 6.7
|
||||
**Solution**: Check if `YACREADER_USE_RHI` is defined in build
|
||||
|
||||
**Problem**: Crashes on resize/reparent
|
||||
**Solution**: `releaseResources()` properly cleans up all QRhi objects
|
||||
|
||||
## Migration from OpenGL
|
||||
|
||||
The RHI version is a **drop-in replacement** requiring no application code changes beyond the build system.
|
||||
|
||||
### What's Different (Internal)
|
||||
|
||||
| OpenGL API | QRhi Equivalent |
|
||||
|------------|-----------------|
|
||||
| `glDrawArraysInstanced()` | `cb->drawIndexed(instanceCount)` |
|
||||
| `glUniform*()` | Update `QRhiBuffer` with uniform data |
|
||||
| `glBindTexture()` | `QRhiShaderResourceBindings` |
|
||||
| `glBlendFunc()` | `QRhiGraphicsPipeline::setTargetBlends()` |
|
||||
| `glEnable(GL_DEPTH_TEST)` | `pipeline->setDepthTest(true)` |
|
||||
|
||||
### What's the Same
|
||||
|
||||
- All public API methods and signatures
|
||||
- Animation system and timing
|
||||
- Preset configurations
|
||||
- Event handling (mouse, keyboard, wheel)
|
||||
- Worker thread texture loading
|
||||
- Performance tiers
|
||||
|
||||
## Known Limitations
|
||||
|
||||
1. **Qt Version**: Requires Qt 6.7+ (released April 2024)
|
||||
2. **QRhi Stability**: QRhi APIs may change in minor Qt releases
|
||||
3. **Mixed Renderers**: Only one graphics API per window
|
||||
4. **Shader Compilation**: Must recompile shaders when modifying source
|
||||
|
||||
## Future Improvements
|
||||
|
||||
Potential enhancements:
|
||||
- [ ] GPU-side frustum culling
|
||||
- [ ] Compute shader for texture generation
|
||||
- [ ] HDR/wide color gamut support
|
||||
- [ ] Ray-traced reflections (via RHI compute)
|
||||
- [ ] Dynamic LOD based on distance
|
||||
|
||||
## References
|
||||
|
||||
- [QRhiWidget Class Documentation](https://doc.qt.io/qt-6/qrhiwidget.html)
|
||||
- [QRhi Overview](https://doc.qt.io/qt-6/qrhi.html)
|
||||
- [Qt RHI Examples](https://doc.qt.io/qt-6/qtwidgets-rhi-cuberhiwidget-example.html)
|
||||
- [Qt Shader Tools (qsb)](https://doc.qt.io/qt-6/qtshadertools-index.html)
|
||||
|
||||
## License
|
||||
|
||||
Same as YACReader project license.
|
||||
|
||||
## Author
|
||||
|
||||
Generated as part of the YACReader OpenGL modernization initiative.
|
||||
49
common/rhi/shaders/README.md
Normal file
49
common/rhi/shaders/README.md
Normal file
@ -0,0 +1,49 @@
|
||||
# YACReader Flow RHI Shaders
|
||||
|
||||
This directory contains the GLSL 4.50 shaders for the QRhiWidget-based flow implementation.
|
||||
|
||||
## Files
|
||||
|
||||
- `flow.vert` - Vertex shader (GLSL 450)
|
||||
- `flow.frag` - Fragment shader (GLSL 450)
|
||||
- `flow.vert.qsb` - Compiled vertex shader (multi-platform)
|
||||
- `flow.frag.qsb` - Compiled fragment shader (multi-platform)
|
||||
- `compile_shaders.bat` - Windows compilation script
|
||||
- `compile_shaders.sh` - Unix/macOS compilation script
|
||||
- `shaders.qrc` - Qt resource file
|
||||
|
||||
## Compiling Shaders
|
||||
|
||||
The shaders must be compiled to `.qsb` format using Qt's `qsb` tool before building YACReader.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Ensure `qsb` is in your PATH. It's typically located in:
|
||||
- Windows: `C:\Qt\6.x.x\msvc2019_64\bin\qsb.exe`
|
||||
- macOS: `/opt/Qt/6.x.x/macos/bin/qsb`
|
||||
- Linux: `/opt/Qt/6.x.x/gcc_64/bin/qsb`
|
||||
|
||||
### Compilation
|
||||
|
||||
**Windows:**
|
||||
```cmd
|
||||
cd common/rhi/shaders
|
||||
compile_shaders.bat
|
||||
```
|
||||
|
||||
**Unix/macOS:**
|
||||
```bash
|
||||
cd common/rhi/shaders
|
||||
chmod +x compile_shaders.sh
|
||||
./compile_shaders.sh
|
||||
```
|
||||
|
||||
The compiled `.qsb` files contain shader variants for:
|
||||
- OpenGL ES 2.0, 3.0
|
||||
- OpenGL 2.1, 3.0+
|
||||
- HLSL (Direct3D 11/12)
|
||||
- Metal Shading Language (macOS/iOS)
|
||||
|
||||
## Note
|
||||
|
||||
The `.qsb` files are included in the repository for convenience. Recompile only if you modify the shader source.
|
||||
19
common/rhi/shaders/compile_shaders.bat
Normal file
19
common/rhi/shaders/compile_shaders.bat
Normal file
@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
REM Compile shaders to .qsb format for Qt RHI
|
||||
REM Requires qsb tool from Qt installation
|
||||
|
||||
echo Compiling flow vertex shader...
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o flow.vert.qsb flow.vert
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Error compiling vertex shader
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Compiling flow fragment shader...
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o flow.frag.qsb flow.frag
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Error compiling fragment shader
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Shader compilation complete!
|
||||
19
common/rhi/shaders/compile_shaders.sh
Normal file
19
common/rhi/shaders/compile_shaders.sh
Normal file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
# Compile shaders to .qsb format for Qt RHI
|
||||
# Requires qsb tool from Qt installation
|
||||
|
||||
echo "Compiling flow vertex shader..."
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o flow.vert.qsb flow.vert
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling vertex shader"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Compiling flow fragment shader..."
|
||||
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o flow.frag.qsb flow.frag
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling fragment shader"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Shader compilation complete!"
|
||||
44
common/rhi/shaders/flow.frag
Normal file
44
common/rhi/shaders/flow.frag
Normal file
@ -0,0 +1,44 @@
|
||||
#version 450
|
||||
|
||||
// Inputs from vertex shader
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
layout(location = 1) in vec4 vColor;
|
||||
layout(location = 2) in float vIsReflection;
|
||||
|
||||
// Output
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Uniform buffer
|
||||
layout(std140, binding = 0) uniform UniformBuffer
|
||||
{
|
||||
mat4 viewProjectionMatrix;
|
||||
vec3 backgroundColor;
|
||||
float _pad0;
|
||||
vec3 shadingColor;
|
||||
float _pad1;
|
||||
float reflectionUp;
|
||||
float reflectionDown;
|
||||
int isReflection;
|
||||
float _pad2;
|
||||
};
|
||||
|
||||
// Texture and sampler
|
||||
layout(binding = 1) uniform sampler2D coverTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 texColor = texture(coverTexture, vTexCoord);
|
||||
|
||||
// Apply shading: multiply texture by vColor.r to darken
|
||||
float shadingAmount = vColor.r;
|
||||
|
||||
// For reflections, apply gradient fade (darker at bottom, fading to black)
|
||||
if (vIsReflection > 0.5) {
|
||||
// vTexCoord.y goes from 1 (top of reflection, near cover) to 0 (bottom, far from cover)
|
||||
// We want it brightest near the cover and fading away
|
||||
float gradientFade = mix(0.0, 0.33, vTexCoord.y);
|
||||
shadingAmount *= gradientFade;
|
||||
}
|
||||
|
||||
fragColor = vec4(texColor.rgb * shadingAmount, texColor.a);
|
||||
}
|
||||
BIN
common/rhi/shaders/flow.frag.qsb
Normal file
BIN
common/rhi/shaders/flow.frag.qsb
Normal file
Binary file not shown.
59
common/rhi/shaders/flow.vert
Normal file
59
common/rhi/shaders/flow.vert
Normal file
@ -0,0 +1,59 @@
|
||||
#version 450
|
||||
|
||||
// Per-vertex attributes
|
||||
layout(location = 0) in vec3 position;
|
||||
layout(location = 1) in vec2 texCoord;
|
||||
|
||||
// Per-instance attributes (mat4 split into 4 vec4s for better D3D11 compatibility)
|
||||
layout(location = 2) in vec4 instanceModel_row0;
|
||||
layout(location = 3) in vec4 instanceModel_row1;
|
||||
layout(location = 4) in vec4 instanceModel_row2;
|
||||
layout(location = 5) in vec4 instanceModel_row3;
|
||||
layout(location = 6) in vec4 instanceShading1;
|
||||
layout(location = 7) in float instanceOpacity;
|
||||
layout(location = 8) in float instanceFlip;
|
||||
|
||||
// Outputs to fragment shader
|
||||
layout(location = 0) out vec2 vTexCoord;
|
||||
layout(location = 1) out vec4 vColor;
|
||||
layout(location = 2) out float vIsReflection;
|
||||
|
||||
// Uniform buffer
|
||||
layout(std140, binding = 0) uniform UniformBuffer
|
||||
{
|
||||
mat4 viewProjectionMatrix;
|
||||
vec3 backgroundColor;
|
||||
float _pad0;
|
||||
vec3 shadingColor;
|
||||
float _pad1;
|
||||
float reflectionUp;
|
||||
float reflectionDown;
|
||||
int isReflection;
|
||||
float _pad2;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
// Reconstruct instance model matrix from 4 vec4 rows
|
||||
mat4 instanceModel = mat4(instanceModel_row0, instanceModel_row1, instanceModel_row2, instanceModel_row3);
|
||||
|
||||
gl_Position = viewProjectionMatrix * instanceModel * vec4(position, 1.0);
|
||||
vTexCoord = texCoord;
|
||||
|
||||
// Flip texture vertically per-instance when requested (reflection)
|
||||
if (instanceFlip != 0.0) {
|
||||
vTexCoord.y = 1.0 - texCoord.y;
|
||||
}
|
||||
|
||||
float leftUpShading = instanceShading1.x;
|
||||
float leftDownShading = instanceShading1.y;
|
||||
float rightUpShading = instanceShading1.z;
|
||||
float rightDownShading = instanceShading1.w;
|
||||
|
||||
float leftShading = mix(leftDownShading, leftUpShading, (position.y + 0.5));
|
||||
float rightShading = mix(rightDownShading, rightUpShading, (position.y + 0.5));
|
||||
float shading = mix(leftShading, rightShading, (position.x + 0.5));
|
||||
|
||||
vColor = vec4(shading * instanceOpacity);
|
||||
vIsReflection = instanceFlip;
|
||||
}
|
||||
BIN
common/rhi/shaders/flow.vert.qsb
Normal file
BIN
common/rhi/shaders/flow.vert.qsb
Normal file
Binary file not shown.
6
common/rhi/shaders/shaders.qrc
Normal file
6
common/rhi/shaders/shaders.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/shaders">
|
||||
<file>flow.vert.qsb</file>
|
||||
<file>flow.frag.qsb</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
1744
common/rhi/yacreader_flow_rhi.cpp
Normal file
1744
common/rhi/yacreader_flow_rhi.cpp
Normal file
File diff suppressed because it is too large
Load Diff
394
common/rhi/yacreader_flow_rhi.h
Normal file
394
common/rhi/yacreader_flow_rhi.h
Normal file
@ -0,0 +1,394 @@
|
||||
// Qt RHI-based Coverflow for YACReader
|
||||
// Compatible with Qt 6.7+ using QRhiWidget
|
||||
#ifndef __YACREADER_FLOW_RHI_H
|
||||
#define __YACREADER_FLOW_RHI_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||
|
||||
#include <QRhiWidget>
|
||||
#include <QtWidgets>
|
||||
#include <QtGui>
|
||||
#include <rhi/qrhi.h>
|
||||
|
||||
#include "pictureflow.h"
|
||||
#include "scroll_management.h"
|
||||
|
||||
// Reuse enums and structs from OpenGL version
|
||||
enum Performance {
|
||||
low = 0,
|
||||
medium,
|
||||
high,
|
||||
ultraHigh
|
||||
};
|
||||
|
||||
// Cover Vector
|
||||
struct YACReader3DVector {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float rot;
|
||||
};
|
||||
|
||||
// the image/texture info struct
|
||||
struct YACReader3DImageRHI {
|
||||
QRhiTexture *texture;
|
||||
|
||||
float width;
|
||||
float height;
|
||||
|
||||
int index;
|
||||
|
||||
YACReader3DVector current;
|
||||
YACReader3DVector animEnd;
|
||||
};
|
||||
|
||||
struct Preset {
|
||||
/*** Animation Settings ***/
|
||||
float animationStep;
|
||||
float animationSpeedUp;
|
||||
float animationStepMax;
|
||||
float animationFadeOutDist;
|
||||
float preRotation;
|
||||
float viewRotateLightStrenght;
|
||||
float viewRotateAdd;
|
||||
float viewRotateSub;
|
||||
float viewAngle;
|
||||
|
||||
/*** Position Configuration ***/
|
||||
float cfX;
|
||||
float cfY;
|
||||
float cfZ;
|
||||
float cfRX;
|
||||
float cfRY;
|
||||
float cfRZ;
|
||||
float rotation;
|
||||
float xDistance;
|
||||
float centerDistance;
|
||||
float zDistance;
|
||||
float yDistance;
|
||||
|
||||
float zoom;
|
||||
};
|
||||
|
||||
extern struct Preset defaultYACReaderFlowConfig;
|
||||
extern struct Preset presetYACReaderFlowClassicConfig;
|
||||
extern struct Preset presetYACReaderFlowStripeConfig;
|
||||
extern struct Preset presetYACReaderFlowOverlappedStripeConfig;
|
||||
extern struct Preset pressetYACReaderFlowUpConfig;
|
||||
extern struct Preset pressetYACReaderFlowDownConfig;
|
||||
|
||||
class ImageLoader3D;
|
||||
class ImageLoaderByteArray3D;
|
||||
|
||||
class YACReaderFlow3D : public QRhiWidget, public ScrollManagement
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
int timerId;
|
||||
|
||||
/*** System variables ***/
|
||||
YACReader3DImageRHI dummy;
|
||||
int viewRotateActive;
|
||||
float stepBackup;
|
||||
|
||||
/*functions*/
|
||||
void calcPos(YACReader3DImageRHI &image, int pos);
|
||||
void calcVector(YACReader3DVector &vector, int pos);
|
||||
bool animate(YACReader3DVector ¤tVector, YACReader3DVector &toVector);
|
||||
void prepareInstanceData(const YACReader3DImageRHI &image, bool isReflection, QVector<float> &data);
|
||||
|
||||
int updateCount;
|
||||
int fontSize;
|
||||
|
||||
// RHI resources
|
||||
QRhiTexture *defaultTexture = nullptr;
|
||||
QRhiTexture *markTexture = nullptr;
|
||||
QRhiTexture *readingTexture = nullptr;
|
||||
|
||||
QRhiBuffer *vertexBuffer = nullptr;
|
||||
QRhiBuffer *instanceBuffer = nullptr;
|
||||
QRhiBuffer *uniformBuffer = nullptr;
|
||||
int alignedUniformSize = 0; // Cached aligned uniform buffer size
|
||||
int uniformBufferCapacity = 0; // Number of uniform slots allocated
|
||||
|
||||
QRhiSampler *sampler = nullptr;
|
||||
QRhiGraphicsPipeline *pipeline = nullptr;
|
||||
QRhiShaderResourceBindings *shaderBindings = nullptr;
|
||||
|
||||
// Cache of shader resource bindings per texture (to avoid recreating every frame)
|
||||
QMap<QRhiTexture *, QRhiShaderResourceBindings *> shaderBindingsCache;
|
||||
|
||||
// Pending texture uploads (for async image loading)
|
||||
struct PendingTextureUpload {
|
||||
int index;
|
||||
QImage image;
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
QVector<PendingTextureUpload> pendingTextureUploads;
|
||||
|
||||
// Uniform buffer data structure
|
||||
struct UniformData {
|
||||
QMatrix4x4 viewProjectionMatrix;
|
||||
QVector3D backgroundColor;
|
||||
float _pad0;
|
||||
QVector3D shadingColor;
|
||||
float _pad1;
|
||||
float reflectionUp;
|
||||
float reflectionDown;
|
||||
int isReflection;
|
||||
float _pad2;
|
||||
};
|
||||
|
||||
void timerEvent(QTimerEvent *);
|
||||
|
||||
int numObjects;
|
||||
int lazyPopulateObjects;
|
||||
bool showMarks;
|
||||
QVector<bool> loaded;
|
||||
QVector<YACReaderComicReadStatus> marks;
|
||||
|
||||
QVector<YACReader3DImageRHI> images;
|
||||
|
||||
bool hasBeenInitialized;
|
||||
|
||||
Performance performance;
|
||||
|
||||
/*** Animation Settings ***/
|
||||
Preset config;
|
||||
|
||||
int currentSelected;
|
||||
|
||||
YACReader3DVector centerPos;
|
||||
|
||||
/*** Style ***/
|
||||
float shadingTop;
|
||||
float shadingBottom;
|
||||
|
||||
float reflectionUp;
|
||||
float reflectionBottom;
|
||||
|
||||
/*** Theme Colors ***/
|
||||
QColor backgroundColor;
|
||||
QColor textColor;
|
||||
QColor shadingColor;
|
||||
|
||||
/*** System info ***/
|
||||
float viewRotate;
|
||||
|
||||
static int updateInterval;
|
||||
|
||||
bool flowRightToLeft;
|
||||
|
||||
void startAnimationTimer();
|
||||
void stopAnimationTimer();
|
||||
|
||||
// QRhiWidget overrides
|
||||
void initialize(QRhiCommandBuffer *cb) override;
|
||||
void render(QRhiCommandBuffer *cb) override;
|
||||
void releaseResources() override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
// Helper methods
|
||||
QRhiTexture *createTextureFromImage(QRhiCommandBuffer *cb, const QImage &image);
|
||||
void updateUniformBuffer(QRhiCommandBuffer *cb, const UniformData &data);
|
||||
void prepareMarkInstanceData(const YACReader3DImageRHI &image, QVector<float> &data);
|
||||
void ensureUniformBufferCapacity(int requiredSlots);
|
||||
void prepareDrawData(const YACReader3DImageRHI &image, bool isReflection, bool isMark,
|
||||
const QMatrix4x4 &viewProjectionMatrix, float *outInstanceData,
|
||||
UniformData &outUniformData);
|
||||
void executeDrawWithOffset(QRhiCommandBuffer *cb, QRhiTexture *texture,
|
||||
const float *instanceData, int uniformSlot);
|
||||
|
||||
protected:
|
||||
QRhi *m_rhi = nullptr;
|
||||
std::unique_ptr<QRhiBuffer> m_vbuf;
|
||||
std::unique_ptr<QRhiBuffer> m_ubuf;
|
||||
std::unique_ptr<QRhiShaderResourceBindings> m_srb;
|
||||
std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
|
||||
QMatrix4x4 m_viewProjection;
|
||||
float m_rotation = 0.0f;
|
||||
|
||||
public:
|
||||
YACReaderFlow3D(QWidget *parent = nullptr, struct Preset p = pressetYACReaderFlowDownConfig);
|
||||
virtual ~YACReaderFlow3D();
|
||||
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
void showPrevious();
|
||||
void showNext();
|
||||
void setCurrentIndex(int pos);
|
||||
void cleanupAnimation();
|
||||
void draw();
|
||||
void updatePositions();
|
||||
void insert(char *name, QRhiTexture *texture, float x, float y, int item = -1);
|
||||
virtual void remove(int item);
|
||||
void add(int item);
|
||||
void replace(char *name, QRhiTexture *texture, float x, float y, int item);
|
||||
void populate(int n);
|
||||
YACReader3DImageRHI getCurrentSelected();
|
||||
|
||||
public slots:
|
||||
void setCF_RX(int value);
|
||||
void setCF_RY(int value);
|
||||
void setCF_RZ(int value);
|
||||
void setZoom(int zoom);
|
||||
void setRotation(int angle);
|
||||
void setX_Distance(int distance);
|
||||
void setCenter_Distance(int distance);
|
||||
void setZ_Distance(int distance);
|
||||
void setCF_Y(int value);
|
||||
void setCF_Z(int value);
|
||||
void setY_Distance(int value);
|
||||
void setFadeOutDist(int value);
|
||||
void setLightStrenght(int value);
|
||||
void setMaxAngle(int value);
|
||||
void setPreset(const Preset &p);
|
||||
void setPerformance(Performance performance);
|
||||
void useVSync(bool b); // Compatibility method (no-op for RHI)
|
||||
void setFlowRightToLeft(bool b);
|
||||
|
||||
// Theme color setters
|
||||
void setBackgroundColor(const QColor &color);
|
||||
void setTextColor(const QColor &color);
|
||||
void setShadingColor(const QColor &color);
|
||||
|
||||
virtual void updateImageData() = 0;
|
||||
|
||||
void reset();
|
||||
void reload();
|
||||
|
||||
void setShowMarks(bool value);
|
||||
void setMarks(QVector<YACReader::YACReaderComicReadStatus> marks);
|
||||
void setMarkImage(QImage &image);
|
||||
void markSlide(int index, YACReader::YACReaderComicReadStatus status);
|
||||
void unmarkSlide(int index);
|
||||
void setSlideSize(QSize size);
|
||||
void clear();
|
||||
void setCenterIndex(unsigned int index);
|
||||
void showSlide(int index);
|
||||
int centerIndex();
|
||||
void updateMarks();
|
||||
void render(); // Compatibility method (triggers update())
|
||||
void resizeGL(int width, int height); // Compatibility method (no-op for RHI)
|
||||
|
||||
QVector3D getPlaneIntersection(int x, int y, YACReader3DImageRHI plane);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
friend class ImageLoader3D;
|
||||
friend class ImageLoaderByteArray3D;
|
||||
|
||||
signals:
|
||||
void centerIndexChanged(int);
|
||||
void selected(unsigned int);
|
||||
};
|
||||
|
||||
class YACReaderComicFlow3D : public YACReaderFlow3D
|
||||
{
|
||||
public:
|
||||
YACReaderComicFlow3D(QWidget *parent = nullptr, struct Preset p = defaultYACReaderFlowConfig);
|
||||
void setImagePaths(QStringList paths);
|
||||
void updateImageData() override;
|
||||
void remove(int item) override;
|
||||
void add(const QString &path, int index);
|
||||
void resortCovers(QList<int> newOrder);
|
||||
friend class ImageLoader3D;
|
||||
|
||||
private:
|
||||
ImageLoader3D *worker;
|
||||
|
||||
protected:
|
||||
QList<QString> paths;
|
||||
};
|
||||
|
||||
class YACReaderPageFlow3D : public YACReaderFlow3D
|
||||
{
|
||||
public:
|
||||
YACReaderPageFlow3D(QWidget *parent = nullptr, struct Preset p = defaultYACReaderFlowConfig);
|
||||
~YACReaderPageFlow3D();
|
||||
void updateImageData() override;
|
||||
void populate(int n);
|
||||
QVector<bool> imagesReady;
|
||||
QVector<QByteArray> rawImages;
|
||||
QVector<bool> imagesSetted;
|
||||
friend class ImageLoaderByteArray3D;
|
||||
|
||||
private:
|
||||
ImageLoaderByteArray3D *worker;
|
||||
};
|
||||
|
||||
class ImageLoader3D : public QThread
|
||||
{
|
||||
public:
|
||||
ImageLoader3D(YACReaderFlow3D *flow);
|
||||
~ImageLoader3D();
|
||||
bool busy() const;
|
||||
void generate(int index, const QString &fileName);
|
||||
void reset()
|
||||
{
|
||||
idx = -1;
|
||||
fileName = "";
|
||||
}
|
||||
int index() const { return idx; }
|
||||
void lock();
|
||||
void unlock();
|
||||
QImage result();
|
||||
YACReaderFlow3D *flow;
|
||||
QImage loadImage(const QString &fileName);
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
QMutex mutex;
|
||||
QWaitCondition condition;
|
||||
|
||||
bool restart;
|
||||
bool working;
|
||||
int idx;
|
||||
QString fileName;
|
||||
QSize size;
|
||||
QImage img;
|
||||
};
|
||||
|
||||
class ImageLoaderByteArray3D : public QThread
|
||||
{
|
||||
public:
|
||||
ImageLoaderByteArray3D(YACReaderFlow3D *flow);
|
||||
~ImageLoaderByteArray3D();
|
||||
bool busy() const;
|
||||
void generate(int index, const QByteArray &raw);
|
||||
void reset()
|
||||
{
|
||||
idx = -1;
|
||||
rawData.clear();
|
||||
}
|
||||
int index() const { return idx; }
|
||||
QImage result();
|
||||
YACReaderFlow3D *flow;
|
||||
QImage loadImage(const QByteArray &rawData);
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
QMutex mutex;
|
||||
QWaitCondition condition;
|
||||
|
||||
bool restart;
|
||||
bool working;
|
||||
int idx;
|
||||
QByteArray rawData;
|
||||
QSize size;
|
||||
QImage img;
|
||||
};
|
||||
|
||||
#endif // QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||
|
||||
#endif // __YACREADER_FLOW_RHI_H
|
||||
Reference in New Issue
Block a user