-
Notifications
You must be signed in to change notification settings - Fork 0
/
HemanApi.cs
181 lines (142 loc) · 6.81 KB
/
HemanApi.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
using System;
using System.IO;
using System.Runtime.InteropServices;
using CC = System.Runtime.InteropServices.CallingConvention;
namespace HemanWinUI
{
internal class HemanApi
{
const int Size = 512;
static readonly int[] cpLocations =
{
000, // Dark Blue
126, // Light Blue
127, // Yellow
128, // Dark Green
160, // Brown
200, // White
255, // White
};
static readonly uint[] cpColors =
{
0x001070, // Dark Blue
0x2C5A7C, // Light Blue
0xE0F0A0, // Yellow
0x5D943C, // Dark Green
0x606011, // Brown
0xFFFFFF, // White
0xFFFFFF, // White
};
static readonly float[] lightPos = { -0.5f, 0.5f, 1.0f };
public static int GetNumberOfThreads()
{
return NativeMethods.heman_get_num_threads();
}
public static string RenderExample()
{
IntPtr[] frames = new IntPtr[5];
GCHandle cpLocationsHandle = GCHandle.Alloc(cpLocations, GCHandleType.Pinned);
GCHandle cpColorsHandle = GCHandle.Alloc(cpColors, GCHandleType.Pinned);
GCHandle lightPosHandle = GCHandle.Alloc(lightPos, GCHandleType.Pinned);
GCHandle framesHandle = GCHandle.Alloc(frames, GCHandleType.Pinned);
try
{
IntPtr cpLocationsPointer = cpLocationsHandle.AddrOfPinnedObject();
IntPtr cpColorsPointer = cpColorsHandle.AddrOfPinnedObject();
IntPtr lightPosPointer = lightPosHandle.AddrOfPinnedObject();
IntPtr framesPointer = framesHandle.AddrOfPinnedObject();
// Create a gradient
var grad = NativeMethods.heman_color_create_gradient(256, cpColors.Length, cpLocationsPointer, cpColorsPointer);
// Generate the heightmap.
var time = (DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0)).Seconds;
var hmap = NativeMethods.heman_generate_island_heightmap(Size, Size, time);
var hmapViz = NativeMethods.heman_ops_normalize_f32(hmap, -0.5f, 0.5f);
// Compute ambient occlusion.
var occ = NativeMethods.heman_lighting_compute_occlusion(hmap);
// Create a normal map.
var norm = NativeMethods.heman_lighting_compute_normals(hmap);
var normviz = NativeMethods.heman_ops_normalize_f32(norm, -1, 1);
// Create an albedo image.
var albedo = NativeMethods.heman_color_apply_gradient(hmap, -0.5f, 0.5f, grad);
NativeMethods.heman_image_destroy(grad);
// Perform lighting.
var final = NativeMethods.heman_lighting_apply(hmap, albedo, 1, 1, 0.5f, lightPosPointer);
// Create film strip image
frames[0] = NativeMethods.heman_color_from_grayscale(hmapViz);
frames[1] = NativeMethods.heman_color_from_grayscale(occ);
frames[2] = normviz;
frames[3] = albedo;
frames[4] = final;
var filmstrip = NativeMethods.heman_ops_stitch_horizontal(framesPointer, frames.Length);
var path = Path.GetTempPath();
var randomFilename = Path.GetRandomFileName();
var fileName = Path.Combine(path, randomFilename.Split('.')[0] + ".png");
NativeMethods.hut_write_image(fileName, filmstrip, 0f, 1f);
// Copy the final IntPtr data to a HemanImage struct
var finalImage = Marshal.PtrToStructure<HemanImage>(final);
var width = finalImage.Width;
// Cleanup
NativeMethods.heman_image_destroy(frames[0]);
NativeMethods.heman_image_destroy(frames[1]);
NativeMethods.heman_image_destroy(hmap);
NativeMethods.heman_image_destroy(hmapViz);
NativeMethods.heman_image_destroy(occ);
NativeMethods.heman_image_destroy(norm);
NativeMethods.heman_image_destroy(normviz);
NativeMethods.heman_image_destroy(albedo);
NativeMethods.heman_image_destroy(final);
return fileName;
}
finally
{
FreeHandle(cpLocationsHandle);
FreeHandle(cpColorsHandle);
FreeHandle(lightPosHandle);
FreeHandle(framesHandle);
}
}
private static void FreeHandle(GCHandle handle)
{
if (handle.IsAllocated)
{
handle.Free();
}
}
private static class NativeMethods
{
const string DLL = "heman.dll";
[DllImport(DLL)]
internal static extern int heman_get_num_threads();
[DllImport(DLL)]
internal static extern IntPtr heman_color_create_gradient(int width, int num_colors, IntPtr cp_locations, IntPtr cp_colors);
[DllImport(DLL)]
internal static extern IntPtr heman_generate_island_heightmap(int width, int height, int seed);
[DllImport(DLL)]
internal static extern IntPtr heman_ops_normalize_f32(IntPtr source, float minval, float maxval);
[DllImport(DLL)]
internal static extern IntPtr heman_lighting_compute_occlusion(IntPtr heightmap);
[DllImport(DLL)]
internal static extern IntPtr heman_lighting_compute_normals(IntPtr heightmap);
[DllImport(DLL)]
internal static extern IntPtr heman_color_apply_gradient(IntPtr heightmap, float minheight, float maxheight, IntPtr gradient);
[DllImport(DLL)]
internal static extern void heman_image_destroy(IntPtr img);
[DllImport(DLL)]
internal static extern IntPtr heman_lighting_apply(IntPtr heightmap, IntPtr colorbuffer, float occlusion, float diffuse, float diffuse_softening, IntPtr light_position);
[DllImport(DLL)]
internal static extern IntPtr heman_color_from_grayscale(IntPtr gray);
[DllImport(DLL)]
internal static extern IntPtr heman_ops_stitch_horizontal(IntPtr images, int count);
[DllImport(DLL, CharSet = CharSet.Ansi)]
internal static extern void hut_write_image(string filename, IntPtr img, float minv, float maxv);
}
[StructLayout(LayoutKind.Sequential)]
public struct HemanImage
{
public int Width;
public int Height;
public int NBands;
public IntPtr data; // Array of floats which we don't need to access
}
}
}