Compare commits
23 Commits
1d64749e76
...
ILGpu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c65346aeec | ||
|
|
a74ae1167e | ||
|
|
d7d2091d64 | ||
|
|
ea28738280 | ||
|
|
2faab96a7d | ||
|
|
8c5ca2ce21 | ||
|
|
d0fbd31c1d | ||
|
|
5cf8612699 | ||
|
|
dfa2cf3f31 | ||
|
|
64b7eb9dcc | ||
|
|
d652c63586 | ||
|
|
9614283dc8 | ||
|
|
b072eea732 | ||
|
|
925e4c9989 | ||
|
|
69d3b517f3 | ||
|
|
2d1368a908 | ||
|
|
3b319da80b | ||
|
|
db54b80b5a | ||
|
|
281e0f4aee | ||
|
|
366a5c1cab | ||
|
|
86c0e97672 | ||
|
|
6fd430a670 | ||
|
|
664c5e02fe |
4012
.editorconfig
Normal file
4012
.editorconfig
Normal file
File diff suppressed because it is too large
Load Diff
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,4 +2,5 @@ bin/
|
|||||||
obj/
|
obj/
|
||||||
/packages/
|
/packages/
|
||||||
riderModule.iml
|
riderModule.iml
|
||||||
/_ReSharper.Caches/
|
/_ReSharper.Caches/
|
||||||
|
publish/
|
||||||
5
.idea/.idea.SDFMapCreator/.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
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>
|
||||||
6
.run/Release Build Linux-x64.run.xml
Normal file
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
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>
|
||||||
19
SDFMapCreator.sln.DotSettings
Normal file
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,12 @@
|
|||||||
<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">
|
<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_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_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_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_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_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_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_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: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:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue"><AssemblyExplorer>
|
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue"><AssemblyExplorer>
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ public static class ImageUtil {
|
|||||||
|
|
||||||
static T[,] ProcessPixelsRgba64<T>(this Image<Rgba64> image) where T : struct, IEquatable<T> {
|
static T[,] ProcessPixelsRgba64<T>(this Image<Rgba64> image) where T : struct, IEquatable<T> {
|
||||||
var max = 65535f;
|
var max = 65535f;
|
||||||
int width = image.Width;
|
var width = image.Width;
|
||||||
int height = image.Height;
|
var height = image.Height;
|
||||||
var result = new T[image.Width, image.Height];
|
var result = new T[image.Width, image.Height];
|
||||||
image.ProcessPixelRows(accessor => {
|
image.ProcessPixelRows(accessor => {
|
||||||
//we use Y as the row index and X as the column index
|
//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);
|
var span = accessor.GetRowSpan(y);
|
||||||
for (int x = 0; x < width; x++) {
|
for (var x = 0; x < width; x++) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case float[,] f:
|
case float[,] f:
|
||||||
f[x, y] = span[x].R / max * (span[x].A / max);
|
f[x, y] = span[x].R / max * (span[x].A / max);
|
||||||
@@ -37,7 +37,7 @@ public static class ImageUtil {
|
|||||||
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
|
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
|
||||||
break;
|
break;
|
||||||
case Vector4[,] f:
|
case Vector4[,] f:
|
||||||
f[x, y] = new Vector4(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,14 +48,14 @@ public static class ImageUtil {
|
|||||||
|
|
||||||
static T[,] ProcessPixelsRgb24<T>(this Image<Rgb24> image) where T : struct, IEquatable<T> {
|
static T[,] ProcessPixelsRgb24<T>(this Image<Rgb24> image) where T : struct, IEquatable<T> {
|
||||||
var max = 255f;
|
var max = 255f;
|
||||||
int width = image.Width;
|
var width = image.Width;
|
||||||
int height = image.Height;
|
var height = image.Height;
|
||||||
var result = new T[image.Width, image.Height];
|
var result = new T[image.Width, image.Height];
|
||||||
image.ProcessPixelRows(accessor => {
|
image.ProcessPixelRows(accessor => {
|
||||||
//we use Y as the row index and X as the column index
|
//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);
|
var span = accessor.GetRowSpan(y);
|
||||||
for (int x = 0; x < width; x++) {
|
for (var x = 0; x < width; x++) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case float[,] f:
|
case float[,] f:
|
||||||
f[x, y] = span[x].R / max;
|
f[x, y] = span[x].R / max;
|
||||||
@@ -75,17 +75,17 @@ public static class ImageUtil {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static T[,] ProcessPixelsRgba32<T>(this Image<Rgba32> image) where T : struct, IEquatable<T> {
|
static T[,] ProcessPixelsRgba32<T>(this Image<Rgba32> image) where T : struct, IEquatable<T> {
|
||||||
var max = 255f;
|
var max = 255f;
|
||||||
int width = image.Width;
|
var width = image.Width;
|
||||||
int height = image.Height;
|
var height = image.Height;
|
||||||
var result = new T[image.Width, image.Height];
|
var result = new T[image.Width, image.Height];
|
||||||
image.ProcessPixelRows(accessor => {
|
image.ProcessPixelRows(accessor => {
|
||||||
//we use Y as the row index and X as the column index
|
//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);
|
var span = accessor.GetRowSpan(y);
|
||||||
for (int x = 0; x < width; x++) {
|
for (var x = 0; x < width; x++) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case float[,] f:
|
case float[,] f:
|
||||||
f[x, y] = span[x].R / max * (span[x].A / max);
|
f[x, y] = span[x].R / max * (span[x].A / max);
|
||||||
@@ -97,7 +97,7 @@ public static class ImageUtil {
|
|||||||
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
|
f[x, y] = new Vector3(span[x].R / max, span[x].G / max, span[x].B / max) * new Vector3(span[x].A / max);
|
||||||
break;
|
break;
|
||||||
case Vector4[,] f:
|
case Vector4[,] f:
|
||||||
f[x, y] = new Vector4(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
f[x, y] = new(span[x].R / max, span[x].G / max, span[x].B / max, span[x].A / max);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,17 +105,17 @@ public static class ImageUtil {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static T[,] ProcessPixelsRgb48<T>(this Image<Rgb48> image) where T : struct, IEquatable<T> {
|
static T[,] ProcessPixelsRgb48<T>(this Image<Rgb48> image) where T : struct, IEquatable<T> {
|
||||||
var max = 65535f;
|
var max = 65535f;
|
||||||
int width = image.Width;
|
var width = image.Width;
|
||||||
int height = image.Height;
|
var height = image.Height;
|
||||||
var result = new T[image.Width, image.Height];
|
var result = new T[image.Width, image.Height];
|
||||||
image.ProcessPixelRows(accessor => {
|
image.ProcessPixelRows(accessor => {
|
||||||
//we use Y as the row index and X as the column index
|
//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);
|
var span = accessor.GetRowSpan(y);
|
||||||
for (int x = 0; x < width; x++) {
|
for (var x = 0; x < width; x++) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case float[,] f:
|
case float[,] f:
|
||||||
f[x, y] = span[x].R / max;
|
f[x, y] = span[x].R / max;
|
||||||
@@ -135,7 +135,7 @@ public static class ImageUtil {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveImage<T>(this T[,] array, string path) where T : struct, IEquatable<T> {
|
public static void SaveImage<T>(this T[,] array, string path) where T : struct, IEquatable<T> {
|
||||||
var width = array.GetLength(0);
|
var width = array.GetLength(0);
|
||||||
var height = array.GetLength(1);
|
var height = array.GetLength(1);
|
||||||
@@ -149,21 +149,21 @@ public static class ImageUtil {
|
|||||||
Console.Write($"Writing image {path}...");
|
Console.Write($"Writing image {path}...");
|
||||||
using Image<Rgb48> image = new(width, height);
|
using Image<Rgb48> image = new(width, height);
|
||||||
image.ProcessPixelRows(accessor => {
|
image.ProcessPixelRows(accessor => {
|
||||||
for (int y = 0; y < height; y++) {
|
for (var y = 0; y < height; y++) {
|
||||||
var span = accessor.GetRowSpan(y);
|
var span = accessor.GetRowSpan(y);
|
||||||
for (int x = 0; x < width; x++) {
|
for (var x = 0; x < width; x++) {
|
||||||
switch (array) {
|
switch (array) {
|
||||||
case float[,] f:
|
case float[,] f:
|
||||||
span[x] = new Rgb48((ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535), (ushort)(f[x,y] * 65535));
|
span[x] = new((ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535), (ushort)(f[x, y] * 65535));
|
||||||
break;
|
break;
|
||||||
case Vector2[,] f:
|
case Vector2[,] f:
|
||||||
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), 0);
|
span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), 0);
|
||||||
break;
|
break;
|
||||||
case Vector3[,] f:
|
case Vector3[,] f:
|
||||||
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), (ushort)(f[x,y].Z * 65535));
|
span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), (ushort)(f[x, y].Z * 65535));
|
||||||
break;
|
break;
|
||||||
case Vector4[,] f:
|
case Vector4[,] f:
|
||||||
span[x] = new Rgb48((ushort)(f[x,y].X * 65535), (ushort)(f[x,y].Y * 65535), (ushort)(f[x,y].Z * 65535));
|
span[x] = new((ushort)(f[x, y].X * 65535), (ushort)(f[x, y].Y * 65535), (ushort)(f[x, y].Z * 65535));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,13 +172,13 @@ public static class ImageUtil {
|
|||||||
Console.WriteLine($"Done!");
|
Console.WriteLine($"Done!");
|
||||||
image.Save(path);
|
image.Save(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
|
static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"""
|
$"""
|
||||||
Image file: {path}
|
Image file: {path}
|
||||||
Resolution: {image1.Width}x{image1.Height}
|
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
|
||||||
|
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using SDFMapCreator;
|
|
||||||
|
|
||||||
public class Program {
|
namespace SDFMapCreator;
|
||||||
private const float MAX = 1f;
|
|
||||||
private const float MIN = 0f;
|
public static class Program {
|
||||||
private static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
|
const float MAX = 1f;
|
||||||
private const bool outputMasks = true;
|
const float MIN = 0f;
|
||||||
private const bool outputSDFs = true;
|
static readonly int MAX_THREADS = Environment.ProcessorCount - 2;
|
||||||
private const bool outputGradients = true;
|
static bool debug = true;
|
||||||
static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS };
|
static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = MAX_THREADS };
|
||||||
static List<Image> Images = new();
|
static List<Image> Images = new();
|
||||||
static List<MaskData> ImageMasks = new();
|
static List<MaskData> ImageMasks = new();
|
||||||
@@ -17,15 +16,22 @@ public class Program {
|
|||||||
static List<SDFData> SDFs = new();
|
static List<SDFData> SDFs = new();
|
||||||
static List<Vector3[,]> Gradients = new();
|
static List<Vector3[,]> Gradients = new();
|
||||||
static readonly SdfKernels kernels = new();
|
static readonly SdfKernels kernels = new();
|
||||||
|
static uint width;
|
||||||
|
static uint height;
|
||||||
|
|
||||||
static void ConsoleUpdateLine(string s) => Console.Write("\r" + s);
|
static void ConsoleUpdateLine(string s) => Console.Write("\r" + s);
|
||||||
|
|
||||||
public static void Main(string[] args) {
|
public static void Main(string[] args) {
|
||||||
Console.WriteLine("Reading images...");
|
Console.WriteLine("Reading images...");
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
if (!Directory.Exists("Debug")) Directory.CreateDirectory("Debug");
|
||||||
|
Console.WriteLine("Debug mode enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var imagesPath = "images";
|
var imagesPath = "images";
|
||||||
|
for (var i = 0; i < 8; i++) {
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
var pixels = ImageUtil.LoadImage<Vector3>($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png");
|
var pixels = ImageUtil.LoadImage<Vector3>($"./{imagesPath}{Path.DirectorySeparatorChar}{i + 1:00}.png");
|
||||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||||
}
|
}
|
||||||
@@ -39,8 +45,7 @@ public class Program {
|
|||||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||||
pixels = ImageUtil.LoadImage<Vector3>($"./spherefull.png");
|
pixels = ImageUtil.LoadImage<Vector3>($"./spherefull.png");
|
||||||
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
Images.Add(new(pixels, pixels.GetLength(0), pixels.GetLength(1)));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
//check if all the images in Images are the same resolution
|
//check if all the images in Images are the same resolution
|
||||||
if (Images.Select(img => (img.Width, img.Height)).Distinct().Count() > 1) {
|
if (Images.Select(img => (img.Width, img.Height)).Distinct().Count() > 1) {
|
||||||
@@ -48,6 +53,12 @@ public class Program {
|
|||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
width = (uint)Images[0].Width;
|
||||||
|
height = (uint)Images[0].Height;
|
||||||
|
|
||||||
|
// sum all images together
|
||||||
|
if(debug) Images[0].Pixels.SaveImage("Debug/Sum0.png");
|
||||||
|
|
||||||
for (int i = 1; i < Images.Count; i++) {
|
for (int i = 1; i < Images.Count; i++) {
|
||||||
for (int x = 0; x < Images[i].Width; x++) {
|
for (int x = 0; x < Images[i].Width; x++) {
|
||||||
for (int y = 0; y < Images[i].Height; y++) {
|
for (int y = 0; y < Images[i].Height; y++) {
|
||||||
@@ -57,62 +68,63 @@ public class Program {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Images[i].Pixels.SaveImage($"./Sum{i}.png");
|
if(debug)Images[i].Pixels.SaveImage($"Debug/Sum{i}.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine("Creating masks...");
|
Console.WriteLine("Creating masks...");
|
||||||
//for each image pair, create a mask
|
for (var i = 0; i < Images.Count; i++) { //for each image pair, create a mask
|
||||||
var width = (uint)Images[0].Width;
|
var selfMask = SelfMask(Images[i].Pixels);
|
||||||
var height = (uint)Images[0].Height;
|
ImageMasks.Add(new(selfMask, Images[i], new()));
|
||||||
for (int i = 0; i < Images.Count; i++) {
|
if (debug) selfMask.SaveImage($"Debug/selfMask{i}.png");
|
||||||
ImageMasks.Add(new(SelfMask(Images[i].Pixels, width, height), Images[i], new()));
|
if (i >= Images.Count - 1) continue;
|
||||||
if (i < Images.Count - 1) {
|
ConsoleUpdateLine($"Creating mask {i}...");
|
||||||
Console.WriteLine($"Creating mask {i}...");
|
var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels);
|
||||||
var mask = GetABMask(Images[i].Pixels, Images[i + 1].Pixels, width, height);
|
TransitionMasks.Add(new(mask, Images[i], Images[i + 1]));
|
||||||
TransitionMasks.Add(new(mask, Images[i], Images[i + 1]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Edge detecting masks...");
|
|
||||||
//EdgeDetect all masks
|
//EdgeDetect all masks
|
||||||
foreach (var t in ImageMasks) EdgeDetect(t);
|
Console.WriteLine("\nEdge detecting masks...");
|
||||||
|
foreach (var mask in ImageMasks) {
|
||||||
if (outputMasks) {
|
ConsoleUpdateLine($"Edge detecting mask {ImageMasks.IndexOf(mask)}...");
|
||||||
Console.WriteLine("Writing masks...");
|
EdgeDetect(mask);
|
||||||
for (int i = 0; i < TransitionMasks.Count; i++) ImageMasks[i].Mask.SaveImage($"mask{i}.png");
|
|
||||||
}
|
}
|
||||||
|
if (debug)
|
||||||
|
for (var i = 0; i < TransitionMasks.Count; i++)
|
||||||
|
ImageMasks[i].Mask.SaveImage($"Debug/mask{i}.png");
|
||||||
|
|
||||||
Console.WriteLine("Creating SDFs...");
|
Console.WriteLine("Creating SDFs...");
|
||||||
for (var i = 0; i < ImageMasks.Count; i++) {
|
for (var i = 0; i < ImageMasks.Count; i++) {
|
||||||
var mask = ImageMasks[i];
|
var mask = ImageMasks[i];
|
||||||
SDFs.Add(SDF(mask));
|
SDFs.Add(SDF(mask));
|
||||||
if (outputSDFs) SDFs[i].SDF.SaveImage($"sdf{i}.png");
|
if (debug) SDFs[i].SDF.SaveImage($"Debug/sdf{i}.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Creating gradients...");
|
Console.WriteLine("Creating gradients...");
|
||||||
for (var i = 0; i < TransitionMasks.Count; i++) {
|
for (var i = 0; i < TransitionMasks.Count; i++) {
|
||||||
Console.WriteLine($"Generating gradient {i}...");
|
ConsoleUpdateLine($"Generating gradient {i}...");
|
||||||
var gradientData = Gradient(TransitionMasks[i], SDFs[i], SDFs[i + 1]);
|
var gradientData = Gradient(TransitionMasks[i], SDFs[i], SDFs[i + 1]);
|
||||||
Gradients.Add(gradientData);
|
Gradients.Add(gradientData);
|
||||||
if (outputGradients) gradientData.SaveImage($"gradient{i}.png");
|
if (debug) gradientData.SaveImage($"Debug/gradient{i}.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate final image
|
// generate final image
|
||||||
var finalImage = new Vector3[width, height];
|
var finalImage = new Vector3[width, height];
|
||||||
var currStep = 0f;
|
var currStep = 0f;
|
||||||
var stepIncrement = MAX / (Gradients.Count);
|
var stepIncrement = MAX / Gradients.Count;
|
||||||
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
finalImage[x, y] = new Vector3(Images[0].Pixels[x, y].X);
|
|
||||||
|
|
||||||
|
|
||||||
|
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++) {
|
for (var i = 0; i < Gradients.Count; i++) {
|
||||||
var mask = ImageMasks[i + 1];
|
var mask = ImageMasks[i + 1];
|
||||||
var gradient = Gradients[i];
|
var gradient = Gradients[i];
|
||||||
Console.WriteLine($"Applying gradient {i}..., {currStep} -> {currStep + stepIncrement}");
|
Console.WriteLine($"Applying gradient {i}..., {currStep} -> {currStep + stepIncrement}");
|
||||||
for (var x = 0; x < mask.Mask.GetLength(0); x++) {
|
for (var x = 0; x < mask.Mask.GetLength(0); x++) {
|
||||||
for (var y = 0; y < mask.Mask.GetLength(1); y++) {
|
for (var y = 0; y < mask.Mask.GetLength(1); y++) {
|
||||||
if (gradient[x, y].X == 0) continue;
|
if (mask.Mask[x,y].X == 0) continue;
|
||||||
var pixel = new Vector3(Remap(gradient[x, y].X, MIN, MAX, 1.0f - currStep,
|
var pixel = new Vector3(Remap(gradient[x, y].X, MIN, MAX, 1.0f - currStep,
|
||||||
1.0f - (currStep + stepIncrement)));
|
1.0f - (currStep + stepIncrement)));
|
||||||
if (pixel.X > finalImage[x, y].X) finalImage[x, y] = pixel;
|
if (pixel.X > finalImage[x, y].X) finalImage[x, y] = pixel;
|
||||||
@@ -120,34 +132,46 @@ public class Program {
|
|||||||
}
|
}
|
||||||
currStep += stepIncrement;
|
currStep += stepIncrement;
|
||||||
}
|
}
|
||||||
finalImage.SaveImage("final.png");
|
|
||||||
|
finalImage.SaveImage("Debug/Final.png");
|
||||||
|
|
||||||
|
// apply directional blur
|
||||||
|
var iterations = 1;
|
||||||
|
var radius = 100f;
|
||||||
|
var step = .5f;
|
||||||
|
var sigma = 1f;
|
||||||
|
var totalMask = SelfMask(Images[^1].Pixels);
|
||||||
|
totalMask.SaveImage("Debug/TotalMask.png");
|
||||||
|
for (var i = 0; i < iterations; i++) {
|
||||||
|
Console.WriteLine($"Applying directional blur {i + 1}/{iterations}...");
|
||||||
|
finalImage = DirectionalBlur(finalImage, totalMask, radius, step, sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalImage.SaveImage("finalBlur.png");
|
||||||
Console.WriteLine("Done!");
|
Console.WriteLine("Done!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EdgeDetect(MaskData maskData) {
|
static void EdgeDetect(MaskData maskData) {
|
||||||
uint width = (uint)maskData.Image.Width;
|
|
||||||
uint height = (uint)maskData.Image.Height;
|
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
Console.WriteLine("Running edge detection...");
|
Console.WriteLine("Running edge detection...");
|
||||||
kernels.EdgeDetect(maskData.Mask, out var temp);
|
kernels.EdgeDetect(maskData.Mask, out var temp);
|
||||||
maskData.Mask = temp;
|
maskData.Mask = temp;
|
||||||
Parallel.For(0, width * height, parallelOptions, (i) => {
|
Parallel.For(0, width * height, parallelOptions, (i) => {
|
||||||
if(maskData.Mask[i % width, i / width].Y != 0) lock (maskData.Edges) maskData.Edges.Add(new(i % width, i / width));
|
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();
|
sw.Stop();
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"\nEdge pixels: {maskData.Edges.Count} | {maskData.Edges.Count / (sw.ElapsedMilliseconds + 1)} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
|
$"\nEdge pixels: {maskData.Edges.Count} | {width * height / (sw.ElapsedMilliseconds + 1)} pixels/s\n Time: {sw.Elapsed.TotalSeconds:F4}s");
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector3[,] Gradient(TransitionMaskData mask, SDFData sdfA, SDFData sdfB) {
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
Vector3[,] temp = new Vector3[width, height];
|
/*Vector3[,] temp = new Vector3[width, height];
|
||||||
|
|
||||||
var min = MAX;
|
var min = MAX;
|
||||||
var max = MIN;
|
var max = MIN;
|
||||||
@@ -168,78 +192,58 @@ public class Program {
|
|||||||
|
|
||||||
if (gradient < min) min = gradient;
|
if (gradient < min) min = gradient;
|
||||||
if (gradient > max) max = gradient;
|
if (gradient > max) max = gradient;
|
||||||
});
|
});*/
|
||||||
|
|
||||||
Console.WriteLine(
|
kernels.Gradient(mask.Mask, sdfA.SDF, sdfB.SDF, out var temp);
|
||||||
$"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / (float)sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
Console.WriteLine($"Gradient Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / (float)sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
Console.WriteLine($"Min: {min} | Max: {max}");
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDFData SDF(MaskData mask) {
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
Parallel.For(0, width * height, parallelOptions, (i) =>
|
kernels.Sdf(mask.Edges.ToArray(), (int)width, (int)height, out var temp);
|
||||||
{
|
Console.WriteLine($"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
//convert 1D index to 2D index
|
|
||||||
var x = (int)(i % width);
|
|
||||||
var y = (int)(i / width);
|
|
||||||
Vector2 p = new(x / (float)width, y / (float)height); //get the pixel position as a Vector2
|
|
||||||
|
|
||||||
float minDist = MAX + 1; //initialize the minimum distance to the maximum possible value
|
|
||||||
|
|
||||||
//loop through all the pixels in the mask
|
|
||||||
foreach (var edge in mask.Edges) {
|
|
||||||
Vector2 edgeNorm = new(edge.X / (float)width, edge.Y / (float)height);
|
|
||||||
float dist = Vector2.DistanceSquared(p, edgeNorm);
|
|
||||||
if (dist < minDist) minDist = dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minDist > MAX)
|
|
||||||
minDist = MAX;
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Console.WriteLine(
|
|
||||||
$"\nSDF Generation Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
|
||||||
sw.Restart();
|
sw.Restart();
|
||||||
Parallel.For(0, width * height, parallelOptions, (i) =>
|
var absMax = 0f;
|
||||||
{
|
foreach (var pixel in temp) {
|
||||||
|
if (pixel.X > absMax) absMax = pixel.X;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parallel.For(0, width * height, parallelOptions, (i) => {
|
||||||
//convert 1D index to 2D index
|
//convert 1D index to 2D index
|
||||||
var x = (int)(i % width);
|
var x = (int)(i % width);
|
||||||
var y = (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();
|
sw.Stop();
|
||||||
|
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"SDF Normalization Time: {sw.Elapsed.TotalSeconds:N4}s ({iterCount / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
$"SDF Normalization Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
Console.WriteLine("AbsMax: " + AbsMax);
|
|
||||||
return new(temp);
|
return new(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Vector3[,] DirectionalBlur(Vector3[,] image, Vector3[,] mask, float radius = 3f, float step = .5f, float sigma = 1f) {
|
||||||
|
var sw = new Stopwatch();
|
||||||
|
sw.Start();
|
||||||
|
kernels.DirectionalBlur(image, mask, out var temp, radius, step, sigma);
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Directional Blur Time: {sw.Elapsed.TotalSeconds:N4}s ({width * height / sw.Elapsed.TotalSeconds:N0} pixels/s)");
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static float EuclideanDistance(Vector2 a, Vector2 b) =>
|
static float EuclideanDistance(Vector2 a, Vector2 b) =>
|
||||||
MathF.Sqrt(MathF.Pow(a.X - b.X, 2) + MathF.Pow(a.Y - b.Y, 2));
|
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) {
|
static Vector3[,] GetABMask(Vector3[,] A, Vector3[,] B) {
|
||||||
kernels.ABMask(A, B, out var temp);
|
kernels.ABMask(A, B, out var temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector3[,] SelfMask(Vector3[,] A, uint resX, uint resY) {
|
static Vector3[,] SelfMask(Vector3[,] A) {
|
||||||
kernels.SelfMask(A, out var temp);
|
kernels.SelfMask(A, out var temp);
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ using System.Numerics;
|
|||||||
namespace SDFMapCreator;
|
namespace SDFMapCreator;
|
||||||
|
|
||||||
public record Image(Vector3[,] Pixels, int Width, int Height);
|
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 Vector3[,] Mask { get; set; } = Mask;
|
||||||
public List<Vector2> Edges { get; set; } = Edges;
|
public List<Vector2> Edges { get; set; } = Edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record SDFData(Vector3[,] SDF);
|
public record SDFData(Vector3[,] SDF);
|
||||||
|
|
||||||
public record TransitionMaskData(Vector3[,] Mask, Image ImageA, Image ImageB);
|
public record TransitionMaskData(Vector3[,] Mask, Image ImageA, Image ImageB);
|
||||||
@@ -8,66 +8,67 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ILGPU" Version="1.5.2" />
|
<PackageReference Include="ILGPU" Version="1.5.2"/>
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
<PackageReference Include="ILGPU.Algorithms" Version="1.5.2"/>
|
||||||
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7"/>
|
||||||
|
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="1.png">
|
<None Update="1.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="2.png">
|
<None Update="2.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="TestPattern.png">
|
<None Update="TestPattern.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\01.png">
|
<None Update="images\01.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\02.png">
|
<None Update="images\02.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\03.png">
|
<None Update="images\03.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\04.png">
|
<None Update="images\04.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\05.png">
|
<None Update="images\05.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\06.png">
|
<None Update="images\06.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\07.png">
|
<None Update="images\07.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="images\08.png">
|
<None Update="images\08.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="spherecut.png">
|
<None Update="spherecut.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="spherefull.png">
|
<None Update="spherefull.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="spherehalf.png">
|
<None Update="spherehalf.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="spherehalf32.png">
|
<None Update="spherehalf32.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="spherefull32.png">
|
<None Update="spherefull32.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="spherecut32.png">
|
<None Update="spherecut32.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="sphereempty.png">
|
<None Update="sphereempty.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -5,48 +5,163 @@ using ILGPU.Runtime;
|
|||||||
namespace SDFMapCreator;
|
namespace SDFMapCreator;
|
||||||
|
|
||||||
public partial class SdfKernels {
|
public partial class SdfKernels {
|
||||||
private static void SelfMaskKernel(Index2D index, ArrayView2D<Vector3, Stride2D.DenseX> input, ArrayView2D<Vector3, Stride2D.DenseX> mask) {
|
|
||||||
int x = index.X;
|
private const float LUMA_THRESHOLD = 0.0f;
|
||||||
int y = index.Y;
|
static void SelfMaskKernel(Index2D index, ArrayView2D<Vector3, Stride2D.DenseX> input, ArrayView2D<Vector3, Stride2D.DenseX> mask) {
|
||||||
Vector3 value = input[x, y];
|
var x = index.X;
|
||||||
float lumaA = (value.X + value.Y + value.Z)/3f;
|
var y = index.Y;
|
||||||
float r = lumaA > 0.99f ? 1f : 0f;
|
var value = input[x, y];
|
||||||
mask[x,y] = new (r, 0f, 0f);
|
var lumaA = value.X;
|
||||||
|
var r = lumaA > LUMA_THRESHOLD ? 1f : 0f;
|
||||||
|
mask[x, y] = new(r, 0f, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ABMaskKernel(Index2D index,
|
static void ABMaskKernel(Index2D index,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX> A,
|
ArrayView2D<Vector3, Stride2D.DenseX> A,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX> B,
|
ArrayView2D<Vector3, Stride2D.DenseX> B,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX> mask
|
ArrayView2D<Vector3, Stride2D.DenseX> mask
|
||||||
) {
|
) {
|
||||||
int x = index.X;
|
var x = index.X;
|
||||||
int y = index.Y;
|
var y = index.Y;
|
||||||
Vector3 valueA = A[x, y];
|
var valueA = A[x, y];
|
||||||
Vector3 valueB = B[x, y];
|
var valueB = B[x, y];
|
||||||
float lumaA = (valueA.X + valueA.Y + valueA.Z) / 3f;
|
var lumaA = valueA.X;
|
||||||
float lumaB = (valueB.X + valueB.Y + valueB.Z) / 3f;
|
var lumaB = valueB.X;
|
||||||
float r = lumaA > 0.99f && lumaB > 0.99f ? 1f : 0f;
|
var r = lumaB - lumaA > LUMA_THRESHOLD ? 1f : 0f;
|
||||||
mask[x, y] = new (r, 0f, 0f);
|
mask[x, y] = new(r, 0f, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EdgeKernel(Index2D index,
|
static void EdgeKernel(Index2D index,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX> mask,
|
ArrayView2D<Vector3, Stride2D.DenseX> mask,
|
||||||
uint width, uint height
|
uint width, uint height
|
||||||
) { // early exit if not on mask
|
) { // early exit if not on mask
|
||||||
if (mask[index].X == 0f) return;
|
if (mask[index].X == 0f) return;
|
||||||
int x = index.X;
|
var x = index.X;
|
||||||
int y = index.Y;
|
var y = index.Y;
|
||||||
//if we are on the edge of the image, 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;
|
if (x == 0 || y == 0 || x == width - 1 || y == height - 1) {
|
||||||
|
mask[index].Y = 1f; //set the edge flag
|
||||||
//check the 3x3 kernel
|
return;
|
||||||
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)
|
//check the 3x3 kernel
|
||||||
continue; //skip out of bounds pixels
|
for (var xi = x - 1; xi <= x + 1; xi++) {
|
||||||
if (mask[xi, yi].X == 0f)
|
for (var yi = y - 1; yi <= y + 1; yi++) {
|
||||||
mask[index].Y = 1f; //if we find a black pixel, return true
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
output[x, y] = new Vector3(float.Abs((gradient.X * 0.5f) + 0.5f),
|
||||||
|
float.Abs((gradient.Y * 0.5f) + 0.5f), 0.5f);
|
||||||
|
return;
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (gradient == Vector2.Zero) {
|
||||||
|
output[x, y] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,110 +5,195 @@ using ILGPU.Runtime;
|
|||||||
using ILGPU.Runtime.CPU;
|
using ILGPU.Runtime.CPU;
|
||||||
using ILGPU.Runtime.Cuda;
|
using ILGPU.Runtime.Cuda;
|
||||||
using ILGPU.Runtime.OpenCL;
|
using ILGPU.Runtime.OpenCL;
|
||||||
|
using ILGPU.Algorithms;
|
||||||
|
|
||||||
namespace SDFMapCreator;
|
namespace SDFMapCreator;
|
||||||
|
|
||||||
public partial class SdfKernels {
|
public partial class SdfKernels {
|
||||||
private Context gpuContext;
|
Context gpuContext;
|
||||||
|
|
||||||
public SdfKernels() {
|
public SdfKernels() {
|
||||||
// Initialize the GPU context
|
// Initialize the GPU context
|
||||||
gpuContext = Context.Create(builder => builder
|
gpuContext = Context.Create(builder => builder
|
||||||
.OpenCL()
|
.OpenCL()
|
||||||
.Cuda()
|
.Cuda()
|
||||||
.CPU()
|
.CPU()
|
||||||
|
.Math(MathMode.Fast32BitOnly)
|
||||||
|
.EnableAlgorithms()
|
||||||
);
|
);
|
||||||
|
|
||||||
Console.WriteLine("Reading available accelerators (CUDA only)...");
|
Console.WriteLine("Reading available accelerators (CUDA only)...");
|
||||||
foreach (var device in gpuContext.GetCudaDevices()) {
|
foreach (var device in gpuContext.GetCudaDevices()) {
|
||||||
using Accelerator accelerator = device.CreateAccelerator(gpuContext);
|
using var accelerator = device.CreateAccelerator(gpuContext);
|
||||||
Console.WriteLine($"{GetInfoString(accelerator)}");
|
Console.WriteLine($"{GetInfoString(accelerator)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Reading available accelerators (OpenCL only)...");
|
Console.WriteLine("Reading available accelerators (OpenCL only)...");
|
||||||
foreach (var device in gpuContext.GetCLDevices()) {
|
foreach (var device in gpuContext.GetCLDevices()) {
|
||||||
using Accelerator accelerator = device.CreateAccelerator(gpuContext);
|
using var accelerator = device.CreateAccelerator(gpuContext);
|
||||||
Console.WriteLine($"{GetInfoString(accelerator)}");
|
Console.WriteLine($"{GetInfoString(accelerator)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Reading available accelerators (CPU only)...");
|
Console.WriteLine("Reading available accelerators (CPU only)...");
|
||||||
foreach (var device in gpuContext.GetCPUDevices()) {
|
foreach (var device in gpuContext.GetCPUDevices()) {
|
||||||
using Accelerator accelerator = device.CreateAccelerator(gpuContext);
|
using var accelerator = device.CreateAccelerator(gpuContext);
|
||||||
Console.WriteLine($"{GetInfoString(accelerator)}");
|
Console.WriteLine($"{GetInfoString(accelerator)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelfMask(Vector3[,] input, out Vector3[,] mask) {
|
public void SelfMask(Vector3[,] input, out Vector3[,] mask) {
|
||||||
var dev = gpuContext.GetPreferredDevice(preferCPU:false);
|
var dev = gpuContext.GetPreferredDevice(false);
|
||||||
int width = input.GetLength(0);
|
var width = input.GetLength(0);
|
||||||
int height = input.GetLength(1);
|
var height = input.GetLength(1);
|
||||||
mask = new Vector3[width, height];
|
mask = new Vector3[width, height];
|
||||||
using Accelerator accelerator = dev.CreateAccelerator(gpuContext);
|
using var accelerator = dev.CreateAccelerator(gpuContext);
|
||||||
|
|
||||||
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||||
buffer.CopyFromCPU(input);
|
buffer.CopyFromCPU(input);
|
||||||
|
|
||||||
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||||
|
|
||||||
var selfMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<Vector3, Stride2D.DenseX>,
|
var selfMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX>>(SelfMaskKernel);
|
ArrayView2D<Vector3, Stride2D.DenseX>>(SelfMaskKernel);
|
||||||
|
|
||||||
selfMaskKernel(new (width, height), buffer.View, maskBuffer.View);
|
selfMaskKernel(new(width, height), buffer.View, maskBuffer.View);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
|
||||||
mask = maskBuffer.GetAsArray2D();
|
mask = maskBuffer.GetAsArray2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ABMask(Vector3[,] A, Vector3[,] B, out Vector3[,] mask) {
|
public void ABMask(Vector3[,] A, Vector3[,] B, out Vector3[,] mask) {
|
||||||
var dev = gpuContext.GetPreferredDevice(preferCPU:false);
|
var dev = gpuContext.GetPreferredDevice(false);
|
||||||
int width = A.GetLength(0);
|
var width = A.GetLength(0);
|
||||||
int height = A.GetLength(1);
|
var height = A.GetLength(1);
|
||||||
mask = new Vector3[width, height];
|
mask = new Vector3[width, height];
|
||||||
using Accelerator accelerator = dev.CreateAccelerator(gpuContext);
|
using var accelerator = dev.CreateAccelerator(gpuContext);
|
||||||
|
|
||||||
using var bufferA = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
using var bufferA = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||||
bufferA.CopyFromCPU(A);
|
bufferA.CopyFromCPU(A);
|
||||||
|
|
||||||
using var bufferB = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
using var bufferB = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||||
bufferB.CopyFromCPU(B);
|
bufferB.CopyFromCPU(B);
|
||||||
|
|
||||||
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
using var maskBuffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||||
|
|
||||||
var abMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
var abMaskKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX>,
|
ArrayView2D<Vector3, Stride2D.DenseX>,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX>>(ABMaskKernel);
|
ArrayView2D<Vector3, Stride2D.DenseX>>(ABMaskKernel);
|
||||||
|
|
||||||
abMaskKernel(new (width, height), bufferA.View, bufferB.View, maskBuffer.View);
|
abMaskKernel(new(width, height), bufferA.View, bufferB.View, maskBuffer.View);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
|
||||||
mask = maskBuffer.GetAsArray2D();
|
mask = maskBuffer.GetAsArray2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EdgeDetect(Vector3[,] mask, out Vector3[,] edge) {
|
public void EdgeDetect(Vector3[,] mask, out Vector3[,] edge) {
|
||||||
var dev = gpuContext.GetPreferredDevice(preferCPU:false);
|
var dev = gpuContext.GetPreferredDevice(false);
|
||||||
int width = mask.GetLength(0);
|
var width = mask.GetLength(0);
|
||||||
int height = mask.GetLength(1);
|
var height = mask.GetLength(1);
|
||||||
edge = new Vector3[width, height];
|
edge = new Vector3[width, height];
|
||||||
using Accelerator accelerator = dev.CreateAccelerator(gpuContext);
|
using var accelerator = dev.CreateAccelerator(gpuContext);
|
||||||
|
|
||||||
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new (width, height));
|
using var buffer = accelerator.Allocate2DDenseX<Vector3>(new(width, height));
|
||||||
buffer.CopyFromCPU(mask);
|
buffer.CopyFromCPU(mask);
|
||||||
|
|
||||||
var edgeKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
var edgeKernel = accelerator.LoadAutoGroupedStreamKernel<Index2D,
|
||||||
ArrayView2D<Vector3, Stride2D.DenseX>, uint, uint>(EdgeKernel);
|
ArrayView2D<Vector3, Stride2D.DenseX>, uint, uint>(EdgeKernel);
|
||||||
|
|
||||||
edgeKernel(new (width, height), buffer.View, (uint)width, (uint)height);
|
edgeKernel(new(width, height), buffer.View, (uint)width, (uint)height);
|
||||||
|
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
|
||||||
edge = buffer.GetAsArray2D();
|
edge = buffer.GetAsArray2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetInfoString(Accelerator a)
|
public void Sdf(Vector2[] edges, int width, int height, out Vector3[,] sdf) {
|
||||||
{
|
var dev = gpuContext.GetPreferredDevice(false);
|
||||||
StringWriter infoString = new StringWriter();
|
using var accelerator = dev.CreateAccelerator(gpuContext);
|
||||||
|
|
||||||
|
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 dev = gpuContext.GetPreferredDevice(false);
|
||||||
|
var width = mask.GetLength(0);
|
||||||
|
var height = mask.GetLength(1);
|
||||||
|
gradient = new Vector3[width, height];
|
||||||
|
using var accelerator = dev.CreateAccelerator(gpuContext);
|
||||||
|
|
||||||
|
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, float radius = 3f,
|
||||||
|
float step = .5f, float sigma = 1f) {
|
||||||
|
var dev = gpuContext.GetPreferredDevice(false);
|
||||||
|
var width = image.GetLength(0);
|
||||||
|
var height = image.GetLength(1);
|
||||||
|
output = new Vector3[width, height];
|
||||||
|
using var accelerator = dev.CreateAccelerator(gpuContext);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
a.PrintInformation(infoString);
|
||||||
return infoString.ToString();
|
return infoString.ToString();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user