Compare commits
47 Commits
f954a77cc5
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
769cb8fd5f | ||
|
|
359ae02e19 | ||
|
|
cdbcabd6a1 | ||
|
|
780baa6e7a | ||
|
|
eaf1ced1c3 | ||
|
|
93002270d5 | ||
|
|
3e90df9e6e | ||
|
|
687de13d6c | ||
|
|
2609d231e7 | ||
|
|
964eb02adb | ||
|
|
8992a6c33d | ||
|
|
ebfb083099 | ||
|
|
de46c11510 | ||
|
|
f37c7039e5 | ||
|
|
1defbd66ff | ||
|
|
f342a2158b | ||
|
|
1de6ee2127 | ||
|
|
f1d1749c40 | ||
|
|
c65346aeec | ||
|
|
a74ae1167e | ||
|
|
d7d2091d64 | ||
|
|
ea28738280 | ||
|
|
2faab96a7d | ||
|
|
8c5ca2ce21 | ||
|
|
d0fbd31c1d | ||
|
|
5cf8612699 | ||
|
|
dfa2cf3f31 | ||
|
|
64b7eb9dcc | ||
|
|
d652c63586 | ||
|
|
9614283dc8 | ||
|
|
b072eea732 | ||
|
|
925e4c9989 | ||
|
|
69d3b517f3 | ||
|
|
2d1368a908 | ||
|
|
3b319da80b | ||
|
|
db54b80b5a | ||
|
|
281e0f4aee | ||
|
|
366a5c1cab | ||
|
|
86c0e97672 | ||
|
|
6fd430a670 | ||
|
|
664c5e02fe | ||
|
|
1d64749e76 | ||
|
|
0ef4ad1c4a | ||
|
|
07c00117f1 | ||
|
|
1bdead0750 | ||
|
|
8173327c79 | ||
|
|
7c484a9af3 |
4012
.editorconfig
Normal file
3
.gitignore
vendored
@@ -2,4 +2,5 @@ bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
/_ReSharper.Caches/
|
||||
publish/
|
||||
5
.idea/.idea.SDFMapCreator/.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
11
.idea/.idea.SDFMapCreator/.idea/riderPublish.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="LocationsWithSilentDeleteHolder">
|
||||
<option name="locations">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/SDFMapCreator/publish/win-x64" />
|
||||
<option value="$PROJECT_DIR$/SDFMapCreator/publish/linux-x64" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
6
.run/Copy Images Psh.run.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Copy Images Psh" type="PowerShellRunType" factoryName="PowerShell" activateToolWindowBeforeRun="false" scriptUrl="I:\SDFMapCreator\SDFMapCreator\copyImages.ps1" workingDirectory="I:\SDFMapCreator\SDFMapCreator" executablePath="C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe">
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Copy Images Sh.run.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Copy Images Sh" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="false" />
|
||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/SDFMapCreator/copyImages.sh" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="/bin/bash" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
6
.run/Release Build Linux-x64.run.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Release Build Linux-x64" type="DotNetFolderPublish" factoryName="Publish to folder">
|
||||
<riderPublish configuration="Release" delete_existing_files="true" include_native_libs_for_self_extract="true" platform="Any CPU" produce_single_file="true" runtime="linux-x64" target_folder="$PROJECT_DIR$/SDFMapCreator/publish/linux-x64" target_framework="net8.0" uuid_high="-7972981449231152312" uuid_low="-5206031561210231144" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
6
.run/Release Build Win-x64.run.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Release Build Win-x64" type="DotNetFolderPublish" factoryName="Publish to folder">
|
||||
<riderPublish configuration="Release" delete_existing_files="true" include_native_libs_for_self_extract="true" platform="Any CPU" produce_single_file="true" runtime="win-x64" target_folder="$PROJECT_DIR$/SDFMapCreator/publish/win-x64" target_framework="net8.0" uuid_high="-7972981449231152312" uuid_low="-5206031561210231144" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
20
.run/Run SDF Tool [8 pic CUDA].run.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run SDF Tool [8 pic CUDA]" type="DotNetProject" factoryName=".NET Project" focusToolWindowBeforeRun="true">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/SDFMapCreator/bin/Debug/net8.0/SDFMapTool.exe" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-D ./images -o "./sdf.png" -i "01.png;02.png;03.png;04.png;05.png;06.png;07.png;08.png" --device CUDA" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/SDFMapCreator/bin/Debug/net8.0" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/SDFMapCreator/SDFMapCreator.csproj" />
|
||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value="net8.0" />
|
||||
<method v="2">
|
||||
<option name="Build" default="false" projectName="SDFMapCreator" projectPath="$PROJECT_DIR$/SDFMapCreator/SDFMapCreator.csproj" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
20
.run/Run SDF Tool [8 pic OpenCL].run.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run SDF Tool [8 pic OpenCL]" type="DotNetProject" factoryName=".NET Project" focusToolWindowBeforeRun="true">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/SDFMapCreator/bin/Debug/net8.0/SDFMapTool.exe" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-D ./images -o "./sdf.png" -i "01.png;02.png;03.png;04.png;05.png;06.png;07.png;08.png" --device OpenCL" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/SDFMapCreator/bin/Debug/net8.0" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/SDFMapCreator/SDFMapCreator.csproj" />
|
||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value="net8.0" />
|
||||
<method v="2">
|
||||
<option name="Build" default="false" projectName="SDFMapCreator" projectPath="$PROJECT_DIR$/SDFMapCreator/SDFMapCreator.csproj" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
20
.run/Run SDF Tool [Debug, 8 pic].run.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run SDF Tool [Debug, 8 pic]" type="DotNetProject" factoryName=".NET Project" focusToolWindowBeforeRun="true">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/SDFMapCreator/bin/Debug/net8.0/SDFMapTool.exe" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d -D "./images" -o "./sdf.png" -i "01.png;02.png;03.png;04.png;05.png;06.png;07.png;08.png"" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/SDFMapCreator/bin/Debug/net8.0" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/SDFMapCreator/SDFMapCreator.csproj" />
|
||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value="net8.0" />
|
||||
<method v="2">
|
||||
<option name="Build" default="false" projectName="SDFMapCreator" projectPath="$PROJECT_DIR$/SDFMapCreator/SDFMapCreator.csproj" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
41
Readme.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# SDF Tool
|
||||
|
||||
*A signed distance fields-based tool to generate shadow transition maps*
|
||||
|
||||
## Key features
|
||||
|
||||
- float16 png output for reduced banding
|
||||
- Automatic CUDA/OpenCL GPU Acceleration for most of the process
|
||||
- *nix style command line interface
|
||||
|
||||
## How to use
|
||||
|
||||
From command line: `SDFMapTool -D <directory_with_images> -i "<image1.png;image2.png;...>" -o <output_file_path.png> ...`
|
||||
|
||||
Available options:
|
||||
|
||||
```terminal
|
||||
|
||||
-d, --debug Enable debug mode.
|
||||
|
||||
-D, --imgDirectory Required. Input Images directory.
|
||||
|
||||
-i, --images Required. Images file names separated by ';' and in the correct order.
|
||||
|
||||
-o, --output Required. Output file path.
|
||||
|
||||
-b, --blur How many blur iterations to run.
|
||||
|
||||
-r, --radius Blur radius.
|
||||
|
||||
-s, --step Blur step size.
|
||||
|
||||
--sigma Blur sigma value (weighting).
|
||||
|
||||
--device Device to use for computation. (CPU, OpenCL, CUDA)
|
||||
|
||||
--help Display this help screen.
|
||||
|
||||
--version Display version information.
|
||||
|
||||
```
|
||||
@@ -12,5 +12,6 @@ Global
|
||||
{915A479D-55CC-4B48-B7C0-75E0B8978698}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{915A479D-55CC-4B48-B7C0-75E0B8978698}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{915A479D-55CC-4B48-B7C0-75E0B8978698}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{915A479D-55CC-4B48-B7C0-75E0B8978698}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
19
SDFMapCreator.sln.DotSettings
Normal file
@@ -0,0 +1,19 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseVar</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_LOCK/@EntryValue">NotRequired</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_REDUNDANT/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_PRIVATE_MODIFIER/@EntryValue">Implicit</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/METHOD_OR_OPERATOR_BODY/@EntryValue">ExpressionBody</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/MODIFIERS_ORDER/@EntryValue">public private protected internal file new static abstract virtual override readonly sealed extern unsafe volatile async required</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_EXPR_METHOD_ON_SINGLE_LINE/@EntryValue">IF_OWNER_IS_SINGLE_LINE</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALLOW_COMMENT_AFTER_LBRACE/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_INVOCABLE/@EntryValue">1</s:Int64>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_FOR_STMT/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_ARROW_WITH_EXPRESSIONS/@EntryValue">True</s:Boolean>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">151</s:Int64>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_OBJECT_AND_COLLECTION_INITIALIZER_STYLE/@EntryValue">WRAP_IF_LONG</s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -1,8 +1,18 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAccelerator_002EAllocations_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fa3e5a0b5353a4a59d3be7bb386db3c46069739eacca1fc6b7323dca1ee7fd_003FAccelerator_002EAllocations_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACPUMultiprocessor_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fmm00_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F5d1e647f49ea4d7aa141f19476dc7451ae33d6321d7fb675b45f9b836878ca1a_003FCPUMultiprocessor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADanywyf_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Ftmp_003FJetBrainsPerUserTemp_002D1000_002D1_003FSandboxFiles_003FLiqequv_003FDanywyf_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEntryPointDescription_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F32b5380d8ca1aa7219c1622702a3e927b2bb32c9a53b43e12bb5a4af9a2862d_003FEntryPointDescription_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AImage_007BTPixel_007D_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F98f0ece83ba33754ab932bd7b5c712d12f3a59029f9f14067f553a3a318c8f_003FImage_007BTPixel_007D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALogger_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F70a76ec6534f41dfb670b3e0b4505f5f2600_003F8a_003F2e6ec04f_003FLogger_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMonitor_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fmm00_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F8056cd3f452fefb9834f05cdb275b762dd41f27b7766cd71174e78592dc495b_003FMonitor_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APixelTypeInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc3cfdca1fb93eb6df5e51a81da5df646adfab8b862fd1a07ee5d247b49c5179_003FPixelTypeInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASafeFileHandle_002EUnix_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fmm00_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F9cf5f68d759deefc91b9c48c5ac3dd27708bb7dc38d0c485661fff5ce15b82_003FSafeFileHandle_002EUnix_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASafeFileHandle_002EWindows_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F261ea83c988816e3d8fe76b15b7ac6c10af64b8f9e739854f83c137c8ba9_003FSafeFileHandle_002EWindows_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F2c8e7ca976f350cba9836d5565dac56b11e0b56656fa786460eb1395857a6fa_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AVector3_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fmm00_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F6edafe13d8727aa238b865f5dc91dbc984b5abfbc60bece3744f6311c2c_003FVector3_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:Int64 x:Key="/Default/Dpa/Thresholds/=AllocationLoh/@EntryIndexedValue">52428800</s:Int64>
|
||||
<s:Int64 x:Key="/Default/Dpa/Thresholds/=AllocationTopSoh/@EntryIndexedValue">26214400</s:Int64>
|
||||
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue"><AssemblyExplorer>
|
||||
<Assembly Path="/mnt/nvme2/Railgun/SDFMapCreator/SDFMapCreator/bin/Debug/net8.0/Magick.NET-Q16-HDRI-OpenMP-x64.dll" />
|
||||
</AssemblyExplorer></s:String></wpf:ResourceDictionary>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
@@ -1,16 +1,31 @@
|
||||
/*
|
||||
Copyright 2025 Railgun Entertainment AS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Numerics;
|
||||
using LineWalker;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace SDFMapCreator;
|
||||
|
||||
public static class ImageUtil {
|
||||
static Logger logger = Logger.GetInstance();
|
||||
|
||||
public static T[,] LoadImage<T>(string path) where T : struct, IEquatable<T> {
|
||||
var image = SixLabors.ImageSharp.Image.Load(path);
|
||||
using var image16 = image as Image<Rgba64> ?? throw new NotSupportedException($"Image format not supported");
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
//result = new T[image.Width, image.Height];
|
||||
return image switch {
|
||||
Image<Rgba64> img => img.ProcessPixelsRgba64<T>(),
|
||||
Image<Rgb24> img => img.ProcessPixelsRgb24<T>(),
|
||||
@@ -21,26 +36,27 @@ public static class ImageUtil {
|
||||
}
|
||||
|
||||
static T[,] ProcessPixelsRgba64<T>(this Image<Rgba64> image) where T : struct, IEquatable<T> {
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var max = 65535f;
|
||||
var width = image.Width;
|
||||
var height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
image.ProcessPixelRows(accessor => {
|
||||
//we use Y as the row index and X as the column index
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (var y = 0; y < height; y++) {
|
||||
var span = accessor.GetRowSpan(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
switch (result) {
|
||||
case float[,] f:
|
||||
f[x, y] = span[x].R;
|
||||
f[x, y] = span[x].R / max * (span[x].A / max);
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new Vector2(span[x].R / max, span[x].G / max) * new Vector2(span[x].A / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -50,26 +66,27 @@ public static class ImageUtil {
|
||||
}
|
||||
|
||||
static T[,] ProcessPixelsRgb24<T>(this Image<Rgb24> image) where T : struct, IEquatable<T> {
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var max = 255f;
|
||||
var width = image.Width;
|
||||
var height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
image.ProcessPixelRows(accessor => {
|
||||
//we use Y as the row index and X as the column index
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (var y = 0; y < height; y++) {
|
||||
var span = accessor.GetRowSpan(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
switch (result) {
|
||||
case float[,] f:
|
||||
f[x, y] = span[x].R;
|
||||
f[x, y] = span[x].R / max;
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, 1f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -77,28 +94,29 @@ public static class ImageUtil {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static T[,] ProcessPixelsRgba32<T>(this Image<Rgba32> image) where T : struct, IEquatable<T> {
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var max = 255f;
|
||||
var width = image.Width;
|
||||
var height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
image.ProcessPixelRows(accessor => {
|
||||
//we use Y as the row index and X as the column index
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (var y = 0; y < height; y++) {
|
||||
var span = accessor.GetRowSpan(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
switch (result) {
|
||||
case float[,] f:
|
||||
f[x, y] = span[x].R;
|
||||
f[x, y] = span[x].R / max * (span[x].A / max);
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new Vector2(span[x].R / max, span[x].G / max) * new Vector2(span[x].A / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -106,29 +124,29 @@ public static class ImageUtil {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static T[,] ProcessPixelsRgb48<T>(this Image<Rgb48> image) where T : struct, IEquatable<T> {
|
||||
using var image16 = image as Image<Rgb48> ?? throw new NotSupportedException($"Image format not supported");
|
||||
int width = image.Width;
|
||||
int height = image.Height;
|
||||
var max = 65535f;
|
||||
var width = image.Width;
|
||||
var height = image.Height;
|
||||
var result = new T[image.Width, image.Height];
|
||||
image16.ProcessPixelRows(accessor => {
|
||||
image.ProcessPixelRows(accessor => {
|
||||
//we use Y as the row index and X as the column index
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (var y = 0; y < height; y++) {
|
||||
var span = accessor.GetRowSpan(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
switch (result) {
|
||||
case float[,] f:
|
||||
f[x, y] = span[x].R;
|
||||
f[x, y] = span[x].R / max;
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max);
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
||||
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, 1f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -136,7 +154,7 @@ public static class ImageUtil {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static void SaveImage<T>(this T[,] array, string path) where T : struct, IEquatable<T> {
|
||||
var width = array.GetLength(0);
|
||||
var height = array.GetLength(1);
|
||||
@@ -147,39 +165,39 @@ public static class ImageUtil {
|
||||
Vector4[,] => 4,
|
||||
_ => throw new NotSupportedException($"Type {typeof(T)} is not supported.")
|
||||
};
|
||||
Console.Write($"Writing image {path}...");
|
||||
logger.Log($"Writing image {path}...");
|
||||
using Image<Rgb48> image = new(width, height);
|
||||
image.ProcessPixelRows(accessor => {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (var y = 0; y < height; y++) {
|
||||
var span = accessor.GetRowSpan(y);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
switch (array) {
|
||||
case float[,] f:
|
||||
span[x] = new Rgb48((ushort)f[x, y], (ushort)f[x, y], (ushort)f[x,y]);
|
||||
span[x] = new((ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535));
|
||||
break;
|
||||
case Vector2[,] f:
|
||||
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, 0);
|
||||
span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), 0);
|
||||
break;
|
||||
case Vector3[,] f:
|
||||
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
|
||||
span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), (ushort)(f[x, y].Z * 65535));
|
||||
break;
|
||||
case Vector4[,] f:
|
||||
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
|
||||
span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), (ushort)(f[x, y].Z * 65535));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Console.WriteLine($"Done!");
|
||||
logger.Log($"Writing image {path}...Done", true);
|
||||
image.Save(path);
|
||||
}
|
||||
|
||||
private static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
|
||||
Console.WriteLine(
|
||||
|
||||
static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
|
||||
logger.Log(
|
||||
$"""
|
||||
Image file: {path}
|
||||
Resolution: {image1.Width}x{image1.Height}
|
||||
Total Pixels: {image1.Width*image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel/4} bits per channel
|
||||
Total Pixels: {image1.Width * image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel / 4} bits per channel
|
||||
|
||||
""");
|
||||
}
|
||||
|
||||
81
SDFMapCreator/OpenSourceLicenses.txt
Normal file
@@ -0,0 +1,81 @@
|
||||
********************************************************************************
|
||||
ILGPU License
|
||||
********************************************************************************
|
||||
University of Illinois/NCSA Open Source License
|
||||
Copyright (c) 2016-2025 ILGPU Project
|
||||
All rights reserved.
|
||||
|
||||
Developed by: Marcel Koester (m4rs@m4rs.net)
|
||||
www.ilgpu.net
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of ILGPU, Marcel Koester, nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
Software without specific prior written permission.
|
||||
|
||||
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 CONTRIBUTORS
|
||||
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 WITH THE SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Six Labors Split License
|
||||
Version 1.0, June 2022
|
||||
Copyright (c) Six Labors
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source
|
||||
code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including
|
||||
but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" (or "Works") shall mean any Six Labors software made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work.
|
||||
|
||||
"Direct Package Dependency" shall mean any Work in Source or Object form that is installed directly by You.
|
||||
|
||||
"Transitive Package Dependency" shall mean any Work in Object form that is installed indirectly by a third party
|
||||
dependency unrelated to Six Labors.
|
||||
|
||||
2. License
|
||||
|
||||
Works in Source or Object form are split licensed and may be licensed under the Apache License, Version 2.0 or a
|
||||
Six Labors Commercial Use License.
|
||||
|
||||
Licenses are granted based upon You meeting the qualified criteria as stated. Once granted,
|
||||
You must reference the granted license only in all documentation.
|
||||
|
||||
Works in Source or Object form are licensed to You under the Apache License, Version 2.0 if.
|
||||
|
||||
- You are consuming the Work in for use in software licensed under an Open Source or Source Available license.
|
||||
- You are consuming the Work as a Transitive Package Dependency.
|
||||
- You are consuming the Work as a Direct Package Dependency in the capacity of a For-profit company/individual with
|
||||
less than 1M USD annual gross revenue.
|
||||
- You are consuming the Work as a Direct Package Dependency in the capacity of a Non-profit organization
|
||||
or Registered Charity.
|
||||
|
||||
For all other scenarios, Works in Source or Object form are licensed to You under the Six Labors Commercial License
|
||||
which may be purchased by visiting https://sixlabors.com/pricing/.
|
||||
|
||||
@@ -1,267 +1,285 @@
|
||||
using System.Diagnostics;
|
||||
/*
|
||||
Copyright 2025 Railgun Entertainment AS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using SDFMapCreator;
|
||||
using CommandLine;
|
||||
using LineWalker;
|
||||
|
||||
public class Program {
|
||||
private const float MAX = 65535f;
|
||||
private const float MIN = 0f;
|
||||
private static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
|
||||
private const bool outputMasks = true;
|
||||
private const bool outputSDFs = true;
|
||||
private const bool outputGradients = true;
|
||||
namespace SDFMapCreator;
|
||||
|
||||
public enum DeviceType {
|
||||
CPU,
|
||||
OpenCL,
|
||||
CUDA
|
||||
}
|
||||
|
||||
public class Options {
|
||||
[Option('d', "debug", Required = false, HelpText = "Enable debug mode.")]
|
||||
public bool Debug { get; set; } = false;
|
||||
[Option('D', "imgDirectory", Required = true, HelpText = "Input Images directory.")]
|
||||
public string ImgDirectory { get; set; } = "images";
|
||||
[Option('i', "images", Required = true, HelpText = "Images file names separated by ';' and in the correct order.")]
|
||||
public string Images { get; set; } = "";
|
||||
[Option('o', "output", Required = true, HelpText = "Output file path.")]
|
||||
public string OutputFile { get; set; } = "output.png";
|
||||
[Option('b', "blur", Required = false, HelpText = "How many blur iterations to run.")]
|
||||
public int BlurIterations { get; set; } = 10;
|
||||
[Option('r', "radius", Required = false, HelpText = "Blur radius.")]
|
||||
public float BlurRadius { get; set; } = 100f;
|
||||
[Option('s', "step", Required = false, HelpText = "Blur step size.")]
|
||||
public float BlurStep { get; set; } = 0.5f;
|
||||
[Option("sigma", Required = false, HelpText = "Blur sigma value (weighting).")]
|
||||
public float BlurSigma { get; set; } = 1f;
|
||||
[Option("device", Required = false, HelpText = "Device to use for computation. (CPU, OpenCL, CUDA)")]
|
||||
public DeviceType? Device { get; set; } = null;
|
||||
}
|
||||
|
||||
public static class Program {
|
||||
#region Magic Values
|
||||
const float MAX = 1f;
|
||||
const float MIN = 0f;
|
||||
static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
|
||||
static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS };
|
||||
static char PSep => Path.DirectorySeparatorChar;
|
||||
#endregion
|
||||
|
||||
static Logger logger = Logger.GetInstance();
|
||||
|
||||
static Options options = null!;
|
||||
|
||||
static List<Image> Images = new();
|
||||
static List<MaskData> ImageMasks = new();
|
||||
static List<TransitionMaskData> TransitionMasks = new();
|
||||
static List<SDFData> SDFs = new();
|
||||
static List<Vector3[,]> Gradients = new();
|
||||
|
||||
static void ConsoleUpdateLine(string s) => Console.Write("\r" + s);
|
||||
static SdfKernels kernels;
|
||||
static uint width;
|
||||
static uint height;
|
||||
|
||||
public static void Main(string[] args) {
|
||||
Console.WriteLine("Reading images...");
|
||||
var parser = Parser.Default;
|
||||
|
||||
var imagesPath = "images";
|
||||
parser.ParseArguments<Options>(args)
|
||||
.WithParsed(o => options = o)
|
||||
.WithNotParsed(_ => {
|
||||
Environment.Exit(1);
|
||||
});
|
||||
if(options.Device != null) kernels = new (options.Device.Value);
|
||||
else kernels = new();
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
var pixels = ImageUtil.LoadImage<Vector3>($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png");
|
||||
string debugPath = $"{Environment.CurrentDirectory}{PSep}Debug";
|
||||
if (options.Debug) {
|
||||
if (!Directory.Exists(debugPath)) Directory.CreateDirectory(debugPath);
|
||||
logger.Log("Debug mode enabled.", LogLevel.Debug);
|
||||
}
|
||||
|
||||
logger.Log("Reading images...");
|
||||
var imageNames = options.Images.Split(';');
|
||||
for (var i = 0; i < imageNames.GetLength(0); i++) {
|
||||
string imgPath = $"{options.ImgDirectory}{PSep}{imageNames[i]}";
|
||||
logger.Log($"Reading image {imgPath}", updatePrevious:true);
|
||||
var pixels = ImageUtil.LoadImage<Vector3>(imgPath);
|
||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||
}
|
||||
|
||||
//check if all the images in Images are the same resolution
|
||||
if (Images.Select(img => (img.Width, img.Height)).Distinct().Count() > 1) {
|
||||
Console.WriteLine("Error: Not all images have the same resolution.");
|
||||
logger.Log("Error: Not all images have the same resolution.", LogLevel.Critical);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
Console.WriteLine("Creating masks...");
|
||||
//for each image pair, create a mask
|
||||
var width = (uint)Images[0].Width;
|
||||
var height = (uint)Images[0].Height;
|
||||
for (int i = 0; i < Images.Count; i++) {
|
||||
ImageMasks.Add(new(SelfMask(Images[i].Pixels, width, height), Images[i], new()));
|
||||
if (i < Images.Count - 1) {
|
||||
Console.WriteLine($"Creating mask {i}...");
|
||||
var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels, width, height);
|
||||
TransitionMasks.Add(new(mask, Images[i], Images[i + 1]));
|
||||
width = (uint)Images[0].Width;
|
||||
height = (uint)Images[0].Height;
|
||||
|
||||
// sum all images together
|
||||
var sumPath = $"{debugPath}{PSep}Sum";
|
||||
if(options.Debug) Images[0].Pixels.SaveImage($"{sumPath}0.png");
|
||||
|
||||
for (int i = 1; i < Images.Count; i++) {
|
||||
for (int x = 0; x < Images[i].Width; x++) {
|
||||
for (int y = 0; y < Images[i].Height; y++) {
|
||||
Images[i].Pixels[x, y].X = MathF.Min(Images[i - 1].Pixels[x, y].X + Images[i].Pixels[x, y].X, MAX);
|
||||
Images[i].Pixels[x, y].Y = MathF.Min(Images[i - 1].Pixels[x, y].Y + Images[i].Pixels[x, y].X, MAX);
|
||||
Images[i].Pixels[x, y].Z = MathF.Min(Images[i - 1].Pixels[x, y].Z + Images[i].Pixels[x, y].X, MAX);
|
||||
}
|
||||
}
|
||||
if(options.Debug)Images[i].Pixels.SaveImage($"{sumPath}{i}.png");
|
||||
}
|
||||
|
||||
logger.Log("Creating masks...");
|
||||
for (var i = 0; i < Images.Count; i++) { //for each image pair, create a mask
|
||||
logger.Log($"Creating mask {i}...", updatePrevious:true);
|
||||
|
||||
var selfMask = SelfMask(Images[i].Pixels);
|
||||
ImageMasks.Add(new(selfMask, Images[i], new()));
|
||||
if (options.Debug) selfMask.SaveImage($"{debugPath}{PSep}selfMask{i}.png");
|
||||
|
||||
if (i >= Images.Count - 1) continue;
|
||||
|
||||
var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels);
|
||||
TransitionMasks.Add(new(mask));
|
||||
}
|
||||
|
||||
Console.WriteLine("Edge detecting masks...");
|
||||
//EdgeDetect all masks
|
||||
foreach (var t in ImageMasks) EdgeDetect(t);
|
||||
|
||||
if (outputMasks) {
|
||||
Console.WriteLine("Writing masks...");
|
||||
for (int i = 0; i < TransitionMasks.Count; i++) ImageMasks[i].Mask.SaveImage($"mask{i}.png");
|
||||
logger.Log("Edge detecting masks...");
|
||||
foreach (var mask in ImageMasks) {
|
||||
EdgeDetect(mask);
|
||||
}
|
||||
|
||||
if (options.Debug)
|
||||
for (var i = 0; i < TransitionMasks.Count; i++)
|
||||
ImageMasks[i].Mask.SaveImage($"{debugPath}{PSep}mask{i}.png");
|
||||
|
||||
Console.WriteLine("Creating SDFs...");
|
||||
logger.Log("Creating SDFs...");
|
||||
for (var i = 0; i < ImageMasks.Count; i++) {
|
||||
var mask = ImageMasks[i];
|
||||
SDFs.Add(SDF(mask));
|
||||
if (outputSDFs) mask.Mask.SaveImage($"sdf{i}.png");
|
||||
if (options.Debug) SDFs[i].SDF.SaveImage($"{debugPath}{PSep}sdf{i}.png");
|
||||
}
|
||||
|
||||
Console.WriteLine("Creating gradients...");
|
||||
logger.Log("Creating gradients...");
|
||||
for (var i = 0; i < TransitionMasks.Count; i++) {
|
||||
Console.WriteLine($"Generating gradient {i}...");
|
||||
var gradientData = Gradient(TransitionMasks[i], SDFs[i], SDFs[i + 1]);
|
||||
Gradients.Add(gradientData);
|
||||
if (outputGradients) gradientData.SaveImage($"gradient{i}.png");
|
||||
if (options.Debug) gradientData.SaveImage($"{debugPath}{PSep}gradient{i}.png");
|
||||
}
|
||||
|
||||
// generate final image
|
||||
var finalImage = new Vector3[width, height];
|
||||
var currStep = 0f;
|
||||
var stepIncrement = MAX / (Gradients.Count + 1);
|
||||
var stepIncrement = MAX / Gradients.Count;
|
||||
|
||||
|
||||
for (var x = 0; x < width; x++)
|
||||
for (var y = 0; y < height; y++)
|
||||
finalImage[x, y] = new(ImageMasks[0].Mask[x, y].X != 0 || ImageMasks[0].Mask[x, y].Y > 0 ? MAX : MIN);
|
||||
|
||||
for (var i = 0; i < Gradients.Count; i++) {
|
||||
var mask = ImageMasks[i + 1];
|
||||
var gradient = Gradients[i];
|
||||
logger.Log($"Applying gradient {i}..., Step: {currStep:F2} -> Next: {(currStep + stepIncrement):F2}");
|
||||
for (var x = 0; x < mask.Mask.GetLength(0); x++) {
|
||||
for (var y = 0; y < mask.Mask.GetLength(1); y++) {
|
||||
if (mask.Mask[x, y].X == 0 || mask.Mask[x, y].Y > 0) continue;
|
||||
finalImage[x, y] = new(Remap(gradient[x, y].X, MAX, MIN, currStep, currStep + stepIncrement));
|
||||
if (mask.Mask[x,y].X == 0) continue;
|
||||
var pixel = new Vector3(Remap(gradient[x, y].X, MIN, MAX, 1.0f - currStep,
|
||||
1.0f - (currStep + stepIncrement)));
|
||||
if (pixel.X > finalImage[x, y].X) finalImage[x, y] = pixel;
|
||||
}
|
||||
}
|
||||
currStep += stepIncrement;
|
||||
}
|
||||
finalImage.SaveImage("final.png");
|
||||
Console.WriteLine("Done!");
|
||||
if(options.Debug) finalImage.SaveImage($"{debugPath}{options.OutputFile}");
|
||||
|
||||
// apply directional blur
|
||||
var iterations = options.BlurIterations;
|
||||
var radius = options.BlurRadius;
|
||||
var step = options.BlurStep;
|
||||
var sigma = options.BlurSigma;
|
||||
var totalMask = SelfMask(Images[^1].Pixels);
|
||||
if(options.Debug) totalMask.SaveImage($"{debugPath}{PSep}TotalMask.png");
|
||||
|
||||
finalImage = DirectionalBlur(finalImage, totalMask, iterations, radius, step, sigma);
|
||||
|
||||
finalImage.SaveImage(options.OutputFile);
|
||||
logger.Log("Done!");
|
||||
Logger.Shutdown();
|
||||
}
|
||||
|
||||
private static void EdgeDetect(MaskData maskData) {
|
||||
uint width = (uint)maskData.Image.Width;
|
||||
uint height = (uint)maskData.Image.Height;
|
||||
int iterCount = 0;
|
||||
static void EdgeDetect(MaskData maskData) {
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Console.WriteLine("Running edge detection...");
|
||||
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||
{
|
||||
int x = (int)(i % width);
|
||||
int y = (int)(i / width);
|
||||
|
||||
if (!EdgeKernel(maskData.Mask, x, y, width, height)) return;
|
||||
var color = maskData.Mask[x, y];
|
||||
color.Y = MAX;
|
||||
maskData.Mask[x, y] = color;
|
||||
lock (maskData.Edges) maskData.Edges.Add(new(x, y));
|
||||
iterCount++;
|
||||
if (iterCount % (width * height / 100) == 0) {
|
||||
ConsoleUpdateLine(
|
||||
$"Progress: {iterCount / (float)(width * height):P} | {iterCount / (sw.Elapsed.TotalSeconds):N0} pixels/s");
|
||||
}
|
||||
kernels.EdgeDetect(maskData.Mask, out var temp);
|
||||
maskData.Mask = temp;
|
||||
Parallel.For(0, width * height, parallelOptions, (i) => {
|
||||
if (maskData.Mask[i % width, i / width].Y == 0) return;
|
||||
// ReSharper disable once PossibleLossOfFraction
|
||||
lock (maskData.Edges) maskData.Edges.Add(new(i % width, i / width));
|
||||
});
|
||||
|
||||
sw.Stop();
|
||||
Console.WriteLine(
|
||||
$"\nEdge pixels: {maskData.Edges.Count} | {maskData.Edges.Count / sw.ElapsedMilliseconds} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
|
||||
string logString = $"Edge detecting mask {ImageMasks.IndexOf(maskData)}..." +
|
||||
Environment.NewLine + $"Edge pixels: {maskData.Edges.Count} | {width * height / (sw.ElapsedMilliseconds + 1)} pixels/s"+
|
||||
Environment.NewLine + $"Time: {sw.Elapsed.TotalSeconds:F4}s";
|
||||
logger.Log(logString, updatePrevious:true);
|
||||
}
|
||||
|
||||
static Vector3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
|
||||
uint width = (uint)mask.ImageA.Width;
|
||||
uint height = (uint)mask.ImageA.Height;
|
||||
int iterCount = 0;
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Vector3[,] temp = new Vector3[width, height];
|
||||
|
||||
var min = MAX;
|
||||
var max = MIN;
|
||||
|
||||
Console.WriteLine("Running gradient generation...");
|
||||
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||
{
|
||||
int x = (int)(i % width);
|
||||
int y = (int)(i / width);
|
||||
|
||||
if (mask.Mask[x, y].X == 0 || mask.Mask[x, y].Y > 0) return;
|
||||
|
||||
var a = sdfA.SDF[x, y].X;
|
||||
var b = sdfB.SDF[x, y].X;
|
||||
|
||||
var gradient = a / (a + b);
|
||||
temp[x, y] = new(Remap(gradient, 0, 1, MIN, MAX));
|
||||
|
||||
if (gradient < min) min = gradient;
|
||||
if (gradient > max) max = gradient;
|
||||
});
|
||||
|
||||
Console.WriteLine(
|
||||
$"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / (float)sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||
Console.WriteLine($"Min: {min} | Max: {max}");
|
||||
kernels.Gradient(mask.Mask, sdfA.SDF, sdfB.SDF, out var temp);
|
||||
logger.Log($"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / (float)sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||
return temp;
|
||||
}
|
||||
|
||||
static SDFData SDF(MaskData mask) {
|
||||
var width = (uint)mask.Mask.GetLength(0);
|
||||
var height = (uint)mask.Mask.GetLength(1);
|
||||
var temp = new Vector3[width, height];
|
||||
float AbsMax = MIN;
|
||||
int iterCount = 0;
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||
{
|
||||
//convert 1D index to 2D index
|
||||
var x = (int)(i % width);
|
||||
var y = (int)(i / width);
|
||||
Vector2 p = new(x, y);
|
||||
|
||||
float minDist = MAX; //initialize the minimum distance to the maximum possible value
|
||||
|
||||
//loop through all the pixels in the mask
|
||||
foreach (var edge in mask.Edges) {
|
||||
float dist = Vector2.DistanceSquared(p, edge);
|
||||
if (dist < minDist) minDist = mask.Mask[x, y].X == 0 ? dist : dist;
|
||||
}
|
||||
|
||||
temp[x, y] = new(minDist);
|
||||
if (minDist > AbsMax) AbsMax = minDist;
|
||||
iterCount++;
|
||||
if (iterCount % (width * height / 100) == 0) {
|
||||
ConsoleUpdateLine(
|
||||
$"Progress: {iterCount / (float)(width * height):P}% | {iterCount / (sw.Elapsed.TotalSeconds):N0} pixels/s");
|
||||
}
|
||||
kernels.Sdf(mask.Edges.ToArray(), (int)width, (int)height, out var temp);
|
||||
string logString = $"SDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)";
|
||||
sw.Restart();
|
||||
var absMax = 0f;
|
||||
Parallel.ForEach(temp.Cast<Vector3>(), pixel => {
|
||||
var localMax = pixel.X;
|
||||
Interlocked.Exchange(ref absMax, MathF.Max(absMax, localMax));
|
||||
});
|
||||
|
||||
Console.WriteLine(
|
||||
$"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||
sw.Restart();
|
||||
Parallel.For(0, width * height, parallelOptions, (i) =>
|
||||
{
|
||||
Parallel.For(0, width * height, parallelOptions, (i) => {
|
||||
//convert 1D index to 2D index
|
||||
var x = (int)(i % width);
|
||||
var y = (int)(i / width);
|
||||
temp[x, y] = new(Remap(temp[x, y].X, 0, AbsMax, MIN, MAX));
|
||||
temp[x, y] = new(Remap(temp[x, y].X, 0, absMax, MIN, MAX));
|
||||
});
|
||||
sw.Stop();
|
||||
logString += Environment.NewLine +
|
||||
$"SDF Normalization Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)";
|
||||
logger.Log(logString, updatePrevious:true);
|
||||
|
||||
Console.WriteLine(
|
||||
$"SDF Normalization Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||
Console.WriteLine("AbsMax: " + AbsMax);
|
||||
return new(temp);
|
||||
}
|
||||
|
||||
static Vector3[,] DirectionalBlur(Vector3[,] image, Vector3[,] mask, int iterations, float radius = 3f, float step = .5f, float sigma = 1f) {
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
kernels.DirectionalBlur(image, mask, out var temp, iterations, radius, step, sigma);
|
||||
logger.Log($"Directional Blur Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height * iterations / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||
return temp;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static float EuclideanDistance(Vector2 a, Vector2 b) =>
|
||||
MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2));
|
||||
static float EuclideanDistance(Vector2 a, Vector2 b) => MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2));
|
||||
|
||||
|
||||
static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B, uint resX, uint resY) {
|
||||
var temp = new Vector3[resX, resY];
|
||||
Parallel.For(0, resX * resY, parallelOptions, (i) =>
|
||||
{
|
||||
uint x = (uint)(i % resX);
|
||||
uint y = (uint)(i / resX);
|
||||
var pixelA = A[x, y];
|
||||
var pixelB = B[x, y];
|
||||
float lumaA = (pixelA.X + pixelA.Y + pixelA.Z) / 3;
|
||||
float lumaB = (pixelB.X + pixelB.Y + pixelB.Z) / 3;
|
||||
float resultPixel = lumaB > lumaA ? MAX : MIN;
|
||||
temp[x, y] = new(resultPixel, 0, 0);
|
||||
});
|
||||
static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B) {
|
||||
kernels.ABMask(A, B, out var temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
static Vector3[,] SelfMask(Vector3[,] A, uint resX, uint resY) {
|
||||
var temp = new Vector3[resX, resY];
|
||||
Parallel.For(0, resX * resY, parallelOptions, (i) =>
|
||||
{
|
||||
uint x = (uint)(i % resX);
|
||||
uint y = (uint)(i / resX);
|
||||
var pixelA = A[x, y];
|
||||
float lumaA = (pixelA.X + pixelA.Y + pixelA.Z) / 3;
|
||||
float resultPixel = lumaA > 0 ? MAX : MIN;
|
||||
temp[x, y] = new(resultPixel, 0, 0);
|
||||
});
|
||||
static Vector3[,] SelfMask(Vector3[,] A) {
|
||||
kernels.SelfMask(A, out var temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
static bool EdgeKernel(Vector3[,] mask, int x, int y, uint width, uint height) {
|
||||
//if we are already empty, return false
|
||||
if (mask[x, y].X == 0) return false;
|
||||
//if we are on the edge of the image, return false
|
||||
if (x == 0 || y == 0 || x == width - 1 || y == height - 1) return false;
|
||||
//check the 3x3 kernel
|
||||
for (int xi = x - 1; xi <= x + 1; xi++) {
|
||||
for (int yi = y - 1; yi <= y + 1; yi++) {
|
||||
if (xi < 0 || xi >= width || yi < 0 || yi >= height)
|
||||
continue; //skip out of bounds pixels
|
||||
if (mask[xi, yi].X == 0)
|
||||
return true; //if we find a black pixel, return true
|
||||
}
|
||||
}
|
||||
//if we didn't find any black pixels, return false
|
||||
return false;
|
||||
}
|
||||
|
||||
static T Lerp<T>(T a, T b, float t)
|
||||
where T : INumber<T>, IMultiplyOperators<T, float, T>, IAdditionOperators<T, T, T>
|
||||
=> a * (1 - t) + b * t;
|
||||
|
||||
static Vector3 Lerp(Vector3 a, Vector3 b, float t) => a * (1 - t) + b * t;
|
||||
|
||||
static T Remap<T>(T value, T min, T max, T newMin, T newMax)
|
||||
where T : INumber<T>, ISubtractionOperators<T, T, T>, IMultiplyOperators<T, T, T>, IAdditionOperators<T, T, T>
|
||||
=> (value - min) / (max - min) * (newMax - newMin) + newMin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,30 @@
|
||||
/*
|
||||
Copyright 2025 Railgun Entertainment AS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Numerics;
|
||||
|
||||
namespace SDFMapCreator;
|
||||
|
||||
public record Image(Vector3[,] Pixels, int Width, int Height);
|
||||
public record MaskData(Vector3[,] Mask, Image Image, List<Vector2> Edges);
|
||||
|
||||
public record MaskData(Vector3[,] Mask, Image Image, List<Vector2> Edges) {
|
||||
public Vector3[,] Mask { get; set; } = Mask;
|
||||
public List<Vector2> Edges { get; set; } = Edges;
|
||||
}
|
||||
|
||||
public record SDFData(Vector3[,] SDF);
|
||||
public record TransitionMaskData(Vector3[,] Mask, Image ImageA, Image ImageB);
|
||||
|
||||
public record TransitionMaskData(Vector3[,] Mask);
|
||||
@@ -5,56 +5,71 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyName>SDFMapTool</AssemblyName>
|
||||
<Company>Circle2Labs</Company>
|
||||
<Product>SDFMapTool</Product>
|
||||
<AssemblyVersion>1.0</AssemblyVersion>
|
||||
<FileVersion>1.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageReference Include="ILGPU" Version="1.5.2"/>
|
||||
<PackageReference Include="ILGPU.Algorithms" Version="1.5.2"/>
|
||||
<PackageReference Include="LineWalker" Version="0.1.2-alpha" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7"/>
|
||||
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="1.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="2.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="TestPattern.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\01.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\02.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\03.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\04.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\05.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\06.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\07.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\08.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="spherecut.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="spherefull.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="spherehalf.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\01.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\02.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\03.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\04.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\05.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\06.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\07.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\08.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\spherecut.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\spherecut32.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\sphereempty.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\spherefull.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\spherefull32.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\spherehalf.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\spherehalf32.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="OpenSourceLicenses.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
180
SDFMapCreator/SdfKernels.Kernels.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright 2025 Railgun Entertainment AS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Numerics;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
|
||||
namespace SDFMapCreator;
|
||||
|
||||
public partial class SdfKernels {
|
||||
|
||||
private const float LUMA_THRESHOLD = 0.0f;
|
||||
static void SelfMaskKernel(Index2D index, ArrayView2D<Vector3, Stride2D.DenseX> input, ArrayView2D<Vector3, Stride2D.DenseX> mask) {
|
||||
var x = index.X;
|
||||
var y = index.Y;
|
||||
var value = input[x, y];
|
||||
var lumaA = value.X;
|
||||
var r = lumaA > LUMA_THRESHOLD ? 1f : 0f;
|
||||
mask[x, y] = new(r, 0f, 0f);
|
||||
}
|
||||
|
||||
static void ABMaskKernel(Index2D index,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> A,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> B,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> mask
|
||||
) {
|
||||
var x = index.X;
|
||||
var y = index.Y;
|
||||
var valueA = A[x, y];
|
||||
var valueB = B[x, y];
|
||||
var lumaA = valueA.X;
|
||||
var lumaB = valueB.X;
|
||||
var r = lumaB - lumaA > LUMA_THRESHOLD ? 1f : 0f;
|
||||
mask[x, y] = new(r, 0f, 0f);
|
||||
}
|
||||
|
||||
static void EdgeKernel(Index2D index,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> mask,
|
||||
uint width, uint height
|
||||
) { // early exit if not on mask
|
||||
if (mask[index].X == 0f) return;
|
||||
var x = index.X;
|
||||
var y = index.Y;
|
||||
//if we are on the edge of the image, return false
|
||||
if (x == 0 || y == 0 || x == width - 1 || y == height - 1) {
|
||||
mask[index].Y = 1f; //set the edge flag
|
||||
return;
|
||||
}
|
||||
|
||||
//check the 3x3 kernel
|
||||
for (var xi = x - 1; xi <= x + 1; xi++) {
|
||||
for (var yi = y - 1; yi <= y + 1; yi++) {
|
||||
if (xi < 0 || xi >= width || yi < 0 || yi >= height)
|
||||
continue; //skip out of bounds pixels
|
||||
if (mask[xi, yi].X == 0f)
|
||||
mask[index].Y = 1f; //if we find a black pixel, return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SdfKernel(Index2D index,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> sdf,
|
||||
ArrayView1D<Vector2, Stride1D.Dense> edges,
|
||||
int width, int height
|
||||
) {
|
||||
Vector2 pos = new((float)index.X / width, (float)index.Y / height);
|
||||
var minDist = 2f;
|
||||
var count = edges.IntExtent.Size;
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
Vector2 edgeNrm = new(edges[i].X / width, edges[i].Y / height);
|
||||
var dist = Vector2.Distance(pos, edgeNrm);
|
||||
if (dist < minDist) minDist = dist;
|
||||
}
|
||||
|
||||
if (minDist > 1f) minDist = 1f;
|
||||
|
||||
sdf[index] = new(minDist);
|
||||
}
|
||||
|
||||
static void GradientKernel(Index2D index,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> mask,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> sdfa,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> sdfb,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> gradient
|
||||
) { //early exit if not on mask
|
||||
if (mask[index].X == 0f) return;
|
||||
var a = sdfa[index].X;
|
||||
var b = sdfb[index].X;
|
||||
gradient[index] = new(a / (a + b));
|
||||
}
|
||||
|
||||
static Vector3 SampleBilinear(ArrayView2D<Vector3, Stride2D.DenseX> image, float x, float y) {
|
||||
int width = image.IntExtent.X;
|
||||
int height = image.IntExtent.Y;
|
||||
|
||||
var x0 = (int)x;
|
||||
var y0 = (int)y;
|
||||
var x1 = x0 + 1;
|
||||
var y1 = y0 + 1;
|
||||
|
||||
if (x0 < 0 || x1 >= width || y0 < 0 || y1 >= height) return Vector3.Zero;
|
||||
|
||||
var a = new Vector2(x - x0, y - y0);
|
||||
var b = new Vector2(1f - a.X, 1f - a.Y);
|
||||
|
||||
return Vector3.Lerp(
|
||||
Vector3.Lerp(image[x0, y0], image[x1, y0], a.X),
|
||||
Vector3.Lerp(image[x0, y1], image[x1, y1], a.X),
|
||||
a.Y
|
||||
);
|
||||
}
|
||||
|
||||
static void DirectionalBlurKernel(Index2D index,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> image,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> mask,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX> output,
|
||||
float radius, float step, float sigma,
|
||||
int width, int height
|
||||
) {
|
||||
var x = index.X;
|
||||
var y = index.Y;
|
||||
var value = image[x, y];
|
||||
var maskValue = mask[x, y];
|
||||
if (maskValue.X == 0f) {
|
||||
output[x, y] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
var gradient = Vector2.Zero;
|
||||
|
||||
// calculate the gradient
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (x + i < 0 || x + i >= width || y + i < 0 || y + i >= height) continue;
|
||||
gradient.X += i * image[x + i, y].X;
|
||||
gradient.Y += i * image[x, y + i].X;
|
||||
}
|
||||
|
||||
if (gradient == Vector2.Zero) {
|
||||
output[x, y] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
//clean up the buffer in case
|
||||
output[index] = new(0f, 0f, 0f);
|
||||
|
||||
gradient = Vector2.Normalize(gradient);
|
||||
float sum = 0;
|
||||
|
||||
// now we follow the direction line and sample the image for length;
|
||||
for (var l = -radius; l <= radius; l += step) {
|
||||
var xOffset = (gradient.X * l);
|
||||
var yOffset = (gradient.Y * l);
|
||||
var xSample = x + xOffset;
|
||||
var ySample = y + yOffset;
|
||||
|
||||
if (xSample < 0 || xSample >= width || ySample < 0 || ySample >= height) continue;
|
||||
|
||||
var sampleValue = SampleBilinear(image, xSample, ySample);
|
||||
var weight = MathF.Exp(-(l * l) / (2f * sigma * sigma));
|
||||
output[x, y] += sampleValue * weight;
|
||||
sum += weight;
|
||||
}
|
||||
|
||||
output[x, y] = output[x, y] / sum;
|
||||
}
|
||||
}
|
||||
232
SDFMapCreator/SdfKernels.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
Copyright 2025 Railgun Entertainment AS
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Numerics;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
using ILGPU.Runtime.CPU;
|
||||
using ILGPU.Runtime.Cuda;
|
||||
using ILGPU.Runtime.OpenCL;
|
||||
using LineWalker;
|
||||
|
||||
namespace SDFMapCreator;
|
||||
|
||||
public partial class SdfKernels {
|
||||
Logger logger = Logger.GetInstance();
|
||||
|
||||
Context gpuContext;
|
||||
Accelerator accelerator;
|
||||
public SdfKernels() {
|
||||
// Initialize the GPU context
|
||||
gpuContext = Context.Create(builder => builder
|
||||
.Cuda()
|
||||
.OpenCL()
|
||||
.CPU()
|
||||
.Math(MathMode.Fast32BitOnly)
|
||||
.EnableAlgorithms()
|
||||
);
|
||||
|
||||
logger.Log("Reading available accelerators (CUDA only)...");
|
||||
foreach (var device in gpuContext.GetCudaDevices()) {
|
||||
accelerator = device.CreateAccelerator(gpuContext);
|
||||
logger.Log($"Found accelerator: {accelerator.Name} ({accelerator.AcceleratorType})");
|
||||
}
|
||||
|
||||
logger.Log("Reading available accelerators (OpenCL only)...");
|
||||
foreach (var device in gpuContext.GetCLDevices()) {
|
||||
accelerator = device.CreateAccelerator(gpuContext);
|
||||
logger.Log($"Found accelerator: {accelerator.Name} ({accelerator.AcceleratorType})");
|
||||
}
|
||||
|
||||
logger.Log("Reading available accelerators (CPU only)...");
|
||||
foreach (var device in gpuContext.GetCPUDevices()) {
|
||||
accelerator = device.CreateAccelerator(gpuContext);
|
||||
logger.Log($"Found accelerator: {accelerator.Name} ({accelerator.AcceleratorType})");
|
||||
}
|
||||
|
||||
accelerator = gpuContext.GetPreferredDevice(false).CreateAccelerator(gpuContext);
|
||||
logger.Log($"Using accelerator: {accelerator.Name} ({accelerator.AcceleratorType})");
|
||||
}
|
||||
|
||||
public SdfKernels(DeviceType device) {
|
||||
logger.Log($"Looking up for {device.ToString()} accelerators...");
|
||||
var builder = Context.Create();
|
||||
switch (device) {
|
||||
case DeviceType.CPU: builder.CPU(); break;
|
||||
case DeviceType.CUDA: builder.Cuda(); break;
|
||||
case DeviceType.OpenCL: builder.OpenCL(); break;
|
||||
}
|
||||
|
||||
gpuContext = builder
|
||||
.Math(MathMode.Fast32BitOnly)
|
||||
.EnableAlgorithms()
|
||||
.ToContext();
|
||||
|
||||
accelerator = gpuContext.GetPreferredDevice(false).CreateAccelerator(gpuContext);
|
||||
logger.Log($"Using accelerator: {accelerator.Name} ({accelerator.AcceleratorType})");
|
||||
}
|
||||
|
||||
public void SelfMask(Vector3[,] input, out Vector3[,] mask) {
|
||||
var width = input.GetLength(0);
|
||||
var height = input.GetLength(1);
|
||||
mask = new Vector3[width, height];
|
||||
|
||||
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
buffer.CopyFromCPU(input);
|
||||
|
||||
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
|
||||
var selfMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>>(SelfMaskKernel);
|
||||
|
||||
selfMaskKernel(new(width, height), buffer.View, maskBuffer.View);
|
||||
|
||||
accelerator.Synchronize();
|
||||
|
||||
mask = maskBuffer.GetAsArray2D();
|
||||
}
|
||||
|
||||
public void ABMask(Vector3[,] A, Vector3[,] B, out Vector3[,] mask) {
|
||||
var width = A.GetLength(0);
|
||||
var height = A.GetLength(1);
|
||||
mask = new Vector3[width, height];
|
||||
|
||||
using var bufferA = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
bufferA.CopyFromCPU(A);
|
||||
|
||||
using var bufferB = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
bufferB.CopyFromCPU(B);
|
||||
|
||||
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
|
||||
var abMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>>(ABMaskKernel);
|
||||
|
||||
abMaskKernel(new(width, height), bufferA.View, bufferB.View, maskBuffer.View);
|
||||
|
||||
accelerator.Synchronize();
|
||||
|
||||
mask = maskBuffer.GetAsArray2D();
|
||||
}
|
||||
|
||||
public void EdgeDetect(Vector3[,] mask, out Vector3[,] edge) {
|
||||
var width = mask.GetLength(0);
|
||||
var height = mask.GetLength(1);
|
||||
edge = new Vector3[width, height];
|
||||
|
||||
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
buffer.CopyFromCPU(mask);
|
||||
|
||||
var edgeKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>, uint, uint>(EdgeKernel);
|
||||
|
||||
edgeKernel(new(width, height), buffer.View, (uint)width, (uint)height);
|
||||
|
||||
accelerator.Synchronize();
|
||||
|
||||
edge = buffer.GetAsArray2D();
|
||||
}
|
||||
|
||||
public void Sdf(Vector2[] edges, int width, int height, out Vector3[,] sdf) {
|
||||
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
|
||||
using var edgeBuffer = accelerator.Allocate1D<Vector2>(edges.Length);
|
||||
edgeBuffer.CopyFromCPU(edges);
|
||||
|
||||
var sdfKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView1D<Vector2, Stride1D.Dense>,
|
||||
int, int>(SdfKernel);
|
||||
|
||||
sdfKernel(new(width, height), buffer.View, edgeBuffer.View, width, height);
|
||||
|
||||
accelerator.Synchronize();
|
||||
|
||||
sdf = buffer.GetAsArray2D();
|
||||
}
|
||||
|
||||
public void Gradient(Vector3[,] mask, Vector3[,] sdfa, Vector3[,] sdfb, out Vector3[,] gradient) {
|
||||
var width = mask.GetLength(0);
|
||||
var height = mask.GetLength(1);
|
||||
gradient = new Vector3[width, height];
|
||||
|
||||
using var bufferMask = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
bufferMask.CopyFromCPU(mask);
|
||||
|
||||
using var bufferSdfa = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
bufferSdfa.CopyFromCPU(sdfa);
|
||||
|
||||
using var bufferSdfb = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
bufferSdfb.CopyFromCPU(sdfb);
|
||||
|
||||
using var bufferGradient = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
|
||||
var gradientKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>>(GradientKernel);
|
||||
|
||||
gradientKernel(new(width, height), bufferMask.View, bufferSdfa.View, bufferSdfb.View, bufferGradient.View);
|
||||
|
||||
accelerator.Synchronize();
|
||||
|
||||
gradient = bufferGradient.GetAsArray2D();
|
||||
}
|
||||
|
||||
public void DirectionalBlur(Vector3[,] image, Vector3[,] mask, out Vector3[,] output, int iterations, float radius = 3f,
|
||||
float step = .5f, float sigma = 1f) {
|
||||
var width = image.GetLength(0);
|
||||
var height = image.GetLength(1);
|
||||
output = new Vector3[width, height];
|
||||
|
||||
using var imageBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
imageBuffer.CopyFromCPU(image);
|
||||
|
||||
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
maskBuffer.CopyFromCPU(mask);
|
||||
|
||||
using var outputBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||
|
||||
var blurKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||
float, float, float, int, int>(DirectionalBlurKernel);
|
||||
|
||||
var stream = accelerator.DefaultStream;
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
if (i > 0) outputBuffer.CopyTo(stream, imageBuffer);
|
||||
blurKernel(new(width, height), imageBuffer.View, maskBuffer.View, outputBuffer.View, radius, step, sigma, width, height);
|
||||
accelerator.Synchronize();
|
||||
}
|
||||
|
||||
output = outputBuffer.GetAsArray2D();
|
||||
}
|
||||
|
||||
static string GetInfoString(Accelerator a) {
|
||||
var infoString = new StringWriter();
|
||||
a.PrintInformation(infoString);
|
||||
return infoString.ToString();
|
||||
}
|
||||
|
||||
~SdfKernels() {
|
||||
accelerator?.Dispose();
|
||||
gpuContext?.Dispose();
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
29
SDFMapCreator/copyImages.ps1
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright 2025 Railgun Entertainment AS
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
$imagesPath = "./images/*"
|
||||
|
||||
if (Test-Path "./bin/Debug/net8.0/")
|
||||
{
|
||||
Write-Output "Copying images to Debug folder"
|
||||
Copy-Item -Path $imagesPath -Destination "./bin/Debug/net8.0/images/"
|
||||
}
|
||||
|
||||
if(Test-Path "./bin/Release/net8.0/")
|
||||
{
|
||||
Write-Output "Copying images to Release folder"
|
||||
Copy-Item -Path $imagesPath -Destination "./bin/Release/net8.0/images/"
|
||||
}
|
||||
|
||||
return 0
|
||||
23
SDFMapCreator/copyImages.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2025 Railgun Entertainment AS
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if [ -d ./bin/Debug/net8.0/ ]; then
|
||||
echo "Copying images to bin/Debug"
|
||||
cp -r ./images ./bin/Debug/net8.0/
|
||||
fi
|
||||
|
||||
if [ -d ./bin/Release/net8.0/ ]; then
|
||||
echo "Copying images to bin/Release"
|
||||
cp -r ./images ./bin/Release/net8.0/
|
||||
fi
|
||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
BIN
SDFMapCreator/images/spherecut32.png
Normal file
|
After Width: | Height: | Size: 680 B |
BIN
SDFMapCreator/images/sphereempty.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
BIN
SDFMapCreator/images/spherefull32.png
Normal file
|
After Width: | Height: | Size: 693 B |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
BIN
SDFMapCreator/images/spherehalf32.png
Normal file
|
After Width: | Height: | Size: 540 B |