From 1f7720d54eed6164eb9365e49159242f65c4e6ba Mon Sep 17 00:00:00 2001 From: thejinchao Date: Sat, 23 Aug 2025 12:19:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8A=97=E9=94=AF=E9=BD=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/console/dv_console_main.cpp | 11 +- source/console/ui/ui_main.cpp | 7 +- source/core/CMakeLists.txt | 2 + source/core/include/dvc_config.h | 8 + source/core/include/pipe/dvc_render_queue.h | 4 +- source/core/include/pipe/dvc_render_step_IA.h | 5 +- source/core/include/pipe/dvc_render_step_OM.h | 87 ++++ source/core/include/pipe/dvc_render_step_PS.h | 17 +- source/core/include/pipe/dvc_render_step_VS.h | 7 +- .../rasterizer/dvc_rasterizer_triangle.h | 9 +- .../core/source/device/dvc_render_target.cpp | 4 +- source/core/source/pipe/dvc_render_queue.cpp | 13 +- .../core/source/pipe/dvc_render_step_OM.cpp | 54 +++ .../core/source/pipe/dvc_render_step_PS.cpp | 29 +- .../rasterizer/dvc_rasterizer_triangle.cpp | 160 ++++++-- source/dv_config.h.in | 1 + test/rasterization/CMakeLists.txt | 2 + test/rasterization/dvr_canvas.cpp | 83 ++++ test/rasterization/dvr_canvas.h | 108 +++++ test/rasterization/dvr_main.cpp | 385 +++++++++++++----- test/rasterization/dvr_triangle.cpp | 33 +- test/rasterization/dvr_triangle.h | 29 +- test/unit/dvt_unit_rasterizer.cpp | 4 +- 23 files changed, 879 insertions(+), 183 deletions(-) create mode 100644 source/core/include/pipe/dvc_render_step_OM.h create mode 100644 source/core/source/pipe/dvc_render_step_OM.cpp create mode 100644 test/rasterization/dvr_canvas.cpp create mode 100644 test/rasterization/dvr_canvas.h diff --git a/source/console/dv_console_main.cpp b/source/console/dv_console_main.cpp index dcb2420..3787a7e 100644 --- a/source/console/dv_console_main.cpp +++ b/source/console/dv_console_main.cpp @@ -14,13 +14,16 @@ #include -int32_t g_screenWidth = 1024; -int32_t g_screenHeight = 768; +int32_t g_screenWidth = 2048; +int32_t g_screenHeight = 1024; static SDL_Window* window = NULL; AdapterTexture g_adapterTexture; SDL_GLContext gl_context; davinci::RenderTarget g_renderTarget; +davinci::AntiAliasingTech g_aaTech = davinci::AntiAliasingTech::AA_None; +int32_t g_canvasWidth = 1024; +int32_t g_canvasHeight = 512; davinci::Scene g_scene; //------------------------------------------------------------------------------------- @@ -99,7 +102,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) // init davinci g_scene.init(); - g_renderTarget.init(512, 256); + g_renderTarget.init(g_canvasWidth, g_canvasHeight); g_adapterTexture.updateTexture(); return SDL_APP_CONTINUE; /* carry on with the program! */ @@ -153,7 +156,7 @@ SDL_AppResult SDL_AppIterate(void* appstate) //draw render result g_adapterTexture.updateTexture(0, 0, g_renderTarget.getColorBuffer()); - g_adapterTexture.updateTexture(512, 0, g_renderTarget.getDepthBuffer()); + g_adapterTexture.updateTexture(g_canvasWidth, 0, g_renderTarget.getDepthBuffer()); g_adapterTexture.draw(); //draw ui diff --git a/source/console/ui/ui_main.cpp b/source/console/ui/ui_main.cpp index ffc3115..4f2294c 100644 --- a/source/console/ui/ui_main.cpp +++ b/source/console/ui/ui_main.cpp @@ -21,6 +21,7 @@ SDL_Window* main_window; extern davinci::Scene g_scene; extern davinci::RenderTarget g_renderTarget; +extern davinci::AntiAliasingTech g_aaTech; bool initMainUI(SDL_Window* window, SDL_GLContext gl_context, const char* glsl_version) { @@ -96,6 +97,8 @@ void drawMainUI() { davinci_utils::export_mesh_to_obj(g_scene); } + const char* aaItem[] = { "None", "MSAA_2X2", "MSAA_4X4"}; + ImGui::Combo("AntiAliasing", (int*)(&g_aaTech), aaItem, IM_ARRAYSIZE(aaItem)); if (ImGui::Button("Render")) { davinci::UniformBuffer uniformBuffer; @@ -112,7 +115,9 @@ void drawMainUI() queue.build(g_scene); g_renderTarget.clear(); - queue.process(uniformBuffer, g_renderTarget); + queue.process(g_aaTech, uniformBuffer, g_renderTarget); + + davinci_utils::dump_render_target("d:\\rendertarget", g_renderTarget); } ImGui::End(); diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index d28d95d..2be2dfe 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -112,6 +112,7 @@ set(DV_CORE_PIPE_INCLUDE_FILES include/pipe/dvc_render_step_IA.h include/pipe/dvc_render_step_VS.h include/pipe/dvc_render_step_PS.h + include/pipe/dvc_render_step_OM.h ) source_group("include/pipe" FILES ${DV_CORE_PIPE_INCLUDE_FILES}) @@ -122,6 +123,7 @@ set(DV_CORE_PIPE_SOURCE_FILES source/pipe/dvc_render_step_IA.cpp source/pipe/dvc_render_step_VS.cpp source/pipe/dvc_render_step_PS.cpp + source/pipe/dvc_render_step_OM.cpp ) source_group("source/pipe" FILES ${DV_CORE_PIPE_SOURCE_FILES}) diff --git a/source/core/include/dvc_config.h b/source/core/include/dvc_config.h index 7bb1ca5..0707023 100644 --- a/source/core/include/dvc_config.h +++ b/source/core/include/dvc_config.h @@ -102,4 +102,12 @@ enum PixelFormat PF_UINT8_RGBA, }; +enum AntiAliasingTech +{ + AA_None, + + AA_MSAA_2X2, + AA_MSAA_4X4, +}; + DV_CORE_END_NAMESPACE diff --git a/source/core/include/pipe/dvc_render_queue.h b/source/core/include/pipe/dvc_render_queue.h index c4aa0dc..afcfeb3 100644 --- a/source/core/include/pipe/dvc_render_queue.h +++ b/source/core/include/pipe/dvc_render_queue.h @@ -17,9 +17,11 @@ public: RenderableConstPtr getRenderable(size_t index) const; void build(const Scene& scene); - void process(UniformBuffer& uniformBuffer, RenderTarget& renderTarget); + + void process(AntiAliasingTech aaTech, UniformBuffer& uniformBuffer, RenderTarget& renderTarget); protected: + AntiAliasingTech m_aaTech; std::vector m_queue; public: diff --git a/source/core/include/pipe/dvc_render_step_IA.h b/source/core/include/pipe/dvc_render_step_IA.h index e3ee92f..f662e2d 100644 --- a/source/core/include/pipe/dvc_render_step_IA.h +++ b/source/core/include/pipe/dvc_render_step_IA.h @@ -23,11 +23,8 @@ public: public: void process(const RenderQueue& renderQueue); - const NodeArray& getNodes(void) const { - return m_nodes; - } -protected: +public: NodeArray m_nodes; }; diff --git a/source/core/include/pipe/dvc_render_step_OM.h b/source/core/include/pipe/dvc_render_step_OM.h new file mode 100644 index 0000000..0f70a40 --- /dev/null +++ b/source/core/include/pipe/dvc_render_step_OM.h @@ -0,0 +1,87 @@ +#pragma once + +#include "dvc_config.h" +#include "dvc_render_step_PS.h" + +DV_CORE_BEGIN_NAMESPACE + +class OutputMergerStep +{ +public: + void process(const PixelShaderStep::StartOffsetArray& startOffsetArray, const PixelShaderStep::FragementArray& fragementArray, + AntiAliasingTech aaTech, RenderTarget& renderTarget); + +private: + void mergeFragement_without_AA(int32_t x, int32_t y, + const std::multimap& fragementArrayMap, + const PixelShaderStep::FragementArray& fragementArray, RenderTarget& renderTarget); + + template + void mergeFragement_with_AA(int32_t x, int32_t y, + const std::multimap& fragementArrayMap, + const PixelShaderStep::FragementArray& fragementArray, RenderTarget& renderTarget); +}; + +template +void OutputMergerStep::mergeFragement_with_AA(int32_t x, int32_t y, const std::multimap& fragementArrayMap, + const PixelShaderStep::FragementArray& fragementArray, RenderTarget& renderTarget) +{ + if (fragementArrayMap.empty()) + { + return; + } + else if (fragementArrayMap.size() == 1) + { + const PixelShaderStep::Fragement& fragement = fragementArray[fragementArrayMap.begin()->second]; + + fVector4 finalColor = fragement.color; + finalColor.w = MathUtil::popcount((uint16_t)(fragement.mask & kSampleMask)) / (float32_t)kSampleSize; + + renderTarget.setPixel(x, y, finalColor, fragement.depth); + } + else + { + std::array samples; + samples.fill(-1); + + float finalDepth = 0; + std::multimap::const_iterator it, end = fragementArrayMap.end(); + for (it = fragementArrayMap.begin(); it != end; ++it) + { + const PixelShaderStep::Fragement& fragement = fragementArray[it->second]; + for (int32_t k = 0; k < kSampleSize; k++) + { + if ((fragement.mask & (1 << k)) != 0) + { + samples[k] = it->second; + } + } + finalDepth = fragement.depth; + } + + fVector3 finalColor(0.f, 0.f, 0.f); + int32_t bitCounts = 0; + for (int32_t k = 0; k < kSampleSize; k++) + { + int32_t fragementID = samples[k]; + if (fragementID < 0 || fragementID >= fragementArray.size()) continue; + + const PixelShaderStep::Fragement& fragement = fragementArray[fragementID]; + finalColor += fragement.color.xyz(); + bitCounts++; + } + + if (bitCounts == 0) + { + return; + } + if (bitCounts > 1) + { + finalColor /= (float32_t)bitCounts; + } + float32_t finalAlpha = bitCounts / (float32_t)kSampleSize; + renderTarget.setPixel(x, y, fVector4(finalColor, finalAlpha), finalDepth); + } +} + +DV_CORE_END_NAMESPACE diff --git a/source/core/include/pipe/dvc_render_step_PS.h b/source/core/include/pipe/dvc_render_step_PS.h index df3c41a..7d0a905 100644 --- a/source/core/include/pipe/dvc_render_step_PS.h +++ b/source/core/include/pipe/dvc_render_step_PS.h @@ -8,8 +8,23 @@ DV_CORE_BEGIN_NAMESPACE class PixelShaderStep { public: - void process(const VertexShaderStep::NodeArray& vsNodeArray, RenderTarget& renderTarget); + struct Fragement + { + float32_t depth; + fVector4 color; + uint32_t mask; + int32_t next; + }; + typedef std::vector StartOffsetArray; + typedef std::vector FragementArray; + +public: + void process(const VertexShaderStep::NodeArray& vsNodeArray, AntiAliasingTech aaTech, int32_t canvasWidth, int32_t canvasHeight); + +public: + StartOffsetArray m_startOffsetArray; + FragementArray m_fragementArray; }; DV_CORE_END_NAMESPACE diff --git a/source/core/include/pipe/dvc_render_step_VS.h b/source/core/include/pipe/dvc_render_step_VS.h index 6e7ef5b..5927d8d 100644 --- a/source/core/include/pipe/dvc_render_step_VS.h +++ b/source/core/include/pipe/dvc_render_step_VS.h @@ -20,15 +20,10 @@ public: }; typedef std::vector NodeArray; -public: - const NodeArray& getNodes() const { - return m_nodes; - } - public: void process(UniformBuffer& uniformBuffer, const InputAssemberStep::NodeArray& assembedNodeArray); -protected: +public: NodeArray m_nodes; }; diff --git a/source/core/include/rasterizer/dvc_rasterizer_triangle.h b/source/core/include/rasterizer/dvc_rasterizer_triangle.h index f988cf2..59bdc0a 100644 --- a/source/core/include/rasterizer/dvc_rasterizer_triangle.h +++ b/source/core/include/rasterizer/dvc_rasterizer_triangle.h @@ -10,7 +10,9 @@ class DV_CORE_API Rasterizer { //Draw Triangle with Larrabee public: - typedef std::function& pos, const fVector3& percent)> DrawTriangleCallback; + typedef std::function< + void(const std::pair& pos, const fVector3& percent, uint32_t mask) + > DrawTriangleCallback; struct DebugParam { @@ -27,9 +29,10 @@ public: }; //Larrabee algorithm - static void drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, + static void drawTriangleLarrabee(AntiAliasingTech aaTech, int32_t canvasWidth, int32_t canvasHeight, const fVector2& v0, const fVector2& v1, const fVector2& v2, - DrawTriangleCallback callback, bool ccw=true, const DebugParam* debugParam=nullptr); + DrawTriangleCallback callback, bool ccw=true, + const DebugParam* debugParam=nullptr); public: //BoundingBox algorithm diff --git a/source/core/source/device/dvc_render_target.cpp b/source/core/source/device/dvc_render_target.cpp index 6db705d..59fff77 100644 --- a/source/core/source/device/dvc_render_target.cpp +++ b/source/core/source/device/dvc_render_target.cpp @@ -16,7 +16,7 @@ void RenderTarget::init(int32_t width, int32_t height) void RenderTarget::clear() { - m_colorBuffer.clear(fVector4::BLACK); + m_colorBuffer.clear(fVector4(0.f, 0.f, 0.f, 0.f)); m_depthBuffer.clear(std::numeric_limits::max()); } @@ -25,7 +25,7 @@ void RenderTarget::setPixel(int32_t x, int32_t y, const fVector4& color, float32 if (x < 0 || x >= m_width || y < 0 || y >= m_height) return; if (depth > m_depthBuffer.getPixel(x, y)) { - return; + // return; } m_colorBuffer.setPixel(x, y, color); m_depthBuffer.setPixel(x, y, depth); diff --git a/source/core/source/pipe/dvc_render_queue.cpp b/source/core/source/pipe/dvc_render_queue.cpp index 0dba60f..e2c85c6 100644 --- a/source/core/source/pipe/dvc_render_queue.cpp +++ b/source/core/source/pipe/dvc_render_queue.cpp @@ -3,6 +3,7 @@ #include "pipe/dvc_render_step_IA.h" #include "pipe/dvc_render_step_VS.h" #include "pipe/dvc_render_step_PS.h" +#include "pipe/dvc_render_step_OM.h" #include "scene/component/dvc_camera_component.h" DV_CORE_BEGIN_NAMESPACE @@ -38,19 +39,25 @@ void RenderQueue::build(const Scene& scene) scene.getRootSceneNode()->buildRenderQueue(fMatrix4::IDENTITY, *this); } -void RenderQueue::process(UniformBuffer& uniformBuffer, RenderTarget& renderTarget) +void RenderQueue::process(AntiAliasingTech aaTech, UniformBuffer& uniformBuffer, RenderTarget& renderTarget) { + m_aaTech = aaTech; + //Assembere input InputAssemberStep IA; IA.process(*this); //Vertex shader VertexShaderStep VS; - VS.process(uniformBuffer, IA.getNodes()); + VS.process(uniformBuffer, IA.m_nodes); //Pixel shader PixelShaderStep PS; - PS.process(VS.getNodes(), renderTarget); + PS.process(VS.m_nodes, m_aaTech, renderTarget.getWidth(), renderTarget.getHeight()); + + //Output Merge + OutputMergerStep OM; + OM.process(PS.m_startOffsetArray, PS.m_fragementArray, m_aaTech, renderTarget); } DV_CORE_END_NAMESPACE diff --git a/source/core/source/pipe/dvc_render_step_OM.cpp b/source/core/source/pipe/dvc_render_step_OM.cpp new file mode 100644 index 0000000..f0e6f29 --- /dev/null +++ b/source/core/source/pipe/dvc_render_step_OM.cpp @@ -0,0 +1,54 @@ +#include "pipe/dvc_render_step_OM.h" + +DV_CORE_BEGIN_NAMESPACE + +void OutputMergerStep::process(const PixelShaderStep::StartOffsetArray& startOffsetArray, const PixelShaderStep::FragementArray& fragementArray, + AntiAliasingTech aaTech, RenderTarget& renderTarget) +{ + int32_t canvasWidth = renderTarget.getWidth(); + int32_t canvasHeight = renderTarget.getHeight(); + + for (int32_t y = 0; y < canvasHeight; y++) + { + for (int32_t x = 0; x < canvasWidth; x++) + { + int32_t fragementID = startOffsetArray[y * canvasWidth + x]; + std::multimap fragementArrayMap; + + while (fragementID >=0 && fragementID < (int32_t)fragementArray.size()) + { + const PixelShaderStep::Fragement& fragement = fragementArray[fragementID]; + fragementArrayMap.insert(std::make_pair(-fragement.depth, fragementID)); + fragementID = fragement.next; + } + + if (aaTech == AntiAliasingTech::AA_None) + { + mergeFragement_without_AA(x, y, fragementArrayMap, fragementArray, renderTarget); + } + else if (aaTech == AntiAliasingTech::AA_MSAA_2X2) + { + mergeFragement_with_AA<4, 0xF>(x, y, fragementArrayMap, fragementArray, renderTarget); + } + else if (aaTech == AntiAliasingTech::AA_MSAA_4X4) + { + mergeFragement_with_AA<16, 0xFFFF>(x, y, fragementArrayMap, fragementArray, renderTarget); + } + } + } +} + +void OutputMergerStep::mergeFragement_without_AA(int32_t x, int32_t y, const std::multimap& fragementArrayMap, + const PixelShaderStep::FragementArray& fragementArray, RenderTarget& renderTarget) +{ + if (fragementArrayMap.empty()) + { + return; + } + + const PixelShaderStep::Fragement& firstFragement = fragementArray[fragementArrayMap.rbegin()->second]; + renderTarget.setPixel(x, y, firstFragement.color, firstFragement.depth); +} + +DV_CORE_END_NAMESPACE + diff --git a/source/core/source/pipe/dvc_render_step_PS.cpp b/source/core/source/pipe/dvc_render_step_PS.cpp index f867b8a..529dc91 100644 --- a/source/core/source/pipe/dvc_render_step_PS.cpp +++ b/source/core/source/pipe/dvc_render_step_PS.cpp @@ -6,17 +6,16 @@ DV_CORE_BEGIN_NAMESPACE -void PixelShaderStep::process(const VertexShaderStep::NodeArray& vsNodeArray, RenderTarget& renderTarget) +void PixelShaderStep::process(const VertexShaderStep::NodeArray& vsNodeArray, AntiAliasingTech aaTech, int32_t canvasWidth, int32_t canvasHeight) { ShaderFileInterface* shaderInterface = davinci::LoadShaderFile("TestShader.dll"); PixelShaderInterface* pixelShader = shaderInterface->getPixelShader("xxx"); - int32_t targetWidth = renderTarget.getWidth(); - int32_t targetHeight = renderTarget.getHeight(); - fMatrix4 view_trans = - fMatrix4::makeTrans(targetWidth / 2.f, targetHeight / 2.f, 0.f) * - fMatrix4::makeScale(targetWidth / 2.f, targetHeight / 2.f, 1.f); + fMatrix4::makeTrans(canvasWidth / 2.f, canvasHeight / 2.f, 0.f) * + fMatrix4::makeScale(canvasWidth / 2.f, canvasHeight / 2.f, 1.f); + + m_startOffsetArray.resize(canvasWidth* canvasHeight, -1); VertexShaderStep::NodeArray::const_iterator it, end = vsNodeArray.end(); for (it = vsNodeArray.begin(); it != end; ++it) @@ -39,9 +38,10 @@ void PixelShaderStep::process(const VertexShaderStep::NodeArray& vsNodeArray, Re std::vector invZ = { node.invZ[i + 0], node.invZ[i + 1], node.invZ[i + 2] }; std::vector vertexDepth = { node.depth[i+0], node.depth[i + 1], node.depth[i + 2]}; - Rasterizer::drawTriangleLarrabee(targetWidth, targetHeight, pos0.xy(), pos1.xy(), pos2.xy(), - [pixelShader, vertex0, vertex1, vertex2, invZ, vertexDepth, &node, &renderTarget] - (const std::pair& dot, const fVector3& percent) + Rasterizer::drawTriangleLarrabee(aaTech, + canvasWidth, canvasHeight, pos0.xy(), pos1.xy(), pos2.xy(), + [this, canvasWidth, pixelShader, vertex0, vertex1, vertex2, invZ, vertexDepth, &node] + (const std::pair& dot, const fVector3& percent, uint32_t mask) { fVector3 percentCorrected(percent); @@ -65,7 +65,16 @@ void PixelShaderStep::process(const VertexShaderStep::NodeArray& vsNodeArray, Re int32_t x = dot.first; int32_t y = dot.second; - renderTarget.setPixel(x, y, color, depth); + int32_t currentOffset = m_startOffsetArray[x + y * canvasWidth]; + + m_startOffsetArray[x + y * canvasWidth] = (int32_t)(m_fragementArray.size()); + + Fragement newFragment; + newFragment.color = color; + newFragment.depth = depth; + newFragment.mask = mask; + newFragment.next = currentOffset; + this->m_fragementArray.push_back(newFragment); } ); } diff --git a/source/core/source/rasterizer/dvc_rasterizer_triangle.cpp b/source/core/source/rasterizer/dvc_rasterizer_triangle.cpp index b5ad10f..91a175d 100644 --- a/source/core/source/rasterizer/dvc_rasterizer_triangle.cpp +++ b/source/core/source/rasterizer/dvc_rasterizer_triangle.cpp @@ -20,22 +20,27 @@ inline bool operator==(const bool3_t& arr, bool value) struct DrawTriangleParam { - bool ccw; - fVector2 verts[3]; - float32_t bbox_min_x; - float32_t bbox_max_x; - float32_t bbox_min_y; - float32_t bbox_max_y; - bool3_t tlBorder; - float32_t area; - iFloat3 edgesDX, edgesDY; - iFloat3 halfEdge; + AntiAliasingTech aaTech; + bool ccw; + fVector2 verts[3]; + float32_t bbox_min_x; + float32_t bbox_max_x; + float32_t bbox_min_y; + float32_t bbox_max_y; + bool3_t tlBorder; + float32_t area; + iFloat3 edgesDX, edgesDY; + + iFloat3 halfEdge; + iFloat3 quaterEdge; + iFloat3 oneEighthEdge; + Rasterizer::DebugParam debugParam; }; enum { MIN_TILE_WIDTH_IN_PIXELS = 64 }; -void _fillPixel(const DrawTriangleParam& param, int32_t xLB, int32_t yLB, Rasterizer::DrawTriangleCallback callback) +void _fillPixel(const DrawTriangleParam& param, int32_t xLB, int32_t yLB, uint32_t mask, Rasterizer::DrawTriangleCallback callback) { fVector2 pixel(xLB + 0.5f, yLB + 0.5f); const fVector2 v0(param.verts[0]), v1(param.verts[1]), v2(param.verts[2]); @@ -46,42 +51,140 @@ void _fillPixel(const DrawTriangleParam& param, int32_t xLB, int32_t yLB, Raster fVector3 t = fVector3(w0 / param.area, (param.ccw ? w1 : w2) / param.area, (param.ccw ? w2 : w1) / param.area); - callback(std::make_pair(xLB, yLB), t); + callback(std::make_pair(xLB, yLB), t, mask); } void _fillTile(const DrawTriangleParam& param, int32_t currentTileSize, int32_t xLB, int32_t yLB, Rasterizer::DrawTriangleCallback callback) { - if (currentTileSize == 1) - { - _fillPixel(param, xLB, yLB, callback); - return; - } - for (int32_t yIndex = yLB; yIndex < yLB + currentTileSize; yIndex++) { for (int32_t xIndex = xLB; xIndex < xLB + currentTileSize; xIndex++) { - _fillPixel(param, xIndex, yIndex, callback); + _fillPixel(param, xIndex, yIndex, ~0, callback); } } } -void _drawPixel(DrawTriangleParam& param, +void _drawPixel_without_AA(DrawTriangleParam& param, int32_t xLB, int32_t yLB, const iFloat3& edgesLB, const bool3_t& intersectant, Rasterizer::DrawTriangleCallback callback) { iFloat3 centerEdges(edgesLB); centerEdges.add(param.halfEdge); - bool insideTriangle = + bool insideTriangle = (centerEdges.x > 0 || (param.tlBorder[0] && centerEdges.x == 0)) && (centerEdges.y > 0 || (param.tlBorder[1] && centerEdges.y == 0)) && (centerEdges.z > 0 || (param.tlBorder[2] && centerEdges.z == 0)); if (insideTriangle) { - _fillPixel(param, xLB, yLB, callback); + _fillPixel(param, xLB, yLB, ~0, callback); + } +} + +void _drawPixel_with_MSAA2X2(DrawTriangleParam& param, + int32_t x, int32_t y, const iFloat3& edgesLB, const bool3_t& intersectant, + Rasterizer::DrawTriangleCallback callback) +{ + // 2x2 MSAA; + iFloat3 sampleEdgesDX(param.edgesDX); + sampleEdgesDX.mul(iFloat::kHalf); + + iFloat3 sampleEdgesDY(param.edgesDY); + sampleEdgesDY.mul(iFloat::kHalf); + + iFloat3 firstSampleEdges(edgesLB); + firstSampleEdges.add(param.quaterEdge); // 0.25f + + iFloat3 rowEdges(firstSampleEdges); + + uint32_t mask = 0; + for (int32_t yIndex = 0; yIndex < 2; yIndex++) + { + iFloat3 sampleEdges(rowEdges); + + for (int32_t xIndex = 0; xIndex < 2; xIndex++) + { + bool sampleInsideTriangle = + (sampleEdges.x > 0 || (param.tlBorder[0] && sampleEdges.x == 0)) && + (sampleEdges.y > 0 || (param.tlBorder[1] && sampleEdges.y == 0)) && + (sampleEdges.z > 0 || (param.tlBorder[2] && sampleEdges.z == 0)); + + if (sampleInsideTriangle) + { + mask |= (1 << (yIndex * 2 + xIndex)); + } + + sampleEdges.sub(sampleEdgesDY); + } + + rowEdges.add(sampleEdgesDX); + } + + _fillPixel(param, x, y, mask, callback); +} + +void _drawPixel_with_MSAA4X4(DrawTriangleParam& param, + int32_t x, int32_t y, const iFloat3& edgesLB, const bool3_t& intersectant, + Rasterizer::DrawTriangleCallback callback) +{ + // 4x4 MSAA; + iFloat3 sampleEdgesDX(param.edgesDX); + sampleEdgesDX.mul(iFloat::kQuater); + + iFloat3 sampleEdgesDY(param.edgesDY); + sampleEdgesDY.mul(iFloat::kQuater); + + iFloat3 firstSampleEdges(edgesLB); + firstSampleEdges.add(param.oneEighthEdge); // 0.125f + + iFloat3 rowEdges(firstSampleEdges); + + uint32_t mask = 0; + for (int32_t yIndex = 0; yIndex < 4; yIndex++) + { + iFloat3 sampleEdges(rowEdges); + + for (int32_t xIndex = 0; xIndex < 4; xIndex++) + { + bool sampleInsideTriangle = + (sampleEdges.x > 0 || (param.tlBorder[0] && sampleEdges.x == 0)) && + (sampleEdges.y > 0 || (param.tlBorder[1] && sampleEdges.y == 0)) && + (sampleEdges.z > 0 || (param.tlBorder[2] && sampleEdges.z == 0)); + + if (sampleInsideTriangle) + { + mask |= (1 << (yIndex * 4 + xIndex)); + } + + sampleEdges.sub(sampleEdgesDY); + } + + rowEdges.add(sampleEdgesDX); + } + + _fillPixel(param, x, y, mask, callback); +} + +void _drawPixel(DrawTriangleParam& param, + int32_t xLB, int32_t yLB, const iFloat3& edgesLB, const bool3_t& intersectant, + Rasterizer::DrawTriangleCallback callback) +{ + switch (param.aaTech) + { + case AntiAliasingTech::AA_MSAA_4X4: + _drawPixel_with_MSAA4X4(param, xLB, yLB, edgesLB, intersectant, callback); + break; + + case AntiAliasingTech::AA_MSAA_2X2: + _drawPixel_with_MSAA2X2(param, xLB, yLB, edgesLB, intersectant, callback); + break; + + case AntiAliasingTech::AA_None: + default: + _drawPixel_without_AA(param, xLB, yLB, edgesLB, intersectant, callback); } } @@ -198,7 +301,7 @@ void _drawTriangle_Tile(DrawTriangleParam& param, int32_t currentTileSize, } } -void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, +void Rasterizer::drawTriangleLarrabee(AntiAliasingTech aaTech, int32_t canvasWidth, int32_t canvasHeight, const fVector2& v0, const fVector2& v1, const fVector2& v2, DrawTriangleCallback callback, bool ccw, const DebugParam* debugParam) { @@ -225,6 +328,7 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, tileSize /= 4; DrawTriangleParam param; + param.aaTech = aaTech; int32_t widthInTiles = canvasWidth / tileSize; //Whether the three input vertices are in the agreed clockwise order or not, @@ -285,7 +389,10 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, size_t v_end = (v + 1) % 3; param.edgesDX[v] = vertices[v_end].x - vertices[v].x; param.edgesDY[v] = vertices[v_end].y - vertices[v].y; + param.halfEdge[v] = (param.edgesDX[v]- param.edgesDY[v]) * iFloat::kHalf; + param.quaterEdge[v] = (param.edgesDX[v] - param.edgesDY[v]) * iFloat::kQuater; + param.oneEighthEdge[v] = (param.edgesDX[v] - param.edgesDY[v]) * iFloat::kOneEighth; tileEdgesDX[v] = param.edgesDX[v] * tileSize; tileEdgesDY[v] = param.edgesDY[v] * tileSize; @@ -374,8 +481,6 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, } iFloat3 rowEdges(edgesFirstLB); - - int32_t tile_row_start = first_tile_y * tileSize + first_tile_x; int32_t yLB = first_tile_y * tileSize; for (int32_t tile_y = first_tile_y; tile_y <= last_tile_y; tile_y++) @@ -384,7 +489,6 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, iFloat3 tileEdgesReject(edgesReject); iFloat3 tileEdgesAccept(edgesAccept); - int32_t tile_i = tile_row_start; int32_t xLB = first_tile_x * tileSize; for (int32_t tile_x = first_tile_x; tile_x <= last_tile_x; tile_x++) @@ -414,7 +518,6 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, edgesTileLB.sub(tileEdgesDY); tileEdgesReject.sub(tileEdgesDY); tileEdgesAccept.sub(tileEdgesDY); - tile_i++; xLB += tileSize; } @@ -422,7 +525,6 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight, rowEdges.add(tileEdgesDX); edgesReject.add(tileEdgesDX); edgesAccept.add(tileEdgesDX); - tile_row_start += widthInTiles; yLB += tileSize; } @@ -505,7 +607,7 @@ void Rasterizer::drawTriangleBoundingBox(int32_t canvasWidth, int32_t canvasHeig fVector3 t = fVector3(w0 / area, (ccw ? w1 : w2) / area, (ccw ? w2 : w1) / area); - callback(std::make_pair(x, y), t); + callback(std::make_pair(x, y), t, ~0); } } } diff --git a/source/dv_config.h.in b/source/dv_config.h.in index 9bab598..449c208 100644 --- a/source/dv_config.h.in +++ b/source/dv_config.h.in @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/test/rasterization/CMakeLists.txt b/test/rasterization/CMakeLists.txt index 371305e..06d720d 100644 --- a/test/rasterization/CMakeLists.txt +++ b/test/rasterization/CMakeLists.txt @@ -8,6 +8,8 @@ add_executable(dvt_rasterization WIN32 dvr_main.cpp dvr_triangle.h dvr_triangle.cpp + dvr_canvas.h + dvr_canvas.cpp ) set_property(TARGET dvt_rasterization PROPERTY FOLDER "test") diff --git a/test/rasterization/dvr_canvas.cpp b/test/rasterization/dvr_canvas.cpp new file mode 100644 index 0000000..2b977c8 --- /dev/null +++ b/test/rasterization/dvr_canvas.cpp @@ -0,0 +1,83 @@ +#include "dvr_canvas.h" + +#include + +#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ +#include + +void Canvas::reset(int32_t width, int32_t height) +{ + m_width = width; + m_height = height; + m_pixels.resize(m_width * m_height); + + for (int32_t i = 0; i < m_width * m_height; i++) + { + m_pixels[i].fragementID = -1; + m_pixels[i].mask = 0; + m_pixels[i].color = 0; + } + + m_fragementArray.clear(); +} + +void Canvas::_insertTriangle(const Triangle& triangle) +{ + for (size_t i = 0; i < triangle.m_pixels.size(); i++) + { + const Triangle::Pixel trianglePixel = triangle.m_pixels[i]; + Pixel& pixel = m_pixels[trianglePixel.y * m_width + trianglePixel.x]; + + Fragement newFragement; + newFragement.id = (int32_t)m_fragementArray.size(); + newFragement.color = triangle.m_pixelColor; + newFragement.mask = trianglePixel.mask; + newFragement.next = pixel.fragementID; + + pixel.fragementID = newFragement.id; + m_fragementArray.push_back(newFragement); + } +} + +void Canvas::_update_without_AA() +{ + for (size_t i = 0; i < m_pixels.size(); i++) + { + Pixel& pixel = m_pixels[i]; + if (pixel.fragementID < 0) continue; + + const Fragement& fragement = m_fragementArray[pixel.fragementID]; + pixel.mask = fragement.mask; + pixel.color = fragement.color; + pixel.alpha = 1.f; + } +} + +void Canvas::update(davinci::AntiAliasingTech aaTech, const TriangleArray& triangleArray, const Triangle* pActionTriangle) +{ + reset(m_width, m_height); + + for (size_t i = 0; i < triangleArray.size(); i++) + { + const Triangle& triangle = triangleArray[i]; + _insertTriangle(triangle); + } + + if (pActionTriangle != nullptr) + { + _insertTriangle(*pActionTriangle); + } + + if (aaTech == davinci::AntiAliasingTech::AA_None) + { + _update_without_AA(); + } + else if (aaTech == davinci::AntiAliasingTech::AA_MSAA_2X2) + { + _update_with_AA<4>(); + } + else if ( aaTech == davinci::AntiAliasingTech::AA_MSAA_4X4) + { + _update_with_AA<16>(); + } +} diff --git a/test/rasterization/dvr_canvas.h b/test/rasterization/dvr_canvas.h new file mode 100644 index 0000000..bc358a2 --- /dev/null +++ b/test/rasterization/dvr_canvas.h @@ -0,0 +1,108 @@ +#pragma once + +#include "dvr_triangle.h" +#include "math/dvc_vector4.h" + +class Canvas +{ +public: + struct Pixel + { + davinci::fVector3 color; + float alpha; + uint32_t mask; + int32_t fragementID; + }; + typedef std::vector PixelArray; + + struct Fragement + { + int32_t id; + davinci::fVector3 color; + uint32_t mask; + int32_t next; + }; + typedef std::vector FragementArray; + +public: + int32_t width() const { return m_width; } + int32_t height() const { return m_height; } + const Pixel& pixel(int32_t x, int32_t y) const + { + return m_pixels[y * m_width + x]; + } + + void reset(int32_t width, int32_t height); + void update(davinci::AntiAliasingTech aaTech, const TriangleArray& riangleArray, const Triangle* pActionTriangle = nullptr); + +private: + void _insertTriangle(const Triangle& triangle); + void _update_without_AA(); + + template + void _update_with_AA() + { + for (size_t i = 0; i < m_pixels.size(); i++) + { + Pixel& pixel = m_pixels[i]; + if (pixel.fragementID < 0) continue; + + FragementArray pixelFragements; + int32_t fragementID = pixel.fragementID; + while (fragementID >= 0 && fragementID < m_fragementArray.size()) + { + const Fragement& fragement = m_fragementArray[fragementID]; + pixelFragements.insert(pixelFragements.begin(), fragement); + fragementID = fragement.next; + } + + if (pixelFragements.size() == 0) continue; + else if (pixelFragements.size() == 1) + { + const Fragement& fragement = pixelFragements[0]; + pixel.mask = fragement.mask; + pixel.color = fragement.color; + pixel.alpha = davinci::MathUtil::popcount((uint16_t)(fragement.mask)) / (float32_t)kSampleSize; + } + else + { + std::array samples; + samples.fill(-1); + for (size_t j = 0; j < pixelFragements.size(); j++) + { + const Fragement& fragement = pixelFragements[j]; + for (int32_t k = 0; k < kSampleSize; k++) + { + if ((fragement.mask & (1 << k)) != 0) + { + samples[k] = fragement.id; + } + } + } + + pixel.mask = 0; + int32_t bitCounts = 0; + for (int32_t k = 0; k < kSampleSize; k++) + { + int32_t fragementID = samples[k]; + if (fragementID < 0 || fragementID>m_fragementArray.size()) continue; + + const Fragement& fragement = m_fragementArray[fragementID]; + pixel.mask |= (1 << k); + pixel.color += fragement.color; + bitCounts++; + } + if (bitCounts > 1) { + pixel.color /= (float32_t)bitCounts; + } + pixel.alpha = bitCounts / (float32_t)kSampleSize; + } + } + } + +private: + int32_t m_width; + int32_t m_height; + PixelArray m_pixels; // final pixels in the canvas + FragementArray m_fragementArray; +}; diff --git a/test/rasterization/dvr_main.cpp b/test/rasterization/dvr_main.cpp index d42d135..ade3272 100644 --- a/test/rasterization/dvr_main.cpp +++ b/test/rasterization/dvr_main.cpp @@ -12,6 +12,8 @@ #include "math/dvc_vector3.h" #include "dvr_triangle.h" +#include "dvr_canvas.h" +#include "rasterizer/dvc_rasterizer_triangle.h" using namespace davinci; @@ -19,53 +21,57 @@ enum MouseAction { MT_NULL, MT_FIRST_LINE, - MT_TRIANGLE + MT_TRIANGLE, + + MT_PAN, }; const float MIN_SCALE = 4.f; -const float MAX_SCALE = 60.f; +const float MAX_SCALE = 120.f; const float TRIANGLE_BORDER_WIDTH = 1.5f; const float ACTION_WIDTH = 1.f; const fVector3 GRID_BORDER_COLOR = fVector3(0.f, 0.f, 0.f); -const fVector3 GRID_CROSS_COLOR = fVector3(0.8f, 0.8f, 0.8f); +const fVector3 GRID_CROSS_COLOR = fVector3(0.1f, 0.1f, 0.1f); const fVector3 TRIANGLE_BORDER_COLOR = fVector3(0.f, 0.f, 0.f); const fVector3 ACTION_COLOR = fVector3(1.f, 0.f, 0.f); - +const int32_t CANVAS_WIDTH = 512; +const int32_t CANVAS_HEIGHT = 256; int32_t g_viewWidth = 2048; int32_t g_viewHeight = 1440; -int32_t g_canvasWidth; -int32_t g_canvasHeight; -float32_t g_scale = MAX_SCALE; +float32_t g_scale = MAX_SCALE/2.0f; int32_t g_lbCorner_x = 20; int32_t g_lbCorner_y = 20; int32_t g_nDrawGridLevel = 0; //0:all 1:fine+coarse+tile 2:coarse+tile 3: tile +int32_t g_screenMousePosX = 0, g_screenMousePosY = 0; float32_t g_mousePosX, g_mousePosY; bool g_bSnapMode = true; float g_fSnapSize = 0.25f; MouseAction g_currentAction = MT_NULL; bool g_bDrawExtension = false; -Triangle g_currentTriangle; -TriangleVector g_allTriangles; +int32_t g_nStartPanX, g_nStartPanY; +int32_t g_nPanX, g_nPanY; + +Triangle g_currentTriangle(INT_MAX, ACTION_COLOR); +TriangleArray g_allTriangles; +Canvas g_canvas; +AntiAliasingTech g_aaTech = AntiAliasingTech::AA_None; SDL_Window* g_window = NULL; SDL_Renderer* g_renderer = NULL; -#define trans_w2s_x(x) ((float32_t)(x) * g_scale + g_lbCorner_x) -#define trans_w2s_y(y) ((float32_t)g_viewHeight - ((float32_t)(y) * g_scale + g_lbCorner_y)) +#define trans_w2s_x(x) ((float32_t)(x) * g_scale + g_lbCorner_x + g_nPanX) +#define trans_w2s_y(y) ((float32_t)g_viewHeight - ((float32_t)(y) * g_scale + g_lbCorner_y + g_nPanY)) -#define trans_s2w_x(x) ((float32_t)(x - g_lbCorner_x) / g_scale) -#define trans_s2w_y(y) ((float32_t)(g_viewHeight - y - g_lbCorner_y) / g_scale) +#define trans_s2w_x(x) ((float32_t)(x - g_lbCorner_x - g_nPanX) / g_scale) +#define trans_s2w_y(y) ((float32_t)(g_viewHeight - y - g_lbCorner_y - g_nPanY) / g_scale) void _onFramebufferSize(int32_t w, int32_t h) { g_viewWidth = w; g_viewHeight = h > 0 ? h : 1; - g_canvasWidth = ((int32_t)floorf(g_viewWidth / (g_scale * 64)) + 1) * 64; - g_canvasHeight = ((int32_t)floorf(g_viewHeight / (g_scale * 64)) + 1) * 64; - if (g_scale < 10.f) g_nDrawGridLevel = 3; else if (g_scale < 20.f) g_nDrawGridLevel = 2; else if (g_scale < 50.f) g_nDrawGridLevel = 1; @@ -77,11 +83,28 @@ static void _drawGrid(void) int32_t horLength = (int32_t)floorf(g_viewWidth / g_scale); int32_t verLength = (int32_t)floorf(g_viewHeight / g_scale); + // draw canvas background + SDL_FRect rect; + rect.x = trans_w2s_x(0); + rect.y = trans_w2s_y(0); + rect.w = g_canvas.width() * g_scale; + rect.h = -g_canvas.height() * g_scale; + SDL_SetRenderDrawColorFloat(g_renderer, 255, 255, 255, SDL_ALPHA_OPAQUE_FLOAT); + SDL_RenderFillRect(g_renderer, &rect); + fVector3 lineColor[] = { fVector3(0.f, 0.f, 0.f), fVector3(0.5f, 0.5f, 0.5f), fVector3(0.7f,0.7f,0.7f), fVector3(0.9f, 0.9f,0.9f) }; // Horizontal lines - for (int i = 0; i <= verLength; i++) { - int level = 3; + for (int32_t i = (int32_t)trans_s2w_y(0); ; i--) + { + if (i > g_canvas.height()) continue; + if (i < 0) break; + + float32_t screenY = trans_w2s_y(i); + if (screenY < 0) continue; + if (screenY > g_viewHeight) break; + + int32_t level = 3; if (i % 64 == 0)level = 0; else if (i % 16 == 0) level = 1; @@ -89,13 +112,20 @@ static void _drawGrid(void) if (level > 3 - g_nDrawGridLevel) continue; SDL_SetRenderDrawColorFloat(g_renderer, lineColor[level].x, lineColor[level].y, lineColor[level].z, SDL_ALPHA_OPAQUE_FLOAT); - - SDL_RenderLine(g_renderer, trans_w2s_x(0), trans_w2s_y(i), trans_w2s_x(horLength), trans_w2s_y(i)); + SDL_RenderLine(g_renderer, trans_w2s_x(0), screenY, trans_w2s_x(g_canvas.width()), screenY); } // Vertical lines - for (int j = 0; j <= horLength; j++) { - int level = 3; + for (int32_t j = (int32_t)trans_s2w_x(0); ; j++) + { + if (j < 0) continue; + if (j > g_canvas.width()) break; + + float32_t screenX = trans_w2s_x(j); + if (screenX < 0) continue; + if (screenX > g_viewWidth) break; + + int32_t level = 3; if (j % 64 == 0)level = 0; else if (j % 16 == 0) level = 1; @@ -103,47 +133,7 @@ static void _drawGrid(void) if (level > 3 - g_nDrawGridLevel) continue; SDL_SetRenderDrawColorFloat(g_renderer, lineColor[level].x, lineColor[level].y, lineColor[level].z, SDL_ALPHA_OPAQUE_FLOAT); - SDL_RenderLine(g_renderer, trans_w2s_x(j), trans_w2s_y(0), trans_w2s_x(j), trans_w2s_y(verLength)); - } - - //cross - if (g_nDrawGridLevel < 3) - { - SDL_SetRenderDrawColorFloat(g_renderer, GRID_CROSS_COLOR.x, GRID_CROSS_COLOR.y, GRID_CROSS_COLOR.z, SDL_ALPHA_OPAQUE_FLOAT); - - float crossLength = 0.2f; - for (int i = 0; i < verLength; i++) - { - for (int j = 0; j < horLength; j++) - { - SDL_RenderLine(g_renderer, - trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f - crossLength), - trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f + crossLength) - ); - - SDL_RenderLine(g_renderer, - trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f + crossLength), - trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f - crossLength) - ); - } - } - } -} - -static void _drawTrianglePixel(const Triangle& triangle) -{ - SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND); - SDL_SetRenderDrawColorFloat(g_renderer, triangle.pixelColor[0], triangle.pixelColor[1], triangle.pixelColor[2], 0.5f); - - for (const auto& dot : triangle.pixels) - { - SDL_FRect rect; - rect.x = trans_w2s_x(dot.first); - rect.y = trans_w2s_y(dot.second); - rect.w = g_scale; - rect.h = -g_scale; - - SDL_RenderFillRect(g_renderer, &rect); + SDL_RenderLine(g_renderer, screenX, trans_w2s_y(0), screenX, trans_w2s_y(g_canvas.height())); } } @@ -152,22 +142,42 @@ void _drawTriangleBorder(const Triangle& triangle, const fVector3& color, float SDL_SetRenderDrawColorFloat(g_renderer, color[0], color[1], color[2], SDL_ALPHA_OPAQUE_FLOAT); SDL_FPoint points[4] = { - {trans_w2s_x(triangle.p0.x), trans_w2s_y(triangle.p0.y)}, - {trans_w2s_x(triangle.p1.x), trans_w2s_y(triangle.p1.y)}, - {trans_w2s_x(triangle.p2.x), trans_w2s_y(triangle.p2.y)}, - {trans_w2s_x(triangle.p0.x), trans_w2s_y(triangle.p0.y)} + {trans_w2s_x(triangle.m_p0.x), trans_w2s_y(triangle.m_p0.y)}, + {trans_w2s_x(triangle.m_p1.x), trans_w2s_y(triangle.m_p1.y)}, + {trans_w2s_x(triangle.m_p2.x), trans_w2s_y(triangle.m_p2.y)}, + {trans_w2s_x(triangle.m_p0.x), trans_w2s_y(triangle.m_p0.y)} }; SDL_RenderLines(g_renderer, points, 4); } +void _drawCanvasPixel() +{ + SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND); + + for (int32_t y = 0; y < g_canvas.height(); y++) + { + for (int32_t x = 0; x < g_canvas.width(); x++) + { + const Canvas::Pixel& pixel = g_canvas.pixel(x, y); + if (pixel.fragementID < 0) continue; + + SDL_FRect rect; + rect.x = trans_w2s_x(x); + rect.y = trans_w2s_y(y); + rect.w = g_scale; + rect.h = -g_scale; + SDL_SetRenderDrawColorFloat(g_renderer, pixel.color.x, pixel.color.y, pixel.color.z, pixel.alpha); + SDL_RenderFillRect(g_renderer, &rect); + } + } +} void _drawTriangles(void) { - for (const auto& triangle : g_allTriangles) { - _drawTrianglePixel(triangle); - } + _drawCanvasPixel(); - for (const auto& triangle : g_allTriangles) { + for (const auto& triangle : g_allTriangles) + { _drawTriangleBorder(triangle, TRIANGLE_BORDER_COLOR, TRIANGLE_BORDER_WIDTH); } } @@ -210,9 +220,12 @@ void _drawAction(void) if (g_bDrawExtension) { SDL_SetRenderDrawColorFloat(g_renderer, ACTION_COLOR.x/2.f, ACTION_COLOR.y/2.f, ACTION_COLOR.z/2.f, SDL_ALPHA_OPAQUE_FLOAT); - _drawSegmentInAABB(g_currentTriangle.p0.xy(), g_currentTriangle.p1.xy(), 0, (float)g_canvasWidth, 0, (float)g_canvasHeight); - _drawSegmentInAABB(g_currentTriangle.p1.xy(), g_currentTriangle.p2.xy(), 0, (float)g_canvasWidth, 0, (float)g_canvasHeight); - _drawSegmentInAABB(g_currentTriangle.p2.xy(), g_currentTriangle.p0.xy(), 0, (float)g_canvasWidth, 0, (float)g_canvasHeight); + _drawSegmentInAABB(g_currentTriangle.m_p0.xy(), g_currentTriangle.m_p1.xy(), + 0, (float)g_canvas.width(), 0, (float)g_canvas.height()); + _drawSegmentInAABB(g_currentTriangle.m_p1.xy(), g_currentTriangle.m_p2.xy(), + 0, (float)g_canvas.width(), 0, (float)g_canvas.height()); + _drawSegmentInAABB(g_currentTriangle.m_p2.xy(), g_currentTriangle.m_p0.xy(), + 0, (float)g_canvas.width(), 0, (float)g_canvas.height()); } SDL_SetRenderDrawColorFloat(g_renderer, ACTION_COLOR.x, ACTION_COLOR.y, ACTION_COLOR.z, SDL_ALPHA_OPAQUE_FLOAT); @@ -221,17 +234,14 @@ void _drawAction(void) case MT_FIRST_LINE: { SDL_RenderLine(g_renderer, - trans_w2s_x(g_currentTriangle.p0.x), trans_w2s_y(g_currentTriangle.p0.y), - trans_w2s_x(g_currentTriangle.p1.x), trans_w2s_y(g_currentTriangle.p1.y) + trans_w2s_x(g_currentTriangle.m_p0.x), trans_w2s_y(g_currentTriangle.m_p0.y), + trans_w2s_x(g_currentTriangle.m_p1.x), trans_w2s_y(g_currentTriangle.m_p1.y) ); } break; case MT_TRIANGLE: { - g_currentTriangle.build(ACTION_COLOR, g_canvasWidth, g_canvasHeight); - - _drawTrianglePixel(g_currentTriangle); _drawTriangleBorder(g_currentTriangle, ACTION_COLOR, ACTION_WIDTH); } break; @@ -241,9 +251,110 @@ void _drawAction(void) } } +void _drawPixelSample() +{ + const float crossLength = 0.2f; + + //sample cross + if (g_nDrawGridLevel < 3) + { + SDL_SetRenderDrawColorFloat(g_renderer, GRID_CROSS_COLOR.x, GRID_CROSS_COLOR.y, GRID_CROSS_COLOR.z, SDL_ALPHA_OPAQUE_FLOAT); + + for (int32_t i = 0; i < g_canvas.height(); i++) + { + for (int32_t j = 0; j < g_canvas.width(); j++) + { + const Canvas::Pixel& pixel = g_canvas.pixel(j, i); + if (pixel.fragementID < 0) continue; + + if (g_aaTech == AntiAliasingTech::AA_None) + { + SDL_RenderLine(g_renderer, + trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f - crossLength), + trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f + crossLength) + ); + + SDL_RenderLine(g_renderer, + trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f + crossLength), + trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f - crossLength) + ); + } + else if (g_aaTech == AntiAliasingTech::AA_MSAA_2X2) + { + for (int32_t ii = 0; ii < 2; ii++) + { + for (int32_t jj = 0; jj < 2; jj++) + { + int32_t maskOffset = ii * 2 + jj; + if (((pixel.mask >> maskOffset) & 1) == 0U) continue; + + SDL_RenderLine(g_renderer, + trans_w2s_x(j + 0.25f + jj * 0.5f - crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f - crossLength / 2), + trans_w2s_x(j + 0.25f + jj * 0.5f + crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f + crossLength / 2) + ); + + SDL_RenderLine(g_renderer, + trans_w2s_x(j + 0.25f + jj * 0.5f - crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f + crossLength / 2), + trans_w2s_x(j + 0.25f + jj * 0.5f + crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f - crossLength / 2) + ); + } + } + } + else if (g_aaTech == AntiAliasingTech::AA_MSAA_4X4) + { + for (int32_t ii = 0; ii < 4; ii++) + { + for (int32_t jj = 0; jj < 4; jj++) + { + int32_t maskOffset = ii * 4 + jj; + if (((pixel.mask >> maskOffset) & 1) == 0U) continue; + + SDL_RenderLine(g_renderer, + trans_w2s_x(j + 0.125f + jj * 0.25f - crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f - crossLength/4), + trans_w2s_x(j + 0.125f + jj * 0.25f + crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f + crossLength/4) + ); + + SDL_RenderLine(g_renderer, + trans_w2s_x(j + 0.125f + jj * 0.25f - crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f + crossLength/4), + trans_w2s_x(j + 0.125f + jj * 0.25f + crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f - crossLength/4) + ); + + } + } + } + + } + } + + //for (int32_t i = (int32_t)trans_s2w_y(0); ; i--) + //{ + // if (i > g_canvas.height()) continue; + // if (i < 0) break; + + //} + + //float crossLength = 0.2f; + //for (int i = 0; i < verLength; i++) + //{ + // for (int j = 0; j < horLength; j++) + // { + // SDL_RenderLine(g_renderer, + // trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f - crossLength), + // trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f + crossLength) + // ); + + // SDL_RenderLine(g_renderer, + // trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f + crossLength), + // trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f - crossLength) + // ); + // } + //} + } +} + void _drawMouseCursor(void) { - if (g_bSnapMode) + if (g_bSnapMode && g_currentAction!=MT_PAN) { SDL_SetRenderDrawColorFloat(g_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE_FLOAT); @@ -268,8 +379,8 @@ void _drawDebugText() SDL_SetRenderDrawColorFloat(g_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE_FLOAT); SDL_SetRenderScale(g_renderer, 1.5f, 1.5f); - SDL_RenderDebugText(g_renderer, g_lbCorner_x, g_lbCorner_y, "Press 'S' to turn on/off snap mode."); - SDL_RenderDebugText(g_renderer, g_lbCorner_x, g_lbCorner_y+TextHeight, "Click 'LeftMouseButton' to draw new triangle."); + SDL_RenderDebugText(g_renderer, 20, 20, "Press 'S' to turn on/off snap mode."); + SDL_RenderDebugText(g_renderer, 20, 20 + TextHeight, "Click 'LeftMouseButton' to draw new triangle."); SDL_SetRenderScale(g_renderer, 1.0f, 1.0f); } @@ -287,13 +398,15 @@ inline float _snapPosition(float pos) } } - void _onMouseMove(float32_t x, float32_t y) { + g_screenMousePosX = (int32_t)x; + g_screenMousePosY = (int32_t)y; g_mousePosX = trans_s2w_x(x); g_mousePosY = trans_s2w_y(y); - if (g_bSnapMode) { + if (g_bSnapMode && g_currentAction != MT_PAN) + { g_mousePosX = _snapPosition(g_mousePosX); g_mousePosY = _snapPosition(g_mousePosY); } @@ -302,13 +415,23 @@ void _onMouseMove(float32_t x, float32_t y) { case MT_FIRST_LINE: { - g_currentTriangle.p1 = fVector3(g_mousePosX, g_mousePosY, 0); + g_currentTriangle.m_p1 = fVector3(g_mousePosX, g_mousePosY, 0); } break; case MT_TRIANGLE: { - g_currentTriangle.p2 = fVector3(g_mousePosX, g_mousePosY, 0); + g_currentTriangle.m_p2 = fVector3(g_mousePosX, g_mousePosY, 0); + g_currentTriangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); + + g_canvas.update(g_aaTech, g_allTriangles, &g_currentTriangle); + } + break; + + case MT_PAN: + { + g_nPanX = g_screenMousePosX - g_nStartPanX; + g_nPanY = -(g_screenMousePosY - g_nStartPanY); } break; @@ -331,6 +454,29 @@ void _onKeyDown(SDL_Keycode key) { g_bSnapMode = !g_bSnapMode; } + else if (SDLK_A == key) + { + if (g_currentAction == MT_NULL) + { + if (g_aaTech == AntiAliasingTech::AA_None) + { + g_aaTech = AntiAliasingTech::AA_MSAA_2X2; + } + else if (g_aaTech == AntiAliasingTech::AA_MSAA_2X2) + { + g_aaTech = AntiAliasingTech::AA_MSAA_4X4; + } + else if (g_aaTech == AntiAliasingTech::AA_MSAA_4X4) + { + g_aaTech = AntiAliasingTech::AA_None; + } + for (auto& triangle : g_allTriangles) + { + triangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); + } + g_canvas.update(g_aaTech, g_allTriangles); + } + } else if (SDLK_ESCAPE == key) { g_currentAction = MT_NULL; @@ -338,7 +484,22 @@ void _onKeyDown(SDL_Keycode key) } } -void _onMouseClick(Uint8 button) +void _onMouseDown(Uint8 button) +{ + if (button == SDL_BUTTON_MIDDLE) + { + if (g_currentAction == MT_NULL) + { + g_currentAction = MT_PAN; + + g_nStartPanX = g_screenMousePosX; + g_nStartPanY = g_screenMousePosY; + g_nPanX = g_nPanY = 0; + } + } +} + +void _onMouseUp(Uint8 button) { if (button == SDL_BUTTON_LEFT) { @@ -346,7 +507,7 @@ void _onMouseClick(Uint8 button) { case MT_NULL: { - g_currentTriangle.p0 = g_currentTriangle.p1 = fVector3(g_mousePosX, g_mousePosY, 0); + g_currentTriangle.m_p0 = g_currentTriangle.m_p1 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_FIRST_LINE; g_bDrawExtension = false; } @@ -354,7 +515,7 @@ void _onMouseClick(Uint8 button) case MT_FIRST_LINE: { - g_currentTriangle.p1 = g_currentTriangle.p2 = fVector3(g_mousePosX, g_mousePosY, 0); + g_currentTriangle.m_p1 = g_currentTriangle.m_p2 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_TRIANGLE; g_bDrawExtension = true; } @@ -362,14 +523,17 @@ void _onMouseClick(Uint8 button) case MT_TRIANGLE: { - g_currentTriangle.p2 = fVector3(g_mousePosX, g_mousePosY, 0); + g_currentTriangle.m_p2 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_NULL; //build triangle - fVector3 randColor = fVector3(rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX); - - g_currentTriangle.build(randColor, g_canvasWidth, g_canvasHeight, true); - g_allTriangles.push_back(g_currentTriangle); + Triangle newTriangle(Triangle::nextID(), Triangle::randomColor()); + newTriangle.m_p0 = g_currentTriangle.m_p0; + newTriangle.m_p1 = g_currentTriangle.m_p1; + newTriangle.m_p2 = g_currentTriangle.m_p2; + newTriangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); + g_allTriangles.push_back(std::move(newTriangle)); + g_canvas.update(g_aaTech, g_allTriangles); g_bDrawExtension = true; } break; @@ -382,6 +546,17 @@ void _onMouseClick(Uint8 button) { g_currentAction = MT_NULL; g_bDrawExtension = false; + g_canvas.update(g_aaTech, g_allTriangles); + } + else if (button == SDL_BUTTON_MIDDLE) + { + if (g_currentAction == MT_PAN) + { + g_currentAction = MT_NULL; + g_lbCorner_x += g_nPanX; + g_lbCorner_y += g_nPanY; + g_nPanX = g_nPanY = 0; + } } } @@ -412,10 +587,12 @@ void _buildDemoTriangles(void) fVector3 p0(triangleData[i * 6 + 0], triangleData[i * 6 + 1], 0.f); fVector3 p1(triangleData[i * 6 + 2], triangleData[i * 6 + 3], 0.f); fVector3 p2(triangleData[i * 6 + 4], triangleData[i * 6 + 5], 0.f); - fVector3 randColor = fVector3(rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX); - Triangle triangle(p0, p1, p2); - triangle.build(randColor, g_canvasWidth, g_canvasHeight, false); + Triangle triangle(Triangle::nextID(), Triangle::randomColor()); + triangle.m_p0 = p0; + triangle.m_p1 = p1; + triangle.m_p2 = p2; + triangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); g_allTriangles.emplace_back(triangle); } } @@ -437,9 +614,13 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) return SDL_APP_FAILURE; } + g_canvas.reset(CANVAS_WIDTH, CANVAS_HEIGHT); + _onFramebufferSize(g_viewWidth, g_viewHeight); _buildDemoTriangles(); + g_canvas.update(g_aaTech, g_allTriangles); + return SDL_APP_CONTINUE; /* carry on with the program! */ } @@ -476,9 +657,14 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + { + _onMouseDown(event->button.button); + } + break; case SDL_EVENT_MOUSE_BUTTON_UP: { - _onMouseClick(event->button.button); + _onMouseUp(event->button.button); } break; } @@ -489,12 +675,13 @@ SDL_AppResult SDL_AppIterate(void* appstate) { SDL_FRect rect; - SDL_SetRenderDrawColor(g_renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); + SDL_SetRenderDrawColor(g_renderer, 0, 99, 177, SDL_ALPHA_OPAQUE); SDL_RenderClear(g_renderer); _drawGrid(); _drawTriangles(); _drawAction(); + _drawPixelSample(); _drawMouseCursor(); _drawDebugText(); diff --git a/test/rasterization/dvr_triangle.cpp b/test/rasterization/dvr_triangle.cpp index cc7e0f2..0a0ab38 100644 --- a/test/rasterization/dvr_triangle.cpp +++ b/test/rasterization/dvr_triangle.cpp @@ -1,23 +1,36 @@ #include "dvr_triangle.h" -#include "rasterizer/dvc_rasterizer_triangle.h" -void Triangle::build(const davinci::fVector3& _pixelColor, int32_t canvasWidth, int32_t canvasHeight, bool debug) +int32_t Triangle::nextID() { - pixelColor = _pixelColor; - pixels.clear(); + static int32_t id = 0; + return id++; +} + +davinci::fVector3 Triangle::randomColor() +{ + return davinci::fVector3(rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX); +} + +void Triangle::build(int32_t canvasWidth, int32_t canvasHeight, davinci::AntiAliasingTech aaTech) +{ + m_pixels.clear(); - //make sure it's cw bool ccw = false; - if ((p2 - p1).crossProduct(p0 - p2).z > 0) { + if ((m_p2 - m_p1).crossProduct(m_p0 - m_p2).z > 0) { ccw = true; } //build pixel data - davinci::Rasterizer::drawTriangleLarrabee(canvasWidth, canvasHeight, - p0.xy(), p1.xy(), p2.xy(), - [this](std::pair pos, const davinci::fVector3& t) + davinci::Rasterizer::drawTriangleLarrabee(aaTech, + canvasWidth, canvasHeight, + m_p0.xy(), m_p1.xy(), m_p2.xy(), + [this](std::pair pos, const davinci::fVector3& t, uint32_t mask) { - pixels.push_back(pos); + Pixel pixel; + pixel.x = pos.first; + pixel.y = pos.second; + pixel.mask = mask; + m_pixels.push_back(pixel); }, ccw ); diff --git a/test/rasterization/dvr_triangle.h b/test/rasterization/dvr_triangle.h index 74cdb3c..2f14e34 100644 --- a/test/rasterization/dvr_triangle.h +++ b/test/rasterization/dvr_triangle.h @@ -1,21 +1,34 @@ #pragma once #include "math/dvc_vector3.h" +#include "rasterizer/dvc_rasterizer_triangle.h" struct Triangle { public: - davinci::fVector3 p0, p1, p2; - davinci::fVector3 pixelColor; - std::vector< std::pair > pixels; + int32_t m_id; + davinci::fVector3 m_p0, m_p1, m_p2; + davinci::fVector3 m_pixelColor; + struct Pixel + { + int32_t x, y; + uint32_t mask; // 0xFFFFFFFF for full pixel, 0x00000000 for empty pixel + }; + typedef std::vector PixelArray; + PixelArray m_pixels; public: - Triangle(){} - Triangle(const davinci::fVector3& _p0, const davinci::fVector3& _p1, const davinci::fVector3& _p2) : p0(_p0), p1(_p1), p2(_p2) { } - Triangle(const Triangle& other) : p0(other.p0), p1(other.p1), p2(other.p2), pixelColor(other.pixelColor), pixels(other.pixels) {} + static int32_t nextID(); + static davinci::fVector3 randomColor(); + + Triangle(int32_t id, const davinci::fVector3& pixelColor) + : m_id(id) + , m_pixelColor(pixelColor) + { + } public: - void build(const davinci::fVector3& _pixelColor, int32_t canvasWidth, int32_t canvasHeight, bool debug = false); + void build(int32_t canvasWidth, int32_t canvasHeight, davinci::AntiAliasingTech aaTech); }; -typedef std::vector TriangleVector; +typedef std::vector TriangleArray; diff --git a/test/unit/dvt_unit_rasterizer.cpp b/test/unit/dvt_unit_rasterizer.cpp index c30f5c9..a27a219 100644 --- a/test/unit/dvt_unit_rasterizer.cpp +++ b/test/unit/dvt_unit_rasterizer.cpp @@ -297,7 +297,7 @@ static bool _triangleRasterizationRules(Canvas& canvas, const Triangle& triangle canvas.clear(); - Rasterizer::drawTriangleLarrabee(canvas.getWidth(), canvas.getHeight(), + Rasterizer::drawTriangleLarrabee(AntiAliasingTech::AA_None, canvas.getWidth(), canvas.getHeight(), triangle.p1, triangle.p2, triangle.p3, razFunc, ccw); @@ -429,7 +429,7 @@ TEST(Rasterizer, Delaunay) uint32_t randCol = 0xFF000000 + ((uint32_t)(rand() / 240) << 16) + ((uint32_t)(rand() / 240) << 8) + ((uint32_t)(rand() / 240)); auto razFunc = std::bind(&Canvas::razFunction, &canvas, std::placeholders::_1, std::placeholders::_2, randCol); - Rasterizer::drawTriangleLarrabee(canvas.getWidth(), canvas.getHeight(), + Rasterizer::drawTriangleLarrabee(AntiAliasingTech::AA_None, canvas.getWidth(), canvas.getHeight(), triangle.p1, triangle.p2, triangle.p3, razFunc, false); }