Compare commits
127 Commits
56f64f00f0
...
a84c8cb752
Author | SHA1 | Date |
---|---|---|
wuyize | a84c8cb752 | |
ArgonarioD | e39eb15f03 | |
ArgonarioD | cee26188e1 | |
karlis | 826a8d3e2e | |
karlis | 769effe49c | |
wuyize | a07bf3bced | |
karlis | b944572204 | |
ArgonarioD | d55b49e119 | |
karlis | 0543a02dfb | |
karlis | e6571faf8c | |
ArgonarioD | bf71d17b5d | |
ArgonarioD | 4b2776d429 | |
karlis | 831541ff36 | |
karlis | 6a1c64a426 | |
wuyize | ae641bb87c | |
karlis | f25f2d2a81 | |
karlis | 8a34f57251 | |
karlis | f06fbbaef6 | |
ArgonarioD | 855dd2e075 | |
wuyize | b6e79ee6de | |
karlis | b3bbf6c1be | |
karlis | 8bf6835c23 | |
karlis | 3904ff0b61 | |
ArgonarioD | 587c09115a | |
ArgonarioD | 66cde802ec | |
ArgonarioD | 4c95d6e362 | |
wuyize | 12b62bf039 | |
ArgonarioD | 0e62672b58 | |
karlis | 69422ba96a | |
karlis | 3d8420f617 | |
yang.yongquan | e48954175d | |
yang.yongquan | 3c2eada43f | |
karlis | 6494c2b9af | |
wuyize | fd1baf42f6 | |
karlis | aeead9d22e | |
karlis | 84bddf4447 | |
wuyize | 31f2c1be8f | |
ArgonarioD | c15e8c3a5b | |
karlis | 24f8daf1fd | |
karlis | 9e4cdb3a63 | |
wuyize | 6a09bdd32c | |
wuyize | 2569b07233 | |
ArgonarioD | 81bb1b4b86 | |
wuyize | 4ff5406acc | |
karlis | 6d554ab265 | |
karlis | a9fb9197e6 | |
wuyize | 15a41d61a5 | |
ArgonarioD | 03a06ce426 | |
wuyize | 78c24ad373 | |
karlis | 627b947738 | |
karlis | 8903419799 | |
karlis | 70d5973a90 | |
karlis | 6c86403c4a | |
karlis | b9c8624dae | |
karlis | 153f6bdd8e | |
karlis | c234c0e9b3 | |
wuyize | 3abc0d9bcd | |
yang.yongquan | 5d88ddf0ca | |
karlis | fa91d80b70 | |
karlis | 3b87644e21 | |
ArgonarioD | 073f68e360 | |
yang.yongquan | 73e63f3817 | |
yang.yongquan | d47d94d044 | |
wuyize | 57d6de47f8 | |
wuyize | c6a4d79888 | |
wuyize | 4ec58dbb8b | |
wuyize | cf3dd43a4a | |
wuyize | 62b9c2b026 | |
karlis | 97097fcc3a | |
karlis | f2ceca724a | |
karlis | eab8d7aeec | |
karlis | dc7a793d3a | |
karlis | 684c28dafd | |
karlis | 72f0f78e64 | |
karlis | 3f1421a1bd | |
karlis | 4c9fe168a9 | |
karlis | de9d7143b6 | |
karlis | ed4c3c0064 | |
wuyize | 0d42af9200 | |
ArgonarioD | acd25b4964 | |
karlis | e3217aa134 | |
karlis | 2cb25b8607 | |
yang.yongquan | 631f0f8af7 | |
yang.yongquan | 50acb3b625 | |
karlis | c92a3553ce | |
wuyize | 4bfdb0d9f6 | |
karlis | ca8d68fe93 | |
karlis | 3dd7fd7c0f | |
wuyize | 6508f54333 | |
ArgonarioD | b981056674 | |
ArgonarioD | 293c1f3096 | |
ArgonarioD | 65e03ed3ba | |
ArgonarioD | 94b16ac536 | |
ArgonarioD | 7c7cd02d71 | |
wuyize | 520597e288 | |
ArgonarioD | 15e2522591 | |
ArgonarioD | 14a1502a22 | |
ArgonarioD | 846f334d54 | |
karlis | fedb147dd3 | |
wuyize | d0cbdd65ec | |
wuyize | f504480050 | |
ArgonarioD | 52734adda8 | |
ArgonarioD | e7bce3f93e | |
karlis | 25eec60e5c | |
ArgonarioD | 652fa483ba | |
karlis | 6f8bfa1558 | |
karlis | ef990cd4b4 | |
wuyize | c2dd8271e3 | |
wuyize | 6412d9c865 | |
yang.yongquan | 11c9ccc3a9 | |
wuyize | 08e54cfc30 | |
wuyize | f4f1547d21 | |
yang.yongquan | 7d4a191f02 | |
yang.yongquan | 1118dc819a | |
karlis | 477517d919 | |
karlis | 368eaa6c89 | |
karlis | edb7e37b91 | |
karlis | 06c96144e4 | |
wuyize | 526f33ceba | |
karlis | 1031ba5808 | |
karlis | 33475f6f57 | |
karlis | 8ca036fafb | |
yang.yongquan | 6a4a724f00 | |
yang.yongquan | 53025b93e4 | |
yang.yongquan | a28e484cb2 | |
yang.yongquan | f578fe6184 | |
karlis | c1ad6a61f0 |
|
@ -0,0 +1,424 @@
|
|||
{
|
||||
"background-color": "#b7a386",
|
||||
"elements": [
|
||||
{
|
||||
"data": {
|
||||
"include": "../svg/2.svg"
|
||||
},
|
||||
"name": "ababa",
|
||||
"type": "svg-file"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"reference-layer": "0.0"
|
||||
},
|
||||
"name": "ababa-group",
|
||||
"type": "group"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"include": "../svg/0.svg"
|
||||
},
|
||||
"name": "ababa2",
|
||||
"type": "svg-file"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"include": "D:/BigC2022/temp/ArchitectureColoredPainting/svg/4_L0.svg"
|
||||
},
|
||||
"name": "4_L0-fill.svg",
|
||||
"type": "svg-file"
|
||||
}
|
||||
],
|
||||
"height": 1080,
|
||||
"project-name": "样例1",
|
||||
"root-layer": {
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"element": 3,
|
||||
"is-folder": false,
|
||||
"name": "4_L0",
|
||||
"styles": [
|
||||
{
|
||||
"material": "AH8A/2pkiv8=",
|
||||
"type": "fill"
|
||||
},
|
||||
{
|
||||
"enableEachSideIndependent": true,
|
||||
"left": "AADAQAEAJJwAf///9dKG/w==",
|
||||
"right": "AADgQAAACpw=",
|
||||
"type": "stroke"
|
||||
}
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": -230,
|
||||
"y": -533
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 0.32341007644113307,
|
||||
"y": 0.32341007644113307
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"is-folder": true,
|
||||
"name": "GroupFolderExample",
|
||||
"referenced-by": 1,
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 50,
|
||||
"y": 50
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "aaaa2",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 127,
|
||||
"y": -109
|
||||
},
|
||||
"rotation": 90,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "aaaa3",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 232,
|
||||
"y": 17
|
||||
},
|
||||
"rotation": 180,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "aaaa4",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 103,
|
||||
"y": 130
|
||||
},
|
||||
"rotation": 270,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "bbbb1",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 197,
|
||||
"y": 265
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "bbbb2",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 323,
|
||||
"y": 156
|
||||
},
|
||||
"rotation": 90,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "bbbb3",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 432,
|
||||
"y": 285
|
||||
},
|
||||
"rotation": 180,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "bbbb4",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 302,
|
||||
"y": 399
|
||||
},
|
||||
"rotation": 270,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "cccc1",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 467,
|
||||
"y": 71
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "cccc2",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 361,
|
||||
"y": -70
|
||||
},
|
||||
"rotation": 90,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "cccc3",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 273,
|
||||
"y": -211
|
||||
},
|
||||
"rotation": 180,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "cccc4",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 574,
|
||||
"y": 198
|
||||
},
|
||||
"rotation": 270,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "dddd1",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 33,
|
||||
"y": -231
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "dddd2",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 55,
|
||||
"y": 352
|
||||
},
|
||||
"rotation": 90,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "dddd3",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": -40,
|
||||
"y": 220
|
||||
},
|
||||
"rotation": 180,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "dddd4",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "eeee1",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "eeee2",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": -149,
|
||||
"y": 85
|
||||
},
|
||||
"rotation": 90,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"element": 1,
|
||||
"is-folder": false,
|
||||
"name": "eeee3",
|
||||
"styles": [
|
||||
],
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 166,
|
||||
"y": 482
|
||||
},
|
||||
"rotation": 180,
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"is-folder": true,
|
||||
"name": "root",
|
||||
"referenced-by": null,
|
||||
"transform": {
|
||||
"offset": {
|
||||
"x": 8,
|
||||
"y": 20
|
||||
},
|
||||
"rotation": 0,
|
||||
"scale": {
|
||||
"x": 1.7159367435419115,
|
||||
"y": 1.7159367435419115
|
||||
}
|
||||
}
|
||||
},
|
||||
"width": 1080
|
||||
}
|
Binary file not shown.
|
@ -104,9 +104,16 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\CaptionButton.cpp" />
|
||||
<ClCompile Include="src\Editor\DataManager\ProjectDataManager.cpp" />
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\FillStyleWidget.cpp" />
|
||||
<ClCompile Include="src\Editor\RightBar\EditorSettingWidget.cpp" />
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\ColorPicker.cpp" />
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.cpp" />
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\LayerStyleDialog.cpp" />
|
||||
<ClCompile Include="src\Editor\EditorWidget.cpp" />
|
||||
<ClCompile Include="src\Editor\EditorWidgetItem.cpp" />
|
||||
<ClCompile Include="src\Editor\ElementManager.cpp" />
|
||||
<ClCompile Include="src\Editor\ElementPoolWidget.cpp" />
|
||||
<ClCompile Include="src\Editor\GraphicElement.cpp" />
|
||||
<ClCompile Include="src\Editor\LayerManager.cpp" />
|
||||
<ClCompile Include="src\Editor\LayerStyle.cpp" />
|
||||
|
@ -118,9 +125,10 @@
|
|||
<ClCompile Include="src\Editor\ThirdPartyLib\qquick\qquicksvgparser.cpp" />
|
||||
<ClCompile Include="src\Editor\ThirdPartyLib\SvgHelper.cpp" />
|
||||
<ClCompile Include="src\Editor\util\PainterPathUtil.cpp" />
|
||||
<ClCompile Include="src\Editor\util\PaintingUtil.cpp" />
|
||||
<ClCompile Include="src\Editor\util\SvgFileLoader.cpp" />
|
||||
<ClCompile Include="src\FluentMenu.cpp" />
|
||||
<ClCompile Include="src\gl.c" />
|
||||
<ClCompile Include="src\IconWidget.cpp" />
|
||||
<ClCompile Include="src\main.cpp" />
|
||||
<ClCompile Include="src\MainWindow.cpp" />
|
||||
<ClCompile Include="src\NavigationBarWidget.cpp" />
|
||||
|
@ -148,10 +156,14 @@
|
|||
<ClCompile Include="src\Renderer\Painting\StraightLine.cpp" />
|
||||
<ClCompile Include="src\Renderer\VirtualTextureManager.cpp" />
|
||||
<ClCompile Include="src\SvgParser.cpp" />
|
||||
<ClCompile Include="src\TitleWidget.cpp" />
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\StrokeStyleWidget.cpp" />
|
||||
<QtUic Include="EditorLayerInfoWidget.ui" />
|
||||
<QtUic Include="EditorSettingWidget.ui" />
|
||||
<QtUic Include="EditorWidget.ui" />
|
||||
<QtUic Include="EditorWidgetItem.ui" />
|
||||
<QtUic Include="MainWindow.ui" />
|
||||
<QtUic Include="RendererWidget.ui" />
|
||||
<QtUic Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\data.json" />
|
||||
|
@ -182,11 +194,23 @@
|
|||
<None Include="res\Shaders\ssgi.comp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\StrokeStyleWidget.h" />
|
||||
<QtMoc Include="src\Editor\RightBar\LayerTreeWidget.h" />
|
||||
<QtMoc Include="src\Editor\RightBar\InfoDisplayWidget.h" />
|
||||
<QtMoc Include="src\MainWindow.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<QtMoc Include="src\Editor\EditorWidget.h" />
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.h" />
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\LayerStyleDialog.h" />
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\ColorPicker.h" />
|
||||
<QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h" />
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\FillStyleWidget.h" />
|
||||
<ClInclude Include="src\Editor\DataManager\ProjectDataManager.h" />
|
||||
<ClInclude Include="src\ColorHelper.hpp" />
|
||||
<ClInclude Include="src\Editor\LayerWrapper.h" />
|
||||
<ClInclude Include="src\Editor\util\EncodeUtil.hpp" />
|
||||
<ClInclude Include="src\Editor\util\JsonUtil.hpp" />
|
||||
<ClInclude Include="src\Editor\ElementManager.h" />
|
||||
<QtMoc Include="src\Editor\ElementPoolWidget.h" />
|
||||
<ClInclude Include="src\Editor\GraphicElement.h" />
|
||||
<ClInclude Include="src\Editor\LayerManager.h" />
|
||||
<ClInclude Include="src\Editor\LayerStyle.h" />
|
||||
|
@ -197,7 +221,9 @@
|
|||
<ClInclude Include="src\Editor\ThirdPartyLib\qquick\qtquickglobal_p.h" />
|
||||
<ClInclude Include="src\Editor\ThirdPartyLib\SvgHelper.h" />
|
||||
<ClInclude Include="src\Editor\util\PainterPathUtil.h" />
|
||||
<ClInclude Include="src\Editor\util\PaintingUtil.h" />
|
||||
<ClInclude Include="src\Editor\util\SvgFileLoader.h" />
|
||||
<QtMoc Include="src\FluentMenu.h" />
|
||||
<ClInclude Include="src\Renderer\IblUtils.h" />
|
||||
<ClInclude Include="src\Renderer\Painting\BaseStyle.h" />
|
||||
<ClInclude Include="src\Renderer\Painting\CubicBezierSignedDistance.h" />
|
||||
|
@ -210,12 +236,9 @@
|
|||
<ClInclude Include="src\Renderer\Preview\ElementRenderer.h" />
|
||||
<ClInclude Include="src\Renderer\VirtualTextureManager.h" />
|
||||
<ClInclude Include="src\SvgParser.h" />
|
||||
<QtMoc Include="src\TitleWidget.h" />
|
||||
<QtMoc Include="src\IconWidget.h" />
|
||||
<QtMoc Include="src\CaptionButton.h" />
|
||||
<QtMoc Include="src\NavigationBarWidget.h" />
|
||||
<QtMoc Include="src\Renderer\RendererWidget.h" />
|
||||
<QtMoc Include="src\Editor\EditorWidget.h" />
|
||||
<QtMoc Include="src\Editor\EditorWidgetItem.h" />
|
||||
<ClInclude Include="src\Renderer\Painting\BvhTree.h" />
|
||||
<ClInclude Include="src\Renderer\Camera.h" />
|
||||
<ClInclude Include="src\Renderer\Painting\CubicBezier.h" />
|
||||
|
@ -240,9 +263,6 @@
|
|||
<Project>{8f360763-a045-3808-87a9-3fae38e69819}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ArchitectureColoredPainting.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||
|
|
|
@ -65,14 +65,44 @@
|
|||
<Filter Include="Header Files\Renderer\Preview">
|
||||
<UniqueIdentifier>{7ead1a66-586a-4584-ae80-9e7a4e667364}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Editor\Style">
|
||||
<UniqueIdentifier>{be3f4585-c8ba-410f-8619-2adcd4349f02}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Editor\Style">
|
||||
<UniqueIdentifier>{b9732a33-aa2e-4f8d-886f-1b1730c66519}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Editor\Element">
|
||||
<UniqueIdentifier>{8d846557-8fd5-47d5-8edf-eb3eb77c226b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Editor\Element">
|
||||
<UniqueIdentifier>{22d7f3ef-8185-476e-8fe1-aea24c4faacc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Editor\Layer">
|
||||
<UniqueIdentifier>{6fc32493-d5a2-44c3-a283-d2d3181330fb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Editor\Layer">
|
||||
<UniqueIdentifier>{e6de889e-8313-4846-8bdf-125b766eef59}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="MainWindow.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
<QtUic Include="EditorWidget.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
<QtUic Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
<QtUic Include="EditorSettingWidget.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
<QtUic Include="EditorLayerInfoWidget.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Editor\EditorWidget.cpp">
|
||||
<ClCompile Include="src\Editor\EditorWidgetItem.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Renderer\Camera.cpp">
|
||||
|
@ -105,18 +135,6 @@
|
|||
<ClCompile Include="src\Renderer\RendererWidget.cpp">
|
||||
<Filter>Source Files\Renderer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\NavigationBarWidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\CaptionButton.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\IconWidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\TitleWidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Renderer\Painting\BvhTree.cpp">
|
||||
<Filter>Source Files\Renderer\Painting</Filter>
|
||||
</ClCompile>
|
||||
|
@ -138,18 +156,6 @@
|
|||
<ClCompile Include="src\Renderer\Painting\Element.cpp">
|
||||
<Filter>Source Files\Renderer\Painting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\GraphicElement.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\ElementManager.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\LayerManager.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\LayerWrapper.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\PreviewWindow.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
|
@ -159,12 +165,6 @@
|
|||
<ClCompile Include="src\Renderer\Painting\CubicBezierSignedDistance.cpp">
|
||||
<Filter>Source Files\Renderer\Painting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\RightBar\LayerTreeWidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\RightBar\InfoDisplayWidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Renderer\Painting\ElementStyle.cpp">
|
||||
<Filter>Source Files\Renderer\Painting</Filter>
|
||||
</ClCompile>
|
||||
|
@ -192,9 +192,6 @@
|
|||
<ClCompile Include="src\Renderer\Preview\ElementRenderer.cpp">
|
||||
<Filter>Source Files\Renderer\Preview</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\LayerStyle.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Renderer\IblUtils.cpp">
|
||||
<Filter>Source Files\Renderer</Filter>
|
||||
</ClCompile>
|
||||
|
@ -207,39 +204,120 @@
|
|||
<ClCompile Include="src\Editor\PixelPath.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\FluentMenu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\util\PaintingUtil.cpp">
|
||||
<Filter>Source Files\Editor\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\LayerStyle.cpp">
|
||||
<Filter>Source Files\Editor\Style</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\LayerStyleDialog.cpp">
|
||||
<Filter>Source Files\Editor\Style</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\StrokeStyleWidget.cpp">
|
||||
<Filter>Source Files\Editor\Style</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\RightBar\InfoDisplayWidget.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\NavigationBarWidget.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\EditorWidget.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\RightBar\EditorSettingWidget.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\FillStyleWidget.cpp">
|
||||
<Filter>Source Files\Editor\Style</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\ElementManager.cpp">
|
||||
<Filter>Source Files\Editor\Element</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\ElementPoolWidget.cpp">
|
||||
<Filter>Source Files\Editor\Element</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\GraphicElement.cpp">
|
||||
<Filter>Source Files\Editor\Element</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\LayerManager.cpp">
|
||||
<Filter>Source Files\Editor\Layer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\RightBar\LayerTreeWidget.cpp">
|
||||
<Filter>Source Files\Editor\Layer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.cpp">
|
||||
<Filter>Source Files\Editor\Layer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\LayerWrapper.cpp">
|
||||
<Filter>Source Files\Editor\Layer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\FillStyleWidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\DataManager\ProjectDataManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Editor\EditorWidgetComponent\ColorPicker.cpp">
|
||||
<Filter>Source Files\Editor</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="src\Renderer\RendererGLWidget.h">
|
||||
<Filter>Header Files\Renderer</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidget.h">
|
||||
<QtMoc Include="src\Editor\EditorWidgetItem.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Renderer\RendererWidget.h">
|
||||
<Filter>Header Files\Renderer</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\NavigationBarWidget.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\CaptionButton.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\IconWidget.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\TitleWidget.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\MainWindow.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\PreviewWindow.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\RightBar\LayerTreeWidget.h">
|
||||
<QtMoc Include="src\FluentMenu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\StrokeStyleWidget.h">
|
||||
<Filter>Header Files\Editor\Style</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\LayerStyleDialog.h">
|
||||
<Filter>Header Files\Editor\Style</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\RightBar\InfoDisplayWidget.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidget.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\MainWindow.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\NavigationBarWidget.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\ColorPicker.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\FillStyleWidget.h">
|
||||
<Filter>Header Files\Editor\Style</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\ElementPoolWidget.h">
|
||||
<Filter>Header Files\Editor\Element</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\LayerCreateWidget.h">
|
||||
<Filter>Header Files\Editor\Layer</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\RightBar\LayerTreeWidget.h">
|
||||
<Filter>Header Files\Editor\Layer</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="src\Editor\EditorWidgetComponent\FillStyleWidget.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
|
@ -322,7 +400,7 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUic Include="EditorWidget.ui">
|
||||
<QtUic Include="EditorWidgetItem.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</QtUic>
|
||||
<QtUic Include="RendererWidget.ui">
|
||||
|
@ -372,18 +450,6 @@
|
|||
<ClInclude Include="src\Renderer\Painting\Element.h">
|
||||
<Filter>Header Files\Renderer\Painting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\GraphicElement.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\LayerStyle.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\LayerManager.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\ElementManager.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Renderer\Painting\LineTree.h">
|
||||
<Filter>Header Files\Renderer\Painting</Filter>
|
||||
</ClInclude>
|
||||
|
@ -423,9 +489,6 @@
|
|||
<ClInclude Include="src\Renderer\Preview\ElementRenderer.h">
|
||||
<Filter>Header Files\Renderer\Preview</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\PixelPath.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Renderer\IblUtils.h">
|
||||
<Filter>Header Files\Renderer</Filter>
|
||||
</ClInclude>
|
||||
|
@ -435,7 +498,37 @@
|
|||
<ClInclude Include="src\Renderer\VirtualTextureManager.h">
|
||||
<Filter>Header Files\Renderer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<ClInclude Include="src\Editor\util\PaintingUtil.h">
|
||||
<Filter>Header Files\Editor\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\LayerStyle.h">
|
||||
<Filter>Header Files\Editor\Style</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\util\JsonUtil.hpp">
|
||||
<Filter>Header Files\Editor\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\util\EncodeUtil.hpp">
|
||||
<Filter>Header Files\Editor\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\ElementManager.h">
|
||||
<Filter>Header Files\Editor\Element</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\GraphicElement.h">
|
||||
<Filter>Header Files\Editor\Element</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\LayerManager.h">
|
||||
<Filter>Header Files\Editor\Layer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\PixelPath.h">
|
||||
<Filter>Header Files\Editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\LayerWrapper.h">
|
||||
<Filter>Header Files\Editor\Layer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ColorHelper.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\Editor\DataManager\ProjectDataManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
@ -444,7 +537,4 @@
|
|||
<Filter>Resource Files</Filter>
|
||||
</QtRcc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ArchitectureColoredPainting.rc" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditorLayerInfoWidget</class>
|
||||
<widget class="QWidget" name="EditorLayerInfoWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>333</width>
|
||||
<height>321</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="widgetLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QtMaterialTextField" name="name">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QtMaterialTextField" name="rotation">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QtMaterialTextField" name="offsetX">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QtMaterialTextField" name="offsetY">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QtMaterialTextField" name="scaleX">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QtMaterialTextField" name="scaleY">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QtMaterialCheckBox" name="flipX">
|
||||
<property name="text">
|
||||
<string>水平翻转</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QtMaterialCheckBox" name="flipY">
|
||||
<property name="text">
|
||||
<string>竖直翻转</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QListWidget" name="styleList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QtMaterialTextField</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header location="global">qtmaterialtextfield.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QtMaterialCheckBox</class>
|
||||
<extends>QCheckBox</extends>
|
||||
<header location="global">qtmaterialcheckbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditorSettingWidget</class>
|
||||
<widget class="QWidget" name="EditorSettingWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="backgroundColorButton">
|
||||
<property name="text">
|
||||
<string>设置背景颜色</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditorSettingWidget</class>
|
||||
<widget class="QWidget" name="EditorSettingWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QPushButton" name="backgroundColorButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>设置背景颜色</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QPushButton" name="renameButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>设置项目名称</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1,19 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditorWidgetClass</class>
|
||||
<widget class="QWidget" name="EditorWidgetClass">
|
||||
<class>EditorWidget</class>
|
||||
<widget class="QWidget" name="EditorWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1124</width>
|
||||
<height>695</height>
|
||||
<width>1139</width>
|
||||
<height>862</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>RendererWidget</string>
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,20">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
@ -27,87 +41,159 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="MainWindow" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,30">
|
||||
<item>
|
||||
<widget class="QLabel" name="Title">
|
||||
<property name="text">
|
||||
<string/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,1,1,1,1,0">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="createButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>新建</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,18,5">
|
||||
<item>
|
||||
<widget class="QWidget" name="LeftBar" native="true"/>
|
||||
<widget class="QPushButton" name="openButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>打开</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PreviewWindow" name="Preview"/>
|
||||
<widget class="QPushButton" name="saveButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>保存</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="RightBar" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="1,2">
|
||||
<widget class="QPushButton" name="saveAsButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>另存为</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="DisplayTab">
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>关闭</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>800</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="InfoDisplayWidget" name="LayerDisplay">
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Layer</string>
|
||||
<string>Tab 1</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="ElementDisplay">
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Element</string>
|
||||
<string>Tab 2</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LayerTreeWidget" name="LayerTree">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PreviewWindow</class>
|
||||
<extends>QOpenGLWidget</extends>
|
||||
<header>PreviewWindow.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LayerTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header location="global">LayerTreeWidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>InfoDisplayWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">InfoDisplayWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditorWidgetItem</class>
|
||||
<widget class="QWidget" name="EditorWidgetItem">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1473</width>
|
||||
<height>1103</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>RendererWidget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="MainWindow" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="20,1">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,12,5">
|
||||
<item>
|
||||
<widget class="QWidget" name="LeftBar" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10801080</width>
|
||||
<height>10801080</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1024</width>
|
||||
<height>1024</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1024</width>
|
||||
<height>1024</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10241024</width>
|
||||
<height>10241024</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="PreviewWindow" name="Preview">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1024</width>
|
||||
<height>1024</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>1024</width>
|
||||
<height>1024</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="RightBar" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="3,2">
|
||||
<property name="spacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="DisplayTab">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="InfoDisplayWidget" name="LayerDisplay">
|
||||
<attribute name="title">
|
||||
<string>图层信息</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="ElementPoolWidget" name="ElementDisplay">
|
||||
<attribute name="title">
|
||||
<string>图元池</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="EditorSettingWidget" name="EditorSetting">
|
||||
<attribute name="title">
|
||||
<string>设置</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LayerTreeWidget" name="LayerTree">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="accessibleName">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>图层名</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>关联图元</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>可见</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PreviewWindow</class>
|
||||
<extends>QOpenGLWidget</extends>
|
||||
<header>PreviewWindow.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LayerTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header location="global">LayerTreeWidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>InfoDisplayWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">InfoDisplayWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ElementPoolWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ElementPoolWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>EditorSettingWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">EditorSettingWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindowClass</class>
|
||||
<widget class="QMainWindow" name="MainWindowClass">
|
||||
<widget class="QWidget" name="MainWindowClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
|
@ -10,19 +10,9 @@
|
|||
<height>722</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 10pt "Segoe UI, Microsoft YaHei UI";</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
|
@ -40,73 +30,26 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="1">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI, Microsoft YaHei UI</family>
|
||||
<pointsize>10</pointsize>
|
||||
<weight>50</weight>
|
||||
<italic>false</italic>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">
|
||||
QTabBar::tab {
|
||||
height: 0px;
|
||||
margin-top:0px;
|
||||
}
|
||||
QTabWidget::tab-bar
|
||||
{
|
||||
height: 0px;
|
||||
top:0px;
|
||||
}
|
||||
QTabWidget::pane {
|
||||
border: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
</string>
|
||||
</property>
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::North</enum>
|
||||
</property>
|
||||
<property name="tabShape">
|
||||
<enum>QTabWidget::Rounded</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="elideMode">
|
||||
<enum>Qt::ElideNone</enum>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="tabsClosable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="EditorWidget" name="editorWidget">
|
||||
<attribute name="title">
|
||||
<string>纹理编辑</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="Renderer::RendererWidget" name="rendererWidget">
|
||||
<attribute name="title">
|
||||
<string>场景渲染</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<item row="0" column="0">
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<widget class="EditorWidget" name="editorWidget"/>
|
||||
<widget class="Renderer::RendererWidget" name="rendererWidget"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
17876391417123941155.jpg 0.json 0 0 1 1
|
||||
11474523244911310074.jpg 1.json 0 0 1 1
|
|
@ -13,7 +13,7 @@
|
|||
<property name="windowTitle">
|
||||
<string>RendererWidget</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
@ -31,8 +31,14 @@
|
|||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QtMaterialFlatButton" name="openButton">
|
||||
|
@ -44,12 +50,18 @@
|
|||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>40</height>
|
||||
<width>50</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>打开</string>
|
||||
<string>文件</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
|
@ -72,38 +84,26 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="textureListWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Ignored">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>打开</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menu"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="Renderer::RendererGLWidget" name="openGLWidget">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
@ -893,7 +893,7 @@ bool angleLargeThanPi(vec2 a, vec2 b)
|
|||
|
||||
/************************************************************************************/
|
||||
|
||||
void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness)
|
||||
void drawLine(in float d, uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness)
|
||||
{
|
||||
elementColor = vec4(1);
|
||||
metallicRoughness = vec2(0.8);
|
||||
|
@ -969,14 +969,38 @@ void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2
|
|||
}
|
||||
}
|
||||
|
||||
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, vec2 tangentBegin, vec2 tangentEndLast)
|
||||
void nextStyleIndex(inout uint styleIndex)
|
||||
{
|
||||
uint headUint = floatBitsToUint(style[styleIndex + 1]);
|
||||
vec4 head = unpackUnorm4x8(headUint);
|
||||
switch (int(head.a * 100) % 10)
|
||||
{
|
||||
/// Plain
|
||||
case 0: {
|
||||
styleIndex += 3;
|
||||
break;
|
||||
}
|
||||
/// RadialGradient
|
||||
case 1: {
|
||||
uint size = headUint % (1 << 15);
|
||||
styleIndex += 2 + size * 2;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast)
|
||||
{
|
||||
vec2 normal;
|
||||
if (onVeryBegin)
|
||||
{
|
||||
if (endType == 0)
|
||||
if (endType%2 == 0)
|
||||
return true;
|
||||
else if (endType == 1)
|
||||
else if (endType%2 == 1)
|
||||
normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
|
||||
}
|
||||
else
|
||||
|
@ -985,17 +1009,26 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, ve
|
|||
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
|
||||
normal = normalLast + normalNow;
|
||||
}
|
||||
return angleLargeThanPi(normal, localUV - p3);
|
||||
return angleLargeThanPi(normal, localUV - p0);
|
||||
}
|
||||
|
||||
bool shouldFillEndCap(vec2 localUV, int endType, vec2 p0, vec2 tangentEnd)
|
||||
bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext)
|
||||
{
|
||||
vec2 normal;
|
||||
if (endType == 0)
|
||||
if (onVeryEnd)
|
||||
{
|
||||
if ((endType/2)%2 == 0)
|
||||
return true;
|
||||
else if (endType == 1)
|
||||
else if ((endType/2)%2 == 1)
|
||||
normal = normalize(mat2(0, 1, -1, 0) * tangentEnd);
|
||||
return angleLargeThanPi(localUV - p0, normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd);
|
||||
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
|
||||
normal = normalLast + normalNow;
|
||||
}
|
||||
return angleLargeThanPi(localUV - p3, normal);
|
||||
}
|
||||
|
||||
void main()
|
||||
|
@ -1006,9 +1039,8 @@ void main()
|
|||
vec4 color = vec4(0);
|
||||
// if(isinf(path[0].x)) imageStore(gBaseColor, ivec2(pixelLocation),
|
||||
// vec4(vec2(pixelLocation)/vec2(imageSize(gBaseColor)), 1,1)); return;
|
||||
for (uint styleIndex = 0; styleIndex < styleSize; styleIndex++)
|
||||
for (uint styleIndex = 0; styleIndex < styleSize;)
|
||||
{
|
||||
|
||||
styleIndex += 6;
|
||||
vec2 localUV = vec2(pixelLocation) / pixelRatio + leftTop;
|
||||
|
||||
|
@ -1039,14 +1071,15 @@ void main()
|
|||
if (num_its % 2 == 1)
|
||||
{
|
||||
hitElement = true;
|
||||
elementColor = vec4(1, 1, 0, 0);
|
||||
|
||||
vec4 head = unpackUnorm4x8(floatBitsToUint(style[styleIndex]));
|
||||
if (head.z == 0)
|
||||
{
|
||||
elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1);
|
||||
elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[styleIndex+1])).rgb, 1);
|
||||
}
|
||||
|
||||
}
|
||||
styleIndex += 2;
|
||||
}
|
||||
else // Stroke
|
||||
{
|
||||
|
@ -1058,31 +1091,76 @@ void main()
|
|||
// endType = 1;
|
||||
int debugBegin = 0;
|
||||
bool onVeryBegin = false;
|
||||
bool onVeryEnd = false;
|
||||
vec2 tangentEndLast;
|
||||
vec2 tangentFirstBegin;
|
||||
uint lastHitIndex = 0;
|
||||
bool lastHitElement = false;
|
||||
hitElement = false;
|
||||
for (uint pathIndex = 0; pathIndex < pathSize; pathIndex++)
|
||||
// for (uint pathIndex = 0; pathIndex < 4; pathIndex++)
|
||||
//for (uint pathIndex = 0; pathIndex < 46; pathIndex++)
|
||||
{
|
||||
vec2 pTemp = path[pathIndex];
|
||||
if (isinf(pTemp.x))
|
||||
{
|
||||
// TODO: ¼ì²âÊÇ·ñ·â±Õ²¢´¦Àí
|
||||
if (hitElement && distance(localUV, p3Last) <= strokeWidth)
|
||||
{
|
||||
hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
|
||||
}
|
||||
|
||||
|
||||
pBegin = path[++pathIndex];
|
||||
p3Last = pBegin;
|
||||
p2Last = pBegin;
|
||||
if(endType == 4)
|
||||
{
|
||||
//onVeryBegin = false;
|
||||
vec2 lastP1 = path[pathSize-3];
|
||||
vec2 lastP2 = path[pathSize-2];
|
||||
vec2 lastP3 = path[pathSize-1];
|
||||
if (lastP3 != lastP2)
|
||||
tangentEndLast = normalize(lastP3 - lastP2);
|
||||
else
|
||||
tangentEndLast = normalize(lastP3 - lastP1);
|
||||
}
|
||||
else
|
||||
onVeryBegin = true;
|
||||
continue;
|
||||
}
|
||||
mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]);
|
||||
|
||||
vec2 tangentBeginNext;
|
||||
if (pathIndex + 1 < pathSize)
|
||||
{
|
||||
vec2 pTemp = path[pathIndex + 1];
|
||||
if (isinf(pTemp.x))
|
||||
{
|
||||
onVeryEnd = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
onVeryEnd = false;
|
||||
vec2 pNext[3] = {p[3], pTemp, path[pathIndex + 2]};
|
||||
if (pNext[0] != pNext[1])
|
||||
tangentBeginNext = normalize(pNext[0] - pNext[1]);
|
||||
else
|
||||
tangentBeginNext = normalize(pNext[0] - pNext[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(endType == 4)
|
||||
{
|
||||
//onVeryEnd = false;
|
||||
tangentBeginNext = tangentFirstBegin;
|
||||
}
|
||||
else
|
||||
onVeryEnd = true;
|
||||
}
|
||||
|
||||
|
||||
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
|
||||
if (d <= strokeWidth)
|
||||
{
|
||||
bool onBegin = distance(localUV, p[0]) <= strokeWidth && p3Last == p[0];
|
||||
bool onBegin = distance(localUV, p[0]) <= strokeWidth;
|
||||
bool onEnd = distance(localUV, p[3]) <= strokeWidth;
|
||||
vec2 tangentBegin;
|
||||
vec2 tangentEnd;
|
||||
if (p[0] != p[1])
|
||||
|
@ -1094,11 +1172,14 @@ void main()
|
|||
else
|
||||
tangentEnd = normalize(p[3] - p[1]);
|
||||
|
||||
if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, p3Last - p2Last)
|
||||
: d < minDistance)
|
||||
bool hit = d < minDistance;
|
||||
if (onBegin)
|
||||
hit = hit &&
|
||||
shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast);
|
||||
if (onEnd)
|
||||
hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext);
|
||||
if (hit)
|
||||
{
|
||||
minDistance = min(minDistance, d);
|
||||
|
||||
bool reverse = p[3].y - p[0].y < 0.;
|
||||
|
||||
if (tangentBegin.y == 0.)
|
||||
|
@ -1111,28 +1192,28 @@ void main()
|
|||
|
||||
if (lineType == 2 || (intTest % 2 == int(lineType)))
|
||||
{
|
||||
minDistance = min(minDistance, d);
|
||||
lastHitElement = hitElement;
|
||||
lastHitIndex = pathIndex;
|
||||
hitElement = true;
|
||||
// elementColor = vec4(1, 1, 0, 1);
|
||||
vec2 metallicRoughness;
|
||||
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
|
||||
}
|
||||
else if (p3Last == p[0])
|
||||
hitElement = false;
|
||||
}
|
||||
tangentEndLast = tangentEnd;
|
||||
if(pathIndex == 4)
|
||||
tangentFirstBegin = tangentBegin;
|
||||
}
|
||||
p3Last = p[3];
|
||||
p2Last = p[2];
|
||||
onVeryBegin = false;
|
||||
}
|
||||
if (hitElement && distance(localUV, p3Last) <= strokeWidth)
|
||||
{
|
||||
hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
|
||||
}
|
||||
nextStyleIndex(styleIndex);
|
||||
|
||||
}
|
||||
if (hitElement)
|
||||
color = elementColor;
|
||||
styleIndex += 100;
|
||||
}
|
||||
if (color.a != 0)
|
||||
imageStore(gBaseColor, ivec2(pixelLocation), color);
|
||||
|
|
|
@ -4,6 +4,11 @@ layout (local_size_x = 8, local_size_y = 8) in;
|
|||
|
||||
layout(location = 0) uniform ivec2 pixelOffset;
|
||||
|
||||
layout(std140, binding = 1) uniform ubo
|
||||
{
|
||||
vec3 backgroundColor;
|
||||
};
|
||||
|
||||
layout(rgba8, binding = 0) uniform image2D gBaseColor;
|
||||
layout(rg8, binding = 1) uniform image2D gMetallicRoughness;
|
||||
|
||||
|
@ -15,29 +20,31 @@ layout(std430, binding = 1) buffer bvhBoundBuffer
|
|||
{
|
||||
vec4 bvhBound[];
|
||||
};
|
||||
layout(std430, binding = 2) buffer elementOffsetBuffer
|
||||
layout(std430, binding = 2) buffer elementTranformBuffer
|
||||
{
|
||||
mat3x2 elementTranform[];
|
||||
};
|
||||
layout(std430, binding = 3) buffer elementOffsetBuffer
|
||||
{
|
||||
/**
|
||||
* @[0] elementBvhRoot
|
||||
* @[1] styleOffset
|
||||
* @[2] pointsOffset
|
||||
* @[3] linesOffset
|
||||
|
||||
*/
|
||||
uint elementOffset[][5];
|
||||
uint elementOffset[][4];
|
||||
};
|
||||
layout(std430, binding = 3) buffer elementIndexBuffer
|
||||
layout(std430, binding = 4) buffer elementIndexBuffer
|
||||
{
|
||||
uint elementIndexs[]; // ÏߺÍÃæ
|
||||
};
|
||||
layout(std430, binding = 4) buffer elementDataBuffer
|
||||
layout(std430, binding = 5) buffer elementDataBuffer
|
||||
{
|
||||
float elementData[]; // µãºÍStyle
|
||||
};
|
||||
|
||||
const float PI = 3.14159265358979;
|
||||
|
||||
|
||||
const uint STACK_SIZE = 10;
|
||||
|
||||
struct Stack
|
||||
|
@ -77,7 +84,6 @@ struct Stack
|
|||
}
|
||||
} stack, elementStack;
|
||||
|
||||
|
||||
// Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
|
||||
// Credits to Doublefresh for hinting there
|
||||
int solve_quadric(vec2 coeffs, inout vec2 roots)
|
||||
|
@ -151,7 +157,6 @@ int solve_cubic(vec3 coeffs, inout vec3 r)
|
|||
return 3;
|
||||
}
|
||||
|
||||
|
||||
int segment_int_test(vec2 uv, vec2 p0, vec2 p1)
|
||||
{
|
||||
p0 -= uv;
|
||||
|
@ -299,15 +304,19 @@ bvec3 cubic_bezier_sign_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
|
|||
|
||||
// int n_ints = 0;
|
||||
bvec3 result = bvec3(false);
|
||||
for(int i=0;i<3;i++){
|
||||
if(i < n_roots){
|
||||
if(roots[i] >= 0. && roots[i] <= 1.){
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (i < n_roots)
|
||||
{
|
||||
if (roots[i] >= 0. && roots[i] <= 1.)
|
||||
{
|
||||
float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
|
||||
x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
|
||||
x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
|
||||
x_pos = x_pos * roots[i] + p0.x;
|
||||
|
||||
if(x_pos > uv.x){
|
||||
if (x_pos > uv.x)
|
||||
{
|
||||
result[1] = !result[1];
|
||||
}
|
||||
}
|
||||
|
@ -320,24 +329,32 @@ bvec3 cubic_bezier_sign_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
|
|||
vec2 nor1 = vec2(tang1.y, -tang1.x);
|
||||
vec2 nor2 = vec2(tang2.y, -tang2.x);
|
||||
|
||||
if(p0.y < p1.y){
|
||||
if((uv.y<=p0.y) && (dot(uv-p0.xy,nor1)>0.)){
|
||||
if (p0.y < p1.y)
|
||||
{
|
||||
if ((uv.y <= p0.y) && (dot(uv - p0.xy, nor1) > 0.))
|
||||
{
|
||||
result[0] = !result[0];
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(!(uv.y<=p0.y) && !(dot(uv-p0.xy,nor1)>0.)){
|
||||
else
|
||||
{
|
||||
if (!(uv.y <= p0.y) && !(dot(uv - p0.xy, nor1) > 0.))
|
||||
{
|
||||
result[0] = !result[0];
|
||||
}
|
||||
}
|
||||
|
||||
if(p2.y<p3.y){
|
||||
if(!(uv.y<=p3.y) && dot(uv-p3.xy,nor2)>0.){
|
||||
if (p2.y < p3.y)
|
||||
{
|
||||
if (!(uv.y <= p3.y) && dot(uv - p3.xy, nor2) > 0.)
|
||||
{
|
||||
result[2] = !result[2];
|
||||
}
|
||||
}
|
||||
else{
|
||||
if((uv.y<=p3.y) && !(dot(uv-p3.xy,nor2)>0.)){
|
||||
else
|
||||
{
|
||||
if ((uv.y <= p3.y) && !(dot(uv - p3.xy, nor2) > 0.))
|
||||
{
|
||||
result[2] = !result[2];
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +372,8 @@ const float eps = .000005;
|
|||
const int halley_iterations = 8;
|
||||
// lagrange positive real root upper bound
|
||||
// see for example: https://doi.org/10.1016/j.jsc.2014.09.038
|
||||
float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
|
||||
float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4)
|
||||
{
|
||||
|
||||
vec4 coeffs1 = vec4(a0, a1, a2, a3);
|
||||
|
||||
|
@ -383,7 +401,8 @@ float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
|
|||
}
|
||||
|
||||
// lagrange upper bound applied to f(-x) to get lower bound
|
||||
float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
|
||||
float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4)
|
||||
{
|
||||
|
||||
vec4 coeffs1 = vec4(-a0, a1, -a2, a3);
|
||||
|
||||
|
@ -410,7 +429,8 @@ float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
|
|||
return -max_max - max_max2;
|
||||
}
|
||||
|
||||
vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3){
|
||||
vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
|
||||
{
|
||||
vec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3);
|
||||
vec2 a1 = (3. * p0 - 6. * p1 + 3. * p2);
|
||||
vec2 a2 = (-3. * p0 + 3. * p1);
|
||||
|
@ -419,7 +439,8 @@ vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3){
|
|||
return (((a0 * t) + a1) * t + a2) * t + a3;
|
||||
}
|
||||
|
||||
void sort_roots3(inout vec3 roots){
|
||||
void sort_roots3(inout vec3 roots)
|
||||
{
|
||||
vec3 tmp;
|
||||
|
||||
tmp[0] = min(roots[0], min(roots[1], roots[2]));
|
||||
|
@ -429,7 +450,8 @@ void sort_roots3(inout vec3 roots){
|
|||
roots = tmp;
|
||||
}
|
||||
|
||||
void sort_roots4(inout vec4 roots){
|
||||
void sort_roots4(inout vec4 roots)
|
||||
{
|
||||
vec4 tmp;
|
||||
|
||||
vec2 min1_2 = min(roots.xz, roots.yw);
|
||||
|
@ -446,7 +468,8 @@ void sort_roots4(inout vec4 roots){
|
|||
roots = tmp;
|
||||
}
|
||||
|
||||
float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x){
|
||||
float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x)
|
||||
{
|
||||
|
||||
float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
|
||||
|
||||
|
@ -457,7 +480,8 @@ float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x){
|
|||
// basically a variant of newton raphson which converges quicker and has bigger basins of convergence
|
||||
// see http://mathworld.wolfram.com/HalleysMethod.html
|
||||
// or https://en.wikipedia.org/wiki/Halley%27s_method
|
||||
float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x){
|
||||
float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x)
|
||||
{
|
||||
|
||||
float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
|
||||
float f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1;
|
||||
|
@ -466,7 +490,8 @@ float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float
|
|||
return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
|
||||
}
|
||||
|
||||
float halley_iteration4(vec4 coeffs, float x){
|
||||
float halley_iteration4(vec4 coeffs, float x)
|
||||
{
|
||||
|
||||
float f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0];
|
||||
float f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1];
|
||||
|
@ -477,7 +502,8 @@ float halley_iteration4(vec4 coeffs, float x){
|
|||
|
||||
// Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
|
||||
// Credits to Doublefresh for hinting there
|
||||
int solve_quartic(vec4 coeffs, inout vec4 s){
|
||||
int solve_quartic(vec4 coeffs, inout vec4 s)
|
||||
{
|
||||
|
||||
float a = coeffs[3];
|
||||
float b = coeffs[2];
|
||||
|
@ -529,17 +555,21 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
|
|||
float u = z * z - r;
|
||||
float v = 2. * z - p;
|
||||
|
||||
if(u > -eps){
|
||||
if (u > -eps)
|
||||
{
|
||||
u = sqrt(abs(u));
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(v > -eps){
|
||||
if (v > -eps)
|
||||
{
|
||||
v = sqrt(abs(v));
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -557,12 +587,15 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
|
|||
int old_num = num;
|
||||
|
||||
num += solve_quadric(quad_coeffs, tmp);
|
||||
if(old_num!=num){
|
||||
if(old_num == 0){
|
||||
if (old_num != num)
|
||||
{
|
||||
if (old_num == 0)
|
||||
{
|
||||
s[0] = tmp[0];
|
||||
s[1] = tmp[1];
|
||||
}
|
||||
else{//old_num == 2
|
||||
else
|
||||
{ // old_num == 2
|
||||
s[2] = tmp[0];
|
||||
s[3] = tmp[1];
|
||||
}
|
||||
|
@ -574,8 +607,10 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
|
|||
float sub = 1. / 4. * a;
|
||||
|
||||
/* single halley iteration to fix cancellation */
|
||||
for(int i=0;i<4;i+=2){
|
||||
if(i < num){
|
||||
for (int i = 0; i < 4; i += 2)
|
||||
{
|
||||
if (i < num)
|
||||
{
|
||||
s[i] -= sub;
|
||||
s[i] = halley_iteration4(coeffs, s[i]);
|
||||
|
||||
|
@ -586,7 +621,8 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
|
|||
|
||||
return num;
|
||||
}
|
||||
float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd){
|
||||
float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd)
|
||||
{
|
||||
|
||||
// switch points when near to end point to minimize numerical error
|
||||
// only needed when control point(s) very far away
|
||||
|
@ -659,57 +695,71 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
|
|||
|
||||
// compute root isolating intervals by roots of derivative and outer root bounds
|
||||
// only roots going form - to + considered, because only those result in a minimum
|
||||
if(num_roots_drv==4){
|
||||
if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) > 0.){
|
||||
if (num_roots_drv == 4)
|
||||
{
|
||||
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) > 0.)
|
||||
{
|
||||
a[0] = lb;
|
||||
b[0] = roots_drv[0];
|
||||
num_roots = 1;
|
||||
}
|
||||
|
||||
if(sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1])) != sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[2]))){
|
||||
if(num_roots == 0){
|
||||
if (sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[1])) != sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[2])))
|
||||
{
|
||||
if (num_roots == 0)
|
||||
{
|
||||
a[0] = roots_drv[1];
|
||||
b[0] = roots_drv[2];
|
||||
num_roots = 1;
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
a[1] = roots_drv[1];
|
||||
b[1] = roots_drv[2];
|
||||
num_roots = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[3]) < 0.){
|
||||
if(num_roots == 0){
|
||||
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[3]) < 0.)
|
||||
{
|
||||
if (num_roots == 0)
|
||||
{
|
||||
a[0] = roots_drv[3];
|
||||
b[0] = ub;
|
||||
num_roots = 1;
|
||||
}
|
||||
else if(num_roots == 1){
|
||||
else if (num_roots == 1)
|
||||
{
|
||||
a[1] = roots_drv[3];
|
||||
b[1] = ub;
|
||||
num_roots = 2;
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
a[2] = roots_drv[3];
|
||||
b[2] = ub;
|
||||
num_roots = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(num_roots_drv==2){
|
||||
if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) < 0.){
|
||||
else
|
||||
{
|
||||
if (num_roots_drv == 2)
|
||||
{
|
||||
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) < 0.)
|
||||
{
|
||||
num_roots = 1;
|
||||
a[0] = roots_drv[1];
|
||||
b[0] = ub;
|
||||
}
|
||||
else if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1]) > 0.){
|
||||
else if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[1]) > 0.)
|
||||
{
|
||||
num_roots = 1;
|
||||
a[0] = lb;
|
||||
b[0] = roots_drv[0];
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
num_roots = 2;
|
||||
|
||||
a[0] = lb;
|
||||
|
@ -718,9 +768,9 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
|
|||
a[1] = roots_drv[1];
|
||||
b[1] = ub;
|
||||
}
|
||||
|
||||
}
|
||||
else{//num_roots_drv==0
|
||||
else
|
||||
{ // num_roots_drv==0
|
||||
vec3 roots_snd_drv = vec3(1e38);
|
||||
int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv);
|
||||
|
||||
|
@ -741,31 +791,44 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
|
|||
int num_roots_trd_drv = 0;
|
||||
vec2 roots_trd_drv = vec2(1e38);
|
||||
|
||||
if(num_roots_snd_drv!=3){
|
||||
if (num_roots_snd_drv != 3)
|
||||
{
|
||||
num_roots_trd_drv = solve_quadric(c3, roots_trd_drv);
|
||||
}
|
||||
|
||||
for(int i=0;i<3;i++){
|
||||
if(i < num_roots){
|
||||
for(int j=0;j<3;j+=2){
|
||||
if(j < num_roots_snd_drv){
|
||||
if(a[i] < roots_snd_drv[j] && b[i] > roots_snd_drv[j]){
|
||||
if(eval_poly5(b0,b1,b2,b3,b4,roots_snd_drv[j]) > 0.){
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (i < num_roots)
|
||||
{
|
||||
for (int j = 0; j < 3; j += 2)
|
||||
{
|
||||
if (j < num_roots_snd_drv)
|
||||
{
|
||||
if (a[i] < roots_snd_drv[j] && b[i] > roots_snd_drv[j])
|
||||
{
|
||||
if (eval_poly5(b0, b1, b2, b3, b4, roots_snd_drv[j]) > 0.)
|
||||
{
|
||||
b[i] = roots_snd_drv[j];
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
a[i] = roots_snd_drv[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int j=0;j<2;j++){
|
||||
if(j < num_roots_trd_drv){
|
||||
if(a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j]){
|
||||
if(eval_poly5(b0,b1,b2,b3,b4,roots_trd_drv[j]) > 0.){
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
if (j < num_roots_trd_drv)
|
||||
{
|
||||
if (a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j])
|
||||
{
|
||||
if (eval_poly5(b0, b1, b2, b3, b4, roots_trd_drv[j]) > 0.)
|
||||
{
|
||||
b[i] = roots_trd_drv[j];
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
a[i] = roots_trd_drv[j];
|
||||
}
|
||||
}
|
||||
|
@ -779,15 +842,17 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
|
|||
|
||||
// compute roots with halley's method
|
||||
|
||||
for(int i=0;i<3;i++){
|
||||
if(i < num_roots){
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (i < num_roots)
|
||||
{
|
||||
roots[i] = .5 * (a[i] + b[i]);
|
||||
|
||||
for(int j=0;j<halley_iterations;j++){
|
||||
for (int j = 0; j < halley_iterations; j++)
|
||||
{
|
||||
roots[i] = halley_iteration5(b0, b1, b2, b3, b4, roots[i]);
|
||||
}
|
||||
|
||||
|
||||
// compute squared distance to nearest point on curve
|
||||
if (roundEnd)
|
||||
{
|
||||
|
@ -797,21 +862,20 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
|
|||
}
|
||||
else
|
||||
{
|
||||
if(roots[i]<0.||roots[i]>1.) d0=min(d0,1e38);
|
||||
if (roots[i] < 0. || roots[i] > 1.)
|
||||
d0 = min(d0, 1e38);
|
||||
else
|
||||
{
|
||||
vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3);
|
||||
d0 = min(d0, dot(to_curve, to_curve));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return sqrt(d0);
|
||||
}
|
||||
|
||||
|
||||
int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool reverse)
|
||||
{
|
||||
float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
|
||||
|
@ -831,8 +895,10 @@ int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool rev
|
|||
}
|
||||
else
|
||||
{
|
||||
if (abs(cu) < .0001) n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy);
|
||||
else n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
|
||||
if (abs(cu) < .0001)
|
||||
n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy);
|
||||
else
|
||||
n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
|
||||
|
||||
for (int i = 0; i < n_roots; i++)
|
||||
{
|
||||
|
@ -843,7 +909,8 @@ int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool rev
|
|||
x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
|
||||
x_pos = x_pos * roots[i] + p0.x;
|
||||
|
||||
if (reverse? x_pos < uv.x: x_pos > uv.x) n_ints++;
|
||||
if (reverse ? x_pos < uv.x : x_pos > uv.x)
|
||||
n_ints++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -858,10 +925,12 @@ int ray_int_test(vec2 uv, vec2 p0, vec2 direction, bool reverse)
|
|||
vec2 nor = -direction;
|
||||
nor = vec2(nor.y, -nor.x);
|
||||
float sgn = p0.y > direction.y ? 1. : -1.;
|
||||
if(reverse) sgn = -sgn;
|
||||
if (reverse)
|
||||
sgn = -sgn;
|
||||
return dot(nor, p0) * sgn < 0. ? 0 : 1;
|
||||
}
|
||||
else return 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec2 bezierTangent(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
|
||||
|
@ -962,65 +1031,63 @@ void drawLine(in float d, in uint styleIndex, out vec4 elementColor, out vec2 me
|
|||
}
|
||||
}
|
||||
|
||||
bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, out vec2 metallicRoughness, inout vec3 debugBVH = vec3(0))
|
||||
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast)
|
||||
{
|
||||
vec2 normal;
|
||||
if (onVeryBegin)
|
||||
{
|
||||
if (endType % 2 == 0)
|
||||
return true;
|
||||
else if (endType % 2 == 1)
|
||||
normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
|
||||
}
|
||||
else
|
||||
{
|
||||
vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEndLast);
|
||||
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
|
||||
normal = normalLast + normalNow;
|
||||
}
|
||||
return angleLargeThanPi(normal, localUV - p0);
|
||||
}
|
||||
|
||||
bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext)
|
||||
{
|
||||
vec2 normal;
|
||||
if (onVeryEnd)
|
||||
{
|
||||
if ((endType / 2) % 2 == 0)
|
||||
return true;
|
||||
else if ((endType / 2) % 2 == 1)
|
||||
normal = normalize(mat2(0, 1, -1, 0) * tangentEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd);
|
||||
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
|
||||
normal = normalLast + normalNow;
|
||||
}
|
||||
return angleLargeThanPi(localUV - p3, normal);
|
||||
}
|
||||
|
||||
bool fillElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex,
|
||||
inout vec4 elementColor, inout vec2 metallicRoughness)
|
||||
{
|
||||
bool hitElement = false;
|
||||
vec4 elementColor = vec4(-1);
|
||||
metallicRoughness = vec2(0, 0.8);
|
||||
|
||||
uint currentOffset[] = elementOffset[elementIndex];
|
||||
uint elementBvhRoot = currentOffset[0];
|
||||
uint styleIndex = currentOffset[1];
|
||||
uint elementBvhLength = 0x80000000;
|
||||
uint pointsOffset = currentOffset[2];
|
||||
uint linesOffset = currentOffset[3];
|
||||
|
||||
elementStack.top = 0;
|
||||
uint elementBvhIndex = 0;
|
||||
while (elementBvhIndex < elementBvhLength || !elementStack.empty())
|
||||
{
|
||||
|
||||
while (elementBvhIndex < elementBvhLength)
|
||||
{
|
||||
vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex];
|
||||
uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x;
|
||||
|
||||
if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw)))
|
||||
{
|
||||
if (leftChild >= elementBvhLength)
|
||||
{
|
||||
if (any(greaterThan(bound.xy+vec2(0.003), localUV)) || any(greaterThan(localUV, bound.zw-vec2(0.003))))
|
||||
{
|
||||
debugBVH.g = 0;
|
||||
debugBVH.r += 1;
|
||||
}
|
||||
//uint styleIndex = bvhChildren[elementBvhRoot + elementBvhIndex].y;
|
||||
//uint elementType = bvhChildren[elementBvhRoot + elementBvhIndex].y;
|
||||
//float elementType = elementData[styleIndex];
|
||||
bool isFillStyle = elementData[styleIndex]<=0;
|
||||
// for(int i = 0; i<200;i++)
|
||||
if (isFillStyle) //Ãæ
|
||||
{
|
||||
uint contourIndex = linesOffset + leftChild - 0x80000000;
|
||||
|
||||
uint num_its = 0;
|
||||
|
||||
uint lineCount = elementIndexs[contourIndex];
|
||||
|
||||
for (uint contourIterator = contourIndex + 1; contourIterator < contourIndex + 1 + lineCount; contourIterator++)
|
||||
{
|
||||
uint lineIndex = elementIndexs[contourIterator];
|
||||
uint pLocation = linesOffset + 2 * lineIndex;
|
||||
uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF);
|
||||
uvec4 pxIndex =
|
||||
uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
|
||||
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
|
||||
uvec4 pyIndex = uvec4(1) + pxIndex;
|
||||
mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]],
|
||||
elementData[pxIndex[1]], elementData[pyIndex[1]],
|
||||
elementData[pxIndex[2]],elementData[pyIndex[2]],
|
||||
elementData[pxIndex[3]], elementData[pyIndex[3]]);
|
||||
// vec2 p[4] = {vec2(elementData[pxIndex[0]], elementData[pyIndex[0]]),
|
||||
// vec2(elementData[pxIndex[1]], elementData[pyIndex[1]]),
|
||||
// vec2(elementData[pxIndex[2]],elementData[pyIndex[2]]),
|
||||
// vec2(elementData[pxIndex[3]], elementData[pyIndex[3]])};
|
||||
mat4x2 p =
|
||||
mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]],
|
||||
elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]);
|
||||
|
||||
// if (bound.z == p[0].x && distance(localUV, p[3]) < 0.01)
|
||||
// {
|
||||
// debugBVH = vec3(0, 0, 1);
|
||||
|
@ -1031,7 +1098,6 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
|
|||
// {
|
||||
// num_its += segment_int_test(localUV, p0, p3);
|
||||
// }
|
||||
//
|
||||
// else
|
||||
num_its += cubic_bezier_int_test(localUV, p[0], p[1], p[2], p[3]);
|
||||
}
|
||||
|
@ -1047,48 +1113,70 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
|
|||
elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])).rgb, 0);
|
||||
metallicRoughness = head.xy;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return hitElement;
|
||||
}
|
||||
else //Ïß
|
||||
|
||||
bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex,
|
||||
inout vec4 elementColor, inout vec2 metallicRoughness)
|
||||
{
|
||||
bool hitElement = false;
|
||||
float strokeWidth = elementData[styleIndex];
|
||||
float widthHeightRatio = uintBitsToFloat(currentOffset[4]);
|
||||
|
||||
vec2 size = normalize(vec2(widthHeightRatio, 1)) + vec2(2 * strokeWidth);
|
||||
vec2 ratio = widthHeightRatio < 1 ? vec2(widthHeightRatio, 1) : vec2(1, 1 / widthHeightRatio);
|
||||
localUV *= ratio;
|
||||
|
||||
|
||||
uint contourIndex = linesOffset + leftChild - 0x80000000;
|
||||
float minDistance = 1e38;
|
||||
uint lineCount = elementIndexs[contourIndex];
|
||||
vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1]));
|
||||
float lineType = floor(styleHead.b * 10);
|
||||
//float lineType = 2;
|
||||
int endType = int(round(styleHead.b * 100)) % 10;
|
||||
vec2 p3Last = vec2(1e38);
|
||||
vec2 p2Last = vec2(1e38);
|
||||
vec2 tangentEndLast;
|
||||
int debugBegin = 0;
|
||||
for ( uint contourIterator_ = contourIndex + 1;contourIterator_ <= contourIndex + 1 + lineCount; contourIterator_++)
|
||||
for (uint contourIterator_ = contourIndex + 1; contourIterator_ < contourIndex + 1 + lineCount; contourIterator_++)
|
||||
{
|
||||
uint contourIterator = contourIterator_;
|
||||
if (contourIterator_ == contourIndex + 1 + lineCount)
|
||||
contourIterator = contourIndex + 1;
|
||||
uint lineIndex = elementIndexs[contourIterator];
|
||||
uint pLocation = linesOffset + 3 * lineIndex;
|
||||
uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF);
|
||||
vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
|
||||
uvec4 pxIndex =
|
||||
uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
|
||||
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
|
||||
uvec4 pyIndex = uvec4(1) + pxIndex;
|
||||
|
||||
mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]],
|
||||
elementData[pxIndex[1]], elementData[pyIndex[1]],
|
||||
elementData[pxIndex[2]], elementData[pyIndex[2]],
|
||||
mat4x2 p =
|
||||
mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]],
|
||||
elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]);
|
||||
|
||||
vec2 tangentBeginNext = vec2(0);
|
||||
if (contourIterator + 1 < contourIndex + 1 + lineCount)
|
||||
{
|
||||
uint lineIndex = elementIndexs[contourIterator + 1];
|
||||
uint pLocation = linesOffset + 3 * lineIndex;
|
||||
// vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
|
||||
uvec4 pxIndex = uvec4(pointsOffset) +
|
||||
2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
|
||||
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
|
||||
uvec4 pyIndex = uvec4(1) + pxIndex;
|
||||
|
||||
mat4x2 pNext = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]],
|
||||
elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]],
|
||||
elementData[pxIndex[3]], elementData[pyIndex[3]]);
|
||||
|
||||
p[0] *= ratio;
|
||||
p[1] *= ratio;
|
||||
p[2] *= ratio;
|
||||
p[3] *= ratio;
|
||||
if (pNext[0] == pNext[1] && pNext[2] == pNext[3])
|
||||
{
|
||||
pNext[1] = (pNext[0] + pNext[3]) / 2;
|
||||
pNext[2] = pNext[1];
|
||||
}
|
||||
|
||||
// if(pNext[0]!=p[3])
|
||||
// break;
|
||||
if (pNext[0] != pNext[1])
|
||||
tangentBeginNext = normalize(pNext[0] - pNext[1]);
|
||||
else
|
||||
tangentBeginNext = normalize(pNext[0] - pNext[2]);
|
||||
}
|
||||
|
||||
if (p[0] == p[1] && p[2] == p[3])
|
||||
{
|
||||
|
@ -1098,52 +1186,70 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
|
|||
|
||||
if (distance(localUV, p[0]) <= 0.001)
|
||||
{
|
||||
if(p3Last==p[0]) debugBegin = 2;
|
||||
else debugBegin = 1;
|
||||
if (p3Last == p[0])
|
||||
debugBegin = 2;
|
||||
else
|
||||
debugBegin = 1;
|
||||
}
|
||||
|
||||
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
|
||||
if (d <= strokeWidth)
|
||||
{
|
||||
bool onBegin = distance(localUV,p[0])<=strokeWidth&&p3Last==p[0];
|
||||
bool fill = true;
|
||||
bool onBegin =
|
||||
distance(localUV, p[0]) <= strokeWidth; //&& (p3Last == p[0] || contourIterator == contourIndex + 1);
|
||||
bool onEnd = distance(localUV, p[3]) <= strokeWidth;
|
||||
|
||||
vec2 tangentBegin;
|
||||
vec2 tangentEnd;
|
||||
if (p[0] != p[1])
|
||||
tangentBegin = normalize(p[0] - p[1]);
|
||||
else
|
||||
tangentBegin = normalize(p[0] - p[2]);
|
||||
if (p[3] != p[2])
|
||||
tangentEnd = normalize(p[3] - p[2]);
|
||||
else
|
||||
tangentEnd = normalize(p[3] - p[1]);
|
||||
|
||||
bool hit = d < minDistance;
|
||||
if (onBegin)
|
||||
hit = hit && shouldFillBeginCap(localUV, contourIterator == contourIndex + 1, endType, p[0],
|
||||
tangentBegin, p3Last - p2Last);
|
||||
if (onEnd)
|
||||
hit = hit && shouldFillEndCap(localUV, tangentBeginNext == vec2(0), endType, p[3], tangentEnd,
|
||||
tangentBeginNext);
|
||||
if (hit)
|
||||
{
|
||||
vec2 normalLast = normalize(mat2(0,1,-1,0)*(p3Last-p2Last));
|
||||
vec2 normalNow = normalize(mat2(0,1,-1,0)*(p[1]-p[0]));
|
||||
vec2 normal = normalLast+normalNow;
|
||||
fill = angleLargeThanPi(normal, localUV-p[0]);
|
||||
}
|
||||
if(onBegin?fill:d<minDistance)
|
||||
{
|
||||
minDistance = min(minDistance, d);
|
||||
|
||||
bool reverse = p[3].y - p[0].y < 0.;
|
||||
|
||||
vec2 tangentBegin = normalize(p[0]-p[1]);
|
||||
vec2 tangentEnd = normalize(p[3]-p[2]);
|
||||
if(tangentBegin.y==0.) tangentBegin.y=reverse?eps:-eps;
|
||||
if(tangentEnd.y==0.) tangentEnd.y=reverse?-eps:eps;
|
||||
int intTest = cubic_bezier_int_test2(localUV, p[0], p[1], p[2], p[3], reverse)
|
||||
+ ray_int_test(localUV, p[0], tangentBegin, reverse)
|
||||
+ ray_int_test(localUV, p[3], tangentEnd, reverse);
|
||||
if(lineType==2 || intTest%2==int(lineType))
|
||||
// if (tangentBegin.y == 0.)
|
||||
// tangentBegin.y = reverse ? eps : -eps;
|
||||
// if (tangentEnd.y == 0.)
|
||||
// tangentEnd.y = reverse ? -eps : eps;
|
||||
int intTest = cubic_bezier_int_test2(localUV, p[0], p[1], p[2], p[3], reverse) +
|
||||
ray_int_test(localUV, p[0], tangentBegin, reverse) +
|
||||
ray_int_test(localUV, p[3], tangentEnd, reverse);
|
||||
|
||||
if (lineType == 2 || (intTest % 2 == int(lineType)))
|
||||
{
|
||||
minDistance = min(minDistance, d);
|
||||
hitElement = true;
|
||||
// elementColor = vec4(1, 1, 0, 1);
|
||||
vec2 metallicRoughness;
|
||||
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
|
||||
}
|
||||
else if(p3Last==p[0]) hitElement = false;
|
||||
// if(distance(localUV,p[0])<=strokeWidth&&p3Last==p[0]&&fill)
|
||||
// {
|
||||
// hitElement = true;
|
||||
// elementColor = vec4(0,0,1,1);
|
||||
// }
|
||||
// else if (p3Last == p[0])
|
||||
// hitElement = false;
|
||||
}
|
||||
|
||||
tangentEndLast = tangentEnd;
|
||||
}
|
||||
p3Last = p[3];
|
||||
p2Last = p[2];
|
||||
}
|
||||
if (hitElement && distance(localUV, p3Last) <= strokeWidth)
|
||||
{
|
||||
// hitElement = shouldFillEndCap(localUV, percent[1] > 1 - 1e-5, endType, p3Last, tangentEndLast, vec2(0));
|
||||
}
|
||||
|
||||
// if (minDistance <= 0.001)
|
||||
// {
|
||||
|
@ -1154,7 +1260,55 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
|
|||
// else if (debugBegin == 2)
|
||||
// elementColor = vec4(0, 1, 0, 1);
|
||||
// }
|
||||
return hitElement;
|
||||
}
|
||||
|
||||
bool drawElement(uint elementIndex, vec2 localUV, out vec3 color, out vec2 metallicRoughness,
|
||||
inout vec3 debugBVH = vec3(0))
|
||||
{
|
||||
bool hitElement = false;
|
||||
vec4 elementColor = vec4(-1);
|
||||
metallicRoughness = vec2(0, 0.8);
|
||||
|
||||
uint currentOffset[] = elementOffset[elementIndex];
|
||||
uint elementBvhRoot = currentOffset[0];
|
||||
uint styleIndex = currentOffset[1];
|
||||
uint pointsOffset = currentOffset[2];
|
||||
uint linesOffset = currentOffset[3];
|
||||
// float widthHeightRatio = uintBitsToFloat(currentOffset[4]);
|
||||
|
||||
elementStack.top = 0;
|
||||
uint elementBvhIndex = 0;
|
||||
uint elementBvhLength = 0x80000000;
|
||||
while (elementBvhIndex < elementBvhLength || !elementStack.empty())
|
||||
{
|
||||
while (elementBvhIndex < elementBvhLength)
|
||||
{
|
||||
vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex];
|
||||
uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x;
|
||||
|
||||
if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw)))
|
||||
{
|
||||
if (leftChild >= elementBvhLength)
|
||||
{
|
||||
if (any(greaterThan(bound.xy + vec2(0.003), localUV)) ||
|
||||
any(greaterThan(localUV, bound.zw - vec2(0.003))))
|
||||
{
|
||||
debugBVH.g = 0;
|
||||
debugBVH.r += 1;
|
||||
}
|
||||
|
||||
uint contourIndex = linesOffset + leftChild - 0x80000000;
|
||||
bool isFillStyle = elementData[styleIndex] <= 0;
|
||||
if (isFillStyle) // Ãæ
|
||||
{
|
||||
hitElement = fillElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex,
|
||||
elementColor, metallicRoughness);
|
||||
}
|
||||
else // Ïß
|
||||
{
|
||||
hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex,
|
||||
elementColor, metallicRoughness);
|
||||
}
|
||||
|
||||
elementBvhIndex = elementBvhLength;
|
||||
|
@ -1182,7 +1336,6 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
|
|||
return hitElement;
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 pixelLocation = ivec2(pixelOffset + gl_GlobalInvocationID.xy);
|
||||
|
@ -1190,12 +1343,13 @@ void main()
|
|||
// imageStore(gBaseColor, pixelLocation, vec4(uv,1,1));
|
||||
// imageStore(gMetallicRoughness, pixelLocation, vec4(uv,1,1));
|
||||
// return;
|
||||
uv = vec2(1)-uv*2;
|
||||
uv = uv * 2 - vec2(1);
|
||||
// vec2 uv = imageLoad(gPaintingTexCoord, pixelLocation).rg;
|
||||
|
||||
vec3 debugBVH = vec3(0);
|
||||
// bool debugHit = false;
|
||||
vec4 color = vec4(1,1,1,-1);
|
||||
// vec4 color = vec4(0.76, 0.33, 0.15, -1);
|
||||
vec4 color = vec4(backgroundColor, -1);
|
||||
vec2 metallicRoughness = vec2(0, 0.8);
|
||||
stack.top = 0;
|
||||
uint index = 0, visitTime = 0;
|
||||
|
@ -1208,47 +1362,40 @@ void main()
|
|||
visitTime++;
|
||||
vec4 bound = bvhBound[index];
|
||||
uint leftChild = bvhChildren[index].x;
|
||||
|
||||
if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw)))
|
||||
{
|
||||
if (any(greaterThan(bound.xy + vec2(0.005), uv)) || any(greaterThan(uv, bound.zw - vec2(0.005))))
|
||||
debugBVH.g += 0.3;
|
||||
|
||||
if (leftChild >= bvhLength)
|
||||
{
|
||||
uint transformIndex = leftChild - 0x80000000;
|
||||
uint zIndex = bvhChildren[index].y >> 18;
|
||||
bvec2 flip = bvec2(bvhChildren[index].y & (1<<16), bvhChildren[index].y & (1<<17));
|
||||
float angle = (float(bvhChildren[index].y&((1<<16)-1)) / 65535.0) * 2 * PI;
|
||||
mat2 rotation = {{cos(angle), -sin(angle)}, {sin(angle), cos(angle)}};
|
||||
vec2 localUV = uv - (bound.xy + bound.zw) / 2;
|
||||
localUV = rotation * localUV;
|
||||
vec2 scale = (bound.zw - bound.xy) / 2;
|
||||
localUV /= scale;
|
||||
if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex>color.w)
|
||||
{
|
||||
//if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005))))
|
||||
if (any(greaterThan(vec2(-1)+vec2(0.005), localUV)) || any(greaterThan(localUV, vec2(1)-vec2(0.005))))
|
||||
debugBVH.g += 0.3;
|
||||
//uint elementIndex = leftChild - bvhLength;
|
||||
//debugBVH.bg += 0.5 * (localUV + vec2(1));
|
||||
uint elementIndex = bvhChildren[index].y - zIndex;
|
||||
mat3x2 transform = elementTranform[transformIndex];
|
||||
vec2 localUV =
|
||||
(mat3(vec3(transform[0], 0), vec3(transform[1], 0), vec3(transform[2], 1)) * vec3(uv, 1)).xy;
|
||||
|
||||
//debugBVH = vec3(0);
|
||||
if(flip.x) localUV.x = -localUV.x;
|
||||
if(flip.y) localUV.y = -localUV.y;
|
||||
vec3 elementColor;
|
||||
vec2 elementMetallicRoughness;
|
||||
if(drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness, debugBVH))
|
||||
if (drawElement(elementIndex, localUV, elementColor, elementMetallicRoughness,
|
||||
debugBVH))
|
||||
{
|
||||
color = vec4(elementColor, zIndex);
|
||||
metallicRoughness = elementMetallicRoughness;
|
||||
}
|
||||
|
||||
}
|
||||
//if(elementIndex == 1 && transformIndex==1)
|
||||
// color = vec4(1,1,0,1);
|
||||
|
||||
index = bvhLength;
|
||||
}
|
||||
else if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw)))
|
||||
else
|
||||
{
|
||||
if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005))))
|
||||
debugBVH.g += 0.3;
|
||||
//debugBVH.r += 0.02;
|
||||
stack.push(index);
|
||||
index = leftChild;
|
||||
}
|
||||
}
|
||||
else
|
||||
index = bvhLength;
|
||||
}
|
||||
|
@ -1272,5 +1419,4 @@ void main()
|
|||
imageStore(gBaseColor, pixelLocation, vec4(debugBVH, 1));
|
||||
imageStore(gMetallicRoughness, pixelLocation, vec4(0, 0.8, 0, 1));
|
||||
}
|
||||
|
||||
}
|
|
@ -36,11 +36,6 @@ void main()
|
|||
lod++;
|
||||
gMetallicRoughness = mt.rg;
|
||||
|
||||
// int pageSize = textureSize(texture_basecolor, levels-1).x;
|
||||
|
||||
// uint pageId = 0;
|
||||
// for(uint i = 0; i < lodExpect; i++)
|
||||
// pageId += 1<<(2*(levels-1-i));
|
||||
uint w = 1<<(levels-1-lodExpect);
|
||||
ivec2 page = ivec2(TexCoords * vec2(w));
|
||||
page = clamp(page, ivec2(0), ivec2(w-1));
|
||||
|
@ -49,7 +44,6 @@ void main()
|
|||
gPaintingIndex = uvec2(0);
|
||||
else
|
||||
gPaintingIndex = uvec2((paintingId<<4)+lodExpect, (page.y<<8)+page.x);
|
||||
gPaintingTexCoord = vec2(1., 1.) - TexCoords * 2;
|
||||
return;
|
||||
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by ArchitectureColoredPainting.rc
|
||||
|
||||
// 新对象的下一组默认值
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
|
@ -1,261 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2018-2022 Antonio Dias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "CaptionButton.h"
|
||||
|
||||
CaptionButton::CaptionButton(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
m_is_active = false;
|
||||
m_is_under_mouse = false;
|
||||
m_is_pressed = false;
|
||||
m_icon_dark = false;
|
||||
|
||||
setAttribute(Qt::WA_Hover);
|
||||
}
|
||||
|
||||
CaptionButton::~CaptionButton()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QPixmap CaptionButton::drawIcon(const QPixmap &icon, bool active, bool force_light)
|
||||
{
|
||||
QImage tmp = icon.toImage();
|
||||
|
||||
if (!active)
|
||||
{
|
||||
for (int i = 0; i < tmp.height(); i++)
|
||||
{
|
||||
for (int j = 0; j < tmp.width(); j++)
|
||||
{
|
||||
QColor pixel = QColor::fromRgba(tmp.pixel(j, i));
|
||||
|
||||
pixel.setRedF(pixel.redF() * 0.5f);
|
||||
pixel.setGreenF(pixel.greenF() * 0.5f);
|
||||
pixel.setBlueF(pixel.blueF() * 0.5f);
|
||||
|
||||
tmp.setPixel(j, i, pixel.rgba());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_icon_dark && !force_light)
|
||||
tmp.invertPixels();
|
||||
|
||||
return QPixmap::fromImage(tmp);
|
||||
}
|
||||
|
||||
void CaptionButton::init(IconType type)
|
||||
{
|
||||
m_type = type;
|
||||
|
||||
setColors();
|
||||
drawIcons();
|
||||
}
|
||||
|
||||
void CaptionButton::drawIcons()
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case IconType::Minimize:
|
||||
{
|
||||
QPixmap icon = QPixmap(":/images/icon_window_minimize.png");
|
||||
|
||||
m_active_icon = drawIcon(icon, true);
|
||||
m_inactive_icon = drawIcon(icon, false);
|
||||
|
||||
break;
|
||||
}
|
||||
case IconType::Restore:
|
||||
{
|
||||
QPixmap icon = QPixmap(":/images/icon_window_restore.png");
|
||||
|
||||
m_active_icon = drawIcon(icon, true);
|
||||
m_inactive_icon = drawIcon(icon, false);
|
||||
|
||||
break;
|
||||
}
|
||||
case IconType::Maximize:
|
||||
{
|
||||
QPixmap icon = QPixmap(":/images/icon_window_maximize.png");
|
||||
|
||||
m_active_icon = drawIcon(icon, true);
|
||||
m_inactive_icon = drawIcon(icon, false);
|
||||
|
||||
break;
|
||||
}
|
||||
case IconType::Close:
|
||||
{
|
||||
QPixmap icon = QPixmap(":/images/icon_window_close.png");
|
||||
|
||||
m_active_icon = drawIcon(icon, true);
|
||||
m_inactive_icon = drawIcon(icon, false);
|
||||
m_close_icon_hover = drawIcon(icon, true, true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CaptionButton::setColors()
|
||||
{
|
||||
if (m_icon_dark)
|
||||
{
|
||||
if (m_type == IconType::Close)
|
||||
{
|
||||
m_normal = QColor("transparent");
|
||||
m_hover = QColor("#F00000");
|
||||
m_pressed = QColor("#F1707A");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_normal = QColor("transparent");
|
||||
m_hover = QColor("#E5E5E5");
|
||||
m_pressed = QColor("#CACACB");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_type == IconType::Close)
|
||||
{
|
||||
m_normal = QColor("transparent");
|
||||
m_hover = QColor("#F00000");
|
||||
m_pressed = QColor("#F1707A");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_normal = QColor("transparent");
|
||||
m_hover = QColor("#505050");
|
||||
m_pressed = QColor("#3F3F3F");
|
||||
}
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void CaptionButton::setIconMode(bool icon_dark)
|
||||
{
|
||||
m_icon_dark = icon_dark;
|
||||
|
||||
drawIcons();
|
||||
setColors();
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void CaptionButton::setActive(bool is_active)
|
||||
{
|
||||
m_is_active = is_active;
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void CaptionButton::setState(int state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case QEvent::HoverEnter:
|
||||
{
|
||||
m_is_under_mouse = true;
|
||||
|
||||
repaint();
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::HoverLeave:
|
||||
{
|
||||
m_is_under_mouse = false;
|
||||
|
||||
repaint();
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
m_is_pressed = true;
|
||||
|
||||
m_is_under_mouse = true;
|
||||
|
||||
repaint();
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
m_is_pressed = false;
|
||||
|
||||
m_is_under_mouse = false;
|
||||
|
||||
repaint();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CaptionButton::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPixmap current_icon = m_active_icon;
|
||||
QColor current_color = m_normal;
|
||||
|
||||
//Change icon if needed
|
||||
if (m_is_under_mouse)
|
||||
{
|
||||
if (m_type == IconType::Close)
|
||||
current_icon = m_close_icon_hover;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_is_active)
|
||||
current_icon = m_inactive_icon;
|
||||
}
|
||||
|
||||
//Change background color if needed
|
||||
if (m_is_pressed)
|
||||
{
|
||||
if (m_is_under_mouse)
|
||||
current_color = m_pressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_is_under_mouse)
|
||||
current_color = m_hover;
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
|
||||
painter.fillRect(rect(), current_color);
|
||||
|
||||
QRect target_rect;
|
||||
target_rect = current_icon.rect();
|
||||
target_rect.setSize(QSize(16, 16));
|
||||
target_rect = QRect(rect().center() - target_rect.center(), target_rect.size());
|
||||
painter.drawPixmap(target_rect, current_icon);
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2018-2022 Antonio Dias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef CAPTIONBUTTON_H
|
||||
#define CAPTIONBUTTON_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
|
||||
class CaptionButton : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CaptionButton(QWidget *parent = nullptr);
|
||||
~CaptionButton();
|
||||
|
||||
enum class IconType
|
||||
{
|
||||
Minimize,
|
||||
Restore,
|
||||
Maximize,
|
||||
Close
|
||||
};
|
||||
|
||||
void init(IconType type);
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
public slots:
|
||||
void setIconMode(bool icon_dark);
|
||||
void setActive(bool is_active);
|
||||
void setState(int state);
|
||||
|
||||
private:
|
||||
//Functions
|
||||
QPixmap drawIcon(const QPixmap &icon, bool active, bool force_light = false);
|
||||
void setColors();
|
||||
void drawIcons();
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
//Variables
|
||||
QPixmap m_inactive_icon;
|
||||
QPixmap m_active_icon;
|
||||
|
||||
QPixmap m_close_icon_hover;
|
||||
|
||||
QColor m_normal;
|
||||
QColor m_hover;
|
||||
QColor m_pressed;
|
||||
|
||||
IconType m_type;
|
||||
bool m_is_active;
|
||||
bool m_is_under_mouse;
|
||||
bool m_is_pressed;
|
||||
bool m_icon_dark;
|
||||
};
|
||||
|
||||
#endif // CAPTIONBUTTON_H
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
#include <lib/qtmaterialstyle.h>
|
||||
#include <lib/qtmaterialtheme.h>
|
||||
#include <QColorDialog>
|
||||
|
||||
class ColorHelper
|
||||
{
|
||||
QtMaterialTheme theme;
|
||||
QColor primary1;
|
||||
public:
|
||||
|
||||
void setPrimary1(const QColor& color)
|
||||
{
|
||||
theme.setColor("primary1", color);
|
||||
primary1 = color;
|
||||
}
|
||||
|
||||
[[nodiscard]] QColor getPrimary1() const
|
||||
{
|
||||
return primary1;
|
||||
}
|
||||
|
||||
ColorHelper()
|
||||
{
|
||||
setPrimary1(QColor::fromRgb(0, 90, 158));
|
||||
QtMaterialStyle::instance().setTheme(&theme);
|
||||
}
|
||||
|
||||
static ColorHelper& instance()
|
||||
{
|
||||
static ColorHelper instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
static QColor execColorDialog(
|
||||
const QColor& initial = instance().getPrimary1(),
|
||||
QWidget* parent = nullptr,
|
||||
const QString& title = ""
|
||||
) {
|
||||
auto dialog = QColorDialog(initial, parent);
|
||||
if (!title.isEmpty())
|
||||
{
|
||||
dialog.setWindowTitle(title);
|
||||
}
|
||||
dialog.adjustSize();
|
||||
dialog.exec();
|
||||
return dialog.selectedColor();
|
||||
}
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
#include "ProjectDataManager.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ProjectDataManager* ProjectDataManager::instance = nullptr;
|
||||
|
||||
ProjectDataManager* ProjectDataManager::Instance()
|
||||
{
|
||||
if (instance == nullptr)
|
||||
instance = new ProjectDataManager();
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ProjectDataManager::addProjectData(ProjectData data)
|
||||
{
|
||||
projectDataList.push_back(data);
|
||||
}
|
||||
|
||||
void ProjectDataManager::setZoom(double x, double y, EditorWidgetItem* item)
|
||||
{
|
||||
for (auto& data : projectDataList) {
|
||||
if (data.item == item) {
|
||||
data.zoomX = x;
|
||||
data.zoomY = y;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPointF ProjectDataManager::getZoomByPainterDeivce(QPaintDevice* device)
|
||||
{
|
||||
for (auto& data : projectDataList) {
|
||||
if (data.item->previewWindow == device) {
|
||||
return QPointF(data.zoomX, data.zoomY);
|
||||
}
|
||||
}
|
||||
return QPointF(1, 1);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include <map>
|
||||
#include <QPaintDevice>
|
||||
#include <QFile>
|
||||
#include <vector>
|
||||
#include "EditorWidgetItem.h"
|
||||
|
||||
struct ProjectData
|
||||
{
|
||||
int width, height;
|
||||
double zoomX, zoomY;
|
||||
QString fileHome;
|
||||
EditorWidgetItem* item;
|
||||
};
|
||||
|
||||
class ProjectDataManager
|
||||
{
|
||||
private:
|
||||
std::vector<ProjectData> projectDataList;
|
||||
ProjectDataManager() = default;
|
||||
~ProjectDataManager() = default;
|
||||
static ProjectDataManager* instance;
|
||||
|
||||
public:
|
||||
static ProjectDataManager* Instance();
|
||||
void addProjectData(ProjectData data);
|
||||
void setZoom(double x, double y, EditorWidgetItem* item);
|
||||
QPointF getZoomByPainterDeivce(QPaintDevice* device);
|
||||
};
|
||||
|
|
@ -1,62 +1,57 @@
|
|||
#include "EditorWidget.h"
|
||||
#include "EditorWidgetItem.h"
|
||||
#include <QMouseEvent>
|
||||
#include <QInputDialog>
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
|
||||
EditorWidget::EditorWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
QImage x;
|
||||
displayLayer = nullptr;
|
||||
displayElement = nullptr;
|
||||
ui.setupUi(this);
|
||||
previewWindow = ui.Preview;
|
||||
treeWidget = ui.LayerTree;
|
||||
tabWidget = ui.DisplayTab;
|
||||
layerInfoDisplayWidget = dynamic_cast<InfoDisplayWidget *>(tabWidget->widget(0));
|
||||
elementInfoDisplayWidget = dynamic_cast<InfoDisplayWidget *>(tabWidget->widget(1));
|
||||
connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidget::onLayerChange);
|
||||
connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this,
|
||||
&EditorWidget::triggerRefreshPreview);
|
||||
connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this,
|
||||
&EditorWidget::triggerRefreshPreview);
|
||||
connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
|
||||
// &EditorWidget::triggerRefreshPreview);
|
||||
// test
|
||||
QFile settingFile;
|
||||
settingFile.setFileName("../data.json");
|
||||
settingFile.open(QFile::ReadOnly);
|
||||
QByteArray setting = settingFile.readAll().trimmed();
|
||||
QJsonParseError jError;
|
||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(setting, &jError));
|
||||
qDebug() << jsonDoc.object().value("height").toDouble();
|
||||
qDebug() << jError.errorString();
|
||||
// end test
|
||||
QJsonObject source = jsonDoc.object();
|
||||
elementManager = new ElementManager(source,previewWindow->getRenderer());
|
||||
layerManager = new LayerManager(source, elementManager);
|
||||
previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toDouble(),jsonDoc.object().value("height").toDouble()));
|
||||
if (layerManager->getRoot() != nullptr)
|
||||
this->createButton = ui.createButton;
|
||||
this->closeButton = ui.closeButton;
|
||||
this->saveButton = ui.saveButton;
|
||||
this->saveAsButton = ui.saveAsButton;
|
||||
this->openButton = ui.openButton;
|
||||
this->tabWidget = ui.tabWidget;
|
||||
while (this->tabWidget->count() > 0)
|
||||
{
|
||||
treeWidget->root = layerManager->getRoot();
|
||||
treeWidget->refresh();
|
||||
treeWidget->addTopLevelItem(treeWidget->root->getQTreeItem());
|
||||
this->tabWidget->removeTab(0);
|
||||
}
|
||||
connect(this->createButton, &QPushButton::clicked, this, [this]() {
|
||||
static int count = 0;
|
||||
this->tabWidget->addTab(new EditorWidgetItem("../data.json",this), "untitled" + QString::number(count++));
|
||||
});
|
||||
connect(this->openButton, &QPushButton::clicked, this, [this]() {
|
||||
QString fileName = QFileDialog::getOpenFileName(this->saveAsButton, QString::fromLocal8Bit("´ò¿ª"), "", QString::fromLocal8Bit("JSONÎļþ(*.json)"));
|
||||
if(!fileName.isEmpty())
|
||||
this->tabWidget->addTab(new EditorWidgetItem(fileName, this), fileName);
|
||||
});
|
||||
connect(this->closeButton, &QPushButton::clicked, this, [this]() {
|
||||
this->tabWidget->removeTab(this->tabWidget->currentIndex());
|
||||
});
|
||||
connect(this->saveButton, &QPushButton::clicked, this, [this]() {
|
||||
EditorWidgetItem* item = dynamic_cast<EditorWidgetItem*>(this->tabWidget->currentWidget());
|
||||
if (item != nullptr)
|
||||
{
|
||||
//item->save();
|
||||
}
|
||||
});
|
||||
connect(this->saveAsButton, &QPushButton::clicked, this, [this]() {
|
||||
EditorWidgetItem* item = dynamic_cast<EditorWidgetItem*>(this->tabWidget->currentWidget());
|
||||
if (item != nullptr)
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this->saveAsButton, QString::fromLocal8Bit("Áí´æΪ"), "", QString::fromLocal8Bit("JSONÎļþ(*.json)"));
|
||||
item->saveAs(fileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EditorWidget::~EditorWidget()
|
||||
void EditorWidget::renameTab(QWidget* target, QString name)
|
||||
{
|
||||
}
|
||||
|
||||
void EditorWidget::paintEvent(QPaintEvent *event)
|
||||
int index = this->tabWidget->indexOf(target);
|
||||
if (index != -1)
|
||||
{
|
||||
this->tabWidget->setTabText(index, name);
|
||||
}
|
||||
|
||||
void EditorWidget::onLayerChange(LayerWrapper *layer)
|
||||
{
|
||||
displayLayer = layer;
|
||||
// TODO : notify InfoDisplayWidget and update
|
||||
dynamic_cast<InfoDisplayWidget *>(tabWidget->widget(0))->setLayer(layer);
|
||||
this->update();
|
||||
}
|
||||
|
||||
void EditorWidget::triggerRefreshPreview()
|
||||
{
|
||||
previewWindow->update();
|
||||
}
|
|
@ -1,39 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "ElementManager.h"
|
||||
#include "InfoDisplayWidget.h"
|
||||
#include "LayerManager.h"
|
||||
#include "LayerTreeWidget.h"
|
||||
#include "PreviewWindow.h"
|
||||
#include <qwidget.h>
|
||||
#include "ui_EditorWidget.h"
|
||||
#include <QPainter>
|
||||
#include <QTreeWidget>
|
||||
#include <QWidget>
|
||||
|
||||
class EditorWidget : public QWidget
|
||||
class EditorWidget :
|
||||
public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
// DATA PART
|
||||
PreviewWindow *previewWindow;
|
||||
ElementManager *elementManager;
|
||||
LayerManager *layerManager;
|
||||
// QT GUI PART
|
||||
Ui::EditorWidgetClass ui;
|
||||
LayerTreeWidget *treeWidget;
|
||||
Ui::EditorWidget ui;
|
||||
QTabWidget* tabWidget;
|
||||
InfoDisplayWidget *layerInfoDisplayWidget, *elementInfoDisplayWidget;
|
||||
// QT DATA PART
|
||||
LayerWrapper *displayLayer;
|
||||
GraphicElement *displayElement;
|
||||
QPushButton* createButton;
|
||||
QPushButton* closeButton;
|
||||
QPushButton* saveButton;
|
||||
QPushButton* saveAsButton;
|
||||
QPushButton* openButton;
|
||||
|
||||
public:
|
||||
EditorWidget(QWidget* parent = nullptr);
|
||||
~EditorWidget();
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void onLayerChange(LayerWrapper *layer);
|
||||
void triggerRefreshPreview();
|
||||
~EditorWidget()=default;
|
||||
void renameTab(QWidget* target, QString name);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#include "ColorPicker.h"
|
||||
|
||||
QString getStyleSheet(const QColor& color)
|
||||
{
|
||||
return
|
||||
"QPushButton#colorPicker {"
|
||||
" border-style: solid;"
|
||||
" border-width: 1px;"
|
||||
" border-color: black;"
|
||||
" background-color: " + color.name() + ";"
|
||||
"}";
|
||||
}
|
||||
|
||||
ColorPicker::ColorPicker(const QColor& color, QWidget* parent) : QPushButton(parent), color(color)
|
||||
{
|
||||
this->setObjectName("colorPicker");
|
||||
this->setStyleSheet(getStyleSheet(color));
|
||||
connect(this, &QPushButton::clicked, this, &ColorPicker::onClicked);
|
||||
}
|
||||
|
||||
QColor ColorPicker::getColor() const
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
void ColorPicker::onClicked()
|
||||
{
|
||||
const QColor newColor = ColorHelper::execColorDialog(this->color, this);
|
||||
if (newColor.isValid() && this->color != newColor)
|
||||
{
|
||||
this->color = newColor;
|
||||
this->setStyleSheet(getStyleSheet(newColor));
|
||||
emit colorChanged(newColor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include "../ColorHelper.hpp"
|
||||
#include <QPushButton>
|
||||
class ColorPicker : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QColor color;
|
||||
public:
|
||||
ColorPicker(const QColor& color = ColorHelper::instance().getPrimary1(), QWidget* parent = nullptr);
|
||||
QColor getColor() const;
|
||||
public slots:
|
||||
void onClicked();
|
||||
signals:
|
||||
void colorChanged(QColor newColor);
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#include "FillStyleWidget.h"
|
||||
#include "ColorPicker.h"
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <qtmaterialtextfield.h>
|
||||
|
||||
FillStyleWidget::FillStyleWidget(std::shared_ptr<MaterialStyleFill> fill, QWidget* parent)
|
||||
: QWidget(parent), fill(fill)
|
||||
{
|
||||
auto* layout = new QGridLayout(this);
|
||||
this->setLayout(layout);
|
||||
|
||||
// ÑÕÉ«
|
||||
auto* material = &plainFill(fill)->material;
|
||||
auto* colorLabel = new QLabel(QStringLiteral("ÑÕÉ«"), this);
|
||||
layout->addWidget(colorLabel, 0, 0);
|
||||
auto* colorPicker = new ColorPicker(material->color);
|
||||
connect(colorPicker, &ColorPicker::colorChanged,
|
||||
[material](QColor color)
|
||||
{
|
||||
material->color = color;
|
||||
});
|
||||
layout->addWidget(colorPicker, 0, 1);
|
||||
|
||||
// ½ðÊô¶È
|
||||
auto* metallicLabel = new QLabel(QStringLiteral("½ðÊô¶È"), this);
|
||||
layout->addWidget(metallicLabel, 1, 0);
|
||||
auto* metallicInput = new QtMaterialTextField(this);
|
||||
metallicInput->setText(QString::number(material->metallicF(), 'g', 3));
|
||||
connect(metallicInput, &QtMaterialTextField::textChanged,
|
||||
[material](const QString& text)
|
||||
{
|
||||
material->setMetallicF(text.toFloat());
|
||||
});
|
||||
layout->addWidget(metallicInput, 1, 1);
|
||||
|
||||
// ´Ö²Ú¶È
|
||||
auto* roughnessLabel = new QLabel(QStringLiteral("´Ö²Ú¶È"), this);
|
||||
layout->addWidget(roughnessLabel, 2, 0);
|
||||
auto* roughnessInput = new QtMaterialTextField(this);
|
||||
roughnessInput->setText(QString::number(material->roughnessF(), 'g', 3));
|
||||
connect(roughnessInput, &QtMaterialTextField::textChanged,
|
||||
[material](const QString& text)
|
||||
{
|
||||
material->setRoughnessF(text.toFloat());
|
||||
});
|
||||
layout->addWidget(roughnessInput, 2, 1);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include "../Renderer/Painting/MaterialStyleFill.h"
|
||||
#include "LayerStyle.h"
|
||||
#include <QWidget>
|
||||
class FillStyleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FillStyleWidget(std::shared_ptr<Renderer::MaterialStyleFill> fill, QWidget* parent = nullptr);
|
||||
std::shared_ptr<Renderer::MaterialStyleFill> fill;
|
||||
};
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#include "LayerCreateWidget.h"
|
||||
#include <QComboBox>
|
||||
|
||||
LayerCreateWidget::LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
this->elementManager = elementManager;
|
||||
ui.setupUi(this);
|
||||
ui.name->setPlaceholderText(QString::fromLocal8Bit(""));
|
||||
ui.name->setText(QString::fromLocal8Bit("×Óͼ²ã-") + QString::number(folderLayer->children.size() + 1));
|
||||
connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
|
||||
elementPool = new ElementPoolWidget(ui.elementPool);
|
||||
elements = elementManager->elements;
|
||||
elementsCheck(folderLayer);
|
||||
elementPool->setElementList(elements);
|
||||
}
|
||||
|
||||
void LayerCreateWidget::elementsCheck(FolderLayerWrapper* parent)
|
||||
{
|
||||
std::set<LayerWrapper*> upSet, downSet;
|
||||
parent->collectUpReachable(upSet);
|
||||
for (auto it = elements.begin(); it != elements.end();)
|
||||
{
|
||||
bool valid = true;
|
||||
auto ele = dynamic_cast<GroupElement*>(*it);
|
||||
if (ele != nullptr)
|
||||
{
|
||||
downSet.clear();
|
||||
ele->collectReachable(downSet);
|
||||
for (auto& layer : downSet)
|
||||
{
|
||||
if (upSet.find(layer) != upSet.end())
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
++it;
|
||||
else
|
||||
it = elements.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
LayerCreateWidget::~LayerCreateWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void LayerCreateWidget::accept()
|
||||
{
|
||||
QJsonObject jsonObj;
|
||||
jsonObj.insert("name", ui.name->text());
|
||||
if (ui.comboBox->currentIndex() == 0) {
|
||||
auto currentEle = elements[elementPool->currentIndex];
|
||||
int index = -1;
|
||||
for (int i = 0; i < elementManager->elements.size(); i++)
|
||||
{
|
||||
if (elementManager->elements[i] == currentEle)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1)
|
||||
return;
|
||||
jsonObj.insert("is-folder", false);
|
||||
jsonObj.insert("element", index);
|
||||
}
|
||||
else {
|
||||
jsonObj.insert("is-folder", true);
|
||||
jsonObj.insert("children", QJsonArray());
|
||||
}
|
||||
QJsonObject transform;
|
||||
QJsonObject offset;
|
||||
QJsonObject scale;
|
||||
scale.insert("x", 1);
|
||||
scale.insert("y", 1);
|
||||
offset.insert("x", 0);
|
||||
offset.insert("y", 0);
|
||||
transform.insert("offset", offset);
|
||||
transform.insert("scale", scale);
|
||||
transform.insert("rotation", 0);
|
||||
jsonObj.insert("transform", transform);
|
||||
jsonObj.insert("referenced-by", QJsonValue());
|
||||
emit LayerInfoReturned(jsonObj);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void LayerCreateWidget::onCurrentIndexChanged(int index) {
|
||||
if (index == 0) {// leaf layer
|
||||
elementPool->setVisible(true);
|
||||
}
|
||||
else {// folder layer
|
||||
elementPool->setVisible(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include <QDialog>
|
||||
#include <QJsonObject>
|
||||
#include "ElementPoolWidget.h"
|
||||
#include "ElementManager.h"
|
||||
#include "ui_LayerCreateWidget.h"
|
||||
|
||||
class LayerCreateWidget :
|
||||
public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
ElementManager* elementManager;
|
||||
std::vector<GraphicElement*> elements;
|
||||
Ui::LayerCreateWidget ui;
|
||||
ElementPoolWidget* elementPool;
|
||||
void elementsCheck(FolderLayerWrapper*);
|
||||
|
||||
|
||||
public:
|
||||
LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent = nullptr);
|
||||
~LayerCreateWidget();
|
||||
void accept() override;
|
||||
|
||||
public slots:
|
||||
void onCurrentIndexChanged(int index);
|
||||
|
||||
signals:
|
||||
void LayerInfoReturned(QJsonObject jsonObj);
|
||||
};
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LayerCreateWidget</class>
|
||||
<widget class="QWidget" name="LayerCreateWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>326</width>
|
||||
<height>355</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,5,1,0">
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maxVisibleItems">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maxCount">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::NoInsert</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>叶子节点</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>组合节点</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>图层名:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="name"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="elementPool" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,71 @@
|
|||
#include "LayerStyleDialog.h"
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
|
||||
LayerStyleDialog::LayerStyleDialog(
|
||||
LayerStyleContainer& styles,
|
||||
const std::shared_ptr<LayerStyle>& existedStyle,
|
||||
QWidget* parent
|
||||
) : QDialog(parent), styles(&styles)
|
||||
{
|
||||
dialogLayout = new QGridLayout;
|
||||
dialogLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
this->setLayout(dialogLayout);
|
||||
|
||||
if (existedStyle)
|
||||
{
|
||||
this->modifyingStyle = existedStyle->clone();
|
||||
|
||||
this->styleWidget = modifyingStyle->getInputWidget();
|
||||
this->styleWidget->setParent(this);
|
||||
dialogLayout->addWidget(styleWidget, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
QStringList unusedStyleNames = styles.unusedStyleNames();
|
||||
auto* typeSelector = new QComboBox(this);
|
||||
|
||||
if (!unusedStyleNames.empty())
|
||||
{
|
||||
typeSelector->addItems(unusedStyleNames);
|
||||
this->modifyingStyle = std::move(styles.makeUnusedStyle(unusedStyleNames[0]));
|
||||
|
||||
dialogLayout->addWidget(typeSelector, 0, 0);
|
||||
|
||||
|
||||
this->styleWidget = this->modifyingStyle->getInputWidget();
|
||||
this->styleWidget->setParent(this);
|
||||
this->dialogLayout->addWidget(styleWidget, 1, 0);
|
||||
connect(typeSelector, &QComboBox::currentTextChanged,
|
||||
this, &LayerStyleDialog::onStyleTypeSelectorChanged);
|
||||
}
|
||||
}
|
||||
auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &LayerStyleDialog::accept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &LayerStyleDialog::reject);
|
||||
dialogLayout->addWidget(buttonBox, 2, 0);
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void LayerStyleDialog::accept()
|
||||
{
|
||||
this->layerStyle = std::move(this->modifyingStyle);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void LayerStyleDialog::onStyleTypeSelectorChanged(const QString& current)
|
||||
{
|
||||
if (this->styleWidget)
|
||||
{
|
||||
this->dialogLayout->removeWidget(this->styleWidget);
|
||||
this->styleWidget->setParent(nullptr);
|
||||
delete styleWidget;
|
||||
}
|
||||
this->modifyingStyle = std::move(styles->makeUnusedStyle(current));
|
||||
this->styleWidget = this->modifyingStyle->getInputWidget();
|
||||
this->styleWidget->setParent(this);
|
||||
this->dialogLayout->addWidget(styleWidget, 1, 0);
|
||||
this->styleWidget->adjustSize();
|
||||
this->adjustSize();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "LayerStyle.h"
|
||||
#include <QDialog>
|
||||
#include <QGridLayout>
|
||||
|
||||
class LayerStyleDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QWidget* styleWidget;
|
||||
QGridLayout* dialogLayout;
|
||||
LayerStyleContainer* styles;
|
||||
std::unique_ptr<LayerStyle> modifyingStyle;
|
||||
public:
|
||||
LayerStyleDialog(
|
||||
LayerStyleContainer& styles,
|
||||
const std::shared_ptr<LayerStyle>& existedStyle = nullptr,
|
||||
QWidget* parent = nullptr
|
||||
);
|
||||
std::shared_ptr<LayerStyle> layerStyle;
|
||||
private slots:
|
||||
void onStyleTypeSelectorChanged(const QString& current);
|
||||
void accept() override;
|
||||
};
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#include "StrokeStyleListView.h"
|
||||
#include "ColorPicker.h"
|
||||
#include <qtmaterialraisedbutton.h>
|
||||
|
||||
constexpr int COLUMN_WIDTH = 0;
|
||||
constexpr int COLUMN_COLOR = 1;
|
||||
constexpr int COLUMN_METALLIC = 2;
|
||||
constexpr int COLUMN_ROUGHNESS = 3;
|
||||
constexpr int COLUMN_OPERATIONS = 4;
|
||||
|
||||
// TODO: 将这个类改为继承QWidget,把table转为其中的一个元素,加上新增行按钮和宽度设置
|
||||
StrokeStyleListView::StrokeStyleListView(
|
||||
std::shared_ptr<Renderer::StrokeRadialGradient> stroke,
|
||||
QWidget* parent
|
||||
) : QTableWidget(parent), stroke(stroke)
|
||||
{
|
||||
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
|
||||
this->setColumnCount(5);
|
||||
this->setRowCount(stroke->materialMap.size());
|
||||
QStringList headers;
|
||||
headers.append(QStringLiteral("离心距离占比"));
|
||||
headers.append(QStringLiteral("颜色"));
|
||||
headers.append(QStringLiteral("金属度"));
|
||||
headers.append(QStringLiteral("粗糙度"));
|
||||
headers.append(QStringLiteral("其他操作"));
|
||||
this->setHorizontalHeaderLabels(headers);
|
||||
for (int row = 0; auto& strokePair : stroke->materialMap)
|
||||
{
|
||||
QTableWidgetItem* widthItem = new QTableWidgetItem;
|
||||
widthItem->setData(Qt::EditRole, strokePair.first);
|
||||
this->setItem(row, COLUMN_WIDTH, widthItem);
|
||||
|
||||
QColor* colorPtr = &(strokePair.second.color);
|
||||
QTableWidgetItem* colorItem = new QTableWidgetItem;
|
||||
colorItem->setData(Qt::DisplayRole, *colorPtr);
|
||||
this->setItem(row, COLUMN_COLOR, colorItem);
|
||||
ColorPicker* colorPicker = new ColorPicker(*colorPtr, this);
|
||||
this->setCellWidget(row, COLUMN_COLOR, colorPicker);
|
||||
connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) {
|
||||
*colorPtr = color;
|
||||
this->update();
|
||||
});
|
||||
|
||||
QTableWidgetItem* metallicItem = new QTableWidgetItem;
|
||||
metallicItem->setData(Qt::EditRole, strokePair.second.metallic);
|
||||
this->setItem(row, COLUMN_METALLIC, metallicItem);
|
||||
|
||||
QTableWidgetItem* roughnessItem = new QTableWidgetItem;
|
||||
roughnessItem->setData(Qt::EditRole, strokePair.second.roughness);
|
||||
this->setItem(row, COLUMN_ROUGHNESS, roughnessItem);
|
||||
|
||||
QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", this);
|
||||
removeButton->setFixedSize(20, 20);
|
||||
this->setCellWidget(row, COLUMN_OPERATIONS, removeButton);
|
||||
connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() {
|
||||
this->stroke->materialMap.erase(this->item(row, COLUMN_WIDTH)->text().toFloat());
|
||||
this->removeRow(row);
|
||||
});
|
||||
|
||||
row++;
|
||||
}
|
||||
connect(this, &StrokeStyleListView::currentItemChanged, this, &StrokeStyleListView::onCurrentItemChanged);
|
||||
connect(this, &StrokeStyleListView::cellChanged, this, &StrokeStyleListView::onCellChanged);
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void StrokeStyleListView::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
|
||||
{
|
||||
if (!current) return;
|
||||
int column = current->column();
|
||||
if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS)
|
||||
{
|
||||
this->currentItemValue = current->text();
|
||||
}
|
||||
}
|
||||
|
||||
void StrokeStyleListView::onCellChanged(int row, int column)
|
||||
{
|
||||
auto changedItem = this->item(row, column);
|
||||
auto changedItemValue = changedItem->text().toFloat();
|
||||
if (changedItemValue < 0 || 1 < changedItemValue)
|
||||
{
|
||||
changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat());
|
||||
return;
|
||||
}
|
||||
auto changedWidth = this->item(row, COLUMN_WIDTH)->text().toFloat();
|
||||
switch (row)
|
||||
{
|
||||
case COLUMN_WIDTH:
|
||||
{
|
||||
float oldWidth = this->currentItemValue.toFloat();
|
||||
auto node = stroke->materialMap.extract(oldWidth);
|
||||
node.key() = changedWidth;
|
||||
stroke->materialMap.insert(std::move(node));
|
||||
break;
|
||||
}
|
||||
case COLUMN_METALLIC:
|
||||
{
|
||||
stroke->materialMap[changedWidth].metallic = changedItemValue;
|
||||
break;
|
||||
}
|
||||
case COLUMN_ROUGHNESS:
|
||||
{
|
||||
stroke->materialMap[changedWidth].roughness = changedItemValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include "LayerStyle.h"
|
||||
#include "../Renderer/Painting/MaterialStyleStroke.h"
|
||||
#include <QListView>
|
||||
#include <QListWidget>
|
||||
#include <QTableWidget>
|
||||
class StrokeStyleListView : public QTableWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QString currentItemValue;
|
||||
|
||||
public:
|
||||
StrokeStyleListView(std::shared_ptr<Renderer::StrokeRadialGradient> stroke, QWidget* parent = nullptr);
|
||||
std::shared_ptr<Renderer::StrokeRadialGradient> stroke;
|
||||
|
||||
protected slots:
|
||||
void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
|
||||
void onCellChanged(int row, int column);
|
||||
};
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
#include "StrokeStyleWidget.h"
|
||||
#include "ColorPicker.h"
|
||||
#include "../ColorHelper.hpp"
|
||||
#include <qtmaterialraisedbutton.h>
|
||||
#include <limits>
|
||||
#include <array>
|
||||
#include <QHeaderView>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
constexpr int COLUMN_WIDTH = 0;
|
||||
constexpr int COLUMN_COLOR = 1;
|
||||
constexpr int COLUMN_METALLIC = 2;
|
||||
constexpr int COLUMN_ROUGHNESS = 3;
|
||||
constexpr int COLUMN_OPERATIONS = 4;
|
||||
|
||||
inline Renderer::Material newMaterial()
|
||||
{
|
||||
return {ColorHelper::instance().getPrimary1()};
|
||||
}
|
||||
|
||||
inline bool isClosedStroke(const std::shared_ptr<MaterialStyleStroke>& stroke)
|
||||
{
|
||||
return stroke->endType == Renderer::StrokeEndType::kClosed;
|
||||
}
|
||||
|
||||
StrokeStyleWidget::StrokeStyleWidget(
|
||||
const std::shared_ptr<MaterialStyleStroke>& stroke,
|
||||
QWidget* parent
|
||||
) : QWidget(parent), stroke(stroke)
|
||||
{
|
||||
auto* viewLayout = new QVBoxLayout(this);
|
||||
this->setLayout(viewLayout);
|
||||
|
||||
initStrokeSettings();
|
||||
auto* strokeProperties = new QWidget(this);
|
||||
auto* strokePropertiesLayout = new QHBoxLayout(strokeProperties);
|
||||
strokePropertiesLayout->setMargin(0);
|
||||
|
||||
strokeProperties->setLayout(strokePropertiesLayout);
|
||||
strokePropertiesLayout->addWidget(enableGradual);
|
||||
if (!isClosedStroke(stroke))
|
||||
{
|
||||
strokePropertiesLayout->addWidget(endTypeBox);
|
||||
}
|
||||
|
||||
viewLayout->addWidget(strokeProperties);
|
||||
viewLayout->addWidget(widthField);
|
||||
|
||||
initTable(radialStroke(stroke));
|
||||
viewLayout->addWidget(strokeTable);
|
||||
|
||||
initAddButton();
|
||||
viewLayout->addWidget(addButton);
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void StrokeStyleWidget::initStrokeSettings()
|
||||
{
|
||||
this->enableGradual = new QtMaterialCheckBox(this);
|
||||
enableGradual->setText(QStringLiteral("渐变"));
|
||||
enableGradual->setChecked(radialStroke(stroke)->gradual);
|
||||
connect(enableGradual, &QtMaterialCheckBox::toggled, [this](bool checked) {
|
||||
radialStroke(this->stroke)->gradual = checked;
|
||||
});
|
||||
|
||||
if (!isClosedStroke(stroke))
|
||||
{
|
||||
this->endTypeBox = new QComboBox(this);
|
||||
for (const auto& displayName : MaterialStyleStroke::strokeEndTypeNames | std::views::keys)
|
||||
{
|
||||
endTypeBox->addItem(displayName);
|
||||
}
|
||||
endTypeBox->setCurrentIndex(static_cast<int>(this->stroke->endType));
|
||||
connect(endTypeBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||
const auto& [displayName, endType] = MaterialStyleStroke::strokeEndTypeNames[index];
|
||||
this->stroke->endType = endType;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this->endTypeBox = nullptr;
|
||||
}
|
||||
|
||||
this->widthField = new QtMaterialTextField(this);
|
||||
widthField->setLabel(QStringLiteral("本侧描边宽度"));
|
||||
widthField->setText(QString::number(stroke->halfWidth));
|
||||
auto* widthValidator = new QDoubleValidator(0.1, std::numeric_limits<float>::max(), 3, widthField);
|
||||
widthValidator->setNotation(QDoubleValidator::StandardNotation);
|
||||
widthField->setValidator(widthValidator);
|
||||
connect(widthField, &QtMaterialTextField::textChanged, [this](const QString& changed) {
|
||||
if (this->widthField->hasAcceptableInput())
|
||||
{
|
||||
this->stroke->halfWidth = changed.toFloat();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void StrokeStyleWidget::initTable(const std::shared_ptr<Renderer::StrokeRadialGradient>& materialStroke)
|
||||
{
|
||||
this->strokeTable = new QTableWidget(this);
|
||||
strokeTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
|
||||
strokeTable->setColumnCount(5);
|
||||
strokeTable->setRowCount(materialStroke->materialMap.size());
|
||||
QStringList headers;
|
||||
headers << QStringLiteral("离心距离占比")
|
||||
<< QStringLiteral("颜色")
|
||||
<< QStringLiteral("金属度")
|
||||
<< QStringLiteral("粗糙度")
|
||||
<< QStringLiteral("其他操作");
|
||||
strokeTable->setHorizontalHeaderLabels(headers);
|
||||
strokeTable->setMinimumHeight(strokeTable->horizontalHeader()->height() * 6);
|
||||
strokeTable->setMinimumWidth(strokeTable->sizeHint().width());
|
||||
int row = 0;
|
||||
// 内容
|
||||
for (auto& [width, material] : std::views::reverse(materialStroke->materialMap))
|
||||
{
|
||||
setTableRow(row, width, material);
|
||||
row++;
|
||||
}
|
||||
connect(strokeTable, &QTableWidget::currentItemChanged, this, &StrokeStyleWidget::onCurrentItemChanged);
|
||||
connect(strokeTable, &QTableWidget::cellChanged, this, &StrokeStyleWidget::onCellChanged);
|
||||
}
|
||||
|
||||
void StrokeStyleWidget::initAddButton()
|
||||
{
|
||||
this->addButton = new QtMaterialRaisedButton("+", strokeTable);
|
||||
addButton->setFixedHeight(30);
|
||||
addButton->setBackgroundColor(ColorHelper::instance().getPrimary1());
|
||||
connect(addButton, &QtMaterialRaisedButton::clicked, [this] {
|
||||
handlingRowInsert = true;
|
||||
auto& materialMap = radialStroke(this->stroke)->materialMap;
|
||||
float newWidth;
|
||||
if (materialMap.empty())
|
||||
{
|
||||
newWidth = 1.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto firstPair = materialMap.begin();
|
||||
newWidth = firstPair->first / 2;
|
||||
}
|
||||
const Renderer::Material newMaterial(ColorHelper::instance().getPrimary1());
|
||||
materialMap[newWidth] = newMaterial;
|
||||
const int newRow = this->strokeTable->rowCount();
|
||||
this->strokeTable->insertRow(newRow);
|
||||
setTableRow(newRow, newWidth, materialMap[newWidth]);
|
||||
this->strokeTable->update();
|
||||
handlingRowInsert = false;
|
||||
});
|
||||
}
|
||||
|
||||
void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& material)
|
||||
{
|
||||
auto* widthItem = new QTableWidgetItem;
|
||||
widthItem->setData(Qt::EditRole, width);
|
||||
strokeTable->setItem(row, COLUMN_WIDTH, widthItem);
|
||||
|
||||
QColor* colorPtr = &material.color;
|
||||
auto* colorItem = new QTableWidgetItem;
|
||||
colorItem->setData(Qt::DisplayRole, *colorPtr);
|
||||
strokeTable->setItem(row, COLUMN_COLOR, colorItem);
|
||||
auto* colorPicker = new ColorPicker(*colorPtr, strokeTable);
|
||||
strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker);
|
||||
connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) {
|
||||
*colorPtr = std::move(color);
|
||||
this->strokeTable->update();
|
||||
});
|
||||
|
||||
auto* metallicItem = new QTableWidgetItem;
|
||||
metallicItem->setData(Qt::EditRole, material.metallicF());
|
||||
strokeTable->setItem(row, COLUMN_METALLIC, metallicItem);
|
||||
|
||||
auto* roughnessItem = new QTableWidgetItem;
|
||||
roughnessItem->setData(Qt::EditRole, material.roughnessF());
|
||||
strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem);
|
||||
|
||||
auto* removeButton = new QtMaterialRaisedButton("-", strokeTable);
|
||||
removeButton->setBackgroundColor(ColorHelper::instance().getPrimary1());
|
||||
removeButton->setFixedSize(20, 20);
|
||||
strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton);
|
||||
connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row] {
|
||||
radialStroke(this->stroke)->materialMap.erase(this->strokeTable->item(row, COLUMN_WIDTH)->text().toFloat());
|
||||
this->strokeTable->removeRow(row);
|
||||
});
|
||||
}
|
||||
|
||||
void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
|
||||
{
|
||||
if (!current) return;
|
||||
const int column = current->column();
|
||||
if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS)
|
||||
{
|
||||
this->currentItemValue = current->data(Qt::EditRole);
|
||||
}
|
||||
}
|
||||
|
||||
void StrokeStyleWidget::onCellChanged(int row, int column)
|
||||
{
|
||||
if (handlingRowInsert) return;
|
||||
const auto changedItem = strokeTable->item(row, column);
|
||||
const auto changedItemValue = changedItem->text().toFloat();
|
||||
if (changedItemValue < 0 || 1 < changedItemValue)
|
||||
{
|
||||
changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat());
|
||||
return;
|
||||
}
|
||||
const auto changedWidth = strokeTable->item(row, COLUMN_WIDTH)->data(Qt::EditRole).toFloat();
|
||||
switch (column)
|
||||
{
|
||||
case COLUMN_WIDTH:
|
||||
{
|
||||
float oldWidth = this->currentItemValue.toFloat();
|
||||
auto node = radialStroke(stroke)->materialMap.extract(oldWidth);
|
||||
if (node.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
node.key() = changedWidth;
|
||||
radialStroke(stroke)->materialMap.insert(std::move(node));
|
||||
strokeTable->sortItems(COLUMN_WIDTH, Qt::DescendingOrder);
|
||||
break;
|
||||
}
|
||||
case COLUMN_METALLIC:
|
||||
{
|
||||
radialStroke(stroke)->materialMap[changedWidth].setMetallicF(changedItemValue);
|
||||
break;
|
||||
}
|
||||
case COLUMN_ROUGHNESS:
|
||||
{
|
||||
radialStroke(stroke)->materialMap[changedWidth].setRoughnessF(changedItemValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
#include "LayerStyle.h"
|
||||
#include "../Renderer/Painting/MaterialStyleStroke.h"
|
||||
#include <QTableWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QComboBox>
|
||||
#include <qtmaterialtextfield.h>
|
||||
#include <qtmaterialcheckbox.h>
|
||||
#include <qtmaterialraisedbutton.h>
|
||||
class StrokeStyleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QVariant currentItemValue;
|
||||
|
||||
QtMaterialCheckBox* enableGradual;
|
||||
QComboBox* endTypeBox;
|
||||
QtMaterialTextField* widthField;
|
||||
QTableWidget* strokeTable;
|
||||
QtMaterialRaisedButton* addButton;
|
||||
bool handlingRowInsert = false;
|
||||
|
||||
void initStrokeSettings();
|
||||
void initTable(const std::shared_ptr<Renderer::StrokeRadialGradient>& materialStroke);
|
||||
void initAddButton();
|
||||
void setTableRow(int row, float width, Renderer::Material& material);
|
||||
|
||||
public:
|
||||
StrokeStyleWidget(const std::shared_ptr<MaterialStyleStroke>& stroke, QWidget* parent = nullptr);
|
||||
std::shared_ptr<MaterialStyleStroke> stroke;
|
||||
|
||||
protected slots:
|
||||
void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
|
||||
void onCellChanged(int row, int column);
|
||||
};
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#include "EditorWidgetItem.h"
|
||||
#include "EditorWidget.h"
|
||||
#include "DataManager/ProjectDataManager.h"
|
||||
#include <QTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
|
||||
EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
QImage x;
|
||||
this->parent = parent;
|
||||
displayLayer = nullptr;
|
||||
displayElement = nullptr;
|
||||
ui.setupUi(this);
|
||||
previewWindow = ui.Preview;
|
||||
treeWidget = ui.LayerTree;
|
||||
tabWidget = ui.DisplayTab;
|
||||
this->filePath = filePath;
|
||||
layerInfoDisplayWidget = dynamic_cast<InfoDisplayWidget *>(tabWidget->widget(0));
|
||||
elementInfoDisplayWidget = dynamic_cast<ElementPoolWidget *>(tabWidget->widget(1));
|
||||
editorSettingWidget = dynamic_cast<EditorSettingWidget*>(tabWidget->widget(2));
|
||||
elementInfoDisplayWidget->enableEdit();
|
||||
qDebug() << layerInfoDisplayWidget;
|
||||
qDebug() << elementInfoDisplayWidget;
|
||||
auto centralRefresh = [this]() {
|
||||
layerInfoDisplayWidget->refresh();
|
||||
elementInfoDisplayWidget->refresh();
|
||||
treeWidget->refresh();
|
||||
previewWindow->refresh();
|
||||
};
|
||||
connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh);
|
||||
connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh);
|
||||
connect(elementInfoDisplayWidget, &ElementPoolWidget::triggerCentralRefresh, centralRefresh);
|
||||
connect(treeWidget, &LayerTreeWidget::triggerCentralRefresh, centralRefresh);
|
||||
connect(editorSettingWidget, &EditorSettingWidget::backgroundColorChanged, this, &EditorWidgetItem::handleBackgroundColorChange);
|
||||
connect(editorSettingWidget, &EditorSettingWidget::projectNameChanged, this, &EditorWidgetItem::handleProjectNameChange);
|
||||
connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex);
|
||||
connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
|
||||
connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged);
|
||||
//connect(treeWidget, &LayerTreeWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
|
||||
// connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
|
||||
connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidgetItem::onLayerChange);
|
||||
// connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this,
|
||||
// &EditorWidgetItem::triggerRefreshPreview);
|
||||
// connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this,
|
||||
// &EditorWidgetItem::triggerRefreshPreview);
|
||||
//connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
|
||||
// connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh);
|
||||
// &EditorWidget::triggerRefreshPreview);
|
||||
// test
|
||||
QFile settingFile;
|
||||
//settingFile.setFileName("../data.json");
|
||||
settingFile.setFileName(filePath);
|
||||
settingFile.open(QFile::ReadOnly);
|
||||
QByteArray setting = settingFile.readAll().trimmed();
|
||||
QJsonParseError jError;
|
||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(setting, &jError));
|
||||
qDebug() << jsonDoc.object().value("height").toDouble();
|
||||
qDebug() << jError.errorString();
|
||||
ProjectData data;
|
||||
data.fileHome = QFileInfo(filePath).absolutePath();
|
||||
data.width = jsonDoc.object().value("height").toInt();
|
||||
data.height = jsonDoc.object().value("width").toInt();
|
||||
data.zoomX = 1.0;
|
||||
data.zoomY = 1.0;
|
||||
data.item = this;
|
||||
ProjectDataManager::Instance()->addProjectData(data);
|
||||
// end test
|
||||
QJsonObject source = jsonDoc.object();
|
||||
elementManager = new ElementManager(source, QFileInfo(filePath).absolutePath());
|
||||
layerManager = new LayerManager(source, elementManager);
|
||||
elementInfoDisplayWidget->setElementManager(elementManager);
|
||||
treeWidget->elementManager = elementManager;
|
||||
//qDebug() << layerManager->toJson();
|
||||
previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toDouble(),jsonDoc.object().value("height").toDouble()));
|
||||
|
||||
|
||||
if (layerManager->getRoot() != nullptr)
|
||||
{
|
||||
treeWidget->root = layerManager->getRoot();
|
||||
treeWidget->refresh();
|
||||
treeWidget->addTopLevelItem(treeWidget->root->getQTreeItem());
|
||||
}
|
||||
this->backgroundColor = source.value("background-color").toVariant().value<QColor>();
|
||||
this->projectName = source.value("project-name").toString();
|
||||
qDebug() << this->backgroundColor;
|
||||
qDebug() << this->projectName;
|
||||
QTimer::singleShot(300, this, [this, centralRefresh]() {
|
||||
handleBackgroundColorChange(this->backgroundColor);
|
||||
handleProjectNameChange(this->projectName);
|
||||
centralRefresh();
|
||||
});
|
||||
}
|
||||
|
||||
EditorWidgetItem::~EditorWidgetItem()
|
||||
{
|
||||
}
|
||||
|
||||
void EditorWidgetItem::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
// 设置画刷的颜色为灰色,并填充整个窗口区域
|
||||
painter.setBrush(Qt::gray);
|
||||
painter.drawRect(this->rect());
|
||||
}
|
||||
|
||||
void EditorWidgetItem::onLayerChange(LayerWrapper *layer)
|
||||
{
|
||||
displayLayer = layer;
|
||||
// TODO : notify InfoDisplayWidget and update
|
||||
dynamic_cast<InfoDisplayWidget *>(tabWidget->widget(0))->setLayer(layer);
|
||||
this->update();
|
||||
}
|
||||
|
||||
void EditorWidgetItem::triggerRefreshPreview()
|
||||
{
|
||||
previewWindow->update();
|
||||
}
|
||||
|
||||
void EditorWidgetItem::save() const
|
||||
{
|
||||
saveImpl(this->filePath);
|
||||
}
|
||||
|
||||
void EditorWidgetItem::saveAs(QString filePath) const
|
||||
{
|
||||
saveImpl(filePath);
|
||||
QString srcHome = QFileInfo(this->filePath).absolutePath();
|
||||
if (!QDir(QFileInfo(filePath).absolutePath() + "/svg").exists())
|
||||
{
|
||||
QDir().mkdir(QFileInfo(filePath).absolutePath() + "/svg");
|
||||
}
|
||||
for (auto& ele : elementManager->elements)
|
||||
{
|
||||
auto e = dynamic_cast<SimpleElement*>(ele);
|
||||
if (e != nullptr)
|
||||
{
|
||||
QString fileName = e->jsonSource["data"].toObject()["include"].toString();
|
||||
QString src = srcHome + fileName;
|
||||
QString dst = QFileInfo(filePath).absolutePath() + fileName;
|
||||
QFile::copy(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EditorWidgetItem::saveImpl(QString filePath) const
|
||||
{
|
||||
QJsonObject source1 = layerManager->toJson();
|
||||
QJsonObject source2 = elementManager->toJson();
|
||||
QJsonObject json;
|
||||
json.insert("width", 1080);
|
||||
json.insert("height", 1080);
|
||||
json.insert("root-layer", source1.value("root-layer"));
|
||||
json.insert("elements", source2.value("elements"));
|
||||
json.insert("project-name", this->projectName);
|
||||
json.insert("background-color", QJsonValue::fromVariant(QVariant::fromValue(this->backgroundColor)));
|
||||
QJsonDocument doc(json);
|
||||
QFile file(filePath);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(doc.toJson());
|
||||
file.close();
|
||||
}
|
||||
|
||||
void EditorWidgetItem::handleBackgroundColorChange(QColor color)
|
||||
{
|
||||
this->backgroundColor = color;
|
||||
previewWindow->setBackgroundColor(color);
|
||||
}
|
||||
|
||||
void EditorWidgetItem::handleProjectNameChange(QString name)
|
||||
{
|
||||
this->projectName = name;
|
||||
auto parent = dynamic_cast<EditorWidget*>(this->parent);
|
||||
qDebug() << name << " " << parent<<" "<<this;
|
||||
if (parent != nullptr)
|
||||
{
|
||||
parent->renameTab(this, name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include "ElementManager.h"
|
||||
#include "ElementPoolWidget.h"
|
||||
#include "InfoDisplayWidget.h"
|
||||
#include "LayerManager.h"
|
||||
#include "LayerTreeWidget.h"
|
||||
#include "PreviewWindow.h"
|
||||
#include "EditorSettingWidget.h"
|
||||
#include "ui_EditorWidgetItem.h"
|
||||
#include <QPainter>
|
||||
#include <QTreeWidget>
|
||||
#include <QWidget>
|
||||
|
||||
class EditorWidgetItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// DATA PART
|
||||
PreviewWindow *previewWindow;
|
||||
ElementManager *elementManager;
|
||||
LayerManager *layerManager;
|
||||
// QT GUI PART
|
||||
Ui::EditorWidgetItem ui;
|
||||
LayerTreeWidget *treeWidget;
|
||||
QTabWidget *tabWidget;
|
||||
InfoDisplayWidget* layerInfoDisplayWidget;
|
||||
ElementPoolWidget* elementInfoDisplayWidget;
|
||||
EditorSettingWidget* editorSettingWidget;
|
||||
// QT DATA PART
|
||||
LayerWrapper *displayLayer;
|
||||
GraphicElement *displayElement;
|
||||
QWidget* parent;
|
||||
void saveImpl(QString filePath)const;
|
||||
public:
|
||||
// PROJECT INFO
|
||||
QString filePath;
|
||||
QString projectName;
|
||||
QColor backgroundColor;
|
||||
|
||||
public:
|
||||
EditorWidgetItem(QString filePath, QWidget *parent = nullptr);
|
||||
~EditorWidgetItem();
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void save() const;
|
||||
void saveAs(QString filePath)const;
|
||||
void handleBackgroundColorChange(QColor color);
|
||||
void handleProjectNameChange(QString name);
|
||||
|
||||
private slots:
|
||||
void onLayerChange(LayerWrapper *layer);
|
||||
void triggerRefreshPreview();
|
||||
};
|
|
@ -1,25 +1,40 @@
|
|||
#include "ElementManager.h"
|
||||
ElementManager::ElementManager(QJsonObject source,Renderer::ElementRenderer* renderer)
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
|
||||
ElementManager::ElementManager(QJsonObject source, QString fileHome)
|
||||
{
|
||||
auto elementsJson = source.value("elements").toArray();
|
||||
qDebug() << elementsJson.size();
|
||||
this->fileHome = fileHome;
|
||||
int index = 0;
|
||||
for (auto elementJson : elementsJson)
|
||||
{
|
||||
if (elementJson.toObject().value("type").toString() == "group")
|
||||
elements.push_back(new GroupElement());
|
||||
else
|
||||
elements.push_back(new SimpleElement(elementJson.toObject()));
|
||||
|
||||
(*elements.rbegin())->renderer = renderer;
|
||||
elements.push_back(new SimpleElement(elementJson.toObject(), fileHome));
|
||||
(*elements.rbegin())->name = elementJson.toObject().value("name").toString();
|
||||
}
|
||||
for (auto element : elements)
|
||||
element->index = index++;
|
||||
}
|
||||
|
||||
void ElementManager::addElement(GraphicElement *element)
|
||||
{
|
||||
this->elements.push_back(element);
|
||||
}
|
||||
|
||||
void ElementManager::removeElement(GraphicElement *pElement)
|
||||
{
|
||||
for (auto& element : elements)
|
||||
{
|
||||
if (element == pElement)
|
||||
{
|
||||
elements.erase(std::find(elements.begin(), elements.end(), element));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GraphicElement *ElementManager::getElementById(int index)
|
||||
|
@ -33,3 +48,57 @@ GraphicElement *ElementManager::getElementById(int index)
|
|||
ElementManager::~ElementManager()
|
||||
{
|
||||
}
|
||||
|
||||
QJsonObject ElementManager::toJson() const
|
||||
{
|
||||
QJsonArray elementsJson;
|
||||
for (auto element : elements)
|
||||
elementsJson.push_back(element->toJson());
|
||||
QJsonObject result;
|
||||
result.insert("elements", elementsJson);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ElementManager::getElementIndex(GraphicElement* pelement)
|
||||
{
|
||||
for (int i = 0; i < elements.size(); i++)
|
||||
if (elements[i] == pelement)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ElementManager::getLayerReferencedBy(const FolderLayerWrapper* layer)
|
||||
{
|
||||
for (int i = 0; i < elements.size(); i++)
|
||||
if (typeid(*elements[i]) == typeid(GroupElement)) {
|
||||
if (((GroupElement*)elements[i])->sourceLayer == layer)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void ElementManager::removeElement(int index)
|
||||
{
|
||||
if (index < elements.size())
|
||||
elements.erase(elements.begin() + index);
|
||||
}
|
||||
|
||||
void ElementManager::createGroupElement(QString name, FolderLayerWrapper* sourceLayer) {
|
||||
auto element = new GroupElement();
|
||||
element->name = name;
|
||||
element->setSourceLayer(sourceLayer);
|
||||
addElement(element);
|
||||
}
|
||||
void ElementManager::createSimpleElement(QString name, QString filePath) {
|
||||
QJsonObject json;
|
||||
QJsonObject data;
|
||||
QFile fileSrc(filePath);
|
||||
QFile::copy(filePath, QDir::cleanPath(fileHome + "/svg/" + QFileInfo(filePath).fileName()));
|
||||
data.insert("include", "/svg/"+QFileInfo(filePath).fileName());
|
||||
json.insert("data", data);
|
||||
auto element = new SimpleElement(json, fileHome);
|
||||
element->name = name;
|
||||
addElement(element);
|
||||
}
|
|
@ -8,19 +8,27 @@ using std::vector;
|
|||
class LayerManager;
|
||||
class GraphicElement;
|
||||
class Renderer::ElementRenderer;
|
||||
class FolderLayerWrapper;
|
||||
|
||||
class ElementManager
|
||||
{
|
||||
private:
|
||||
public:
|
||||
vector<GraphicElement *> elements;
|
||||
QString fileHome;
|
||||
|
||||
public:
|
||||
ElementManager(QJsonObject source,Renderer::ElementRenderer *renderer);
|
||||
ElementManager(QJsonObject source, QString fileHome);
|
||||
~ElementManager();
|
||||
void addElement(GraphicElement *element);
|
||||
void removeElement(GraphicElement *pElement);
|
||||
void removeElement(int index);
|
||||
void createGroupElement(QString name, FolderLayerWrapper* sourceLayer);
|
||||
void createSimpleElement(QString name, QString filePath);
|
||||
QJsonObject toJson()const;
|
||||
/**
|
||||
* only used in initialization
|
||||
*/
|
||||
GraphicElement *getElementById(int index);
|
||||
int getElementIndex(GraphicElement* pElement);
|
||||
int getLayerReferencedBy(const FolderLayerWrapper* layer);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
#include "ElementPoolWidget.h"
|
||||
#include <QMenu>
|
||||
#include <QInputDialog>
|
||||
#include <QFileDialog>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
ElementPoolWidget::ElementPoolWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
elementManager = nullptr;
|
||||
iconWidth = 120, iconHeight = 90;
|
||||
pictureList = new QListWidget(this);
|
||||
pictureList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
pictureList->setIconSize(QSize(iconWidth, iconHeight));
|
||||
pictureList->setWindowFlags(Qt::FramelessWindowHint);
|
||||
pictureList->setResizeMode(QListWidget::Adjust);
|
||||
pictureList->setViewMode(QListWidget::IconMode);
|
||||
pictureList->setMovement(QListWidget::Static);
|
||||
pictureList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
pictureList->setWrapping(true);
|
||||
pictureList->setSpacing(5);
|
||||
pictureList->setStyleSheet("QListWidget::Item:hover{background-color: #f5f5f5;border-radius:5px; }"
|
||||
"QListWidget::item:selected{background-color:rgba(234,234,234,1);color:rgb(61,61,61);border:1px solid #778899;border-radius:2px; }"
|
||||
"QScrollBar:vertical{width:6px}"
|
||||
"QListWidget{outline:none;border:0px}");
|
||||
pictureList->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
QLayout* layout = new QHBoxLayout();
|
||||
layout->addWidget(pictureList);
|
||||
setLayout(layout);
|
||||
//pictureList->setFixedSize(600, 800);
|
||||
|
||||
connect(pictureList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(pictureItemClicked(QListWidgetItem*)));
|
||||
}
|
||||
|
||||
void ElementPoolWidget::setElementList(std::vector<GraphicElement*> elements) {
|
||||
pictureList->clear();
|
||||
this->elements = elements;
|
||||
for (int index = 0; index < elements.size(); index++) {
|
||||
QListWidgetItem* pItem = new QListWidgetItem(
|
||||
elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25)),
|
||||
elements[index]->name);
|
||||
pItem->setSizeHint(QSize(iconWidth, iconHeight));
|
||||
pictureList->insertItem(index, pItem);
|
||||
}
|
||||
if(elements.size() > 0)
|
||||
pictureList->setCurrentRow(0),
|
||||
currentIndex = 0;
|
||||
}
|
||||
|
||||
ElementPoolWidget::~ElementPoolWidget() {
|
||||
|
||||
}
|
||||
|
||||
int ElementPoolWidget::pictureItemClicked(QListWidgetItem* item) {
|
||||
//qDebug() << pictureList->currentRow();
|
||||
currentIndex = pictureList->currentRow();
|
||||
emit elementSelected(this->elements[pictureList->currentRow()]);
|
||||
return pictureList->currentRow();
|
||||
}
|
||||
|
||||
void ElementPoolWidget::setElementManager(ElementManager* element)
|
||||
{
|
||||
this->elementManager = element;
|
||||
this->setElementList(this->elementManager->elements);
|
||||
}
|
||||
|
||||
void ElementPoolWidget::refresh() {
|
||||
this->setElementList(this->elementManager->elements);
|
||||
// update();
|
||||
}
|
||||
|
||||
void ElementPoolWidget::refreshPicture(GraphicElement* element) {
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
if (element == elements[i]) {
|
||||
pictureList->item(i)->setIcon(elements[i]->getPreview(QSize(iconWidth - 25, iconHeight - 25)));
|
||||
// update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElementPoolWidget::refreshPictureByIndex(int index) {
|
||||
if (index >= 0 && index < elements.size())
|
||||
{
|
||||
pictureList->item(index)->setIcon(elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25)));
|
||||
// update();
|
||||
}
|
||||
}
|
||||
|
||||
void ElementPoolWidget::enableEdit()
|
||||
{
|
||||
connect(this->pictureList, &QListWidget::customContextMenuRequested, this, &ElementPoolWidget::popMenu);
|
||||
}
|
||||
|
||||
void ElementPoolWidget::popMenu(const QPoint& pos)
|
||||
{
|
||||
QListWidgetItem* item = pictureList->itemAt(pos);
|
||||
int currentIndex = -1;
|
||||
if (item != nullptr)
|
||||
{
|
||||
currentIndex = pictureList->row(item);
|
||||
}
|
||||
QMenu* menu = new QMenu(this);
|
||||
if (currentIndex >= 0 && currentIndex < elementManager->elements.size())
|
||||
{
|
||||
auto currentElement = this->elementManager->elements[currentIndex];
|
||||
menu->addAction(QString::fromLocal8Bit("重命名"), this, [this, currentElement]() {
|
||||
bool bOk = false;
|
||||
QString sName =
|
||||
QInputDialog::getText(this, QString::fromLocal8Bit("重命名"), QString::fromLocal8Bit("新名称:"), QLineEdit::Normal, currentElement->name, &bOk);
|
||||
if (bOk && !sName.isEmpty())
|
||||
{
|
||||
currentElement->name = sName;
|
||||
emit triggerCentralRefresh();
|
||||
}
|
||||
});
|
||||
menu->addAction(QString::fromLocal8Bit("删除"), this, [this, currentElement]() {
|
||||
this->elementManager->removeElement(currentElement);
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
menu->actions().last()->setDisabled(currentElement->referencedCount > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu->addAction(QString::fromLocal8Bit("添加元素(从svg导入)"), this, [this]() {
|
||||
QString filePath = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("打开文件"), "", "SVG Files (*.svg)");
|
||||
QFileInfo fileInfo(filePath);
|
||||
QString fileName = fileInfo.fileName();
|
||||
qDebug() << fileName << " " << filePath;
|
||||
this->elementManager->createSimpleElement(fileName, filePath);
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
}
|
||||
menu->popup(mapToGlobal(pos));
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <vector>
|
||||
#include <GraphicElement.h>
|
||||
#include <QListWidget>
|
||||
#include <ElementManager.h>
|
||||
#include <QLayout>
|
||||
|
||||
class ElementPoolWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
std::vector<GraphicElement*> elements;
|
||||
QListWidget* pictureList;
|
||||
int iconWidth, iconHeight;
|
||||
ElementManager* elementManager;
|
||||
|
||||
public:
|
||||
int currentIndex = -1;
|
||||
ElementPoolWidget(QWidget* parent = nullptr);
|
||||
void setElementList(std::vector<GraphicElement*> elementList);
|
||||
void setElementManager(ElementManager* element);
|
||||
~ElementPoolWidget();
|
||||
void enableEdit();
|
||||
|
||||
signals:
|
||||
void elementSelected(GraphicElement* element);
|
||||
void refreshLayerTree();
|
||||
void triggerCentralRefresh();
|
||||
|
||||
public slots:
|
||||
int pictureItemClicked(QListWidgetItem* item);
|
||||
void refresh();
|
||||
void refreshPicture(GraphicElement* element);
|
||||
void refreshPictureByIndex(int index);
|
||||
void popMenu(const QPoint& pos);
|
||||
};
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
#include "GraphicElement.h"
|
||||
#include "util/SvgFileLoader.h"
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QDir>
|
||||
|
||||
using namespace std;
|
||||
|
||||
PixelPath SimpleElement::getPaintObject() const
|
||||
{
|
||||
PixelPath result;
|
||||
result.addPath(painterPath);
|
||||
//qDebug() << result.getPainterPath();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -14,14 +19,19 @@ void SimpleElement::loadSvgFile(const QString& filePath)
|
|||
// TODO ÑùʽÎÊÌâ
|
||||
SvgFileLoader loader;
|
||||
loader.loadSvgFile(filePath, painterPath);
|
||||
qDebug() << "load svg file success " << painterPath.elementCount();
|
||||
auto startPoint = static_cast<QPointF>(painterPath.elementAt(0));
|
||||
auto endPoint = static_cast<QPointF>(painterPath.elementAt(painterPath.elementCount() - 1));
|
||||
this->closed = startPoint == endPoint;
|
||||
qDebug() << "load svg file success " << painterPath.elementCount() << (isClosed() ? "is" : "not") << "closed";
|
||||
}
|
||||
|
||||
SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource)
|
||||
SimpleElement::SimpleElement(QJsonObject jsonSource, QString fileHome) : jsonSource(jsonSource)
|
||||
{
|
||||
painterPath.clear();
|
||||
filePath = jsonSource["data"].toObject()["include"].toString();
|
||||
//loadSvgFile("D:\\Projects\\BigC\\svg\\3.svg");
|
||||
loadSvgFile("../"/*TODO: 改成json文件所在文件夹路径*/ + jsonSource.value("data").toObject().value("include").toString());
|
||||
QFileInfo info(QDir::cleanPath(fileHome + "/" + filePath));
|
||||
loadSvgFile(info.absoluteFilePath());
|
||||
}
|
||||
|
||||
GroupElement::GroupElement(FolderLayerWrapper* sourceLayer)
|
||||
|
@ -43,23 +53,11 @@ PixelPath GroupElement::getPaintObject() const
|
|||
}
|
||||
|
||||
//TODO: apply styles and send back
|
||||
PixelPath SimpleElement::getPaintObject(std::vector<Renderer::ElementStyleStrokeDemo> styles) const {
|
||||
PixelPath result;
|
||||
Renderer::ElementStyleStrokeDemo demo(2);
|
||||
auto [img, mov] = renderer->drawElement(painterPath, demo, 1.0, false);
|
||||
//qDebug() << img << " ------";
|
||||
result.addImage(img, mov);
|
||||
//result.addPath(painterPath);
|
||||
// QImage img(80,80,QImage::Format_ARGB32);
|
||||
// QPainter pt(&img);
|
||||
//pt.setPen(QPen(Qt::red, 2));
|
||||
//pt.drawLine(0, 0, 80, 80);
|
||||
//pt.end();
|
||||
//result.addImage(img, QPoint(0, 0));
|
||||
return result;
|
||||
PixelPath SimpleElement::getPaintObject(const LayerStyleContainer& styles) const {
|
||||
return this->getPaintObject();
|
||||
}
|
||||
|
||||
PixelPath GroupElement::getPaintObject(std::vector<Renderer::ElementStyleStrokeDemo> styles) const {
|
||||
PixelPath GroupElement::getPaintObject(const LayerStyleContainer& styles) const {
|
||||
return getPaintObject();
|
||||
}
|
||||
|
||||
|
@ -76,3 +74,101 @@ PixelPath GroupElement::getPaintObject(std::vector<Renderer::ElementStyleStrokeD
|
|||
// rawPath.addPath(path);
|
||||
// }
|
||||
//}
|
||||
//TODO : Ìí¼Óϸ½Ú
|
||||
QJsonObject SimpleElement::toJson() const
|
||||
{
|
||||
QJsonObject result;
|
||||
QJsonObject data;
|
||||
data["include"] = filePath;
|
||||
result["type"] = "svg-file";
|
||||
result["data"] = data;
|
||||
result["name"] = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
QJsonObject GroupElement::toJson() const
|
||||
{
|
||||
QJsonObject result;
|
||||
QJsonObject data;
|
||||
data["reference-layer"] = "0.0";
|
||||
result["type"] = "group";
|
||||
result["data"] = data;
|
||||
result["name"] = name;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SimpleElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles)
|
||||
{
|
||||
painter->save();
|
||||
painter->setTransform(transform);
|
||||
if (styles.empty())
|
||||
{
|
||||
painter->drawPath(painterPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
double angle = atan(transform.m12() / transform.m11());
|
||||
double maxScale;
|
||||
if (fabs(cos(angle))>1e-5)
|
||||
maxScale = std::max(fabs(transform.m11() / cos(angle)), fabs(transform.m22() / cos(angle)));
|
||||
else
|
||||
maxScale = std::max(fabs(transform.m12() / sin(angle)), fabs(transform.m21() / sin(angle)));
|
||||
double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio();
|
||||
auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, styles, pixelRatio);
|
||||
transform.translate(mov.x(), mov.y());
|
||||
painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio));
|
||||
painter->drawImage(0, 0, img);
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
bool SimpleElement::isClosed() const
|
||||
{
|
||||
return closed;
|
||||
}
|
||||
|
||||
void GroupElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles)
|
||||
{
|
||||
sourceLayer->paint(painter, transform, true);
|
||||
}
|
||||
|
||||
bool GroupElement::isClosed() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QPixmap SimpleElement::getPreview(QSize size)
|
||||
{
|
||||
QPixmap result(size + QSize(5, 5));
|
||||
QPainter painter(&result);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter.scale(size.width() / painterPath.boundingRect().width(), size.height() / painterPath.boundingRect().height());
|
||||
painter.drawPath(painterPath);
|
||||
return result;
|
||||
}
|
||||
|
||||
QPixmap GroupElement::getPreview(QSize size)
|
||||
{
|
||||
auto cache = sourceLayer->getCache();
|
||||
QPixmap result(QSize(1024, 1024));
|
||||
QPainter painter(&result);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
sourceLayer->paint(&painter, QTransform(), true);
|
||||
painter.end();
|
||||
QRect rect(cache.getBoundingRect().toRect());
|
||||
rect.setTopLeft(rect.topLeft() - QPoint(5, 5));
|
||||
rect.setBottomRight(rect.bottomRight() + QPoint(5, 5));
|
||||
result = result.copy(rect);
|
||||
return result.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
void GroupElement::collectReachable(std::set<LayerWrapper*>& set) const
|
||||
{
|
||||
if (sourceLayer != nullptr)
|
||||
{
|
||||
sourceLayer->collectDownReachable(set);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "LayerWrapper.h"
|
||||
#include <QJsonArray>
|
||||
#include "LayerStyle.h"
|
||||
#include <QJsonObject>
|
||||
#include <QPainterPath>
|
||||
#include <QImage>
|
||||
|
@ -20,26 +20,40 @@ class ComposedPainterPath;
|
|||
class GraphicElement
|
||||
{
|
||||
public:
|
||||
size_t referencedCount = 0;
|
||||
Renderer::ElementRenderer *renderer;
|
||||
QString name = "";
|
||||
int index;
|
||||
// TODO: ¸ÄΪBitmapPath
|
||||
virtual QJsonObject toJson() const = 0;
|
||||
virtual PixelPath getPaintObject() const = 0;
|
||||
virtual PixelPath getPaintObject(std::vector<Renderer::ElementStyleStrokeDemo>) const = 0;
|
||||
virtual PixelPath getPaintObject(const LayerStyleContainer& styles) const = 0;
|
||||
virtual void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) = 0;
|
||||
virtual bool isClosed() const = 0;
|
||||
virtual QPixmap getPreview(QSize size) = 0;
|
||||
};
|
||||
|
||||
class SimpleElement : public GraphicElement
|
||||
{
|
||||
private:
|
||||
bool closed;
|
||||
public:
|
||||
QJsonObject jsonSource;
|
||||
// TODO: ¸ÄΪComposedPainterPath
|
||||
QPainterPath painterPath;
|
||||
QString filePath;
|
||||
void loadSvgFile(const QString& filePath);
|
||||
|
||||
public:
|
||||
SimpleElement(QJsonObject jsonSource);
|
||||
QJsonObject toJson() const override;
|
||||
SimpleElement(QJsonObject jsonSource, QString fileHome);
|
||||
SimpleElement(QString filePath);
|
||||
~SimpleElement() = default;
|
||||
PixelPath getPaintObject() const override;
|
||||
PixelPath getPaintObject(std::vector<Renderer::ElementStyleStrokeDemo>) const override;
|
||||
PixelPath getPaintObject(const LayerStyleContainer& styles) const override;
|
||||
void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override;
|
||||
bool isClosed() const override;
|
||||
QPixmap getPreview(QSize size) override;
|
||||
};
|
||||
|
||||
class GroupElement : public GraphicElement
|
||||
|
@ -48,12 +62,17 @@ public:
|
|||
FolderLayerWrapper* sourceLayer;
|
||||
|
||||
public:
|
||||
QJsonObject toJson() const override;
|
||||
GroupElement() = default;
|
||||
GroupElement(FolderLayerWrapper* mSourceLayer);
|
||||
~GroupElement() = default;
|
||||
PixelPath getPaintObject() const override;
|
||||
PixelPath getPaintObject(std::vector<Renderer::ElementStyleStrokeDemo>) const override;
|
||||
PixelPath getPaintObject(const LayerStyleContainer& styles) const override;
|
||||
void setSourceLayer(FolderLayerWrapper* sourceLayer);
|
||||
void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override;
|
||||
bool isClosed() const override;
|
||||
QPixmap getPreview(QSize size) override;
|
||||
void collectReachable(std::set<LayerWrapper*>& set) const;
|
||||
};
|
||||
|
||||
//******************************** BitmapPath ********************************//
|
||||
|
|
|
@ -11,10 +11,23 @@ LayerWrapper *LayerManager::getRoot() const
|
|||
{
|
||||
return root;
|
||||
}
|
||||
void LayerManager::paint(QPainter *painter, QSize size) const
|
||||
void LayerManager::paint(QPainter *painter, QSize size,LayerWrapper* selecetedLayer) const
|
||||
{
|
||||
auto p = root->getCache().resizedPixel(size);
|
||||
painter->drawPixmap(0, 0, p);
|
||||
painter->save();
|
||||
root->getCache();
|
||||
root->paint(painter);
|
||||
painter->restore();
|
||||
painter->save();
|
||||
// painter->setBrush(QBrush(Qt::white));
|
||||
//painter->setCompositionMode(QPainter::CompositionMode_Difference);
|
||||
if (selecetedLayer != nullptr)
|
||||
{
|
||||
painter->setPen(QPen(Qt::gray, 2, Qt::DashLine));
|
||||
selecetedLayer->paintVisualBounding(painter);
|
||||
//painter->setPen(QPen(Qt::gray, 2, Qt::DashDotLine));
|
||||
//selecetedLayer->paintVisualBounding(painter);
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
bool LayerManager::singleSelectedCheck() const
|
||||
{
|
||||
|
@ -62,11 +75,20 @@ bool LayerManager::changeParent(FolderLayerWrapper *newParent) const
|
|||
selectedLayers[0]->setParent(newParent);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LayerManager::addLayer(LayerWrapper *layer)
|
||||
{
|
||||
layerSet.insert(layer);
|
||||
}
|
||||
|
||||
void LayerManager::removeLayer(LayerWrapper *layer)
|
||||
{
|
||||
layerSet.erase(layer);
|
||||
}
|
||||
|
||||
QJsonObject LayerManager::toJson() const
|
||||
{
|
||||
QJsonObject result;
|
||||
result.insert("root-layer", root->toJson());
|
||||
return result;
|
||||
}
|
|
@ -31,7 +31,8 @@ class LayerManager
|
|||
LayerWrapper *getRoot() const;
|
||||
LayerManager() = default;
|
||||
LayerManager(QJsonObject source, ElementManager* elementManager);
|
||||
void paint(QPainter *painter, QSize size) const;
|
||||
QJsonObject toJson() const;
|
||||
void paint(QPainter *painter, QSize size, LayerWrapper* selecetedLayer=nullptr) const;
|
||||
bool rename(QString newName) const;
|
||||
bool combine() const;
|
||||
// bool seperate() const;
|
||||
|
|
|
@ -1,6 +1,381 @@
|
|||
#include "LayerStyle.h"
|
||||
#include "./EditorWidgetComponent/StrokeStyleWidget.h"
|
||||
#include "./EditorWidgetComponent/FillStyleWidget.h"
|
||||
#include "./util/EncodeUtil.hpp"
|
||||
#include "../ColorHelper.hpp"
|
||||
#include <qtmaterialcheckbox.h>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#define _USE_JOIN_VIEW_INPUT_RANGE
|
||||
#include <QJsonArray>
|
||||
#include <ranges>
|
||||
|
||||
std::vector<Renderer::BaseStyle> StrokeElementStyle::toBaseStyles() const
|
||||
std::vector<Renderer::BaseStyle> StrokeElementLayerStyle::toBaseStyles() const
|
||||
{
|
||||
return std::vector<Renderer::BaseStyle>();
|
||||
std::vector<Renderer::BaseStyle> baseStyles;
|
||||
if (enableEachSideIndependent)
|
||||
{
|
||||
if (!radialStroke(strokePair.first)->materialMap.empty())
|
||||
{
|
||||
baseStyles.push_back({ std::make_shared<Renderer::TransformStyle>(), strokePair.first });
|
||||
}
|
||||
if (!radialStroke(strokePair.second)->materialMap.empty())
|
||||
{
|
||||
baseStyles.push_back({ std::make_shared<Renderer::TransformStyle>(), strokePair.second });
|
||||
}
|
||||
}
|
||||
else if (!radialStroke(strokePair.first)->materialMap.empty())
|
||||
{
|
||||
const auto material = std::shared_ptr(std::move(strokePair.first->clone()));
|
||||
std::static_pointer_cast<MaterialStyleStroke>(material)->strokeType = Renderer::StrokeType::kBothSides;
|
||||
|
||||
baseStyles.push_back({ std::make_shared<Renderer::TransformStyle>(), material });
|
||||
}
|
||||
return baseStyles;
|
||||
}
|
||||
|
||||
QWidget* StrokeElementLayerStyle::getInputWidget()
|
||||
{
|
||||
auto* w = new QWidget;
|
||||
auto* materialList = new QListView;
|
||||
|
||||
auto* layout = new QVBoxLayout(w);
|
||||
layout->setMargin(0);
|
||||
|
||||
auto* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w);
|
||||
layout->addWidget(leftStrokeView);
|
||||
|
||||
auto* checkEachSideIndependent = new QtMaterialCheckBox(w);
|
||||
checkEachSideIndependent->setText(QStringLiteral("ÓÒ²à¶ÀÁ¢Ãè±ß"));
|
||||
checkEachSideIndependent->setChecked(enableEachSideIndependent);
|
||||
layout->addWidget(checkEachSideIndependent);
|
||||
|
||||
auto* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w);
|
||||
layout->addWidget(rightStrokeView);
|
||||
rightStrokeView->setDisabled(!this->enableEachSideIndependent);
|
||||
|
||||
QObject::connect(checkEachSideIndependent, &QtMaterialCheckBox::toggled, [this, rightStrokeView](bool toggled) {
|
||||
this->enableEachSideIndependent = toggled;
|
||||
rightStrokeView->setDisabled(!toggled);
|
||||
});
|
||||
return w;
|
||||
}
|
||||
|
||||
QWidget* StrokeElementLayerStyle::getListDisplayWidget() const
|
||||
{
|
||||
auto* w = new QWidget;
|
||||
auto* name = new QLabel(w);
|
||||
name->setText(QStringLiteral("Ãè±ß"));
|
||||
auto* layout = new QHBoxLayout(w);
|
||||
layout->setMargin(0);
|
||||
layout->addWidget(name);
|
||||
return w;
|
||||
}
|
||||
|
||||
void LayerStyleContainer::computeNewHash()
|
||||
{
|
||||
hash = 0;
|
||||
for (auto& f : styles
|
||||
| std::views::values
|
||||
| std::views::transform(&LayerStyle::toBaseStyles)
|
||||
| std::views::join
|
||||
| std::views::transform(&Renderer::BaseStyle::material)
|
||||
| std::views::transform(&MaterialStyle::encoded)
|
||||
| std::views::join)
|
||||
{
|
||||
const unsigned int u = *reinterpret_cast<unsigned int*>(&f);
|
||||
hash ^= u + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
LayerStyleContainer LayerStyleContainer::fromJson(bool isClosedElement, const QJsonArray& jsonArray)
|
||||
{
|
||||
LayerStyleContainer container(isClosedElement);
|
||||
for (const auto& style : jsonArray)
|
||||
{
|
||||
container.useStyle(LayerStyle::fromJson(style.toObject()));
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
LayerStyleContainer::LayerStyleContainer(bool isClosedElement) : hash(0)
|
||||
{
|
||||
for (const auto& style : commonStyles)
|
||||
{
|
||||
unusedStyles.insert(style);
|
||||
}
|
||||
if (isClosedElement)
|
||||
{
|
||||
for (const auto& style : closedOnlyStyles)
|
||||
{
|
||||
unusedStyles.insert(style);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& style : unclosedOnlyStyles)
|
||||
{
|
||||
unusedStyles.insert(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Renderer::BaseStyle> LayerStyleContainer::toBaseStyles() const
|
||||
{
|
||||
std::vector<Renderer::BaseStyle> result;
|
||||
for (const auto& style : styles | std::views::values)
|
||||
{
|
||||
auto baseStyles = style->toBaseStyles();
|
||||
result.insert(result.end(),
|
||||
std::make_move_iterator(baseStyles.begin()),
|
||||
std::make_move_iterator(baseStyles.end()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QJsonArray LayerStyleContainer::toJson() const
|
||||
{
|
||||
QJsonArray json;
|
||||
for (const auto& style : styles | std::views::values)
|
||||
{
|
||||
json.append(style->toJson());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
QStringList LayerStyleContainer::unusedStyleNames() const
|
||||
{
|
||||
QStringList result;
|
||||
for(const auto& name : unusedStyles | std::views::keys)
|
||||
{
|
||||
result << name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<LayerStyle> LayerStyleContainer::makeUnusedStyle(const QString& styleName) const
|
||||
{
|
||||
return unusedStyles.at(styleName)();
|
||||
}
|
||||
|
||||
bool LayerStyleContainer::empty() const
|
||||
{
|
||||
return styles.empty();
|
||||
}
|
||||
|
||||
bool LayerStyleContainer::full() const
|
||||
{
|
||||
return unusedStyles.empty();
|
||||
}
|
||||
|
||||
std::map<QString, std::shared_ptr<LayerStyle>>::iterator LayerStyleContainer::begin()
|
||||
{
|
||||
return styles.begin();
|
||||
}
|
||||
|
||||
std::map<QString, std::shared_ptr<LayerStyle>>::iterator LayerStyleContainer::end()
|
||||
{
|
||||
return styles.end();
|
||||
}
|
||||
|
||||
bool LayerStyleContainer::useStyle(const std::shared_ptr<LayerStyle>& style)
|
||||
{
|
||||
auto styleNode = unusedStyles.extract(style->getDisplayName());
|
||||
if (styleNode.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
styles[styleNode.key()] = style;
|
||||
usedStyles.insert(std::move(styleNode));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LayerStyleContainer::dropStyle(const QString& styleName)
|
||||
{
|
||||
auto styleNode = usedStyles.extract(styleName);
|
||||
if (styleNode.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
styles.erase(styleName);
|
||||
unusedStyles.insert(std::move(styleNode));
|
||||
return true;
|
||||
}
|
||||
|
||||
float LayerStyleContainer::boundingBoxAffectValue() const {
|
||||
float maxLineWidth = 0;
|
||||
const auto strokeStyle = styles.find(StrokeElementLayerStyle::displayName());
|
||||
if (strokeStyle != styles.end())
|
||||
{
|
||||
if (const auto strokeElementLayerStyle =
|
||||
std::dynamic_pointer_cast<StrokeElementLayerStyle>(strokeStyle->second);
|
||||
strokeElementLayerStyle != nullptr)
|
||||
{
|
||||
const auto& leftStyleStroke = strokeElementLayerStyle->strokePair.first;
|
||||
const auto& rightStyleStroke = strokeElementLayerStyle->strokePair.second;
|
||||
if (leftStyleStroke != nullptr)
|
||||
{
|
||||
maxLineWidth = std::max(maxLineWidth, leftStyleStroke->halfWidth);
|
||||
}
|
||||
if (rightStyleStroke != nullptr)
|
||||
{
|
||||
maxLineWidth = std::max(maxLineWidth, rightStyleStroke->halfWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxLineWidth;
|
||||
}
|
||||
|
||||
size_t LayerStyleContainer::getHash() const
|
||||
{
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::unique_ptr<StrokeElementLayerStyle> StrokeElementLayerStyle::fromJson(const QJsonObject& json)
|
||||
{
|
||||
auto ptr = std::make_unique<StrokeElementLayerStyle>(
|
||||
std::static_pointer_cast<MaterialStyleStroke>(
|
||||
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["left"].toString()))))
|
||||
),
|
||||
std::static_pointer_cast<MaterialStyleStroke>(
|
||||
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["right"].toString()))))
|
||||
)
|
||||
);
|
||||
ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
StrokeElementLayerStyle::StrokeElementLayerStyle(bool isClosed)
|
||||
{
|
||||
const auto materialMap = std::map<float, Renderer::Material>();
|
||||
this->strokePair.first = std::make_shared<MaterialStyleStroke>(
|
||||
7,
|
||||
Renderer::StrokeType::kLeftSide, isClosed ? Renderer::StrokeEndType::kClosed : Renderer::StrokeEndType::kFlat,
|
||||
std::make_shared<Renderer::StrokeRadialGradient>(materialMap, false)
|
||||
);
|
||||
|
||||
this->strokePair.second = std::make_shared<MaterialStyleStroke>(
|
||||
7,
|
||||
Renderer::StrokeType::kRightSide, isClosed ? Renderer::StrokeEndType::kClosed : Renderer::StrokeEndType::kFlat,
|
||||
std::make_shared<Renderer::StrokeRadialGradient>(materialMap, false)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
StrokeElementLayerStyle::StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right)
|
||||
{
|
||||
this->strokePair.first = left;
|
||||
this->strokePair.second = right ? right : std::static_pointer_cast<MaterialStyleStroke>(
|
||||
std::shared_ptr(std::move(left->clone()))
|
||||
);
|
||||
}
|
||||
|
||||
StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& other)
|
||||
{
|
||||
strokePair.first = std::static_pointer_cast<MaterialStyleStroke>(
|
||||
std::shared_ptr(std::move(other.strokePair.first->clone()))
|
||||
);
|
||||
strokePair.second = std::static_pointer_cast<MaterialStyleStroke>(
|
||||
std::shared_ptr(std::move(other.strokePair.second->clone()))
|
||||
);
|
||||
enableEachSideIndependent = other.enableEachSideIndependent;
|
||||
}
|
||||
|
||||
QJsonObject StrokeElementLayerStyle::toJson() const
|
||||
{
|
||||
auto json = LayerStyle::toJson();
|
||||
json["enableEachSideIndependent"] = enableEachSideIndependent;
|
||||
json["left"] = EncodeUtil::toBase64<GLfloat>(strokePair.first->encoded());
|
||||
json["right"] = EncodeUtil::toBase64<GLfloat>(strokePair.second->encoded());
|
||||
return json;
|
||||
}
|
||||
|
||||
std::unique_ptr<LayerStyle> StrokeElementLayerStyle::clone() const
|
||||
{
|
||||
return std::make_unique<StrokeElementLayerStyle>(StrokeElementLayerStyle(*this));
|
||||
}
|
||||
|
||||
std::unique_ptr<FillElementLayerStyle> FillElementLayerStyle::fromJson(const QJsonObject& json)
|
||||
{
|
||||
auto ptr = std::make_unique<FillElementLayerStyle>(
|
||||
std::static_pointer_cast<MaterialStyleFill>(
|
||||
std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64<GLfloat>(json["material"].toString()))))
|
||||
)
|
||||
);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::vector<Renderer::BaseStyle> FillElementLayerStyle::toBaseStyles() const
|
||||
{
|
||||
return { {std::make_shared<Renderer::TransformStyle>(), fillMaterialStyle} };
|
||||
}
|
||||
|
||||
QWidget* FillElementLayerStyle::getInputWidget()
|
||||
{
|
||||
return new FillStyleWidget(fillMaterialStyle);
|
||||
}
|
||||
|
||||
QWidget* FillElementLayerStyle::getListDisplayWidget() const
|
||||
{
|
||||
auto* w = new QWidget;
|
||||
auto* name = new QLabel(w);
|
||||
name->setText(QStringLiteral("Ìî³ä"));
|
||||
auto* layout = new QHBoxLayout(w);
|
||||
layout->setMargin(0);
|
||||
layout->addWidget(name);
|
||||
return w;
|
||||
}
|
||||
|
||||
FillElementLayerStyle::FillElementLayerStyle(const PMaterialStyleFill& fillMaterialStyle)
|
||||
: fillMaterialStyle(fillMaterialStyle)
|
||||
{
|
||||
if (!fillMaterialStyle)
|
||||
{
|
||||
this->fillMaterialStyle = std::make_shared<MaterialStyleFill>(
|
||||
std::make_shared<Renderer::FillPlain>(ColorHelper::instance().getPrimary1())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other)
|
||||
{
|
||||
this->fillMaterialStyle = std::static_pointer_cast<MaterialStyleFill>(
|
||||
std::shared_ptr(std::move(other.fillMaterialStyle->clone()))
|
||||
);
|
||||
}
|
||||
|
||||
QJsonObject FillElementLayerStyle::toJson() const
|
||||
{
|
||||
auto json = LayerStyle::toJson();
|
||||
json["material"] = EncodeUtil::toBase64<GLfloat>(fillMaterialStyle->encoded());
|
||||
return json;
|
||||
}
|
||||
|
||||
std::unique_ptr<LayerStyle> FillElementLayerStyle::clone() const
|
||||
{
|
||||
return std::make_unique<FillElementLayerStyle>(FillElementLayerStyle(*this));
|
||||
}
|
||||
|
||||
std::unique_ptr<LayerStyle> LayerStyle::fromJson(const QJsonObject& json)
|
||||
{
|
||||
QString type = json["type"].toString();
|
||||
if (type == StrokeElementLayerStyle::typeName())
|
||||
{
|
||||
return StrokeElementLayerStyle::fromJson(json);
|
||||
}
|
||||
if (type == FillElementLayerStyle::typeName())
|
||||
{
|
||||
return FillElementLayerStyle::fromJson(json);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QJsonObject LayerStyle::toJson() const
|
||||
{
|
||||
QJsonObject json;
|
||||
json["type"] = this->getTypeName();
|
||||
return json;
|
||||
}
|
||||
|
|
|
@ -1,24 +1,136 @@
|
|||
#pragma once
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <QListWidget>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include "../Renderer/Painting/ElementStyle.h"
|
||||
#include "../Renderer/Painting/MaterialStyleStroke.h"
|
||||
#include "../Renderer/Painting/MaterialStyleFill.h"
|
||||
|
||||
class LayerStyle
|
||||
using Renderer::MaterialStyle;
|
||||
using Renderer::MaterialStyleStroke;
|
||||
using Renderer::MaterialStyleFill;
|
||||
|
||||
#define STYLE_NAME(display_name, type_name) \
|
||||
static QString displayName() { return QStringLiteral(display_name); } \
|
||||
QString getDisplayName() const override { return QStringLiteral(display_name); } \
|
||||
static QString typeName() { return type_name; } \
|
||||
QString getTypeName() const override { return type_name; }
|
||||
#define radialStroke(stroke) std::static_pointer_cast<Renderer::StrokeRadialGradient>((stroke)->materialStroke)
|
||||
#define plainFill(fill) std::static_pointer_cast<Renderer::FillPlain>((fill)->materialFill)
|
||||
|
||||
class LayerStyle : public Renderer::ElementStyle
|
||||
{
|
||||
public:
|
||||
virtual void apply() = 0;
|
||||
static std::unique_ptr<LayerStyle> fromJson(const QJsonObject& json);
|
||||
virtual ~LayerStyle() = default;
|
||||
|
||||
virtual QString getDisplayName() const = 0;
|
||||
virtual QString getTypeName() const = 0;
|
||||
|
||||
virtual QWidget* getInputWidget() = 0;
|
||||
virtual QWidget* getListDisplayWidget() const = 0;
|
||||
|
||||
virtual QJsonObject toJson() const;
|
||||
virtual std::unique_ptr<LayerStyle> clone() const = 0;
|
||||
};
|
||||
|
||||
struct EditorStrokeMaterialStyle
|
||||
class StrokeElementLayerStyle : public LayerStyle
|
||||
{
|
||||
float applyWidth;
|
||||
Renderer::StrokeType strokeType;
|
||||
Renderer::StrokeEndType endType;
|
||||
std::shared_ptr<Renderer::MaterialStroke> materialStroke;
|
||||
};
|
||||
using PMaterialStyleStroke = std::shared_ptr<MaterialStyleStroke>;
|
||||
|
||||
class StrokeElementStyle : Renderer::ElementStyle
|
||||
{
|
||||
public:
|
||||
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override;
|
||||
std::vector<EditorStrokeMaterialStyle> materialStyles;
|
||||
STYLE_NAME("描边", "stroke")
|
||||
static std::unique_ptr<StrokeElementLayerStyle> fromJson(const QJsonObject& json);
|
||||
|
||||
StrokeElementLayerStyle(bool isClosed);
|
||||
StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right = nullptr);
|
||||
StrokeElementLayerStyle(const StrokeElementLayerStyle& other);
|
||||
~StrokeElementLayerStyle() override = default;
|
||||
|
||||
std::vector<Renderer::BaseStyle> toBaseStyles() const override;
|
||||
QWidget* getInputWidget() override;
|
||||
QWidget* getListDisplayWidget() const override;
|
||||
QJsonObject toJson() const override;
|
||||
std::unique_ptr<LayerStyle> clone() const override;
|
||||
|
||||
std::pair<PMaterialStyleStroke, PMaterialStyleStroke> strokePair;
|
||||
bool enableEachSideIndependent = false;
|
||||
};
|
||||
|
||||
class FillElementLayerStyle : public LayerStyle
|
||||
{
|
||||
using PMaterialStyleFill = std::shared_ptr<MaterialStyleFill>;
|
||||
|
||||
public:
|
||||
STYLE_NAME("填充", "fill")
|
||||
static std::unique_ptr<FillElementLayerStyle> fromJson(const QJsonObject& json);
|
||||
|
||||
FillElementLayerStyle(const PMaterialStyleFill& fillMaterialStyle = nullptr);
|
||||
FillElementLayerStyle(const FillElementLayerStyle& other);
|
||||
~FillElementLayerStyle() override = default;
|
||||
|
||||
std::vector<Renderer::BaseStyle> toBaseStyles() const override;
|
||||
QWidget* getInputWidget() override;
|
||||
QWidget* getListDisplayWidget() const override;
|
||||
QJsonObject toJson() const override;
|
||||
std::unique_ptr<LayerStyle> clone() const override;
|
||||
|
||||
PMaterialStyleFill fillMaterialStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
* LayerStyle的容器,在每次数据变更时需要手动调用computeNewHash()方法,否则哈希值不会更新
|
||||
*/
|
||||
class LayerStyleContainer : public Renderer::ElementStyle
|
||||
{
|
||||
using DisplayNameWithSupplier = std::map<QString, std::function<std::unique_ptr<LayerStyle>()>>;
|
||||
|
||||
private:
|
||||
inline const static DisplayNameWithSupplier commonStyles = { };
|
||||
inline const static DisplayNameWithSupplier closedOnlyStyles = {
|
||||
{
|
||||
FillElementLayerStyle::displayName(),
|
||||
[] { return std::make_unique<FillElementLayerStyle>(); }
|
||||
},
|
||||
{
|
||||
StrokeElementLayerStyle::displayName(),
|
||||
[] { return std::make_unique<StrokeElementLayerStyle>(true); }
|
||||
}
|
||||
};
|
||||
inline const static DisplayNameWithSupplier unclosedOnlyStyles = { {
|
||||
StrokeElementLayerStyle::displayName(),
|
||||
[] { return std::make_unique<StrokeElementLayerStyle>(false); }
|
||||
} };
|
||||
|
||||
DisplayNameWithSupplier unusedStyles;
|
||||
DisplayNameWithSupplier usedStyles;
|
||||
std::map<QString, std::shared_ptr<LayerStyle>> styles;
|
||||
size_t hash;
|
||||
public:
|
||||
static LayerStyleContainer fromJson(bool isClosedElement, const QJsonArray& jsonArray);
|
||||
|
||||
LayerStyleContainer(bool isClosedElement);
|
||||
std::vector<Renderer::BaseStyle> toBaseStyles() const override;
|
||||
QJsonArray toJson() const;
|
||||
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
std::map<QString, std::shared_ptr<LayerStyle>>::iterator begin();
|
||||
std::map<QString, std::shared_ptr<LayerStyle>>::iterator end();
|
||||
|
||||
QStringList unusedStyleNames() const;
|
||||
std::unique_ptr<LayerStyle> makeUnusedStyle(const QString& styleName) const;
|
||||
bool useStyle(const std::shared_ptr<LayerStyle>& style);
|
||||
bool dropStyle(const QString& styleName);
|
||||
float boundingBoxAffectValue() const;
|
||||
size_t getHash() const;
|
||||
|
||||
/**
|
||||
* 需要在每次更改后手动调用
|
||||
*/
|
||||
void computeNewHash();
|
||||
};
|
|
@ -23,16 +23,22 @@ FolderLayerWrapper*LayerWrapper::getParent() const
|
|||
return this == nullptr ? nullptr : this->parent;
|
||||
}
|
||||
|
||||
PixelPath LayerWrapper::getCache()
|
||||
PixelPath LayerWrapper::getCache(LayerWrapper* selectedLayer)
|
||||
{
|
||||
this->refresh();
|
||||
this->refresh(selectedLayer);
|
||||
if (selectedLayer == this)
|
||||
{
|
||||
this->cache.highLight();
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
// TODO: undone
|
||||
LayerWrapper::LayerWrapper(QJsonObject json, FolderLayerWrapper*parent)
|
||||
LayerWrapper::LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementManager* elementManager)
|
||||
{
|
||||
this->parent = parent;
|
||||
this->elementManager = elementManager;
|
||||
this->qTreeWidgetItem = new QTreeWidgetItem();
|
||||
auto transformJson = json.value("transform").toObject();
|
||||
property.name = json.value("name").toString();
|
||||
property.offset = {transformJson.value("offset").toObject().value("x").toDouble(),
|
||||
|
@ -40,10 +46,12 @@ LayerWrapper::LayerWrapper(QJsonObject json, FolderLayerWrapper*parent)
|
|||
property.scale = {transformJson.value("scale").toObject().value("x").toDouble(),
|
||||
transformJson.value("scale").toObject().value("y").toDouble()};
|
||||
property.rotation = {transformJson.value("rotation").toDouble()};
|
||||
selected = false;
|
||||
hidden = false;
|
||||
}
|
||||
|
||||
FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent)
|
||||
: LayerWrapper(json, parent)
|
||||
: LayerWrapper(json, parent, elementManager)
|
||||
{
|
||||
qDebug() << json.value("name").toString() << " " << this;
|
||||
QJsonArray childrenJson = json.value("children").toArray();
|
||||
|
@ -53,6 +61,7 @@ FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *element
|
|||
auto p = reinterpret_cast<GroupElement *>(elementManager->getElementById(referencedJson.toInt()));
|
||||
if (p != nullptr)
|
||||
p->setSourceLayer(this);
|
||||
this->referencedBy = referencedJson.toInt();
|
||||
}
|
||||
for (auto childJson : childrenJson)
|
||||
{
|
||||
|
@ -66,13 +75,37 @@ FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *element
|
|||
}
|
||||
|
||||
LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager* elementManager, FolderLayerWrapper* parent)
|
||||
: LayerWrapper(json, parent)
|
||||
: LayerWrapper(json, parent, elementManager),
|
||||
wrappedElement(elementManager->getElementById(json.value("element").toInt())),
|
||||
styles(LayerStyleContainer::fromJson(wrappedElement->isClosed(), json.value("styles").toArray()))
|
||||
{
|
||||
qDebug() << json.value("name").toString() << " " << this;
|
||||
int elementIndex = json.value("element").toInt();
|
||||
wrappedElement = elementManager->getElementById(elementIndex);
|
||||
if(wrappedElement != nullptr)
|
||||
wrappedElement->referencedCount++;
|
||||
}
|
||||
void LayerWrapper::SimpleProperty::apply(PixelPath&cache) const
|
||||
|
||||
LeafLayerWrapper::~LeafLayerWrapper()
|
||||
{
|
||||
if (wrappedElement != nullptr)
|
||||
wrappedElement->referencedCount--;
|
||||
}
|
||||
|
||||
void LayerWrapper::SimpleProperty::apply(PixelPath&cache)
|
||||
{
|
||||
transform.reset();
|
||||
double centerX = cache.getBoundingRect().center().x();
|
||||
double centerY = cache.getBoundingRect().center().y();
|
||||
//qDebug() << name << " " << cache.boundingRect().center();
|
||||
//qDebug() << name << " " << cache.boundingRect();
|
||||
transform.translate(centerX, centerY);
|
||||
transform.translate(offset.x(), offset.y());
|
||||
transform.rotate(rotation);
|
||||
transform.scale(scale.x(), scale.y());
|
||||
transform.translate(-centerX, -centerY);
|
||||
cache = cache.trans(transform);
|
||||
}
|
||||
|
||||
QTransform LayerWrapper::getTransform()
|
||||
{
|
||||
QTransform trans;
|
||||
double centerX = cache.getBoundingRect().center().x();
|
||||
|
@ -80,28 +113,28 @@ void LayerWrapper::SimpleProperty::apply(PixelPath&cache) const
|
|||
//qDebug() << name << " " << cache.boundingRect().center();
|
||||
//qDebug() << name << " " << cache.boundingRect();
|
||||
trans.translate(centerX, centerY);
|
||||
trans.scale(scale.x(), scale.y());
|
||||
trans.rotate(rotation);
|
||||
trans.translate(property.offset.x(), property.offset.y());
|
||||
trans.rotate(property.rotation);
|
||||
trans.scale(property.scale.x(), property.scale.y());
|
||||
trans.translate(-centerX, -centerY);
|
||||
trans.translate(offset.x(), offset.y());
|
||||
cache = cache.trans(trans);
|
||||
return trans;
|
||||
}
|
||||
void LayerWrapper::refresh()
|
||||
|
||||
void LayerWrapper::refresh(LayerWrapper* layer)
|
||||
{
|
||||
property.apply(cache);
|
||||
}
|
||||
|
||||
void FolderLayerWrapper::refresh()
|
||||
void FolderLayerWrapper::refresh(LayerWrapper* layer)
|
||||
{
|
||||
cache.clear();
|
||||
for (auto& child : children) {
|
||||
qDebug() << child.get();
|
||||
cache.addPath(child.get()->getCache());
|
||||
cache.addPath(child.get()->getCache(layer));
|
||||
}
|
||||
LayerWrapper::refresh();
|
||||
}
|
||||
|
||||
void LeafLayerWrapper::refresh()
|
||||
void LeafLayerWrapper::refresh(LayerWrapper* layer)
|
||||
{
|
||||
cache.clear();
|
||||
if (wrappedElement != nullptr)
|
||||
|
@ -119,22 +152,22 @@ void LayerWrapper::setParent(FolderLayerWrapper* newParent)
|
|||
void FolderLayerWrapper::removeAllChild()
|
||||
{
|
||||
children.clear();
|
||||
qTreeWidgetItem.takeChildren();
|
||||
qTreeWidgetItem->takeChildren();
|
||||
}
|
||||
|
||||
void LayerWrapper::del() {
|
||||
qDebug() << "LayerWrapper::del()";
|
||||
if (parent != nullptr){
|
||||
qTreeWidgetItem.takeChildren();
|
||||
parent->qTreeWidgetItem.removeChild(&qTreeWidgetItem);
|
||||
qTreeWidgetItem->takeChildren();
|
||||
parent->qTreeWidgetItem->removeChild(qTreeWidgetItem);
|
||||
}
|
||||
}
|
||||
|
||||
void LayerWrapper::delSelf() {
|
||||
qDebug() << "LayerWrapper::delSelf()";
|
||||
if (parent != nullptr) {
|
||||
qTreeWidgetItem.takeChildren();
|
||||
parent->qTreeWidgetItem.removeChild(&qTreeWidgetItem);
|
||||
qTreeWidgetItem->takeChildren();
|
||||
parent->qTreeWidgetItem->removeChild(qTreeWidgetItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +187,7 @@ void FolderLayerWrapper::delSelf() {
|
|||
qDebug() << this;
|
||||
for (auto& child : this->children) {
|
||||
this->parent->addChild(child);
|
||||
this->parent->qTreeWidgetItem.addChild(&child.get()->qTreeWidgetItem);
|
||||
this->parent->qTreeWidgetItem->addChild(child.get()->qTreeWidgetItem);
|
||||
child->setParent(this->parent);
|
||||
}
|
||||
while (!this->children.empty()) {
|
||||
|
@ -166,18 +199,258 @@ void FolderLayerWrapper::delSelf() {
|
|||
|
||||
QTreeWidgetItem* LayerWrapper::getQTreeItem()
|
||||
{
|
||||
this->qTreeWidgetItem.setText(0, this->property.name);
|
||||
this->qTreeWidgetItem.setData(0, Qt::UserRole, QVariant::fromValue(this));
|
||||
return &this->qTreeWidgetItem;
|
||||
this->qTreeWidgetItem->setData(0, Qt::UserRole, QVariant::fromValue(this));
|
||||
this->qTreeWidgetItem->setCheckState(0, Qt::Checked);
|
||||
return this->qTreeWidgetItem;
|
||||
}
|
||||
|
||||
QTreeWidgetItem* LeafLayerWrapper::getQTreeItem()
|
||||
{
|
||||
if (this->qTreeWidgetItem == nullptr)
|
||||
this->qTreeWidgetItem = new QTreeWidgetItem();
|
||||
if (typeid(*wrappedElement) == typeid(GroupElement))
|
||||
{
|
||||
this->qTreeWidgetItem->setText(0, "@ "+this->property.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->qTreeWidgetItem->setText(0, this->property.name);
|
||||
}
|
||||
this->qTreeWidgetItem->setText(1,">> "+this->wrappedElement->name);
|
||||
this->qTreeWidgetItem->setTextColor(1, Qt::blue);
|
||||
return LayerWrapper::getQTreeItem();
|
||||
}
|
||||
|
||||
QTreeWidgetItem* FolderLayerWrapper::getQTreeItem()
|
||||
{
|
||||
while (this->qTreeWidgetItem.childCount() > 0) {
|
||||
this->qTreeWidgetItem.removeChild(this->qTreeWidgetItem.child(0));
|
||||
}
|
||||
for (auto& child : this->children) {
|
||||
this->qTreeWidgetItem.addChild(child->getQTreeItem());
|
||||
this->qTreeWidgetItem->addChild(child->getQTreeItem());
|
||||
}
|
||||
this->qTreeWidgetItem->setText(0, this->property.name);
|
||||
auto ele = this->elementManager->getElementById(this->getReferencedBy());
|
||||
if (ele != nullptr)
|
||||
{
|
||||
this->qTreeWidgetItem->setText(1, "<< " + ele->name);
|
||||
this->qTreeWidgetItem->setTextColor(1, Qt::darkGreen);
|
||||
}
|
||||
return LayerWrapper::getQTreeItem();
|
||||
}
|
||||
|
||||
//TODO: add effects
|
||||
|
||||
QJsonObject LayerWrapper::toJson() const
|
||||
{
|
||||
QJsonObject json;
|
||||
json.insert("name", property.name);
|
||||
QJsonObject transformJson;
|
||||
transformJson.insert("offset", QJsonObject({ {"x", property.offset.x()}, {"y", property.offset.y()} }));
|
||||
transformJson.insert("scale", QJsonObject({ {"x", property.scale.x()}, {"y", property.scale.y()} }));
|
||||
transformJson.insert("rotation", property.rotation);
|
||||
json.insert("transform", transformJson);
|
||||
return json;
|
||||
}
|
||||
|
||||
QJsonObject FolderLayerWrapper::toJson() const
|
||||
{
|
||||
QJsonObject json = LayerWrapper::toJson();
|
||||
QJsonArray childrenJson;
|
||||
for (auto& child : children)
|
||||
if(child != nullptr)
|
||||
childrenJson.push_back(child->toJson());
|
||||
json.insert("children", childrenJson);
|
||||
json.insert("is-folder", true);
|
||||
if(this->getReferencedBy() != -1)
|
||||
json.insert("referenced-by", this->getReferencedBy());
|
||||
else
|
||||
json.insert("referenced-by", QJsonValue());
|
||||
return json;
|
||||
}
|
||||
|
||||
QJsonObject LeafLayerWrapper::toJson() const
|
||||
{
|
||||
QJsonObject json = LayerWrapper::toJson();
|
||||
json.insert("element", elementManager->getElementIndex(wrappedElement));
|
||||
json.insert("is-folder", false);
|
||||
json.insert("styles", styles.toJson());
|
||||
return json;
|
||||
}
|
||||
|
||||
int FolderLayerWrapper::getReferencedBy()const
|
||||
{
|
||||
if (this->elementManager != nullptr)
|
||||
return this->elementManager->getLayerReferencedBy(this);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void LayerWrapper::paint(QPainter* painter, QTransform transform, bool force)
|
||||
{
|
||||
// if (this->selected)
|
||||
// {
|
||||
// painter->save();
|
||||
//painter->setPen(QPen(Qt::red, 2));
|
||||
//painter->setTransform(transform);
|
||||
//painter->drawRect(this->cache.getBoundingRect());
|
||||
//painter->restore();
|
||||
// }
|
||||
}
|
||||
|
||||
void FolderLayerWrapper::paint(QPainter* painter, QTransform transform, bool force)
|
||||
{
|
||||
if (hidden && !force)
|
||||
return;
|
||||
LayerWrapper::paint(painter, transform, force);
|
||||
transform = property.transform * transform;
|
||||
//qDebug() << transform;
|
||||
for (auto& child : children)
|
||||
child->paint(painter, transform, force);
|
||||
}
|
||||
|
||||
void LeafLayerWrapper::paint(QPainter* painter, QTransform transform, bool force)
|
||||
{
|
||||
if (hidden && !force)
|
||||
return;
|
||||
LayerWrapper::paint(painter, transform, force);
|
||||
transform = property.transform * transform;
|
||||
//qDebug() << transform;
|
||||
if (wrappedElement != nullptr)
|
||||
{
|
||||
wrappedElement->paint(painter, transform, styles);
|
||||
}
|
||||
}
|
||||
|
||||
void LayerWrapper::collectUpReachable(std::set<LayerWrapper*>& reachable)
|
||||
{
|
||||
auto cPos = this;
|
||||
while (cPos != nullptr)
|
||||
{
|
||||
reachable.insert(cPos);
|
||||
cPos = cPos->parent;
|
||||
}
|
||||
}
|
||||
|
||||
void LayerWrapper::collectDownReachable(std::set<LayerWrapper*>& reachable)
|
||||
{
|
||||
reachable.insert(this);
|
||||
}
|
||||
|
||||
void LeafLayerWrapper::collectDownReachable(std::set<LayerWrapper*>& reachable)
|
||||
{
|
||||
LayerWrapper::collectDownReachable(reachable);
|
||||
auto ele = dynamic_cast<GroupElement*>(wrappedElement);
|
||||
if (ele != nullptr)
|
||||
{
|
||||
ele->collectReachable(reachable);
|
||||
}
|
||||
}
|
||||
|
||||
void FolderLayerWrapper::collectDownReachable(std::set<LayerWrapper*>& reachable)
|
||||
{
|
||||
LayerWrapper::collectDownReachable(reachable);
|
||||
for (auto& child : children)
|
||||
child->collectDownReachable(reachable);
|
||||
}
|
||||
|
||||
void LayerWrapper::refreshTreeItem()
|
||||
{
|
||||
hidden = qTreeWidgetItem->checkState(0) == Qt::Unchecked;
|
||||
}
|
||||
|
||||
void LeafLayerWrapper::refreshTreeItem()
|
||||
{
|
||||
LayerWrapper::refreshTreeItem();
|
||||
if (typeid(*wrappedElement) == typeid(GroupElement))
|
||||
{
|
||||
this->qTreeWidgetItem->setText(0, "@ " + this->property.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->qTreeWidgetItem->setText(0, this->property.name);
|
||||
}
|
||||
this->qTreeWidgetItem->setText(1, ">> " + this->wrappedElement->name);
|
||||
this->qTreeWidgetItem->setTextColor(1, Qt::blue);
|
||||
}
|
||||
|
||||
void FolderLayerWrapper::refreshTreeItem()
|
||||
{
|
||||
LayerWrapper::refreshTreeItem();
|
||||
for (auto& child : this->children) {
|
||||
child->refreshTreeItem();
|
||||
}
|
||||
this->qTreeWidgetItem->setText(0, this->property.name);
|
||||
auto ele = this->elementManager->getElementById(this->getReferencedBy());
|
||||
if (ele != nullptr)
|
||||
{
|
||||
this->qTreeWidgetItem->setText(1, "<< " + ele->name);
|
||||
this->qTreeWidgetItem->setTextColor(1, Qt::darkGreen);
|
||||
}
|
||||
if (this->referencedCount() > 0)
|
||||
{
|
||||
this->qTreeWidgetItem->setToolTip(0,QString::fromLocal8Bit("子树被引用计数:") + QString::number(this->referencedCount(true)) + "\n"
|
||||
+ QString::fromLocal8Bit("当前节点被引用计数:") + QString::number(this->getReferencedBy() != -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->qTreeWidgetItem->setToolTip(0, "");
|
||||
}
|
||||
}
|
||||
|
||||
size_t LayerWrapper::referencedCount(bool excludeSelf) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t FolderLayerWrapper::referencedCount(bool excludeSelf) const
|
||||
{
|
||||
size_t count = 0;
|
||||
for (auto& child : children)
|
||||
count += child->referencedCount();
|
||||
if (!excludeSelf && this->getReferencedBy() != -1)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
bool LayerWrapper::deleteable(bool excludeSubTree) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FolderLayerWrapper::deleteable(bool excludeSubTree) const
|
||||
{
|
||||
if (excludeSubTree)
|
||||
return this->getReferencedBy() == -1;
|
||||
else
|
||||
return this->referencedCount() == 0;
|
||||
}
|
||||
|
||||
bool LayerWrapper::referencingGroupElement() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LeafLayerWrapper::referencingGroupElement() const
|
||||
{
|
||||
return typeid(*wrappedElement) == typeid(GroupElement);
|
||||
}
|
||||
|
||||
bool LayerWrapper::canApplyStyles() const
|
||||
{
|
||||
return typeid(*this) == typeid(LeafLayerWrapper) && !referencingGroupElement();
|
||||
}
|
||||
|
||||
void LayerWrapper::paintVisualBounding(QPainter* painter) const
|
||||
{
|
||||
if (hidden)
|
||||
return;
|
||||
QTransform transform;
|
||||
auto layer = this->parent;
|
||||
while (layer != nullptr)
|
||||
{
|
||||
transform = transform * layer->property.transform;
|
||||
layer = layer->parent;
|
||||
}
|
||||
painter->save();
|
||||
painter->setTransform(transform);
|
||||
painter->drawRect(cache.getBoundingRect());
|
||||
painter->restore();
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include <QGraphicsItemGroup>
|
||||
#include <QGraphicsScene>
|
||||
#include <QJSonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QLine>
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
|
@ -28,12 +29,15 @@ class LayerWrapper
|
|||
protected:
|
||||
FolderLayerWrapper* parent;
|
||||
QPointF referencePoint;
|
||||
ElementManager* elementManager;
|
||||
// vector<LayerStyle> styles;
|
||||
// TODO: 将cache移到子类,对Leaf用ComposedPainterPath,对Folder用FolderBitmapPath
|
||||
PixelPath cache;
|
||||
|
||||
public:
|
||||
QTreeWidgetItem qTreeWidgetItem;
|
||||
QTreeWidgetItem* qTreeWidgetItem;
|
||||
bool selected;
|
||||
bool hidden;
|
||||
struct SimpleProperty
|
||||
{
|
||||
QString name = "";
|
||||
|
@ -42,17 +46,20 @@ class LayerWrapper
|
|||
double rotation = 0;
|
||||
bool flipHorizontally = 0;
|
||||
bool flipVertically = 0;
|
||||
QTransform transform;
|
||||
// TODO: 将QPainterPath改为BitmapPath
|
||||
void apply(PixelPath&cache) const;
|
||||
void apply(PixelPath&cache);
|
||||
} property;
|
||||
virtual void setParent(FolderLayerWrapper*newParent);
|
||||
virtual void refresh();
|
||||
virtual void refresh(LayerWrapper* layer = nullptr);
|
||||
virtual QTreeWidgetItem* getQTreeItem();
|
||||
// TODO: 将QPainterPath改为BitmapPath/QImage,或者直接将其删除,绘制时直接使用BitmapPath的paint方法
|
||||
virtual PixelPath getCache();
|
||||
virtual PixelPath getCache(LayerWrapper* selectedLayer=nullptr);
|
||||
QTransform getTransform();
|
||||
FolderLayerWrapper*getParent() const; // invoke by manager, then invoke parent's applyStyles
|
||||
LayerWrapper(QJsonObject json, FolderLayerWrapper*parent);
|
||||
LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementManager* elementManager=nullptr);
|
||||
LayerWrapper() = default;
|
||||
virtual void paint(QPainter* painter, QTransform transform=QTransform(), bool force = false);
|
||||
// TODO : export Function
|
||||
// virtual LayerWrapper *addChild() = 0; // Leaf Child Only
|
||||
// virtual LayerWrapper *addParent() = 0; // Folder Parent Only
|
||||
|
@ -60,18 +67,28 @@ class LayerWrapper
|
|||
// virtual void deleteAll() const = 0;
|
||||
virtual void del();
|
||||
virtual void delSelf();
|
||||
virtual QJsonObject toJson() const;
|
||||
~LayerWrapper() = default;
|
||||
virtual void collectUpReachable(std::set<LayerWrapper*>& reachable);
|
||||
virtual void collectDownReachable(std::set<LayerWrapper*>& reachable);
|
||||
virtual void refreshTreeItem();
|
||||
virtual size_t referencedCount(bool excludeSelf = false) const;
|
||||
virtual bool deleteable(bool excludeSubTree = false) const;
|
||||
virtual bool referencingGroupElement() const;
|
||||
virtual void paintVisualBounding(QPainter* painter) const;
|
||||
bool canApplyStyles() const;
|
||||
};
|
||||
|
||||
class FolderLayerWrapper : public LayerWrapper
|
||||
{
|
||||
public:
|
||||
vector<shared_ptr<LayerWrapper>> children;
|
||||
int referencedBy = -1;
|
||||
|
||||
public:
|
||||
|
||||
~FolderLayerWrapper() = default;
|
||||
void refresh() override;
|
||||
void refresh(LayerWrapper* layer=nullptr) override;
|
||||
FolderLayerWrapper() = default;
|
||||
FolderLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent);
|
||||
void addChild(shared_ptr<LayerWrapper> child);
|
||||
|
@ -80,19 +97,31 @@ class FolderLayerWrapper : public LayerWrapper
|
|||
void del() override;
|
||||
void delSelf() override;
|
||||
QTreeWidgetItem* getQTreeItem() override;
|
||||
QJsonObject toJson() const override;
|
||||
int getReferencedBy()const;
|
||||
void paint(QPainter* painter, QTransform transform = QTransform(), bool force = false) override;
|
||||
void collectDownReachable(std::set<LayerWrapper*>& reachable) override;
|
||||
void refreshTreeItem() override;
|
||||
size_t referencedCount(bool excludeSelf = false) const override;
|
||||
bool deleteable(bool excludeSubTree = false) const override;
|
||||
};
|
||||
|
||||
class LeafLayerWrapper : public LayerWrapper
|
||||
{
|
||||
public:
|
||||
GraphicElement *wrappedElement;
|
||||
const vector<Renderer::ElementStyleStrokeDemo> styles;
|
||||
LayerStyleContainer styles;
|
||||
|
||||
public:
|
||||
~LeafLayerWrapper() = default;
|
||||
void refresh() override;
|
||||
LeafLayerWrapper() = default;
|
||||
~LeafLayerWrapper();
|
||||
void refresh(LayerWrapper* layer = nullptr) override;
|
||||
LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent);
|
||||
QJsonObject toJson() const override;
|
||||
void paint(QPainter* painter, QTransform transform = QTransform(), bool force = false) override;
|
||||
void collectDownReachable(std::set<LayerWrapper*>& reachable) override;
|
||||
QTreeWidgetItem* getQTreeItem() override;
|
||||
void refreshTreeItem() override;
|
||||
bool referencingGroupElement() const override;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(LayerWrapper *)
|
||||
|
|
|
@ -32,10 +32,15 @@ QPixmap PixelPath::getPixmap() const
|
|||
return pixmap;
|
||||
}
|
||||
|
||||
QPainterPath PixelPath::getPainterPath() const {
|
||||
return painterPath;
|
||||
}
|
||||
|
||||
void PixelPath::addPath(const PixelPath& path)
|
||||
{
|
||||
QPainter painter(&pixmap);
|
||||
painter.drawPixmap(0, 0, path.getPixmap());
|
||||
this->painterPath.addPath(path.getPainterPath());
|
||||
boundingRect = boundingRect.united(path.getBoundingRect());
|
||||
}
|
||||
|
||||
|
@ -46,6 +51,7 @@ void PixelPath::addPath(const QPainterPath& path)
|
|||
painter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
painter.setPen(QPen(Qt::black,1));
|
||||
painter.drawPath(path);
|
||||
this->painterPath.addPath(path);
|
||||
boundingRect = boundingRect.united(path.boundingRect());
|
||||
}
|
||||
|
||||
|
@ -60,6 +66,7 @@ void PixelPath::clear()
|
|||
{
|
||||
pixmap.fill(Qt::transparent);
|
||||
boundingRect = QRectF(0, 0, 0, 0);
|
||||
painterPath.clear();
|
||||
}
|
||||
|
||||
PixelPath PixelPath::trans(QTransform& mat)const
|
||||
|
@ -70,7 +77,9 @@ PixelPath PixelPath::trans(QTransform& mat)const
|
|||
painter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
painter.setTransform(mat);
|
||||
painter.drawPixmap(0, 0, pixmap);
|
||||
result.boundingRect = mat.mapRect(boundingRect);
|
||||
result.painterPath.addPath(this->painterPath);
|
||||
result.painterPath = mat.map(result.painterPath);
|
||||
result.boundingRect = result.painterPath.boundingRect();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -83,5 +92,32 @@ QPixmap PixelPath::resizedPixel(QSize size)const
|
|||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
painter.drawPixmap(0, 0, pixmap.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QPixmap PixelPath::getDetail()const
|
||||
{
|
||||
QPixmap result;
|
||||
auto rect = boundingRect.toRect();
|
||||
rect.setHeight(rect.height() + 20);
|
||||
rect.setWidth(rect.width() + 20);
|
||||
qDebug() << rect;
|
||||
result = pixmap.copy(rect);
|
||||
return result;
|
||||
}
|
||||
|
||||
void PixelPath::highLight()
|
||||
{
|
||||
// 创建一个QPainter对象,关联到QPixmap对象
|
||||
QPainter painter(&pixmap);
|
||||
|
||||
// 设置画笔的颜色、宽度和样式
|
||||
painter.setPen(QPen(Qt::black, 1, Qt::DashLine));
|
||||
|
||||
// 绘制一个矩形,指定左上角和右下角的坐标
|
||||
painter.drawRect(boundingRect);
|
||||
|
||||
// 结束绘制
|
||||
painter.end();
|
||||
}
|
|
@ -7,20 +7,24 @@
|
|||
|
||||
class PixelPath
|
||||
{
|
||||
private:
|
||||
public:
|
||||
QRectF boundingRect;
|
||||
QPixmap pixmap;
|
||||
QPainterPath painterPath;
|
||||
int w,h;
|
||||
public:
|
||||
PixelPath(int w=1920, int h= 1080);
|
||||
PixelPath(QPainterPath painterPath,int w = 1920, int h = 1080);
|
||||
PixelPath(int w=16, int h= 16);
|
||||
PixelPath(QPainterPath painterPath,int w = 16, int h = 16);
|
||||
~PixelPath() = default;
|
||||
QRectF getBoundingRect() const;
|
||||
QPixmap getPixmap() const;
|
||||
QPainterPath getPainterPath() const;
|
||||
void addPath(const PixelPath& path);
|
||||
void addPath(const QPainterPath& path);
|
||||
void addImage(const QImage& image,const QPointF& pos);
|
||||
void clear();
|
||||
PixelPath trans(QTransform& mat)const;
|
||||
QPixmap resizedPixel(QSize size)const;
|
||||
QPixmap getDetail()const;
|
||||
void highLight();
|
||||
};
|
|
@ -1,8 +1,11 @@
|
|||
#include "PreviewWindow.h"
|
||||
#include <QApplication>
|
||||
|
||||
PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent)
|
||||
{
|
||||
this->renderer = new Renderer::ElementRenderer(this);
|
||||
//this->setFixedSize(QSize(108, 108));
|
||||
this->setStyleSheet("border: 1px solid black");
|
||||
this->renderer = Renderer::ElementRenderer::instance();
|
||||
QSurfaceFormat surfaceFormat;
|
||||
surfaceFormat.setSamples(16);
|
||||
setFormat(surfaceFormat);
|
||||
|
@ -10,12 +13,16 @@ PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent)
|
|||
painter->setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter->setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
layerManager = nullptr;
|
||||
currentLayer = nullptr;
|
||||
zoomStep = 0;
|
||||
backgroundColor = QColor(255, 255, 255, 255);
|
||||
}
|
||||
|
||||
void PreviewWindow::initialize(LayerManager *layerManager,QSize windowSize)
|
||||
{
|
||||
this->logicalSize = windowSize;
|
||||
this->layerManager = layerManager;
|
||||
this->setFixedSize(windowSize);
|
||||
}
|
||||
|
||||
void PreviewWindow::show()
|
||||
|
@ -36,18 +43,18 @@ void PreviewWindow::show()
|
|||
|
||||
void PreviewWindow::initializeGL()
|
||||
{
|
||||
this->renderer->initialize();
|
||||
initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
void PreviewWindow::paintGL()
|
||||
{
|
||||
glClearColor(1.0, 1.0, 1.0, 1.0);
|
||||
glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), backgroundColor.alphaF());
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
painter->begin(this);
|
||||
painter->setWindow(0, 0, logicalSize.width(), logicalSize.height());
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
layerManager->paint(painter,this->size());
|
||||
layerManager->paint(painter,this->size(),currentLayer);
|
||||
painter->end();
|
||||
}
|
||||
|
||||
|
@ -58,3 +65,89 @@ void PreviewWindow::resizeGL(int w, int h)
|
|||
Renderer::ElementRenderer* const PreviewWindow::getRenderer()const {
|
||||
return this->renderer;
|
||||
}
|
||||
|
||||
void PreviewWindow::currentLayerChanged(LayerWrapper* layer)
|
||||
{
|
||||
this->currentLayer = layer;
|
||||
}
|
||||
|
||||
void PreviewWindow::refresh()
|
||||
{
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void PreviewWindow::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
// 当鼠标按下时,记录当前的位置
|
||||
m_lastPos = event->pos();
|
||||
}
|
||||
|
||||
void PreviewWindow::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
// 当鼠标移动时,计算移动的距离,并根据需要更新图形的状态
|
||||
int dx = event->x() - m_lastPos.x();
|
||||
int dy = event->y() - m_lastPos.y();
|
||||
if (currentLayer != nullptr) {
|
||||
if (QApplication::keyboardModifiers() == Qt::ControlModifier && (event->buttons() & Qt::LeftButton))
|
||||
{
|
||||
currentLayer->property.scale.setX(std::max(0.0, currentLayer->property.scale.x() + dx / 50.0));
|
||||
currentLayer->property.scale.setY(std::max(0.0, currentLayer->property.scale.y() + dy / 50.0));
|
||||
}
|
||||
else if (QApplication::keyboardModifiers() == (Qt::ControlModifier | Qt::ShiftModifier) && (event->buttons() & Qt::LeftButton))
|
||||
{
|
||||
currentLayer->property.scale.setX(std::max(0.0, currentLayer->property.scale.x() * (1.0 + dx / 50.0)));
|
||||
currentLayer->property.scale.setY(std::max(0.0, currentLayer->property.scale.y() * (1.0 + dx / 50.0)));
|
||||
}
|
||||
else if (event->buttons() & Qt::LeftButton) {
|
||||
// 如果按下的是左键,那么平移图形
|
||||
currentLayer->property.offset.setX(currentLayer->property.offset.x() + dx);
|
||||
currentLayer->property.offset.setY(currentLayer->property.offset.y() + dy);
|
||||
}
|
||||
else if (event->buttons() & Qt::RightButton) {
|
||||
// 如果按下的是右键,那么旋转图形
|
||||
qreal angle = dx;
|
||||
currentLayer->property.rotation += angle;
|
||||
}
|
||||
auto layer = currentLayer;
|
||||
while (layer != nullptr)
|
||||
{
|
||||
auto index = -1;
|
||||
if (typeid(*layer) == typeid(FolderLayerWrapper))
|
||||
index = dynamic_cast<FolderLayerWrapper*>(layer)->getReferencedBy();
|
||||
layer = layer->getParent();
|
||||
}
|
||||
}
|
||||
// 更新上一次的位置
|
||||
emit triggerCentralRefresh();
|
||||
m_lastPos = event->pos();
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void PreviewWindow::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
//emit layerInfoChanged();
|
||||
}
|
||||
|
||||
void PreviewWindow::setBackgroundColor(QColor color)
|
||||
{
|
||||
this->backgroundColor = color;
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void PreviewWindow::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (QApplication::keyboardModifiers() == Qt::ControlModifier)
|
||||
{
|
||||
if (event->delta() > 0 && zoomStep < ZOOM_STEP_MAX)
|
||||
{
|
||||
zoomStep++;
|
||||
this->setFixedSize(logicalSize * (1 + zoomStep * ZOOM_RATE));
|
||||
}
|
||||
else if(event->delta() < 0 && zoomStep > ZOOM_STEP_MIN)
|
||||
{
|
||||
zoomStep--;
|
||||
this->setFixedSize(logicalSize * (1 + zoomStep * ZOOM_RATE));
|
||||
}
|
||||
this->repaint();
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QMouseEvent>
|
||||
#include <QOpenGLWidget>
|
||||
#include "../Renderer/Preview/ElementRenderer.h"
|
||||
|
||||
|
@ -15,10 +16,26 @@ class PreviewWindow : public QOpenGLWidget, protected QOpenGLFunctions
|
|||
Q_OBJECT
|
||||
|
||||
private:
|
||||
constexpr static double ZOOM_RATE = 0.25;
|
||||
constexpr static double ZOOM_DEFAULT = 1.0;
|
||||
constexpr static int ZOOM_STEP_MIN = -2;
|
||||
constexpr static int ZOOM_STEP_MAX = 4;
|
||||
|
||||
|
||||
private:
|
||||
int zoomStep;
|
||||
QPainter *painter;
|
||||
LayerManager *layerManager;
|
||||
Renderer::ElementRenderer* renderer;
|
||||
QSize logicalSize;
|
||||
QRectF viewportRect;
|
||||
LayerWrapper* currentLayer;
|
||||
QPointF m_lastPos;
|
||||
QColor backgroundColor;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
public:
|
||||
PreviewWindow(QWidget *parent = nullptr);
|
||||
|
@ -28,4 +45,15 @@ class PreviewWindow : public QOpenGLWidget, protected QOpenGLFunctions
|
|||
void paintGL() override;
|
||||
void resizeGL(int w, int h) override;
|
||||
Renderer::ElementRenderer* const getRenderer()const;
|
||||
void setBackgroundColor(QColor color);
|
||||
|
||||
public slots:
|
||||
void currentLayerChanged(LayerWrapper*);
|
||||
void refresh();
|
||||
|
||||
signals:
|
||||
void layerInfoChanged();
|
||||
void refreshElementPreview(GraphicElement*);
|
||||
void refreshElementPreviewByIndex(int);
|
||||
void triggerCentralRefresh();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#include "EditorSettingWidget.h"
|
||||
#include "../ColorHelper.hpp"
|
||||
#include <QPushButton>
|
||||
#include <QInputDialog>
|
||||
|
||||
EditorSettingWidget::EditorSettingWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
connect(ui.backgroundColorButton, &QPushButton::clicked, this, [this]() {
|
||||
QColor color = ColorHelper::execColorDialog(Qt::white, this, QString::fromLocal8Bit("选择背景颜色"));
|
||||
if (color.isValid())
|
||||
{
|
||||
emit backgroundColorChanged(color);
|
||||
}
|
||||
});
|
||||
connect(ui.renameButton, &QPushButton::clicked, this, [this]() {
|
||||
QString name = QInputDialog::getText(this, QString::fromLocal8Bit("重命名"), QString::fromLocal8Bit("请输入新的项目名称"));
|
||||
emit projectNameChanged(name);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include <qwidget.h>
|
||||
#include "ui_EditorSettingWidget.h"
|
||||
|
||||
class EditorSettingWidget :
|
||||
public QWidget
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
private:
|
||||
Ui::EditorSettingWidget ui;
|
||||
|
||||
public:
|
||||
EditorSettingWidget(QWidget* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void backgroundColorChanged(QColor);
|
||||
void projectNameChanged(QString);
|
||||
|
||||
};
|
||||
|
|
@ -1,34 +1,31 @@
|
|||
#include "InfoDisplayWidget.h"
|
||||
#include "./EditorWidgetComponent/LayerStyleDialog.h"
|
||||
#include <QLineEdit>
|
||||
#include <QTextBlock>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QComboBox>
|
||||
#include <qtmaterialraisedbutton.h>
|
||||
#include <qtmaterialflatbutton.h>
|
||||
|
||||
void InfoDisplayWidget::setLayer(LayerWrapper *layer)
|
||||
{
|
||||
this->displayLayer = layer;
|
||||
generateLayerForm();
|
||||
}
|
||||
void InfoDisplayWidget::setElement(GraphicElement *element)
|
||||
{
|
||||
this->displayElement = element;
|
||||
generateElementForm();
|
||||
}
|
||||
|
||||
void InfoDisplayWidget::generateLayerForm()
|
||||
{
|
||||
QLayoutItem *item;
|
||||
if (this->layout() != nullptr)
|
||||
{
|
||||
while ((item = this->layout()->takeAt(0)) != nullptr)
|
||||
while (this->layout()->count() > 0 && (item = this->layout()->takeAt(0)) != nullptr)
|
||||
{
|
||||
delete item->widget();
|
||||
item->widget()->deleteLater();
|
||||
delete item;
|
||||
}
|
||||
delete this->layout();
|
||||
}
|
||||
|
||||
QFormLayout *layout = new QFormLayout();
|
||||
layout->setRowWrapPolicy(QFormLayout::WrapAllRows);
|
||||
if (this->displayLayer == nullptr)
|
||||
|
@ -47,27 +44,27 @@ void InfoDisplayWidget::generateLayerForm()
|
|||
rotation->setValidator(new QIntValidator(-10000, 10000, this));
|
||||
connect(rotation, &QLineEdit::textChanged, [=](QString content) {
|
||||
this->displayLayer->property.rotation = content.toDouble();
|
||||
emit requireRefreshPreview();
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
offsetX->setValidator(new QIntValidator(-10000, 10000, this));
|
||||
connect(offsetX, &QLineEdit::textChanged, [=](QString content) {
|
||||
this->displayLayer->property.offset = {content.toDouble(), this->displayLayer->property.offset.y()};
|
||||
emit requireRefreshPreview();
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
offsetY->setValidator(new QIntValidator(-10000, 10000, this));
|
||||
connect(offsetY, &QLineEdit::textChanged, [=](QString content) {
|
||||
this->displayLayer->property.offset = {this->displayLayer->property.offset.x(), content.toDouble()};
|
||||
emit requireRefreshPreview();
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
scaleX->setValidator(new QDoubleValidator(0.001, 1000, 4, this));
|
||||
scaleX->setValidator(new QDoubleValidator(-1000, 1000, 4, this));
|
||||
connect(scaleX, &QLineEdit::textChanged, [=](QString content) {
|
||||
this->displayLayer->property.scale = {content.toDouble(), this->displayLayer->property.scale.y()};
|
||||
emit requireRefreshPreview();
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
scaleY->setValidator(new QDoubleValidator(0.001, 1000, 4, this));
|
||||
scaleY->setValidator(new QDoubleValidator(-1000, 1000, 4, this));
|
||||
connect(scaleY, &QLineEdit::textChanged, [=](QString content) {
|
||||
this->displayLayer->property.scale = {this->displayLayer->property.scale.x(), content.toDouble()};
|
||||
emit requireRefreshPreview();
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
|
||||
layout->addRow("layer name:", name);
|
||||
|
@ -78,78 +75,113 @@ void InfoDisplayWidget::generateLayerForm()
|
|||
layout->addRow("scale-Y:", scaleY);
|
||||
layout->setRowWrapPolicy(QFormLayout::DontWrapRows);
|
||||
|
||||
bool styleEnabled = true;
|
||||
if (styleEnabled) {
|
||||
QListWidget* styleList = new QListWidget(this);
|
||||
QListWidgetItem* item = new QListWidgetItem("样式列表");
|
||||
item->setFlags(Qt::NoItemFlags);
|
||||
styleList->addItem(item);
|
||||
static vector<QString> styleNames = { "样例1", "样例2", "样例3" };
|
||||
auto createStyleItem = [this, styleList](int index) {
|
||||
QListWidgetItem* item = new QListWidgetItem;
|
||||
QWidget* w = new QWidget;
|
||||
item->setSizeHint(QSize(50, 40));
|
||||
QHBoxLayout* layout = new QHBoxLayout;
|
||||
QPushButton* deleteButton = new QPushButton(w);
|
||||
QPushButton* detailButton = new QPushButton(w);
|
||||
QLabel* name = new QLabel(w);
|
||||
name->setText(styleNames[index]);
|
||||
detailButton->setText("...");
|
||||
detailButton->setFixedSize(QSize(20, 20));
|
||||
deleteButton->setText("×");
|
||||
deleteButton->setFixedSize(QSize(20, 20));
|
||||
connect(detailButton, &QPushButton::clicked, [styleList, item, this, index]() {
|
||||
QDialog dlg(this);
|
||||
dlg.setWindowTitle("样式详情");
|
||||
dlg.resize(400, 200);
|
||||
QGridLayout *contentLayout = new QGridLayout(&dlg);
|
||||
QLineEdit* name = new QLineEdit(styleNames[index], &dlg);
|
||||
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
contentLayout->addWidget(buttonBox);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);
|
||||
bool updateStyle = dlg.exec();
|
||||
if (updateStyle) {
|
||||
styleNames[index] = name->text();
|
||||
qDebug() << name->text();
|
||||
// 在此处修改新样式信息至内存
|
||||
emit requireRefreshPreview();
|
||||
emit requireSelfRefresh();
|
||||
if (auto* leafP = dynamic_cast<LeafLayerWrapper*>(this->displayLayer); leafP) {
|
||||
auto* styleList = new QListWidget(this);
|
||||
|
||||
auto* header = new QListWidgetItem;
|
||||
auto* headerWidget = new QWidget(styleList);
|
||||
auto* headerLayout = new QHBoxLayout;
|
||||
|
||||
auto* headerLabel = new QLabel(headerWidget);
|
||||
headerLabel->setText("样式列表");
|
||||
headerLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||
|
||||
//QtMaterialRaisedButton* addStyleButton = new QtMaterialRaisedButton("+", headerWidget);
|
||||
auto* addStyleButton = new QPushButton("+", headerWidget);
|
||||
addStyleButton->setFixedSize(QSize(20, 20));
|
||||
if (leafP->styles.full())
|
||||
{
|
||||
addStyleButton->setDisabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(addStyleButton, &QPushButton::clicked, [&, leafP] {
|
||||
auto* dialog = new LayerStyleDialog(leafP->styles, nullptr, this);
|
||||
dialog->exec();
|
||||
if (dialog->layerStyle)
|
||||
{
|
||||
leafP->styles.useStyle(dialog->layerStyle);
|
||||
leafP->styles.computeNewHash();
|
||||
emit triggerCentralRefresh();
|
||||
}
|
||||
});
|
||||
connect(deleteButton, &QPushButton::clicked, [styleList,item,this]() {
|
||||
styleList->removeItemWidget(item);
|
||||
delete item;
|
||||
// 删除layer对应样式
|
||||
emit requireRefreshPreview();
|
||||
emit requireSelfRefresh();
|
||||
}
|
||||
|
||||
headerLayout->addWidget(headerLabel);
|
||||
headerLayout->addWidget(addStyleButton);
|
||||
headerLayout->setContentsMargins(5, 0, 5, 0);
|
||||
headerWidget->setLayout(headerLayout);
|
||||
|
||||
header->setFlags(Qt::NoItemFlags);
|
||||
styleList->addItem(header);
|
||||
styleList->setItemWidget(header, headerWidget);
|
||||
|
||||
auto* styles = &leafP->styles;
|
||||
for (auto styleIterator = styles->begin(); styleIterator != styles->end(); ++styleIterator)
|
||||
{
|
||||
auto* item = new QListWidgetItem;
|
||||
auto* w = new QWidget(this);
|
||||
item->setSizeHint(QSize(50, 40));
|
||||
auto* layout = new QHBoxLayout(w);
|
||||
layout->setAlignment(Qt::AlignmentFlag::AlignRight);
|
||||
//QtMaterialFlatButton* detailButton = new QtMaterialFlatButton(w);
|
||||
//QtMaterialFlatButton* removeButton = new QtMaterialFlatButton(w);
|
||||
auto* detailButton = new QPushButton(w);
|
||||
auto* removeButton = new QPushButton(w);
|
||||
detailButton->setText("...");
|
||||
detailButton->setFixedSize(QSize(20, 20));
|
||||
removeButton->setText("×");
|
||||
removeButton->setFixedSize(QSize(20, 20));
|
||||
|
||||
connect(detailButton, &QPushButton::clicked, this,
|
||||
[this, styles, styleIterator]
|
||||
{
|
||||
auto* dialog =
|
||||
new LayerStyleDialog(*styles, styleIterator->second, this);
|
||||
dialog->exec();
|
||||
|
||||
if (dialog->layerStyle)
|
||||
{
|
||||
styleIterator->second = dialog->layerStyle;
|
||||
styles->computeNewHash();
|
||||
emit triggerCentralRefresh();
|
||||
}
|
||||
});
|
||||
layout->addWidget(name);
|
||||
|
||||
connect(removeButton, &QPushButton::clicked, this,
|
||||
[this, styleIterator, styles]
|
||||
{
|
||||
styles->dropStyle(styleIterator->first);
|
||||
styles->computeNewHash();
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
|
||||
QWidget* styleDisplayWidget = styleIterator->second->getListDisplayWidget();
|
||||
styleDisplayWidget->setParent(w);
|
||||
styleDisplayWidget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||
|
||||
layout->addWidget(styleDisplayWidget);
|
||||
layout->addWidget(detailButton);
|
||||
layout->addWidget(deleteButton);
|
||||
layout->addWidget(removeButton);
|
||||
w->setLayout(layout);
|
||||
|
||||
styleList->addItem(item);
|
||||
styleList->setItemWidget(item, w);
|
||||
};
|
||||
for (int i = 0; i < styleNames.size(); i++)
|
||||
createStyleItem(i);
|
||||
|
||||
|
||||
}
|
||||
layout->addRow(styleList);
|
||||
}
|
||||
}
|
||||
this->setLayout(layout);
|
||||
}
|
||||
|
||||
|
||||
void InfoDisplayWidget::generateElementForm()
|
||||
{
|
||||
}
|
||||
|
||||
void InfoDisplayWidget::triggerSelfRefresh()
|
||||
{
|
||||
if (this->displayLayer != nullptr)
|
||||
this->generateLayerForm();
|
||||
else
|
||||
this->generateElementForm();
|
||||
}
|
||||
|
||||
void InfoDisplayWidget::refresh()
|
||||
{
|
||||
if (this->displayLayer != nullptr)
|
||||
this->generateLayerForm();
|
||||
}
|
|
@ -4,26 +4,27 @@
|
|||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include "ElementPoolWidget.h"
|
||||
|
||||
class InfoDisplayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
LayerWrapper *displayLayer;
|
||||
GraphicElement *displayElement;
|
||||
|
||||
|
||||
public:
|
||||
void setLayer(LayerWrapper *layer);
|
||||
void setElement(GraphicElement *element);
|
||||
void generateLayerForm();
|
||||
void generateElementForm();
|
||||
void refresh();
|
||||
|
||||
public slots:
|
||||
void triggerSelfRefresh();
|
||||
|
||||
signals:
|
||||
void triggerCentralRefresh();
|
||||
void requireRefreshPreview();
|
||||
void requireSelfRefresh();
|
||||
|
||||
void requireRefreshElementWidget();
|
||||
|
||||
};
|
||||
|
|
|
@ -1,21 +1,36 @@
|
|||
#include "LayerTreeWidget.h"
|
||||
#include <QInputDialog>
|
||||
#include <QMenu>
|
||||
#include "./EditorWidgetComponent/LayerCreateWidget.h"
|
||||
#include <QTimer>
|
||||
|
||||
LayerTreeWidget::LayerTreeWidget(QWidget *parent)
|
||||
{
|
||||
emit displayLayerChange(nullptr);
|
||||
this->selectedItem = nullptr;
|
||||
this->copiedItem = nullptr;
|
||||
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
this->setHeaderLabel("Layer Content");
|
||||
this->setColumnWidth(0, 240);
|
||||
connect(this, &QTreeWidget::customContextMenuRequested, this, &LayerTreeWidget::popMenu);
|
||||
connect(this, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *currentItem) {
|
||||
if (this->selectedItem != nullptr) {
|
||||
this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>()->selected = false;
|
||||
}
|
||||
this->selectedItem = currentItem;
|
||||
if(this->selectedItem !=nullptr)
|
||||
emit displayLayerChange(this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper *>());
|
||||
else
|
||||
if (this->selectedItem != nullptr) {
|
||||
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
|
||||
layer->selected = true;
|
||||
emit displayLayerChange(layer);
|
||||
}
|
||||
else {
|
||||
emit displayLayerChange(nullptr);
|
||||
}
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
connect(this, &QTreeWidget::itemChanged, this, [=]() {
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
|
||||
// connect(this, &QTreeWidget::itemDoubleClicked, this, &LayerTreeWidget::onItemDoubleClicked);
|
||||
}
|
||||
|
||||
|
@ -35,27 +50,66 @@ void LayerTreeWidget::popMenu(const QPoint &pos)
|
|||
QMenu menu;
|
||||
QTreeWidgetItem *item = itemAt(pos);
|
||||
this->selectedItem = item;
|
||||
// TODO
|
||||
menu.addAction(QString::fromLocal8Bit("´´½¨×Ó½Úµã"), this, &LayerTreeWidget::onRenameEvent);
|
||||
if (item != nullptr) {
|
||||
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
|
||||
if (layer != nullptr) {
|
||||
if (typeid(*layer) == typeid(FolderLayerWrapper)) {
|
||||
menu.addAction(QString::fromLocal8Bit("创建子节点"), this, [this, layer]() {
|
||||
auto dialog = new LayerCreateWidget(elementManager, dynamic_cast<FolderLayerWrapper*>(layer), this);
|
||||
connect(dialog, &LayerCreateWidget::LayerInfoReturned, this, [this, layer](QJsonObject jsonObj) {
|
||||
auto folderLayer = dynamic_cast<FolderLayerWrapper*>(layer);
|
||||
LayerWrapper* newLayer;
|
||||
qDebug() << this->elementManager;
|
||||
if(jsonObj.value("is-folder").toBool())
|
||||
newLayer = new FolderLayerWrapper(jsonObj, this->elementManager, folderLayer);
|
||||
else
|
||||
newLayer = new LeafLayerWrapper(jsonObj, this->elementManager, folderLayer);
|
||||
|
||||
folderLayer->addChild(std::shared_ptr<LayerWrapper>(newLayer));
|
||||
folderLayer->qTreeWidgetItem->addChild(newLayer->getQTreeItem());
|
||||
qDebug() << jsonObj<<"----------------------";
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
dialog->exec();
|
||||
});
|
||||
}
|
||||
if (layer != root) {
|
||||
menu.addAction(QString::fromLocal8Bit("删除"), this, [this]() {
|
||||
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
|
||||
layer->del();
|
||||
layer->getParent()->removeChild(layer);
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
menu.actions().last()->setEnabled(layer->deleteable());
|
||||
menu.addAction(QString::fromLocal8Bit("重命名"), this, &LayerTreeWidget::onRenameEvent);
|
||||
// menu.addAction("Copy", this, &LayerTreeWidget::onRenameEvent);
|
||||
if (item != nullptr && item->childCount() > 0)
|
||||
if(typeid(*layer) == typeid(FolderLayerWrapper))
|
||||
{
|
||||
menu.addAction(QString::fromLocal8Bit("删除(保留子节点)"), this, [this]() {
|
||||
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
|
||||
layer->delSelf();
|
||||
layer->getParent()->removeChild(layer);
|
||||
this->refresh();
|
||||
emit requireRefreshPreview();
|
||||
emit triggerCentralRefresh();
|
||||
});
|
||||
menu.addAction(QString::fromLocal8Bit("ɾ³ý"), this, [this]() {
|
||||
if (this->selectedItem == nullptr)
|
||||
return;
|
||||
auto layer = this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>();
|
||||
layer->del();
|
||||
layer->getParent()->removeChild(layer);
|
||||
this->refresh();
|
||||
emit requireRefreshPreview();
|
||||
menu.actions().last()->setEnabled(layer->deleteable(true));
|
||||
}
|
||||
}
|
||||
if (typeid(*layer) == typeid(FolderLayerWrapper) && ((FolderLayerWrapper*)layer)->getReferencedBy() == -1) {
|
||||
menu.addAction(QString::fromLocal8Bit("创建组合元素"), this, [this, layer]() {
|
||||
auto layer = dynamic_cast<FolderLayerWrapper*>(this->selectedItem->data(0, Qt::UserRole).value<LayerWrapper*>());
|
||||
if (layer != nullptr) {
|
||||
bool ok;
|
||||
QString name = QInputDialog::getText(this, QString::fromLocal8Bit("创建组合元素"),
|
||||
QString::fromLocal8Bit("组合元素名称:"), QLineEdit::Normal,
|
||||
QString::fromLocal8Bit("图源") + layer->property.name, &ok);
|
||||
if (ok && !name.isEmpty()) {
|
||||
elementManager->createGroupElement(name, layer);
|
||||
emit triggerCentralRefresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
menu.exec(mapToGlobal(pos));
|
||||
}
|
||||
|
||||
|
@ -76,9 +130,5 @@ void LayerTreeWidget::onRenameEvent()
|
|||
}
|
||||
|
||||
void LayerTreeWidget::refresh() {
|
||||
// if(this->root!=nullptr)
|
||||
//{
|
||||
// this->clear();
|
||||
// this->addTopLevelItem(this->root->getQTreeItem());
|
||||
//}
|
||||
this->root->refreshTreeItem();
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "LayerWrapper.h"
|
||||
#include "ElementManager.h"
|
||||
#include <QPoint>
|
||||
#include <QTreeWidget>
|
||||
class LayerTreeWidget : public QTreeWidget
|
||||
|
@ -10,6 +11,7 @@ class LayerTreeWidget : public QTreeWidget
|
|||
LayerWrapper *copiedItem;
|
||||
|
||||
public:
|
||||
ElementManager* elementManager;
|
||||
LayerWrapper* root;
|
||||
LayerTreeWidget(QWidget *parent = nullptr);
|
||||
void onRenameEvent();
|
||||
|
@ -19,6 +21,8 @@ class LayerTreeWidget : public QTreeWidget
|
|||
// void onItemDoubleClicked(QTreeWidgetItem *item, int column = 0);
|
||||
|
||||
signals:
|
||||
void triggerCentralRefresh();
|
||||
void displayLayerChange(LayerWrapper *);
|
||||
void requireRefreshPreview();
|
||||
void requireRefreshElementWidget();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include <QByteArray>
|
||||
|
||||
namespace EncodeUtil
|
||||
{
|
||||
#include <vector>
|
||||
template<typename S>
|
||||
QString toBase64(const std::vector<S>& vec)
|
||||
{
|
||||
QByteArray ba;
|
||||
ba.resize(vec.size() * sizeof(S));
|
||||
memcpy_s(ba.data(), ba.size(), vec.data(), vec.size() * sizeof(S));
|
||||
return ba.toBase64();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> fromBase64(const QString& str)
|
||||
{
|
||||
QByteArray ba = QByteArray::fromBase64(str.toUtf8());
|
||||
std::vector<T> vec;
|
||||
vec.resize(ba.size() / sizeof(T));
|
||||
memcpy_s(vec.data(), vec.size() * sizeof(T), ba.data(), ba.size());
|
||||
return vec;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include <QJsonArray>
|
||||
|
||||
namespace JsonUtil
|
||||
{
|
||||
#include <vector>
|
||||
template<typename T>
|
||||
QJsonArray toQJsonArray(const std::vector<T>& vec)
|
||||
{
|
||||
QJsonArray array;
|
||||
std::copy(vec.begin(), vec.end(), std::back_inserter(array));
|
||||
return array;
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ vector<vector<Point>> PainterPathUtil::transformToLines(const QPainterPath& pai
|
|||
for (int elementIndex = 0; elementIndex < painterPath.elementCount(); elementIndex++) {
|
||||
auto element = painterPath.elementAt(elementIndex);
|
||||
point = element;
|
||||
qDebug() << element;
|
||||
//qDebug() << element;
|
||||
if (element.isMoveTo()) {
|
||||
if (line.size() >= 2) {
|
||||
lines.push_back(line);
|
||||
|
@ -43,7 +43,7 @@ vector<vector<Point>> PainterPathUtil::transformToLines(const QPainterPath& pai
|
|||
return lines;
|
||||
}
|
||||
|
||||
QPainterPath PainterPathUtil::monotonization(QPainterPath& painterPath) {
|
||||
QPainterPath PainterPathUtil::monotonization(const QPainterPath& painterPath) {
|
||||
QPainterPath resPath;
|
||||
vector<vector<Point> > lines = transformToLines(painterPath);
|
||||
vector<shared_ptr<Line>> linePtrVector;
|
||||
|
@ -62,15 +62,15 @@ QPainterPath PainterPathUtil::monotonization(QPainterPath& painterPath) {
|
|||
return resPath;
|
||||
}
|
||||
|
||||
std::pair<QPainterPath, float> PainterPathUtil::normalized(const QPainterPath& path)
|
||||
std::pair<QPainterPath, float> PainterPathUtil::normalized(const QPainterPath& path, float width)
|
||||
{
|
||||
auto rect = path.boundingRect();
|
||||
return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999))).map(path),
|
||||
return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999)) * QTransform::fromScale(1 / (1 + width),1 / (1 + width))).map(path),
|
||||
rect.width() / rect.height() };
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::vector<Renderer::Point>>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path)
|
||||
std::pair<std::vector<std::vector<Renderer::Point>>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path, float width)
|
||||
{
|
||||
auto [p, ratio] = normalized(path);
|
||||
auto [p, ratio] = normalized(path, width);
|
||||
return { transformToLines(p), ratio };
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ class PainterPathUtil
|
|||
{
|
||||
public:
|
||||
static std::vector<std::vector<Renderer::Point>> transformToLines(const QPainterPath& painterPath);
|
||||
static QPainterPath monotonization(QPainterPath& painterPath);
|
||||
static std::pair<QPainterPath, float> normalized(const QPainterPath& path);
|
||||
static std::pair<std::vector<std::vector<Renderer::Point>>, float> toNormalizedLines(const QPainterPath& path);
|
||||
static QPainterPath monotonization(const QPainterPath& painterPath);
|
||||
static std::pair<QPainterPath, float> normalized(const QPainterPath& path, float width = 0);
|
||||
static std::pair<std::vector<std::vector<Renderer::Point>>, float> toNormalizedLines(const QPainterPath& path, float width = 0);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
#include "PaintingUtil.h"
|
||||
#include <QFile>
|
||||
#include <QJsondocument>
|
||||
#include "PainterPathUtil.h"
|
||||
#include <queue>
|
||||
#include <QFileInfo>
|
||||
|
||||
using Renderer::Painting;
|
||||
using Renderer::BaseElement;
|
||||
using Renderer::ElementTransform;
|
||||
using glm::bvec2;
|
||||
using std::max;
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
using std::min;
|
||||
using std::queue;
|
||||
|
||||
struct LayerNode {
|
||||
LayerWrapper* nowLayer;
|
||||
QTransform transfrom;
|
||||
};
|
||||
|
||||
QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) {
|
||||
QFile jsonFile(jsonFilePath);
|
||||
qDebug() << jsonFilePath;
|
||||
jsonFile.open(QFile::ReadOnly);
|
||||
QByteArray fileContent = jsonFile.readAll().trimmed();
|
||||
jsonFile.close();
|
||||
QJsonParseError jError;
|
||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(fileContent, &jError));
|
||||
return jsonDoc.object();
|
||||
}
|
||||
|
||||
Painting PaintingUtil::transfromToPainting(QString jsonFilePath) {
|
||||
Painting painting;
|
||||
glm::bvec2 flip(0, 0);
|
||||
QJsonObject jsonObj = readJsonFile(jsonFilePath);
|
||||
qDebug() << jsonObj;
|
||||
shared_ptr<ElementManager> elementManager = make_shared<ElementManager>(jsonObj, QFileInfo(jsonFilePath).absolutePath());
|
||||
shared_ptr<LayerManager> layerManager = make_shared<LayerManager>(jsonObj, elementManager.get());
|
||||
//qDebug() << elementManager->toJson();
|
||||
//qDebug() << layerManager->toJson();
|
||||
//qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath;
|
||||
//qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath;
|
||||
//qDebug() << elementManager->toJson();
|
||||
//qDebug() << layerManager->toJson();
|
||||
//qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath;
|
||||
//qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath;
|
||||
queue<LayerNode> layerQueue;
|
||||
LayerWrapper* root = layerManager->getRoot();
|
||||
root->getCache();
|
||||
//double maxLineWidth = getMaxLineWidth(root);
|
||||
layerQueue.push({ root, root->property.transform });
|
||||
while (!layerQueue.empty()) {
|
||||
auto layerNode = layerQueue.front();
|
||||
layerQueue.pop();
|
||||
FolderLayerWrapper* nowLayer = handleLayerWrapper(layerNode.nowLayer, layerNode.transfrom, painting);
|
||||
if (nowLayer != nullptr) {
|
||||
for (auto sonLayer : nowLayer->children) {
|
||||
layerQueue.push({ sonLayer.get(), layerNode.transfrom });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return painting;
|
||||
}
|
||||
|
||||
FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTransform& transform, Painting& painting) {
|
||||
LeafLayerWrapper* leafLayer = dynamic_cast<LeafLayerWrapper*>(nowLayer);
|
||||
|
||||
transform = nowLayer->property.transform * transform;
|
||||
|
||||
if (leafLayer != nullptr) {
|
||||
|
||||
GroupElement* wrapperElement = dynamic_cast<GroupElement*>(leafLayer->wrappedElement);
|
||||
if (wrapperElement != nullptr) {
|
||||
transform = wrapperElement->sourceLayer->property.transform * transform;
|
||||
return wrapperElement->sourceLayer;
|
||||
}
|
||||
|
||||
PixelPath pixelPath = nowLayer->getCache();
|
||||
QPainterPath painterPath = pixelPath.getPainterPath();
|
||||
QRectF bound = painterPath.boundingRect();
|
||||
//qDebug() << leafLayer<<"------" << painterPath;
|
||||
// transform to -1£¬ 1
|
||||
QTransform trans;
|
||||
double maxLen = std::max(bound.width(), bound.height());
|
||||
qDebug() << maxLen << bound;
|
||||
trans.scale(1 / maxLen, 1 / maxLen);
|
||||
trans.translate(-bound.center().x(), -bound.center().y());
|
||||
|
||||
painterPath = trans.map(painterPath);
|
||||
shared_ptr<vector<vector<Renderer::Point> >> contour = std::make_shared<vector<vector<Renderer::Point> >>(PainterPathUtil::transformToLines(painterPath));
|
||||
QSize screenSize = QSize(1024, 1024);
|
||||
|
||||
ElementTransform elementTransform;
|
||||
transform = trans.inverted() * transform * QTransform::fromScale(2. / screenSize.width(), 2. / screenSize.height()) * QTransform::fromTranslate(-1, -1) * QTransform::fromScale(1, -1);
|
||||
|
||||
auto baseStyles = leafLayer->styles.toBaseStyles();
|
||||
Renderer::BaseElement element;
|
||||
element.contour = contour;
|
||||
for (auto& baseStyle : baseStyles) {
|
||||
double lineWidth = 0;
|
||||
if (baseStyle.material->type() == Renderer::MaterialStyleType::kStroke) {
|
||||
auto material = std::static_pointer_cast<MaterialStyleStroke>(baseStyle.material);
|
||||
material->halfWidth /= maxLen;
|
||||
lineWidth = material->halfWidth;
|
||||
qDebug() << material->halfWidth;
|
||||
}
|
||||
QPainterPathStroker stroker;
|
||||
stroker.setWidth(lineWidth * 2);
|
||||
stroker.setCapStyle(Qt::RoundCap);
|
||||
stroker.setJoinStyle(Qt::RoundJoin);
|
||||
QPainterPath strokePath = stroker.createStroke(painterPath);
|
||||
auto rect = transform.map(strokePath).boundingRect();
|
||||
elementTransform.bound = glm::vec4(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
|
||||
qDebug() << elementTransform.bound.x << elementTransform.bound.y << elementTransform.bound.z << elementTransform.bound.z;
|
||||
transform = transform.inverted();
|
||||
elementTransform.transform = glm::mat3x2(
|
||||
transform.m11(), transform.m12(), transform.m21(),
|
||||
transform.m22(), transform.m31(), transform.m32()
|
||||
);
|
||||
//qDebug() << transform;
|
||||
elementTransform.zIndex = 0;
|
||||
|
||||
element.style = baseStyle.material;
|
||||
painting.addElement(element, elementTransform);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FolderLayerWrapper* folderLayer = dynamic_cast<FolderLayerWrapper*>(nowLayer);
|
||||
return folderLayer;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include "../../Renderer/Painting/Painting.h"
|
||||
#include <QJsonObject>
|
||||
#include <ElementManager.h>
|
||||
class PaintingUtil
|
||||
{
|
||||
private:
|
||||
//static const double pi;
|
||||
static QJsonObject readJsonFile(QString jsonFilePath);
|
||||
static FolderLayerWrapper* handleLayerWrapper(LayerWrapper* nowLayer, QTransform& transform, Renderer::Painting& painting);
|
||||
//static double getMaxLineWidth(LayerWrapper* root);
|
||||
public:
|
||||
static Renderer::Painting transfromToPainting(QString jsonFilePath);
|
||||
};
|
||||
|
|
@ -86,7 +86,6 @@ QPolygonF SvgFileLoader::handleAttrPoints(QString points) {
|
|||
void SvgFileLoader::handleAttrTransform(QString transformStyle, QPainterPath& painterPath) {
|
||||
QTransform trans;
|
||||
QStringList ops = transformStyle.split(')');
|
||||
reverse(ops.begin(), ops.end());
|
||||
vector<double> numbers;
|
||||
for (auto op : ops) {
|
||||
op = op.simplified();
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#include "FluentMenu.h"
|
||||
#include <QPainter>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
::FluentMenu::FluentMenu(QWidget* parent) : QMenu(parent)
|
||||
{
|
||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setStyleSheet(QString::fromStdString(std::format("QMenu {{margin:{}px;border-radius:{}px;padding:4px;border: 1px solid #c1c1c1;}}"
|
||||
"QMenu::item {{height:30px;width:100px;padding-left:20px;border-radius:{}px;}}"
|
||||
"QMenu::item:selected {{background-color:#dedede;}}", shadowRadius, borderRadius, itemBorderRadius)));
|
||||
}
|
||||
|
||||
void ::FluentMenu::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
for (qreal i = 0; i < shadowRadius; i += 1 / devicePixelRatioF())
|
||||
{
|
||||
painter.setPen(QColor(0, 0, 0, glm::mix(0.22 * 255, 0., glm::pow(i / shadowRadius, 0.2))));
|
||||
painter.drawRoundedRect(QRectF(shadowRadius - i, shadowRadius - i, width() - (shadowRadius - i) * 2, height() - (shadowRadius - i) * 2), borderRadius + i, borderRadius + i);
|
||||
}
|
||||
QMenu::paintEvent(event);
|
||||
}
|
||||
|
||||
QAction* FluentMenu::exec(const QPoint& pos, QAction* at)
|
||||
{
|
||||
return QMenu::exec(parentWidget()->mapToGlobal(parentWidget()->mapFromGlobal(pos) + QPoint(-shadowRadius, -shadowRadius)), at);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <QMenu>
|
||||
|
||||
class FluentMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FluentMenu(QWidget* parent = nullptr);
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
QAction* exec(const QPoint& pos, QAction* at = nullptr);
|
||||
int shadowRadius = 16;
|
||||
int borderRadius = 6;
|
||||
int itemBorderRadius = 4;
|
||||
};
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2018-2022 Antonio Dias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "iconwidget.h"
|
||||
|
||||
#define ICONWIDTH 16
|
||||
#define ICONHEIGHT 16
|
||||
|
||||
IconWidget::IconWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
void IconWidget::setPixmap(const QPixmap &pixmap)
|
||||
{
|
||||
m_pixmap = pixmap;
|
||||
|
||||
QImage tmp = m_pixmap.toImage();
|
||||
|
||||
for (int i = 0; i < m_pixmap.width(); i++)
|
||||
{
|
||||
for (int j = 0; j < m_pixmap.height(); j++)
|
||||
{
|
||||
int gray = qGray(tmp.pixel(i, j));
|
||||
|
||||
int alpha = qAlpha(tmp.pixel(i, j));
|
||||
|
||||
tmp.setPixel(i, j, qRgba(gray, gray, gray, alpha));
|
||||
}
|
||||
}
|
||||
|
||||
m_grayed_pixmap = QPixmap::fromImage(tmp);
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void IconWidget::setActive(bool active)
|
||||
{
|
||||
m_active = active;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void IconWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
|
||||
|
||||
painter.drawPixmap((width() - ICONWIDTH)/ 2,
|
||||
(height() - ICONHEIGHT) / 2,
|
||||
ICONWIDTH, ICONHEIGHT,
|
||||
m_active ? m_pixmap : m_grayed_pixmap);
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2018-2022 Antonio Dias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ICONWIDGET_H
|
||||
#define ICONWIDGET_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
|
||||
class IconWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IconWidget(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void setPixmap(const QPixmap &pixmap);
|
||||
void setActive(bool active);
|
||||
|
||||
private:
|
||||
//Functions
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
//Variables
|
||||
QPixmap m_pixmap;
|
||||
QPixmap m_grayed_pixmap;
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
#endif // ICONWIDGET_H
|
|
@ -2,6 +2,7 @@
|
|||
#include "Renderer/RendererGLWidget.h"
|
||||
#include "qslider.h"
|
||||
#include <QPushButton>
|
||||
#include <QScreen>
|
||||
#include "NavigationBarWidget.h"
|
||||
#include <FramelessHelper/Core/utils.h>
|
||||
#include <FramelessHelper/Widgets/standardtitlebar.h>
|
||||
|
@ -11,19 +12,13 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
CentralWidget::CentralWidget(QWidget* parent) : QMainWindow(parent)
|
||||
CentralWidget::CentralWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
NavigationBarWidget* navigationBarWidget = new NavigationBarWidget();
|
||||
|
||||
QHBoxLayout* tabBarLayout = new QHBoxLayout(ui.tabWidget);
|
||||
tabBarLayout->setSpacing(0);
|
||||
tabBarLayout->setMargin(0);
|
||||
tabBarLayout->addWidget(navigationBarWidget, 0, Qt::AlignTop | Qt::AlignHCenter);
|
||||
|
||||
QObject::connect(navigationBarWidget->tabs, &QtMaterialTabs::currentChanged, ui.tabWidget, &QTabWidget::setCurrentIndex);
|
||||
QObject::connect(ui.tabWidget, &QTabWidget::currentChanged,
|
||||
ui.rendererWidget, &Renderer::RendererWidget::currentTabChanged);
|
||||
NavigationBarWidget* navigationBarWidget = new NavigationBarWidget(this);
|
||||
ui.gridLayout->addWidget(navigationBarWidget, 0, 0, 1, 1, Qt::AlignTop | Qt::AlignHCenter);
|
||||
QObject::connect(navigationBarWidget->tabs, &QtMaterialTabs::currentChanged, ui.stackedWidget, &QStackedWidget::setCurrentIndex);
|
||||
QObject::connect(ui.stackedWidget, &QStackedWidget::currentChanged, ui.rendererWidget, &Renderer::RendererWidget::currentTabChanged);
|
||||
}
|
||||
|
||||
CentralWidget::~CentralWidget()
|
||||
|
@ -44,7 +39,7 @@ MainWindow::MainWindow(QWidget* parent, const Qt::WindowFlags flags)
|
|||
m_titleBar->chromePalette()->setTitleBarActiveBackgroundColor(QColor(0, 0, 0, 0));
|
||||
m_titleBar->chromePalette()->setTitleBarInactiveBackgroundColor(QColor(0, 0, 0, 0));
|
||||
|
||||
m_central_widget = new CentralWidget();
|
||||
m_central_widget = new CentralWidget(this);
|
||||
|
||||
setMenuWidget(m_titleBar);
|
||||
setCentralWidget(m_central_widget);
|
||||
|
@ -55,15 +50,15 @@ MainWindow::MainWindow(QWidget* parent, const Qt::WindowFlags flags)
|
|||
helper->setSystemButton(m_titleBar->maximizeButton(), Global::SystemButtonType::Maximize);
|
||||
helper->setSystemButton(m_titleBar->closeButton(), Global::SystemButtonType::Close);
|
||||
|
||||
/*connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper]() {
|
||||
helper->moveWindowToDesktopCenter();
|
||||
});*/
|
||||
//connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper]() {
|
||||
// helper->moveWindowToDesktopCenter();
|
||||
// });
|
||||
|
||||
setWindowIcon(QIcon(":/images/icon.png"));
|
||||
setWindowTitle("ArchitectureColoredPainting");
|
||||
|
||||
resize(m_central_widget->size());
|
||||
//move(QGuiApplication::primaryScreen()->availableGeometry().center() - rect().center());
|
||||
move(QGuiApplication::primaryScreen()->availableGeometry().center() - rect().center());
|
||||
|
||||
}
|
||||
|
||||
|
@ -77,4 +72,5 @@ void MainWindow::closeEvent(QCloseEvent* event)
|
|||
|
||||
if (result != QMessageBox::Yes)
|
||||
event->ignore();*/
|
||||
qDebug() << "closeEvent";
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
class StandardTitleBar;
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
class CentralWidget : public QMainWindow
|
||||
class CentralWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
#pragma once
|
||||
#include <QOpenGLFunctions_4_5_Core>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QVector2D>
|
||||
#include <QVector3D>
|
||||
#include <vector>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLWidget>
|
||||
#include <assimp/vector3.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include "Drawable.h"
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
QVector3D Position;
|
||||
QVector3D Normal;
|
||||
QVector2D TexCoords;
|
||||
Vertex(const aiVector3D& position, const aiVector3D& Normal, const aiVector3D& TexCoords);
|
||||
glm::vec3 Position;
|
||||
glm::vec3 Normal;
|
||||
glm::vec2 TexCoords;
|
||||
Vertex(const aiVector3D& position, const aiVector3D& normal, const aiVector3D& texCoords);
|
||||
};
|
||||
|
||||
struct Texture
|
||||
|
@ -38,8 +37,8 @@ namespace Renderer
|
|||
class Mesh : public Drawable
|
||||
{
|
||||
public:
|
||||
QVector<Vertex> vertices;
|
||||
QVector<unsigned int> indices;
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
//QVector<Texture*> textures;
|
||||
GLuint textureBasecolor = 0;
|
||||
GLuint textureMetallicRoughness = 0;
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
#include "../Editor/util/PainterPathUtil.h"
|
||||
#include "../Editor/util/SvgFileLoader.h"
|
||||
#include <ThirdPartyLib/qquick/qquicksvgparser_p.h>
|
||||
#include <util/PaintingUtil.h>
|
||||
#include "Painting/MaterialStyleStroke.h"
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
using namespace Renderer;
|
||||
using std::vector;
|
||||
|
@ -30,14 +33,12 @@ Model::Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram,
|
|||
}
|
||||
|
||||
void Model::draw() {
|
||||
//shaderProgram->bind();
|
||||
for (auto& mesh : meshes) {
|
||||
mesh->draw();
|
||||
}
|
||||
}
|
||||
|
||||
void Model::drawShadow() {
|
||||
//shaderProgram->bind();
|
||||
for (auto& mesh : meshes) {
|
||||
mesh->drawShadow();
|
||||
}
|
||||
|
@ -45,34 +46,73 @@ void Model::drawShadow() {
|
|||
|
||||
void Renderer::Model::loadModel(QString path)
|
||||
{
|
||||
directory = path;
|
||||
QFileInfo modelFile(path);
|
||||
name = modelFile.baseName();
|
||||
directory = modelFile.dir();
|
||||
|
||||
Assimp::Importer importer;
|
||||
const aiScene* scene = importer.ReadFile(directory.absolutePath().toUtf8(), aiProcess_Triangulate | aiProcess_FlipUVs);
|
||||
const aiScene* scene = importer.ReadFile(modelFile.absoluteFilePath().toUtf8(), aiProcess_Triangulate);
|
||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
||||
{
|
||||
qDebug() << "ERROR::ASSIMP::" << importer.GetErrorString() << endl;
|
||||
qCritical() << "ERROR::ASSIMP::" << importer.GetErrorString();
|
||||
return;
|
||||
}
|
||||
qDebug() << directory.absolutePath() << "Loaded Successfully";
|
||||
qDebug() << modelFile.absoluteFilePath() << "Loaded Successfully";
|
||||
qDebug() << "NumMeshes: " << scene->mNumMeshes;
|
||||
qDebug() << "NumMaterials: " << scene->mNumMaterials;
|
||||
qDebug() << "NumTextures: " << scene->mNumTextures;
|
||||
directory.cdUp();
|
||||
|
||||
unloadModel();
|
||||
|
||||
|
||||
if (QFile paintingConfigFile(directory.filePath(name + ".txt")); paintingConfigFile.open(QFile::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QTextStream stream(&paintingConfigFile);
|
||||
while (!stream.atEnd())
|
||||
{
|
||||
QString source, target;
|
||||
glm::vec2 leftBottom, rightTop;
|
||||
stream >> source >> target >> leftBottom.x >> leftBottom.y >> rightTop.x >> rightTop.y;
|
||||
qDebug() << source << target << leftBottom.x << leftBottom.y << rightTop.x << rightTop.y;
|
||||
paintingMap.emplace(source.toStdString(), std::forward_as_tuple(target.toStdString(), leftBottom, rightTop));
|
||||
}
|
||||
paintingConfigFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Painting Config Not Found!";
|
||||
}
|
||||
|
||||
|
||||
aiMatrix4x4 transform;
|
||||
aiMatrix4x4::Scaling(aiVector3D(1 / 0.008), transform);
|
||||
processNode(scene->mRootNode, scene, transform * scene->mRootNode->mTransformation);
|
||||
AABB.clear();
|
||||
AABB.emplace_back(minX, minY, minZ);
|
||||
AABB.emplace_back(minX, minY, maxZ);
|
||||
AABB.emplace_back(minX, maxY, minZ);
|
||||
AABB.emplace_back(minX, maxY, maxZ);
|
||||
AABB.emplace_back(maxX, minY, minZ);
|
||||
AABB.emplace_back(maxX, minY, maxZ);
|
||||
AABB.emplace_back(maxX, maxY, minZ);
|
||||
AABB.emplace_back(maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
void Renderer::Model::unloadModel()
|
||||
{
|
||||
paintingMap.clear();
|
||||
for (auto& i : paintingLoaded)
|
||||
vtManager->deleteVirtualTexture(i.second);
|
||||
paintingLoaded.clear();
|
||||
texturesLoaded.clear();
|
||||
meshes.clear();
|
||||
|
||||
minX = std::numeric_limits<float>::max();
|
||||
maxX = std::numeric_limits<float>::min();
|
||||
minY = std::numeric_limits<float>::max();
|
||||
maxY = std::numeric_limits<float>::min();
|
||||
minZ = std::numeric_limits<float>::max();
|
||||
maxZ = std::numeric_limits<float>::min();
|
||||
processNode(scene->mRootNode, scene);
|
||||
AABB.push_back(QVector3D(minX, minY, minZ));
|
||||
AABB.push_back(QVector3D(minX, minY, maxZ));
|
||||
AABB.push_back(QVector3D(minX, maxY, minZ));
|
||||
AABB.push_back(QVector3D(minX, maxY, maxZ));
|
||||
AABB.push_back(QVector3D(maxX, minY, minZ));
|
||||
AABB.push_back(QVector3D(maxX, minY, maxZ));
|
||||
AABB.push_back(QVector3D(maxX, maxY, minZ));
|
||||
AABB.push_back(QVector3D(maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4)
|
||||
|
@ -93,86 +133,76 @@ void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4)
|
|||
|
||||
std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 model)
|
||||
{
|
||||
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
QMatrix4x4 modelQ((float*)&model);
|
||||
|
||||
aiString str;
|
||||
material->GetTexture(aiTextureType_BASE_COLOR, 0, &str);
|
||||
|
||||
if (paintingProgram != nullptr && (std::strcmp(str.C_Str(), "17876391417123941155.jpg") == 0 || std::strcmp(str.C_Str(), "11474523244911310074.jpg") == 0))
|
||||
{
|
||||
qDebug() << str.C_Str() << "Replaced";
|
||||
// 初始化网格
|
||||
auto m_mesh = std::make_unique<PaintingMesh>(glFunc, paintingProgram, shadowProgram, modelQ);
|
||||
// 遍历网格的每个顶点
|
||||
std::vector<Vertex> vertices;
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
|
||||
{
|
||||
if (mesh->mNormals && mesh->mTextureCoords[0])
|
||||
{
|
||||
Vertex vertex(mesh->mVertices[i], mesh->mNormals[i], mesh->mTextureCoords[0][i]);
|
||||
minX = std::min(minX, vertex.Position.x());
|
||||
maxX = std::max(maxX, vertex.Position.x());
|
||||
minY = std::min(minY, vertex.Position.y());
|
||||
maxY = std::max(maxY, vertex.Position.y());
|
||||
minZ = std::min(minZ, vertex.Position.z());
|
||||
maxZ = std::max(maxZ, vertex.Position.z());
|
||||
m_mesh->vertices.push_back(vertex);
|
||||
auto pos = mesh->mVertices[i];
|
||||
vertices.push_back(Vertex(pos, mesh->mNormals[i], mesh->mTextureCoords[0][i]));
|
||||
auto worldPos = model * pos;
|
||||
minX = std::min(minX, worldPos.x);
|
||||
maxX = std::max(maxX, worldPos.x);
|
||||
minY = std::min(minY, worldPos.y);
|
||||
maxY = std::max(maxY, worldPos.y);
|
||||
minZ = std::min(minZ, worldPos.z);
|
||||
maxZ = std::max(maxZ, worldPos.z);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
|
||||
std::vector<unsigned int> indices;
|
||||
for (auto face = mesh->mFaces; face < mesh->mFaces + mesh->mNumFaces; face++)
|
||||
indices.insert(indices.end(), face->mIndices, face->mIndices + face->mNumIndices);
|
||||
|
||||
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
|
||||
if (auto iter = paintingMap.find([&] {
|
||||
aiString str;
|
||||
material->GetTexture(aiTextureType_BASE_COLOR, 0, &str);
|
||||
return std::string(str.C_Str());
|
||||
}()); paintingProgram != nullptr && iter != paintingMap.end())
|
||||
{
|
||||
aiFace face = mesh->mFaces[i];
|
||||
// 将所有面的索引数据添加到索引数组中
|
||||
for (unsigned int j = 0; j < face.mNumIndices; j++) {
|
||||
m_mesh->indices.push_back(face.mIndices[j]);
|
||||
}
|
||||
qDebug() << iter->first.c_str() << "Replaced";
|
||||
|
||||
auto mesh = std::make_unique<PaintingMesh>(glFunc, paintingProgram, shadowProgram, modelQ);
|
||||
|
||||
auto& [paintingPath, leftBottom, rightTop] = iter->second;
|
||||
|
||||
for (auto& v : vertices)
|
||||
{
|
||||
v.TexCoords = (v.TexCoords - leftBottom) / (rightTop - leftBottom);
|
||||
//qDebug() << v.TexCoords.x << v.TexCoords.y;
|
||||
}
|
||||
|
||||
m_mesh->paintingId = loadPainting(std::string(str.C_Str()));
|
||||
auto& handle = vtManager->getPaintingHandle(m_mesh->paintingId);
|
||||
m_mesh->textureBasecolor = handle.baseColor;
|
||||
m_mesh->textureMetallicRoughness = handle.metallicRoughness;
|
||||
m_mesh->setupMesh();
|
||||
return m_mesh;
|
||||
mesh->vertices = vertices;
|
||||
mesh->indices = indices;
|
||||
|
||||
mesh->paintingId = loadPainting(paintingPath);
|
||||
auto& handle = vtManager->getPaintingHandle(mesh->paintingId);
|
||||
mesh->textureBasecolor = handle.baseColor;
|
||||
mesh->textureMetallicRoughness = handle.metallicRoughness;
|
||||
mesh->setupMesh();
|
||||
return mesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 初始化网格
|
||||
auto m_mesh = std::make_unique<Mesh>(glFunc, shaderProgram, shadowProgram, modelQ);
|
||||
// 遍历网格的每个顶点
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
|
||||
{
|
||||
if (mesh->mNormals && mesh->mTextureCoords[0])
|
||||
{
|
||||
Vertex vertex(mesh->mVertices[i], mesh->mNormals[i], mesh->mTextureCoords[0][i]);
|
||||
minX = std::min(minX, vertex.Position.x());
|
||||
maxX = std::max(maxX, vertex.Position.x());
|
||||
minY = std::min(minY, vertex.Position.y());
|
||||
maxY = std::max(maxY, vertex.Position.y());
|
||||
minZ = std::min(minZ, vertex.Position.z());
|
||||
maxZ = std::max(maxZ, vertex.Position.z());
|
||||
m_mesh->vertices.push_back(vertex);
|
||||
}
|
||||
}
|
||||
auto mesh = std::make_unique<Mesh>(glFunc, shaderProgram, shadowProgram, modelQ);
|
||||
mesh->vertices = vertices;
|
||||
mesh->indices = indices;
|
||||
|
||||
// 将所有面的索引数据添加到索引数组中
|
||||
for (auto face = mesh->mFaces; face < mesh->mFaces + mesh->mNumFaces; face++)
|
||||
for (auto indice = face->mIndices; indice < face->mIndices + face->mNumIndices; indice++)
|
||||
m_mesh->indices.push_back(*indice);
|
||||
|
||||
// 处理材质
|
||||
if (!(m_mesh->textureBasecolor = loadMaterialTextures(material, aiTextureType_BASE_COLOR)))
|
||||
if (!(mesh->textureBasecolor = loadMaterialTextures(material, aiTextureType_BASE_COLOR)))
|
||||
qWarning() << "Basecolor Texture Loading Failed!";
|
||||
if (!(m_mesh->textureMetallicRoughness = loadMaterialTextures(material, aiTextureType_METALNESS)))
|
||||
if (!(mesh->textureMetallicRoughness = loadMaterialTextures(material, aiTextureType_METALNESS)))
|
||||
qWarning() << "MetallicRoughness Texture Loading Failed!";
|
||||
if (!(m_mesh->textureNormal = loadMaterialTextures(material, aiTextureType_NORMALS)))
|
||||
if (!(mesh->textureNormal = loadMaterialTextures(material, aiTextureType_NORMALS)))
|
||||
qWarning() << "Normal Texture Loading Failed!";
|
||||
|
||||
if (m_mesh->textureBasecolor && m_mesh->textureMetallicRoughness && m_mesh->textureNormal)
|
||||
if (mesh->textureBasecolor && mesh->textureMetallicRoughness && mesh->textureNormal)
|
||||
{
|
||||
m_mesh->setupMesh();
|
||||
return m_mesh;
|
||||
mesh->setupMesh();
|
||||
return mesh;
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
|
@ -203,7 +233,7 @@ GLuint Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type)
|
|||
texture.setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
|
||||
texture.setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
|
||||
texture.setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
|
||||
texture.setData(data);
|
||||
texture.setData(data.mirrored());
|
||||
return texture.textureId();
|
||||
}
|
||||
|
||||
|
@ -213,12 +243,13 @@ GLuint Renderer::Model::loadPainting(std::string path)
|
|||
if (iter != paintingLoaded.end())
|
||||
return iter->second;
|
||||
|
||||
//vector<std::shared_ptr<Contour>> contour = {
|
||||
// std::make_shared<Contour>(SvgParser("M100,100C-.5,100,0,100.5,0,0L40,.07C40,59.5,39.5,60,100,60Z", 100, 100).parse()),
|
||||
// std::make_shared<Contour>(SvgParser("M308.49,212.25l23,28.38-82,78.31c-14.28,13.64-26.34-20.6-53.44,9.32l-30.24-13.4,63.56-51.59L190.71,215.6l-32.92,26.72L149.5,232.1l32.92-26.72L173.2,194l-32.91,26.72-7.38-9.08L165.83,185l-38.69-47.66L94.22,164,85,152.65l32.91-26.72-9.21-11.35L75.79,141.3l-5.53-6.81,32.92-26.72L94,96.42,61.05,123.14l-12-14.76L37.72,117.6l12,14.75L30.41,148,0,110.55,136.2,0l30.4,37.46L147.31,53.12l-12-14.76L124,47.58l12,14.75L103.05,89.05l9.21,11.35,32.92-26.72,5.52,6.81-32.91,26.72L127,118.56l32.92-26.72,9.21,11.35-32.91,26.72,38.69,47.67,32.91-26.72,7.37,9.08-32.91,26.72L191.49,198l32.92-26.72,8.29,10.22-32.92,26.71,38.7,47.68L302,204.3l6.45,7.95Z", 331.52, 328.26).parse()),
|
||||
// std::make_shared<Contour>(SvgParser("M377,459.61a11.26,11.26,0,0,1,11.27-11.27H696.12a11.27,11.27,0,0,0,11-8.62A359.84,359.84,0,0,0,708,280.56a11.26,11.26,0,0,0-11-8.73H388.27A11.26,11.26,0,0,1,377,260.57h0a11.26,11.26,0,0,1,11.27-11.26H683.71A11.32,11.32,0,0,0,694.28,234C649.8,113.69,542.57,23.85,412.3,4.12a11.22,11.22,0,0,0-12.76,11.17v158.9a11.26,11.26,0,0,0,11.26,11.27H583.12a11.32,11.32,0,0,0,9.26-17.75c-31.67-46.59-78.51-75.2-109.11-90.07a11.25,11.25,0,0,0-16.13,10.17V115.2a11.24,11.24,0,0,0,6.22,10.07l7.51,3.76a11.28,11.28,0,0,1,5,15.12h0a11.27,11.27,0,0,1-15.11,5l-20-10a11.27,11.27,0,0,1-6.22-10.07V54a11.27,11.27,0,0,1,14.62-10.75c5.11,1.59,125.66,40.35,172.24,149A11.27,11.27,0,0,1,621.11,208H388.27A11.26,11.26,0,0,1,377,196.73V11.36A11.32,11.32,0,0,0,365.89.08C363.34,0,360.79,0,358.22,0s-5.11,0-7.66.08a11.32,11.32,0,0,0-11.11,11.28V196.74A11.26,11.26,0,0,1,328.18,208H95.35A11.27,11.27,0,0,1,85,192.3c46.57-108.67,167.12-147.42,172.23-149A11.26,11.26,0,0,1,271.86,54v75.11a11.25,11.25,0,0,1-6.23,10.07l-20,10a11.27,11.27,0,0,1-15.11-5h0a11.26,11.26,0,0,1,5-15.11l7.52-3.76a11.27,11.27,0,0,0,6.22-10.07V87.82a11.25,11.25,0,0,0-16.14-10.16c-30.6,14.87-77.45,43.48-109.1,90.07a11.3,11.3,0,0,0,9.25,17.74H305.66a11.26,11.26,0,0,0,11.27-11.26V15.31A11.22,11.22,0,0,0,304.17,4.14C173.88,23.86,66.66,113.71,22.17,234a11.32,11.32,0,0,0,10.56,15.29H328.18a11.26,11.26,0,0,1,11.27,11.26v0a11.26,11.26,0,0,1-11.27,11.26H19.52a11.26,11.26,0,0,0-11,8.72,359.84,359.84,0,0,0,.83,159.16,11.26,11.26,0,0,0,11,8.61H328.18a11.26,11.26,0,0,1,11.27,11.27h0a11.26,11.26,0,0,1-11.27,11.26h-294a11.32,11.32,0,0,0-10.53,15.4C69,604.65,175.3,692.78,304.16,712.3a11.21,11.21,0,0,0,12.76-11.16V542.22A11.26,11.26,0,0,0,305.66,531h-166c-9.53,0-14.89,11.22-8.69,18.47,34.09,39.77,74.45,65.66,101.77,80.18a11.25,11.25,0,0,0,16.53-10V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,271.85,591v63.85A11.27,11.27,0,0,1,256.8,665.5c-4.45-1.59-109.58-40-171-139.9a11.27,11.27,0,0,1,9.59-17.17H328.18a11.26,11.26,0,0,1,11.27,11.26V705.08a11.32,11.32,0,0,0,11.11,11.28q3.82.07,7.66.08c2.57,0,5.12,0,7.67-.08A11.32,11.32,0,0,0,377,705.08V519.69a11.25,11.25,0,0,1,11.27-11.26H621.1a11.26,11.26,0,0,1,9.59,17.16c-61.46,99.87-166.59,138.3-171,139.9a11.27,11.27,0,0,1-15-10.61V591a11.26,11.26,0,0,1,11.26-11.26h0A11.26,11.26,0,0,1,467.14,591v28.6a11.25,11.25,0,0,0,16.53,10c27.33-14.53,67.68-40.42,101.77-80.19,6.2-7.23.85-18.46-8.69-18.46h-166a11.26,11.26,0,0,0-11.26,11.26V701.12a11.21,11.21,0,0,0,12.76,11.17c128.86-19.51,235.14-107.66,280.48-226a11.33,11.33,0,0,0-10.53-15.41h-294A11.25,11.25,0,0,1,377,459.61ZM35.27,399.53V316.9a11.26,11.26,0,0,1,11.27-11.26H669.92a11.25,11.25,0,0,1,11.26,11.26v82.63a11.25,11.25,0,0,1-11.26,11.26H46.54a11.27,11.27,0,0,1-11.27-11.26Z", 716.45, 716.44).parse())
|
||||
//};
|
||||
|
||||
Painting painting;
|
||||
path = "../test.json";
|
||||
if (auto file = QFileInfo(QString(path.c_str())); file.isFile())
|
||||
painting = PaintingUtil::transfromToPainting(file.filePath());
|
||||
else
|
||||
{
|
||||
qDebug() << path.c_str() << "Not Found, Using Default Painting";
|
||||
vector<std::pair<std::shared_ptr<Contour>, float>> contours;
|
||||
|
||||
QPainterPath painterPaths[3];
|
||||
|
@ -248,13 +279,84 @@ GLuint Renderer::Model::loadPainting(std::string path)
|
|||
std::make_shared<Element>(Element{ contours[1].first, style[2], contours[1].second}),
|
||||
std::make_shared<Element>(Element{ contours[2].first, style[0], contours[2].second}),
|
||||
};
|
||||
Painting painting;
|
||||
|
||||
if (path == "17876391417123941155.jpg")
|
||||
if (path == "0.json")
|
||||
{
|
||||
painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,-0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 });
|
||||
painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45, 0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 });
|
||||
painting.addElement(*element[2], ElementTransform{ glm::vec2(0.50,-0.45), glm::vec2(0.6,0.7) / 2.f, 0, glm::bvec2(false), 0 });
|
||||
//painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,-0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 });
|
||||
//painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.45, 0.45), glm::vec2(0.5,0.5) / 2.f, 0, glm::bvec2(false), 0 });
|
||||
//painting.addElement(*element[2], ElementTransform{ glm::vec2(0.50,-0.45), glm::vec2(0.6,0.7) / 2.f, 0, glm::bvec2(false), 0 });
|
||||
}
|
||||
else if (path == "1.json")
|
||||
{
|
||||
//painting.backgroundColor = QColor(196, 81, 35);
|
||||
float widths[] = { 0.22, 0.22 * 0.25 / 0.15, 0.22 * 0.25 / 0.15 };
|
||||
QPainterPath painterPaths[6];
|
||||
for (int i = 0; i < 6; i++)
|
||||
if (!SvgFileLoader().loadSvgFile(QString(std::format("../svg/{}.svg", i + 1).c_str()), painterPaths[i]))
|
||||
qCritical() << "load error";
|
||||
|
||||
vector<std::pair<std::shared_ptr<Contour>, float>> contours;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto [contour, ratio] = PainterPathUtil::toNormalizedLines(painterPaths[i], widths[i]);
|
||||
contours.emplace_back(std::make_shared<Contour>(contour), ratio);
|
||||
}
|
||||
class StyleStrokeRadialGradient : public Renderer::ElementStyle
|
||||
{
|
||||
public:
|
||||
float width;
|
||||
StrokeType type;
|
||||
StyleStrokeRadialGradient(float width, StrokeType type) :width(width), type(type) {};
|
||||
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override
|
||||
{
|
||||
std::map<float, Material> materialMap = {
|
||||
{0.09, Material{QColor(255,255,255),0,0.8}},
|
||||
{0.63, Material{QColor(165,176,207),0,0.8}},
|
||||
{1.00, Material{QColor(58,64,151),0,0.8}}
|
||||
};
|
||||
return { BaseStyle(std::make_shared<TransformStyle>(),
|
||||
std::make_shared<MaterialStyleStroke>(width, type, StrokeEndType::kFlat,
|
||||
std::make_shared<StrokeRadialGradient>(materialMap, false))) };
|
||||
}
|
||||
};
|
||||
vector<std::shared_ptr<ElementStyle>> style = {
|
||||
std::make_shared<StyleStrokeRadialGradient>(widths[0], StrokeType::kLeftSide),
|
||||
std::make_shared<StyleStrokeRadialGradient>(widths[1], StrokeType::kRightSide),
|
||||
std::make_shared<StyleStrokeRadialGradient>(widths[2], StrokeType::kLeftSide),
|
||||
};
|
||||
std::map<float, Material> materialMap = {
|
||||
{0.09, Material{QColor(255,255,255),0,0.8}},
|
||||
{0.63, Material{QColor(165,176,207),0,0.8}},
|
||||
{1.00, Material{QColor(58,64,151),0,0.8}}
|
||||
};
|
||||
vector<std::shared_ptr<BaseElement>> element = {
|
||||
std::make_shared<BaseElement>(contours[0].first, std::make_shared<MaterialStyleStroke>(
|
||||
widths[0], StrokeType::kLeftSide, StrokeEndType::kFlat, std::make_shared<StrokeRadialGradient>(materialMap, false))),
|
||||
std::make_shared<BaseElement>(contours[1].first, std::make_shared<MaterialStyleStroke>(
|
||||
widths[1], StrokeType::kRightSide, StrokeEndType::kFlat, std::make_shared<StrokeRadialGradient>(materialMap, false))),
|
||||
std::make_shared<BaseElement>(contours[2].first, std::make_shared<MaterialStyleStroke>(
|
||||
widths[2], StrokeType::kLeftSide, StrokeEndType::kFlat, std::make_shared<StrokeRadialGradient>(materialMap, false))),
|
||||
};
|
||||
|
||||
QTransform trans = QTransform::fromScale(0.3, 0.3).inverted();
|
||||
glm::mat3x2 mat(trans.m11(), trans.m12(), trans.m21(), trans.m22(), trans.m31(), trans.m32());
|
||||
|
||||
trans = QTransform::fromTranslate(0.5, 0).scale(0.3, 0.3).inverted();
|
||||
glm::mat3x2 mat2(trans.m11(), trans.m12(), trans.m21(), trans.m22(), trans.m31(), trans.m32());
|
||||
//mat = glm::mat3x2(11, 22, 33, 44, 55, 66);
|
||||
//mat2 = glm::mat3x2(1, 2, 3, 4, 5, 6);
|
||||
|
||||
qDebug() << std::format("\n{} {} {}\n {} {} {}\n{} {} {}",
|
||||
trans.m11(), trans.m21(), trans.m31(),
|
||||
trans.m12(), trans.m22(), trans.m32(),
|
||||
trans.m13(), trans.m23(), trans.m33()).c_str();
|
||||
|
||||
//painting.addElement(*element[0], ElementTransform{ glm::vec4(-1,-1,1,1), mat, 0});
|
||||
painting.addElement(*element[1], ElementTransform{ glm::vec4(-1,-1,0,1), mat, 0 });
|
||||
painting.addElement(*element[2], ElementTransform{ glm::vec4(0,-1,1,1), mat2, 0 });
|
||||
//painting.addElement(*element[0], ElementTransform{ glm::vec2(-0.45,0.45), glm::vec2(0.25), 0, glm::bvec2(false), 0 });
|
||||
//painting.addElement(*element[1], ElementTransform{ glm::vec2(-0.535,0.33), glm::vec2(0.15), 0, glm::bvec2(false), 0 });
|
||||
//painting.addElement(*element[2], ElementTransform{ glm::vec2(-0.535,0.23), glm::vec2(0.15), 0, glm::bvec2(false), 0 });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -262,11 +364,10 @@ GLuint Renderer::Model::loadPainting(std::string path)
|
|||
{
|
||||
float x = (float)rand() / RAND_MAX * 2 - 1;
|
||||
float y = (float)rand() / RAND_MAX * 2 - 1;
|
||||
painting.addElement(*element[i % 3], ElementTransform{ glm::vec2(x,y), glm::vec2(0.025), (float)rand() / RAND_MAX * 360, glm::bvec2(false), 0 });
|
||||
//painting.addElement(*element[i % 3], ElementTransform{ glm::vec2(x,y), glm::vec2(0.025), (float)rand() / RAND_MAX * 360, glm::bvec2(false), 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
painting.generateBuffers(glFunc);
|
||||
|
||||
auto index = vtManager->createVirtualTexture(painting);
|
||||
|
|
|
@ -15,22 +15,27 @@ namespace Renderer
|
|||
void draw();
|
||||
void drawShadow();
|
||||
void loadModel(QString path);
|
||||
void unloadModel();
|
||||
Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, VirtualTextureManager* vtManager);
|
||||
private:
|
||||
QOpenGLContext* context;
|
||||
QOpenGLContext* context = nullptr;
|
||||
QOpenGLFunctions_4_5_Core* glFunc = nullptr;
|
||||
QOpenGLShaderProgram* shaderProgram = nullptr;
|
||||
QOpenGLShaderProgram* paintingProgram = nullptr;
|
||||
QOpenGLShaderProgram* shadowProgram = nullptr;
|
||||
VirtualTextureManager* vtManager = nullptr;
|
||||
|
||||
/* 模型数据 */
|
||||
/**
|
||||
* @brief key BaseColor路径 \n
|
||||
* value json路径, 纹理坐标
|
||||
*/
|
||||
std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>> paintingMap;
|
||||
std::unordered_map<std::string, GLuint> paintingLoaded;
|
||||
std::unordered_map<std::string, QOpenGLTexture> texturesLoaded;
|
||||
std::vector<std::unique_ptr<Drawable>> meshes;
|
||||
|
||||
/// 模型所在路径
|
||||
QDir directory;
|
||||
QDir directory; /// 模型所在路径
|
||||
QString name; /// 模型文件名
|
||||
|
||||
float minX, maxX, minY, maxY, minZ, maxZ;
|
||||
|
||||
|
|
|
@ -1,6 +1,43 @@
|
|||
#include "BaseStyle.h"
|
||||
#include "MaterialStyleFill.h"
|
||||
#include "MaterialStyleStroke.h"
|
||||
|
||||
using namespace Renderer;
|
||||
using namespace glm;
|
||||
|
||||
Renderer::Material::Material(const QColor& color, float metallic, float roughness)
|
||||
: color(color)
|
||||
{
|
||||
setMetallicF(metallic);
|
||||
setRoughnessF(roughness);
|
||||
}
|
||||
|
||||
Renderer::Material::Material(const glm::vec4& color, const glm::vec2& metallicRoughness)
|
||||
: color(QColor::fromRgbF(color.r, color.g, color.b, color.a))
|
||||
{
|
||||
setMetallicF(metallicRoughness.r);
|
||||
setRoughnessF(metallicRoughness.g);
|
||||
}
|
||||
|
||||
float Renderer::Material::metallicF() const
|
||||
{
|
||||
return metallic / 255.f;
|
||||
}
|
||||
|
||||
float Renderer::Material::roughnessF() const
|
||||
{
|
||||
return roughness / 255.f;
|
||||
}
|
||||
|
||||
void Renderer::Material::setMetallicF(float metallic)
|
||||
{
|
||||
this->metallic = metallic * 255;
|
||||
}
|
||||
|
||||
void Renderer::Material::setRoughnessF(float roughness)
|
||||
{
|
||||
this->roughness = roughness * 255;
|
||||
}
|
||||
|
||||
bool Renderer::Material::operator==(const Material& m) const
|
||||
{
|
||||
|
@ -9,5 +46,52 @@ bool Renderer::Material::operator==(const Material& m) const
|
|||
|
||||
std::pair<glm::vec4, glm::vec2> Renderer::Material::toVec() const
|
||||
{
|
||||
return { glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()), glm::vec2(metallic, roughness)};
|
||||
return { glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()), glm::vec2(metallicF(), roughnessF())};
|
||||
}
|
||||
|
||||
std::unique_ptr<MaterialStyle> Renderer::MaterialStyle::decoded(const std::vector<GLfloat>& encoded)
|
||||
{
|
||||
if (encoded[0] <= 0) /// MaterialStyleFill
|
||||
{
|
||||
std::unique_ptr<MaterialFill> materiallFill;
|
||||
glm::vec4 head = glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[0]));
|
||||
if (head.z == 0)
|
||||
{
|
||||
materiallFill = std::make_unique<FillPlain>(Material(glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[1])), glm::vec2(head.r, head.g)));
|
||||
}
|
||||
return std::make_unique<MaterialStyleFill>(std::move(materiallFill));
|
||||
}
|
||||
else /// MaterialStyleStroke
|
||||
{
|
||||
std::unique_ptr<MaterialStroke> materialStroke;
|
||||
uint headUint = floatBitsToUint(encoded[1]);
|
||||
vec4 head = unpackUnorm4x8(headUint);
|
||||
StrokeType strokeType = (StrokeType)floor(head.b * 10);
|
||||
StrokeEndType endType = (StrokeEndType)(int(round(head.b * 100)) % 10);
|
||||
switch (int(head.a * 100) % 10)
|
||||
{
|
||||
/// Plain
|
||||
case 0: {
|
||||
materialStroke = std::make_unique<StrokePlain>(Material(glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[2])), glm::vec2(head.r, head.g)));
|
||||
break;
|
||||
}
|
||||
/// RadialGradient
|
||||
case 1: {
|
||||
uint size = headUint % (1 << 15);
|
||||
bool gradual = (headUint & (1 << 15)) != 0;
|
||||
std::map<float, Material> materialMap;
|
||||
for (uint i = 0; i < size; i++)
|
||||
{
|
||||
auto data = floatBitsToUint(encoded[2 + i * 2]);
|
||||
auto level = unpackUnorm2x16(data).y;
|
||||
auto color = unpackUnorm4x8(floatBitsToUint(encoded[3 + i * 2]));
|
||||
auto metallicRoughness = unpackUnorm4x8(data);
|
||||
materialMap.emplace(level, Material(color, glm::vec2(metallicRoughness.r, metallicRoughness.g)));
|
||||
}
|
||||
materialStroke = std::make_unique<StrokeRadialGradient>(materialMap, gradual);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::make_unique<MaterialStyleStroke>(encoded[0], strokeType, endType, std::move(materialStroke));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@ namespace Renderer
|
|||
public:
|
||||
virtual MaterialStyleType type() const = 0;
|
||||
virtual std::vector<GLfloat> encoded() const = 0;
|
||||
virtual std::unique_ptr<MaterialStyle> clone() const = 0;
|
||||
virtual bool operator==(const MaterialStyle&) const = 0;
|
||||
static std::unique_ptr<MaterialStyle> decoded(const std::vector<GLfloat>& encoded);
|
||||
};
|
||||
|
||||
struct BaseStyle
|
||||
|
@ -35,8 +37,16 @@ namespace Renderer
|
|||
struct Material
|
||||
{
|
||||
QColor color;
|
||||
float metallic;
|
||||
float roughness;
|
||||
std::uint8_t metallic;
|
||||
std::uint8_t roughness;
|
||||
|
||||
Material() = default;
|
||||
Material(const QColor& color, float metallic = 0, float roughness = 0.5);
|
||||
Material(const glm::vec4& color, const glm::vec2& metallicRoughness);
|
||||
float metallicF() const;
|
||||
float roughnessF() const;
|
||||
void setMetallicF(float metallic);
|
||||
void setRoughnessF(float roughness);
|
||||
bool operator==(const Material&) const;
|
||||
std::pair<glm::vec4, glm::vec2> toVec() const;
|
||||
};
|
||||
|
|
|
@ -20,12 +20,12 @@ QVector4D BvhTree::Union(QVector4D a, QVector4D b) {
|
|||
|
||||
QVector4D BvhTree::merge(BvhPtr lp, BvhPtr rp) {
|
||||
QVector4D a = lp->bound, b = rp->bound;
|
||||
if (lp->isLeaf) {
|
||||
/*if (lp->isLeaf) {
|
||||
a = BvhTreeData::boundWithRotation(a, lp->getRightSon());
|
||||
}
|
||||
if (rp->isLeaf) {
|
||||
b = BvhTreeData::boundWithRotation(b, rp->getRightSon());
|
||||
}
|
||||
}*/
|
||||
return Union(a, b);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#include "Element.h"
|
||||
|
||||
void Renderer::ElementTransform::applyTransformStyle(const TransformStyle& t)
|
||||
{
|
||||
center += t.translation;
|
||||
scale *= t.scale;
|
||||
rotation += t.rotation;
|
||||
flip ^= t.flip;
|
||||
}
|
||||
|
||||
Renderer::ElementTransform Renderer::ElementTransform::appliedTransformStyle(const TransformStyle& t) const
|
||||
{
|
||||
ElementTransform result = *this;
|
||||
result.applyTransformStyle(t);
|
||||
return result;
|
||||
}
|
||||
//void Renderer::ElementTransform::applyTransformStyle(const TransformStyle& t)
|
||||
//{
|
||||
// /*center += t.translation;
|
||||
// scale *= t.scale;
|
||||
// rotation += t.rotation;
|
||||
// flip ^= t.flip;*/
|
||||
//}
|
||||
//
|
||||
//Renderer::ElementTransform Renderer::ElementTransform::appliedTransformStyle(const TransformStyle& t) const
|
||||
//{
|
||||
// ElementTransform result = *this;
|
||||
// result.applyTransformStyle(t);
|
||||
// return result;
|
||||
//}
|
||||
|
|
|
@ -18,14 +18,15 @@ namespace Renderer
|
|||
|
||||
struct ElementTransform
|
||||
{
|
||||
glm::vec2 center;
|
||||
//glm::vec2 size;
|
||||
glm::vec2 scale; /// 相对于画布
|
||||
float rotation; /// 角度制
|
||||
glm::bvec2 flip;
|
||||
//glm::vec2 center;
|
||||
//glm::vec2 scale; /// 相对于画布
|
||||
//float rotation; /// 角度制
|
||||
//glm::bvec2 flip;
|
||||
glm::vec4 bound; /// 包围盒,不影响变换
|
||||
glm::mat3x2 transform; /// 逆变换
|
||||
GLuint zIndex;
|
||||
|
||||
void applyTransformStyle(const TransformStyle& t);
|
||||
ElementTransform appliedTransformStyle(const TransformStyle& t) const;
|
||||
//void applyTransformStyle(const TransformStyle& t);
|
||||
//ElementTransform appliedTransformStyle(const TransformStyle& t) const;
|
||||
};
|
||||
}
|
|
@ -141,12 +141,13 @@ bool LineTree::handleShortCutNode(LineTreeNode& fa, LineTreeNode& nowTreeNode, d
|
|||
nowTreeNode.lineSet.push_back(lineIndex);
|
||||
}
|
||||
}
|
||||
if (nowTreeNode.lineSet.size() <= requiredLineMin) {
|
||||
if (nowTreeNode.lineSet.size() <= requiredLineMin
|
||||
|| (nowTreeNode.bound.z()-nowTreeNode.bound.x())*sqrt(2) <= lineWidth) {
|
||||
if (nowTreeNode.lineSet.empty())
|
||||
return false;
|
||||
restOfTreeNodes.push_back(nowTreeNode);
|
||||
nowTreeNode.divided = false;
|
||||
v.push_back(nowTreeNode);
|
||||
//v.push_back(nowTreeNode);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
using namespace Renderer;
|
||||
|
||||
Renderer::FillPlain::FillPlain(QColor color, float metallic, float roughness)
|
||||
: color(color), metallic(metallic), roughness(roughness)
|
||||
: material(color, metallic, roughness)
|
||||
{
|
||||
}
|
||||
|
||||
Renderer::FillPlain::FillPlain(const Material& material)
|
||||
: material(material)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -14,16 +19,20 @@ MaterialFillType Renderer::FillPlain::type() const
|
|||
|
||||
std::vector<GLfloat> Renderer::FillPlain::encoded() const
|
||||
{
|
||||
return { glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(metallic, roughness, 0, 1))),
|
||||
glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF())))};
|
||||
auto pair = material.toVec();
|
||||
return { glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(pair.second, 0, 1))),
|
||||
glm::uintBitsToFloat(glm::packUnorm4x8(pair.first))};
|
||||
}
|
||||
|
||||
std::unique_ptr<MaterialFill> Renderer::FillPlain::clone() const
|
||||
{
|
||||
return std::make_unique<FillPlain>(*this);
|
||||
}
|
||||
|
||||
bool Renderer::FillPlain::operator==(const MaterialFill& m) const
|
||||
{
|
||||
return type() == m.type()
|
||||
&& color == static_cast<const FillPlain&>(m).color
|
||||
&& metallic == static_cast<const FillPlain&>(m).metallic
|
||||
&& roughness == static_cast<const FillPlain&>(m).roughness;
|
||||
&& material == static_cast<const FillPlain&>(m).material;
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,6 +51,11 @@ std::vector<GLfloat> Renderer::MaterialStyleFill::encoded() const
|
|||
return materialFill->encoded();
|
||||
}
|
||||
|
||||
std::unique_ptr<MaterialStyle> Renderer::MaterialStyleFill::clone() const
|
||||
{
|
||||
return std::make_unique<MaterialStyleFill>(materialFill->clone());
|
||||
}
|
||||
|
||||
bool Renderer::MaterialStyleFill::operator==(const MaterialStyle& m) const
|
||||
{
|
||||
return type() == m.type() && *materialFill == *static_cast<const MaterialStyleFill&>(m).materialFill;
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Renderer
|
|||
public:
|
||||
virtual MaterialFillType type() const = 0;
|
||||
virtual std::vector<GLfloat> encoded() const = 0;
|
||||
virtual std::unique_ptr<MaterialFill> clone() const = 0;
|
||||
virtual bool operator==(const MaterialFill&) const = 0;
|
||||
};
|
||||
|
||||
|
@ -17,13 +18,13 @@ namespace Renderer
|
|||
{
|
||||
public:
|
||||
FillPlain(QColor color, float metallic, float roughness);
|
||||
FillPlain(const Material& material);
|
||||
virtual MaterialFillType type() const override;
|
||||
virtual std::vector<GLfloat> encoded() const override;
|
||||
virtual std::unique_ptr<MaterialFill> clone() const override;
|
||||
virtual bool operator==(const MaterialFill&) const override;
|
||||
|
||||
QColor color;
|
||||
float metallic;
|
||||
float roughness;
|
||||
Material material;
|
||||
};
|
||||
|
||||
class MaterialStyleFill : public MaterialStyle
|
||||
|
@ -32,8 +33,9 @@ namespace Renderer
|
|||
MaterialStyleFill(std::shared_ptr<MaterialFill> materialFill);
|
||||
virtual MaterialStyleType type() const override;
|
||||
virtual std::vector<GLfloat> encoded() const override;
|
||||
virtual std::unique_ptr<MaterialStyle> clone() const override;
|
||||
virtual bool operator==(const MaterialStyle&) const override;
|
||||
protected:
|
||||
//protected:
|
||||
std::shared_ptr<MaterialFill> materialFill;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "MaterialStyleStroke.h"
|
||||
#include <QDebug>
|
||||
#include <array>
|
||||
|
||||
using namespace Renderer;
|
||||
|
||||
|
@ -18,8 +19,14 @@ MaterialStrokeType Renderer::StrokePlain::type() const
|
|||
return MaterialStrokeType::kPlain;
|
||||
}
|
||||
|
||||
std::unique_ptr<MaterialStroke> Renderer::StrokePlain::clone() const
|
||||
{
|
||||
return std::make_unique<StrokePlain>(*this);
|
||||
}
|
||||
|
||||
std::vector<GLfloat> Renderer::StrokePlain::encoded() const
|
||||
{
|
||||
qDebug() << material.color;
|
||||
return { glm::uintBitsToFloat(glm::packUnorm4x8(glm::vec4(material.toVec().second, 0.f, 0.f))),
|
||||
glm::uintBitsToFloat(glm::packUnorm4x8(material.toVec().first)) };
|
||||
}
|
||||
|
@ -53,11 +60,16 @@ std::vector<GLfloat> Renderer::StrokeRadialGradient::encoded() const
|
|||
v.y = pair.first;
|
||||
result.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(v)));
|
||||
result.push_back(glm::uintBitsToFloat(glm::packUnorm4x8(color)));
|
||||
qDebug() << pair.first;
|
||||
//qDebug() << pair.first;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<MaterialStroke> Renderer::StrokeRadialGradient::clone() const
|
||||
{
|
||||
return std::make_unique<StrokeRadialGradient>(*this);
|
||||
}
|
||||
|
||||
bool Renderer::StrokeRadialGradient::operator==(const MaterialStroke& m) const
|
||||
{
|
||||
return type() == m.type()
|
||||
|
@ -65,8 +77,8 @@ bool Renderer::StrokeRadialGradient::operator==(const MaterialStroke& m) const
|
|||
&& materialMap == static_cast<const StrokeRadialGradient&>(m).materialMap;
|
||||
}
|
||||
|
||||
Renderer::MaterialStyleStroke::MaterialStyleStroke(float width, StrokeType strokeType, StrokeEndType endType, std::shared_ptr<MaterialStroke> materialStroke)
|
||||
: halfWidth(width/2), strokeType(strokeType), endType(endType), materialStroke(materialStroke)
|
||||
Renderer::MaterialStyleStroke::MaterialStyleStroke(float halfWidth, StrokeType strokeType, StrokeEndType endType, std::shared_ptr<MaterialStroke> materialStroke)
|
||||
: halfWidth(halfWidth), strokeType(strokeType), endType(endType), materialStroke(materialStroke)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -87,9 +99,18 @@ std::vector<GLfloat> Renderer::MaterialStyleStroke::encoded() const
|
|||
return v;
|
||||
}
|
||||
|
||||
std::unique_ptr<MaterialStyle> Renderer::MaterialStyleStroke::clone() const
|
||||
{
|
||||
return std::make_unique<MaterialStyleStroke>(halfWidth, strokeType, endType, materialStroke->clone());
|
||||
}
|
||||
|
||||
bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const
|
||||
{
|
||||
return type() == m.type() && *materialStroke == *static_cast<const MaterialStyleStroke&>(m).materialStroke;
|
||||
return type() == m.type()
|
||||
&& halfWidth == static_cast<const MaterialStyleStroke&>(m).halfWidth
|
||||
&& strokeType == static_cast<const MaterialStyleStroke&>(m).strokeType
|
||||
&& endType == static_cast<const MaterialStyleStroke&>(m).endType
|
||||
&& *materialStroke == *static_cast<const MaterialStyleStroke&>(m).materialStroke;
|
||||
}
|
||||
|
||||
float Renderer::MaterialStyleStroke::getHalfWidth() const
|
||||
|
@ -97,4 +118,10 @@ float Renderer::MaterialStyleStroke::getHalfWidth() const
|
|||
return halfWidth;
|
||||
}
|
||||
|
||||
|
||||
#define endTypeBoxLabel(start, end) QStringLiteral(start##" -> "##end)
|
||||
const std::array<std::pair<QString, StrokeEndType>, 4> Renderer::MaterialStyleStroke::strokeEndTypeNames = {
|
||||
std::pair{endTypeBoxLabel("Բͷ", "Բͷ"), StrokeEndType::kRound},
|
||||
std::pair{endTypeBoxLabel("ƽͷ", "Բͷ"), StrokeEndType::kFlatRound},
|
||||
std::pair{endTypeBoxLabel("Բͷ", "ƽͷ"), StrokeEndType::kRoundFlat},
|
||||
std::pair{endTypeBoxLabel("ƽͷ", "ƽͷ"), StrokeEndType::kFlat}
|
||||
};
|
|
@ -11,6 +11,7 @@ namespace Renderer
|
|||
public:
|
||||
virtual MaterialStrokeType type() const = 0;
|
||||
virtual std::vector<GLfloat> encoded() const = 0;
|
||||
virtual std::unique_ptr<MaterialStroke> clone() const = 0;
|
||||
virtual bool operator==(const MaterialStroke&) const = 0;
|
||||
};
|
||||
|
||||
|
@ -20,7 +21,9 @@ namespace Renderer
|
|||
StrokePlain(QColor color, float metallic, float roughness);
|
||||
StrokePlain(const Material& material);
|
||||
virtual MaterialStrokeType type() const override;
|
||||
virtual std::unique_ptr<MaterialStroke> clone() const override;
|
||||
virtual std::vector<GLfloat> encoded() const override;
|
||||
|
||||
virtual bool operator==(const MaterialStroke&) const override;
|
||||
|
||||
Material material;
|
||||
|
@ -32,6 +35,7 @@ namespace Renderer
|
|||
StrokeRadialGradient(const std::map<float, Material>& materialMap, bool gradual);
|
||||
virtual MaterialStrokeType type() const override;
|
||||
virtual std::vector<GLfloat> encoded() const override;
|
||||
virtual std::unique_ptr<MaterialStroke> clone() const override;
|
||||
virtual bool operator==(const MaterialStroke&) const override;
|
||||
|
||||
std::map<float, Material> materialMap;
|
||||
|
@ -39,7 +43,7 @@ namespace Renderer
|
|||
};
|
||||
|
||||
enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 };
|
||||
enum class StrokeEndType { kRound = 0, kFlat = 1 };
|
||||
enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01, kClosed = 0b100/*用于封闭图形*/ };
|
||||
|
||||
class MaterialStyleStroke : public MaterialStyle
|
||||
{
|
||||
|
@ -47,12 +51,14 @@ namespace Renderer
|
|||
MaterialStyleStroke(float width, StrokeType strokeType, StrokeEndType endType, std::shared_ptr<MaterialStroke> materialStroke);
|
||||
virtual MaterialStyleType type() const override;
|
||||
virtual std::vector<GLfloat> encoded() const override;
|
||||
virtual std::unique_ptr<MaterialStyle> clone() const override;
|
||||
virtual bool operator==(const MaterialStyle&) const override;
|
||||
float getHalfWidth() const;
|
||||
protected:
|
||||
|
||||
float halfWidth;
|
||||
StrokeType strokeType;
|
||||
StrokeEndType endType;
|
||||
std::shared_ptr<MaterialStroke> materialStroke;
|
||||
static const std::array<std::pair<QString, StrokeEndType>, 4> strokeEndTypeNames;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ using namespace Renderer;
|
|||
|
||||
constexpr int kMaxLineCount = 20;
|
||||
|
||||
Painting::Painting()
|
||||
Painting::Painting(QColor backgroundColor) : backgroundColor(backgroundColor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -53,87 +53,40 @@ void Renderer::Painting::addElement(ElementWithTransform elementWithTransform)
|
|||
elementPool.insert({ element, 0 });
|
||||
}
|
||||
elements.push_back(elementWithTransform);
|
||||
elementTransformPool.emplace(elementWithTransform.transform.transform, 0);
|
||||
}
|
||||
|
||||
void Renderer::Painting::addElement(const Element& element, const ElementTransform& transform)
|
||||
void Renderer::Painting::addElement(const BaseElement& element, const ElementTransform& transform)
|
||||
{
|
||||
auto contour = element.contour;
|
||||
auto it = elementStyleMap.find(element.style);
|
||||
if (it == elementStyleMap.end())
|
||||
{
|
||||
std::vector<BaseStyle> baseStyles;
|
||||
for (auto& style : element.style->toBaseStyles())
|
||||
{
|
||||
auto [iter, _] = styleSet.insert(style.material);
|
||||
baseStyles.push_back(BaseStyle{ style.transform, *iter });
|
||||
}
|
||||
it = elementStyleMap.insert({ element.style, baseStyles }).first;
|
||||
}
|
||||
for (int i = 0; i < it->second.size(); i++)
|
||||
{
|
||||
auto& style = it->second[i];
|
||||
ElementTransform trans = transform;
|
||||
trans.applyTransformStyle(*style.transform);
|
||||
trans.zIndex = trans.zIndex * 10 + i;
|
||||
|
||||
addElement(ElementWithTransform{ BaseElement{element.contour, style.material, element.ratio}, trans });
|
||||
}
|
||||
addElement({ element , transform });
|
||||
}
|
||||
|
||||
Renderer::BaseTransform::BaseTransform(ElementTransform t)
|
||||
: bound(glm::vec4(t.center - t.scale, t.center + t.scale))
|
||||
, rotation(t.rotation)
|
||||
, flip(t.flip)
|
||||
, zIndex(t.zIndex)
|
||||
BvhTreeData Painting::encodeElementLeaf(const ElementWithTransform& e)
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::Painting::addElement(std::shared_ptr<Element> element, QVector4D bound, float rotation, int zIndex)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BvhTreeData Painting::encodeElementLeaf(ElementWithTransform e)
|
||||
{
|
||||
glm::vec4 bound;
|
||||
switch (e.element.style->type())
|
||||
{
|
||||
case MaterialStyleType::kStroke:
|
||||
{
|
||||
auto w = std::static_pointer_cast<MaterialStyleStroke>(e.element.style)->getHalfWidth();
|
||||
glm::vec2 size = e.element.ratio < 1 ? glm::vec2(e.element.ratio, 1) : glm::vec2(1, 1 / e.element.ratio);
|
||||
glm::vec2 scale = size * e.transform.scale;
|
||||
bound = glm::vec4(e.transform.center - scale, e.transform.center + scale);
|
||||
break;
|
||||
}
|
||||
case MaterialStyleType::kFill:
|
||||
{
|
||||
bound = glm::vec4(e.transform.center - e.transform.scale, e.transform.center + e.transform.scale);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//bound = glm::vec4(e.transform.center - e.transform.scale, e.transform.center + e.transform.scale);
|
||||
GLuint rightSon = (GLuint)(glm::mod(e.transform.rotation, 360.f) / 360.f * (1 << 16))
|
||||
+ (e.transform.flip.x << 16) + (e.transform.flip.y << 17) + (e.transform.zIndex << 18);
|
||||
return BvhTreeData(QVector4D(bound.x, bound.y, bound.z, bound.w), elementPool[e.element], rightSon);
|
||||
QVector4D bound(e.transform.bound.x, e.transform.bound.y, e.transform.bound.z, e.transform.bound.w);
|
||||
GLuint rightSon = elementPool[e.element] + (e.transform.zIndex << 18);
|
||||
return { bound, elementTransformPool[e.transform.transform], rightSon };
|
||||
}
|
||||
|
||||
void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc)
|
||||
{
|
||||
qDebug() << "Element Count: " << elementPool.size();
|
||||
qDebug() << "Coutour Count: " << contourPool.size();
|
||||
qDebug() << "Contour Count: " << contourPool.size();
|
||||
qDebug() << " Style Count: " << stylePool.size();
|
||||
|
||||
bvhChildren.clear();
|
||||
bvhBounds.clear();
|
||||
elementTransform.clear();
|
||||
elementOffsets.clear();
|
||||
elementIndex.clear();
|
||||
elementData.clear();
|
||||
|
||||
for (int index = 0; auto & i : elementPool)
|
||||
{
|
||||
i.second = index++;
|
||||
}
|
||||
for (int index = 0; auto & i : elementTransformPool)
|
||||
i.second = index++;
|
||||
|
||||
|
||||
|
||||
std::vector<BvhTreeData> rootBvhTreeData;
|
||||
for (auto& i : elements)
|
||||
|
@ -162,27 +115,35 @@ void Painting::generateBuffers(QOpenGLFunctions_4_5_Core* glFunc)
|
|||
elementData.insert(elementData.end(), encodedStyle.begin(), encodedStyle.end());
|
||||
}
|
||||
|
||||
for (auto & i : elementTransformPool)
|
||||
elementTransform.emplace_back(i.first);
|
||||
|
||||
for (auto& i : elementPool)
|
||||
{
|
||||
//qDebug() <<"element:" << i.second;
|
||||
//std::shared_ptr<ContourBuffer> contourBuffer = i.first.style->type() == MaterialStyleType::kStroke ? contourPool[i.first.contour].second : contourPool[i.first.contour].first;
|
||||
auto& contourBuffer = contourPool[{i.first.contour, i.first.style->type()}];
|
||||
elementOffsets.push_back({ contourBuffer.bvhOffset, stylePool[i.first.style], contourBuffer.pointsOffset, contourBuffer.linesOffset, glm::floatBitsToUint(i.first.ratio) });
|
||||
elementOffsets.push_back({ contourBuffer.bvhOffset, stylePool[i.first.style], contourBuffer.pointsOffset, contourBuffer.linesOffset });
|
||||
//std::cout << std::format("{} {} {} {}\n", contourBuffer->bvhOffset, stylePool[i.first->style], contourBuffer->pointsOffset, contourBuffer->linesOffset);
|
||||
}
|
||||
|
||||
glFunc->glCreateBuffers(5, buffers.data());
|
||||
glFunc->glCreateBuffers(7, buffers.data());
|
||||
GLuint& bvhSSBO = buffers[0];
|
||||
GLuint& bvhBoundSSBO = buffers[1];
|
||||
GLuint& elementOffsetSSBO = buffers[2];
|
||||
GLuint& elementIndexSSBO = buffers[3];
|
||||
GLuint& elementDataSSBO = buffers[4];
|
||||
GLuint& elementTransformSSBO = buffers[2];
|
||||
GLuint& elementOffsetSSBO = buffers[3];
|
||||
GLuint& elementIndexSSBO = buffers[4];
|
||||
GLuint& elementDataSSBO = buffers[5];
|
||||
GLuint& backgroundColorUBO = buffers[6];
|
||||
|
||||
glFunc->glNamedBufferData(buffers[0], bvhChildren.size() * sizeof(bvhChildren[0]), bvhChildren.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[1], bvhBounds.size() * sizeof(bvhBounds[0]), bvhBounds.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[2], elementOffsets.size() * sizeof(elementOffsets[0]), elementOffsets.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[3], elementIndex.size() * sizeof(elementIndex[0]), elementIndex.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[4], elementData.size() * sizeof(elementData[0]), elementData.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[2], elementTransform.size() * sizeof(elementTransform[0]), elementTransform.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[3], elementOffsets.size() * sizeof(elementOffsets[0]), elementOffsets.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[4], elementIndex.size() * sizeof(elementIndex[0]), elementIndex.data(), GL_STATIC_READ);
|
||||
glFunc->glNamedBufferData(buffers[5], elementData.size() * sizeof(elementData[0]), elementData.data(), GL_STATIC_READ);
|
||||
glm::vec3 color(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF());
|
||||
glFunc->glNamedBufferData(buffers[6], sizeof(glm::vec3), &color, GL_STATIC_READ);
|
||||
}
|
||||
|
||||
GLuint Renderer::Painting::getElementCount()
|
||||
|
@ -220,3 +181,17 @@ bool Renderer::Painting::CompareMaterialStyle::operator()(const std::shared_ptr<
|
|||
else
|
||||
return left < right;
|
||||
}
|
||||
|
||||
std::size_t Renderer::Painting::HashMat3x2::operator()(const glm::mat3x2& mat) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
constexpr long long P = 998244353;
|
||||
long long base = 1;
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
result += base * mat[i][j];
|
||||
base *= P;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -15,24 +15,13 @@ namespace Renderer
|
|||
{
|
||||
std::shared_ptr<Contour> contour;
|
||||
std::shared_ptr<MaterialStyle> style;
|
||||
float ratio; /// ¿í¸ß±È
|
||||
bool operator<(const BaseElement& e) const;
|
||||
};
|
||||
|
||||
struct BaseTransform
|
||||
{
|
||||
glm::vec4 bound;
|
||||
float rotation;
|
||||
glm::bvec2 flip;
|
||||
GLuint zIndex;
|
||||
BaseTransform(ElementTransform t);
|
||||
};
|
||||
|
||||
struct ElementWithTransform
|
||||
{
|
||||
BaseElement element;
|
||||
ElementTransform transform;
|
||||
//BaseTransform transform;
|
||||
};
|
||||
|
||||
struct ContourBuffer
|
||||
|
@ -52,7 +41,6 @@ namespace Renderer
|
|||
GLuint styleOffset;
|
||||
GLuint pointsOffset;
|
||||
GLuint linesOffset;
|
||||
GLuint ratio;
|
||||
};
|
||||
|
||||
class Painting
|
||||
|
@ -60,15 +48,16 @@ namespace Renderer
|
|||
public:
|
||||
std::vector<GLuint> bvhChildren;
|
||||
std::vector<QVector4D> bvhBounds;
|
||||
std::vector<glm::mat3x2> elementTransform;
|
||||
std::vector<ElementOffset> elementOffsets;
|
||||
std::vector<GLuint> elementIndex;
|
||||
std::vector<GLfloat> elementData;
|
||||
int paintingId = 0;
|
||||
std::array<GLuint, 5> buffers;
|
||||
std::array<GLuint, 7> buffers;
|
||||
QColor backgroundColor;
|
||||
|
||||
Painting();
|
||||
void addElement(const Element& element, const ElementTransform& transform);
|
||||
void addElement(std::shared_ptr<Element> element, QVector4D bound, float rotation, int zIndex);
|
||||
Painting(QColor backgroundColor = Qt::white);
|
||||
void addElement(const BaseElement& element, const ElementTransform& transform);
|
||||
void generateBuffers(QOpenGLFunctions_4_5_Core* glFunc);
|
||||
GLuint getElementCount();
|
||||
private:
|
||||
|
@ -76,14 +65,15 @@ namespace Renderer
|
|||
std::unordered_map<std::tuple<std::shared_ptr<Contour>, MaterialStyleType>, ContourBuffer, ContourHash> contourPool;
|
||||
struct CompareMaterialStyle { bool operator()(const std::shared_ptr<MaterialStyle>&, const std::shared_ptr<MaterialStyle>&) const; };
|
||||
std::set<std::shared_ptr<MaterialStyle>, CompareMaterialStyle> styleSet;
|
||||
std::unordered_map<std::shared_ptr<ElementStyle>, std::vector<BaseStyle>> elementStyleMap;
|
||||
std::unordered_map<std::shared_ptr<MaterialStyle>, GLuint> stylePool;
|
||||
struct HashMat3x2 { std::size_t operator()(const glm::mat3x2&) const; };
|
||||
std::unordered_map<glm::mat3x2, GLuint, HashMat3x2> elementTransformPool;
|
||||
std::map<BaseElement, GLuint> elementPool;
|
||||
std::vector<ElementWithTransform> elements;
|
||||
|
||||
void addElement(ElementWithTransform element);
|
||||
void insertContourBuffer(ContourBuffer& buffer);
|
||||
BvhTreeData encodeElementLeaf(ElementWithTransform e);
|
||||
BvhTreeData encodeElementLeaf(const ElementWithTransform& e);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <QOpenGLFunctions_4_5_Core>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <vector>
|
||||
#include <QVector2D>
|
||||
#include <QVector3D>
|
||||
#include <QOpenGLShaderProgram>
|
||||
|
@ -18,8 +18,8 @@ namespace Renderer
|
|||
class PaintingMesh : public Drawable
|
||||
{
|
||||
public:
|
||||
QVector<Vertex> vertices;
|
||||
QVector<GLuint> indices;
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<GLuint> indices;
|
||||
GLuint textureBasecolor;
|
||||
GLuint textureMetallicRoughness;
|
||||
QMatrix4x4 model;
|
||||
|
|
|
@ -10,24 +10,9 @@
|
|||
#include "../Painting/Element.h"
|
||||
#include "../Painting/Painting.h"
|
||||
#include "../Painting/MaterialStyleStroke.h"
|
||||
#include <util/PainterPathUtil.h>
|
||||
using namespace Renderer;
|
||||
|
||||
Renderer::ElementRenderer::ElementRenderer(QOpenGLWidget* glWidget)
|
||||
: glWidget(glWidget)
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::ElementRenderer::initialize()
|
||||
{
|
||||
initializeOpenGLFunctions();
|
||||
shader = std::make_unique<QOpenGLShaderProgram>();
|
||||
if (!shader->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/element.comp"))
|
||||
qDebug() << "ERROR: " << shader->log();
|
||||
if (!shader->link())
|
||||
qDebug() << "ERROR: " << shader->log();
|
||||
|
||||
}
|
||||
|
||||
std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
|
||||
{
|
||||
std::vector<glm::vec2> pathBuffer;
|
||||
|
@ -91,8 +76,10 @@ std::vector<GLfloat> generateStyleBuffer(const std::vector<BaseStyle>& styles)
|
|||
styleBuffer.push_back(style.transform->scale.y);
|
||||
styleBuffer.push_back(style.transform->rotation);
|
||||
styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip)));
|
||||
|
||||
auto encoded = style.material->encoded();
|
||||
styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end());
|
||||
//qDebug() << "style size" << styleBuffer.size();
|
||||
}
|
||||
return styleBuffer;
|
||||
}
|
||||
|
@ -101,13 +88,23 @@ QRectF calcBoundingRect(const QPainterPath& path, const std::vector<BaseStyle>&
|
|||
{
|
||||
QRectF bound = path.boundingRect();
|
||||
|
||||
ElementTransform originTransform{ glm::vec2(bound.center().x(), bound.center().y()), glm::vec2(bound.width(), bound.height()), 0, glm::bvec2(false), 0 };
|
||||
//ElementTransform originTransform{ glm::vec2(bound.center().x(), bound.center().y()), glm::vec2(bound.width(), bound.height()), 0, glm::bvec2(false), 0 };
|
||||
|
||||
glm::vec2 leftTop(std::numeric_limits<float>::max()), rightBottom(std::numeric_limits<float>::min());
|
||||
|
||||
for (auto& baseStyle : styles)
|
||||
{
|
||||
BaseTransform transform(originTransform.appliedTransformStyle(*baseStyle.transform));
|
||||
struct BaseTransform
|
||||
{
|
||||
glm::vec4 bound;
|
||||
float rotation = 0;
|
||||
glm::bvec2 flip = glm::bvec2(false);
|
||||
GLuint zIndex = 0;
|
||||
};
|
||||
//BaseTransform transform(originTransform.appliedTransformStyle(*baseStyle.transform));
|
||||
glm::vec2 center(bound.center().x(), bound.center().y());
|
||||
glm::vec2 scale(bound.width(), bound.height());
|
||||
BaseTransform transform{ glm::vec4(center - scale, center + scale) };
|
||||
if (baseStyle.material->type() == MaterialStyleType::kStroke)
|
||||
{
|
||||
float halfWidth = std::static_pointer_cast<MaterialStyleStroke>(baseStyle.material)->getHalfWidth();
|
||||
|
@ -130,27 +127,51 @@ QRectF calcBoundingRect(const QPainterPath& path, const std::vector<BaseStyle>&
|
|||
return QRectF(QPointF(leftTop.x, leftTop.y), QPointF(rightBottom.x, rightBottom.y));
|
||||
}
|
||||
|
||||
std::pair<QImage, QPointF> Renderer::ElementRenderer::drawElement(const QPainterPath& path, const ElementStyle& style, float pixelRatio, bool releaseContext)
|
||||
Renderer::ElementRenderer::ElementRenderer()
|
||||
{
|
||||
auto baseStyles = style.toBaseStyles();
|
||||
QRectF bound = calcBoundingRect(path, baseStyles);
|
||||
surface.create();
|
||||
thread = std::jthread([&](std::stop_token stop) {
|
||||
std::stop_callback cb(stop, [&] {
|
||||
draw.notify_all();
|
||||
});
|
||||
|
||||
QOpenGLContext context;
|
||||
context.create();
|
||||
context.makeCurrent(&surface);
|
||||
|
||||
auto gl = context.versionFunctions<QOpenGLFunctions_4_5_Core>();
|
||||
shader = std::make_unique<QOpenGLShaderProgram>();
|
||||
if (!shader->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/element.comp"))
|
||||
qDebug() << "ERROR: " << shader->log();
|
||||
if (!shader->link())
|
||||
qDebug() << "ERROR: " << shader->log();
|
||||
|
||||
initialized = true;
|
||||
|
||||
while (!stop.stop_requested())
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(drawMutex);
|
||||
draw.wait(lock, [&] {return needDraw || stop.stop_requested(); });
|
||||
if (needDraw)
|
||||
{
|
||||
needDraw = false;
|
||||
auto baseStyles = style->toBaseStyles();
|
||||
QRectF bound = calcBoundingRect(*path, baseStyles);
|
||||
QPointF leftTop = bound.topLeft();
|
||||
QSize size(ceil(bound.width() * pixelRatio), ceil(bound.height() * pixelRatio));
|
||||
|
||||
auto pathBuffer = generatePathBuffer(path);
|
||||
auto pathBuffer = generatePathBuffer(*path);
|
||||
auto styleBuffer = generateStyleBuffer(baseStyles);
|
||||
|
||||
if (releaseContext) glWidget->makeCurrent();
|
||||
|
||||
GLuint ssbo[2];
|
||||
glCreateBuffers(2, ssbo);
|
||||
glNamedBufferData(ssbo[0], pathBuffer.size() * sizeof(glm::vec2), pathBuffer.data(), GL_STATIC_READ);
|
||||
glNamedBufferData(ssbo[1], styleBuffer.size() * sizeof(GLfloat), styleBuffer.data(), GL_STATIC_READ);
|
||||
gl->glCreateBuffers(2, ssbo);
|
||||
gl->glNamedBufferData(ssbo[0], pathBuffer.size() * sizeof(glm::vec2), pathBuffer.data(), GL_STATIC_READ);
|
||||
gl->glNamedBufferData(ssbo[1], styleBuffer.size() * sizeof(GLfloat), styleBuffer.data(), GL_STATIC_READ);
|
||||
|
||||
auto fbo = QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::NoAttachment, GL_TEXTURE_2D);
|
||||
fbo.bind();
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
gl->glClearColor(0, 0, 0, 0);
|
||||
gl->glClear(GL_COLOR_BUFFER_BIT);
|
||||
fbo.release();
|
||||
|
||||
shader->bind();
|
||||
|
@ -158,14 +179,43 @@ std::pair<QImage, QPointF> Renderer::ElementRenderer::drawElement(const QPainter
|
|||
shader->setUniformValue("styleSize", (GLint)styleBuffer.size());
|
||||
shader->setUniformValue("leftTop", leftTop);
|
||||
shader->setUniformValue("pixelRatio", pixelRatio);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 10, ssbo[0]);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 11, ssbo[1]);
|
||||
glBindImageTexture(0, fbo.texture(), 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
|
||||
glDispatchCompute(ceil(size.width() / 8.), ceil(size.height() / 8.), 1);
|
||||
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 10, ssbo[0]);
|
||||
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 11, ssbo[1]);
|
||||
gl->glBindImageTexture(0, fbo.texture(), 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
|
||||
gl->glDispatchCompute(ceil(size.width() / 8.), ceil(size.height() / 8.), 1);
|
||||
shader->release();
|
||||
|
||||
auto image = fbo.toImage(false);
|
||||
glDeleteBuffers(2, ssbo);
|
||||
if (releaseContext) glWidget->doneCurrent();
|
||||
return { image, leftTop };
|
||||
gl->glDeleteBuffers(2, ssbo);
|
||||
result = { image, leftTop };
|
||||
drawFinished = true;
|
||||
}
|
||||
draw.notify_all();
|
||||
}
|
||||
context.doneCurrent();
|
||||
});
|
||||
|
||||
while (!initialized)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
ElementRenderer* Renderer::ElementRenderer::instance()
|
||||
{
|
||||
static ElementRenderer renderer;
|
||||
return &renderer;
|
||||
}
|
||||
|
||||
std::pair<QImage, QPointF> Renderer::ElementRenderer::drawElement(const QPainterPath& path, const ElementStyle& style, float pixelRatio)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(drawMutex);
|
||||
draw.wait(lock, [&] {return drawFinished; });
|
||||
drawFinished = false;
|
||||
QPainterPath monotonized = PainterPathUtil::monotonization(path);
|
||||
this->path = &monotonized;
|
||||
this->style = &style;
|
||||
this->pixelRatio = pixelRatio;
|
||||
needDraw = true;
|
||||
draw.notify_all();
|
||||
draw.wait(lock, [&] {return drawFinished; });
|
||||
return result;
|
||||
}
|
|
@ -3,32 +3,40 @@
|
|||
#include <QOpenGLFunctions_4_5_Core>
|
||||
#include <QOPenGLShaderProgram>
|
||||
#include "../Painting/ElementStyle.h"
|
||||
#include <QOffscreenSurface>
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
class ElementRenderer : protected QOpenGLFunctions_4_5_Core
|
||||
class ElementRenderer
|
||||
{
|
||||
public:
|
||||
ElementRenderer(QOpenGLWidget* glWidget);
|
||||
|
||||
/**
|
||||
* @brief 须在initializeGL函数中调用
|
||||
*/
|
||||
void initialize();
|
||||
static ElementRenderer* instance();
|
||||
|
||||
/**
|
||||
* @brief 将图元绘制到QImage
|
||||
* @param path 图元几何数据
|
||||
* @param style 图元样式
|
||||
* @param pixelRatio path中的单位坐标对应的像素大小
|
||||
* @param releaseContext 若在initializeGL, resizeGL或paintGL中调用须传入false
|
||||
* @return QImage 绘制得到的位图
|
||||
* @return QPointF 位图原点(左上角)在QPainterPath坐标系下的坐标
|
||||
*/
|
||||
std::pair<QImage, QPointF> drawElement(const QPainterPath& path, const ElementStyle& style, float pixelRatio, bool releaseContext = true);
|
||||
std::pair<QImage, QPointF> drawElement(const QPainterPath& path, const ElementStyle& style, float pixelRatio);
|
||||
protected:
|
||||
QOpenGLWidget* glWidget;
|
||||
std::unique_ptr<QOpenGLShaderProgram> shader;
|
||||
std::jthread thread;
|
||||
QOffscreenSurface surface;
|
||||
QOpenGLContext context;
|
||||
std::atomic<bool> initialized = false;
|
||||
bool drawFinished = true;
|
||||
bool needDraw = false;
|
||||
std::condition_variable draw;
|
||||
std::mutex drawMutex;
|
||||
const QPainterPath* path;
|
||||
const ElementStyle* style;
|
||||
float pixelRatio;
|
||||
std::pair<QImage, QPointF> result;
|
||||
|
||||
ElementRenderer();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -73,17 +73,14 @@ void RendererGLWidget::stopTimer()
|
|||
timerId = -1;
|
||||
}
|
||||
|
||||
void RendererGLWidget::setModel()
|
||||
void RendererGLWidget::setModel(QString path)
|
||||
{
|
||||
makeCurrent();
|
||||
model->loadModel("Models/Sponza/Sponza.gltf");
|
||||
//model = new Model("E:\\3D Objects\\gallery_gltf\\gallery_gltf.gltf", context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper);
|
||||
//model->loadModel("Models/Sponza/Sponza.gltf");
|
||||
//model->loadModel("E:\\3D Objects\\Gate\\gltf\\Gate.gltf");
|
||||
model->loadModel(path);
|
||||
light.model = model;
|
||||
qDebug() << model->AABB;
|
||||
//paintingHelper->allocateBuffers();
|
||||
//paintingCompProgramPtr->bind();
|
||||
//paintingHelper->bindPaintingBuffers();
|
||||
//paintingCompProgramPtr->release();
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Renderer
|
|||
void startTimer();
|
||||
void stopTimer();
|
||||
public slots:
|
||||
void setModel();
|
||||
void setModel(QString path);
|
||||
void setMainLightPitch(float pitch);
|
||||
void setMainLightYaw(float yaw);
|
||||
void setExposure(float exposure);
|
||||
|
|
|
@ -1,12 +1,37 @@
|
|||
#include "RendererWidget.h"
|
||||
#include "RendererGLWidget.h"
|
||||
#include "../FluentMenu.h"
|
||||
#include <QFileDialog>
|
||||
|
||||
Renderer::RendererWidget::RendererWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
FluentMenu* menu = new FluentMenu(this);
|
||||
auto openAction = new QAction(QStringLiteral("´ò¿ª"), menu);
|
||||
auto saveAction = new QAction(QStringLiteral("±£´æ"), menu);
|
||||
auto testAction = new QAction(QStringLiteral("²âÊÔ"), menu);
|
||||
auto test2Action = new QAction(QStringLiteral("²âÊÔ2"), menu);
|
||||
menu->addAction(openAction);
|
||||
menu->addAction(saveAction);
|
||||
menu->addAction(testAction);
|
||||
menu->addAction(test2Action);
|
||||
|
||||
ui.openButton->setHaloVisible(false);
|
||||
ui.openButton->setOverlayStyle(::Material::TintedOverlay);
|
||||
ui.openButton->setCheckable(true);
|
||||
|
||||
QObject::connect(menu, &QMenu::aboutToShow, [&]() {
|
||||
ui.openButton->setChecked(true);
|
||||
});
|
||||
QObject::connect(menu, &QMenu::aboutToHide, [&]() {
|
||||
ui.openButton->setChecked(false);
|
||||
});
|
||||
QObject::connect(ui.openButton, &QPushButton::clicked, [&, menu]() {
|
||||
menu->exec(ui.openButton->mapToGlobal(QPoint(0, ui.openButton->height())));
|
||||
});
|
||||
|
||||
QObject::connect(ui.horizontalSlider, &QSlider::valueChanged,
|
||||
ui.openGLWidget, &Renderer::RendererGLWidget::setMainLightPitch);
|
||||
QObject::connect(ui.horizontalSlider_2, &QSlider::valueChanged,
|
||||
|
@ -15,11 +40,21 @@ Renderer::RendererWidget::RendererWidget(QWidget *parent)
|
|||
ui.openGLWidget->setExposure(value / 100.f);
|
||||
});
|
||||
|
||||
QObject::connect(openAction, &QAction::triggered, [&] {
|
||||
QString fileName = QFileDialog::getOpenFileName(this, QStringLiteral("´ò¿ªÄ£ÐÍ"), QString(), QStringLiteral("glTF 2.0 (*.gltf)"));
|
||||
qDebug() << fileName;
|
||||
if (fileName != QString())
|
||||
ui.openGLWidget->setModel(fileName);
|
||||
});
|
||||
QObject::connect(testAction, &QAction::triggered, [&] {
|
||||
ui.openGLWidget->setModel("Models/Sponza/Sponza.gltf");
|
||||
});
|
||||
QObject::connect(test2Action, &QAction::triggered, [&] {
|
||||
ui.openGLWidget->setModel("E:\\3D Objects\\Gate\\Gate.gltf");
|
||||
});
|
||||
ui.horizontalSlider->setValue(105);
|
||||
ui.horizontalSlider_2->setValue(80);
|
||||
ui.exposureSlider->setValue(60);
|
||||
QObject::connect(ui.openButton, &QPushButton::clicked,
|
||||
ui.openGLWidget, &Renderer::RendererGLWidget::setModel);
|
||||
}
|
||||
|
||||
Renderer::RendererWidget::~RendererWidget()
|
||||
|
@ -36,3 +71,4 @@ void Renderer::RendererWidget::currentTabChanged(int index)
|
|||
ui.openGLWidget->stopTimer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMenu>
|
||||
#include "ui_RendererWidget.h"
|
||||
namespace Renderer
|
||||
{
|
||||
class RendererWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
RendererWidget(QWidget* parent = nullptr);
|
||||
~RendererWidget();
|
||||
public slots:
|
||||
void currentTabChanged(int index);
|
||||
|
||||
private:
|
||||
Ui::RendererWidgetClass ui;
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ Renderer::VirtualTextureManager::VirtualTextureManager(GladGLContext* glMain)
|
|||
surface.create();
|
||||
mainContext->doneCurrent();
|
||||
|
||||
thread = std::jthread([&] {
|
||||
thread = std::jthread([&](std::stop_token stop) {
|
||||
QOpenGLContext context;
|
||||
context.setFormat(mainContext->format());
|
||||
context.setShareContext(mainContext);
|
||||
|
@ -67,7 +67,7 @@ Renderer::VirtualTextureManager::VirtualTextureManager(GladGLContext* glMain)
|
|||
GLuint pageLoadTimeQuery;
|
||||
gl->GenQueries(1, &pageLoadTimeQuery);
|
||||
|
||||
while (true)
|
||||
while (!stop.stop_requested())
|
||||
{
|
||||
if (needUpdate)
|
||||
{
|
||||
|
@ -85,6 +85,7 @@ Renderer::VirtualTextureManager::VirtualTextureManager(GladGLContext* glMain)
|
|||
//qDebug() << duration;
|
||||
pageLoadDuration += duration;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -123,8 +124,9 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
|
|||
glMain->TextureParameteri(metallicRoughness, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glMain->TextureStorage2D(metallicRoughness, levels, GL_RG8, GLsizei(textureSize), GLsizei(textureSize));
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
glMain->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]);
|
||||
glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[6]);
|
||||
|
||||
for (auto level = levels - 1; level < levels; ++level)
|
||||
{
|
||||
|
@ -142,7 +144,7 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
|
|||
GL_TRUE);
|
||||
|
||||
program.bind();
|
||||
glMain->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * i, static_cast<GLsizei>(pageSize) * j);
|
||||
glMain->Uniform2i(0 /*pixelOffset*/, static_cast<GLsizei>(pageSize) * i, static_cast<GLsizei>(pageSize) * j);
|
||||
glMain->BindImageTexture(0, baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
|
||||
glMain->BindImageTexture(1, metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
|
||||
glMain->DispatchCompute(pageSize / 8, pageSize / 8, 1);
|
||||
|
@ -150,10 +152,30 @@ std::uint16_t Renderer::VirtualTextureManager::createVirtualTexture(Painting pai
|
|||
|
||||
}
|
||||
}
|
||||
if (const auto it = std::find_if(paintings.begin(), paintings.end(), [](const PaintingHandle& i) { return i.baseColor == 0; });
|
||||
it != paintings.end())
|
||||
{
|
||||
*it = { baseColor, metallicRoughness, painting.buffers };
|
||||
return it - paintings.begin() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
paintings.emplace_back(baseColor, metallicRoughness, painting.buffers);
|
||||
return paintings.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Renderer::VirtualTextureManager::deleteVirtualTexture(std::uint16_t id)
|
||||
{
|
||||
auto& painting = getPaintingHandle(id);
|
||||
glMain->DeleteTextures(2, (GLuint*)&painting);
|
||||
glMain->DeleteBuffers(7, painting.buffers.data());
|
||||
painting.baseColor = 0;
|
||||
painting.metallicRoughness = 0;
|
||||
painting.buffers.fill(0);
|
||||
}
|
||||
|
||||
Renderer::PaintingHandle& Renderer::VirtualTextureManager::getPaintingHandle(std::uint16_t id)
|
||||
{
|
||||
return paintings[id - 1];
|
||||
|
@ -187,8 +209,9 @@ void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pag
|
|||
if (commit)
|
||||
{
|
||||
program.bind();
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]);
|
||||
glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[6]);
|
||||
gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y);
|
||||
gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
|
||||
gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Renderer
|
|||
{
|
||||
GLuint baseColor;
|
||||
GLuint metallicRoughness;
|
||||
std::array<GLuint, 5> buffers;
|
||||
std::array<GLuint, 7> buffers;
|
||||
};
|
||||
|
||||
class VirtualTextureManager
|
||||
|
@ -24,11 +24,12 @@ namespace Renderer
|
|||
VirtualTextureManager(GladGLContext* glMain);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param painting
|
||||
* @brief 创建彩绘虚拟纹理
|
||||
* @param painting 彩绘
|
||||
* @return ÐéÄâÎÆÀíid
|
||||
*/
|
||||
std::uint16_t createVirtualTexture(Painting painting);
|
||||
void deleteVirtualTexture(std::uint16_t id);
|
||||
PaintingHandle& getPaintingHandle(std::uint16_t id);
|
||||
void tryUpdatePages(const std::vector<glm::u16vec2>& pageIds);
|
||||
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2018-2022 Antonio Dias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "titlewidget.h"
|
||||
|
||||
TitleWidget::TitleWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
void TitleWidget::setText(const QString &text)
|
||||
{
|
||||
m_title = text;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void TitleWidget::setActive(bool active)
|
||||
{
|
||||
m_active = active;
|
||||
repaint();
|
||||
}
|
||||
|
||||
void TitleWidget::setTitleColor(const QColor &active_color, const QColor &inactive_color)
|
||||
{
|
||||
m_active_color = active_color;
|
||||
m_inactive_color = inactive_color;
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
void TitleWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHints(QPainter::Antialiasing);
|
||||
|
||||
QFont font;
|
||||
font.setPointSize(10);
|
||||
#ifdef Q_OS_WIN
|
||||
font.setFamily("Segoe UI, Microsoft YaHei UI");
|
||||
#else
|
||||
font.setFamily(qApp->font().family());
|
||||
#endif
|
||||
|
||||
painter.setFont(font);
|
||||
|
||||
QPen pen;
|
||||
pen.setColor(m_active ? m_active_color : m_inactive_color);
|
||||
|
||||
painter.setPen(pen);
|
||||
|
||||
QFontMetrics metrics(painter.font());
|
||||
QSize title_size = metrics.size(0, m_title);
|
||||
|
||||
QString title = metrics.elidedText(m_title, Qt::ElideRight, width());
|
||||
|
||||
painter.drawText(0, (height() - title_size.height()) / 2, title_size.width(), title_size.height(), 0, title);
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2018-2022 Antonio Dias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef TITLEWIDGET_H
|
||||
#define TITLEWIDGET_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
|
||||
class TitleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TitleWidget(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void setText(const QString &text);
|
||||
void setActive(bool active);
|
||||
void setTitleColor(const QColor &active_color, const QColor &inactive_color);
|
||||
|
||||
private:
|
||||
//Functions
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
//Variables
|
||||
QString m_title;
|
||||
bool m_active;
|
||||
QColor m_active_color;
|
||||
QColor m_inactive_color;
|
||||
};
|
||||
|
||||
#endif // TITLEWIDGET_H
|
|
@ -1,4 +1,5 @@
|
|||
#include "MainWindow.h"
|
||||
#include "ColorHelper.hpp"
|
||||
#include <QGuiApplication>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <FramelessHelper/Core/private/framelessconfig_p.h>
|
||||
|
@ -49,10 +50,12 @@ int main(int argc, char* argv[])
|
|||
//QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
QApplication a(argc, argv);
|
||||
Q_INIT_RESOURCE(resources);
|
||||
ColorHelper::instance();
|
||||
//FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
FramelessConfig::instance()->set(Global::Option::ForceNonNativeBackgroundBlur);
|
||||
//FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
FramelessConfig::instance()->set(Global::Option::CenterWindowBeforeShow);
|
||||
//FramelessConfig::instance()->set(Global::Option::CenterWindowBeforeShow);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue