Last active
April 1, 2019 19:41
-
-
Save Auburn/6c26380869f99e998c5122d044036f2c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "MyForm.h" | |
#include "FastNoise.h" | |
#include <cmath> | |
#include <Windows.h> | |
using namespace Project1; | |
using namespace System::Windows::Forms; | |
[STAThread] | |
int main(array<String^>^ args) | |
{ | |
Application::EnableVisualStyles(); | |
Application::SetCompatibleTextRenderingDefault(false); | |
Project1::MyForm form; | |
Application::Run(%form); | |
return 0; | |
} | |
typedef struct RGB | |
{ | |
unsigned char r; | |
unsigned char g; | |
unsigned char b; | |
} RGB; | |
typedef struct HSV | |
{ | |
unsigned char h; | |
unsigned char s; | |
unsigned char v; | |
} HSV; | |
static RGB HSV2RGB(HSV hsv); | |
void MyForm::TextEnter(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) | |
{ | |
if (e->KeyCode.Equals(Keys::Enter)) | |
{ | |
e->Handled = true; | |
RebuildBitmap(nullptr, nullptr); | |
} | |
} | |
void MyForm::MouseScroll(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) | |
{ | |
auto textBox = dynamic_cast<System::Windows::Forms::TextBox^>(sender); | |
if (!textBox || e->Delta == 0) | |
return; | |
float newValue = 0; | |
try { newValue = Convert::ToSingle(textBox->Text, format); } | |
catch (System::FormatException^ e) { MessageBox::Show(e->Message); } | |
if (e->Delta > 0) | |
newValue *= 1.25f * (e->Delta / WHEEL_DELTA); | |
else | |
newValue /= -1.25f * (e->Delta / WHEEL_DELTA); | |
textBox->Text = newValue.ToString(); | |
RebuildBitmap(nullptr, nullptr); | |
} | |
void MyForm::MouseScrollFix(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) | |
{ | |
auto updown = dynamic_cast<System::Windows::Forms::NumericUpDown^>(sender); | |
if (!updown || e->Delta == 0) | |
return; | |
auto hlm = dynamic_cast<System::Windows::Forms::HandledMouseEventArgs^>(e); | |
if (hlm) | |
hlm->Handled = true; | |
System::Decimal newValue = 0; | |
newValue = min(max(System::Decimal::Add(updown->Value, updown->Increment * (e->Delta / WHEEL_DELTA)) | |
, updown->Minimum), updown->Maximum); | |
updown->Value = newValue; | |
} | |
void Project1::MyForm::randSeed_Click(System::Object ^ sender, System::EventArgs ^ e) | |
{ | |
Random^ r = gcnew Random(); | |
seedBox->Text = r->Next().ToString(); | |
RebuildBitmap(nullptr, nullptr); | |
} | |
void MyForm::RebuildBitmap(System::Object^ sender, System::EventArgs^ e) | |
{ | |
FastNoise fNoise; | |
FastNoise perturbNoise; | |
perturbNoise.SetFrequency(0.015f); | |
int size = 512; | |
try { size = Convert::ToInt32(sizeBox->Text); } | |
catch (System::FormatException^ e) { MessageBox::Show("Size: " + e->Message); } | |
if (!noiseTypeList->Text->Contains("Vector")) | |
fNoise.SetNoiseType((FastNoise::NoiseType)noiseTypeList->SelectedIndex); | |
fNoise.SetInterp((FastNoise::Interp)interpBox->SelectedIndex); | |
try { fNoise.SetSeed(Convert::ToInt32(seedBox->Text)); } | |
catch (System::FormatException^ e) { MessageBox::Show("Seed: " + e->Message); } | |
try { fNoise.SetFrequency(Convert::ToSingle(frequencyBox->Text, format)); } | |
catch (System::FormatException^ e) { MessageBox::Show("Frequency: " + e->Message); } | |
fNoise.SetFractalType((FastNoise::FractalType)fractalTypeBox->SelectedIndex); | |
try { fNoise.SetFractalOctaves(Convert::ToInt32(octavesBox->Value)); } | |
catch (System::FormatException^ e) { MessageBox::Show("Fractal octaves: " + e->Message); } | |
try { fNoise.SetFractalLacunarity(Convert::ToSingle(lacunarityBox->Text, format)); } | |
catch (System::FormatException^ e) { MessageBox::Show("Fractal lacunarity: " + e->Message); } | |
try { fNoise.SetFractalGain(Convert::ToSingle(gainBox->Text, format)); } | |
catch (System::FormatException^ e) { MessageBox::Show("Fractal gain: " + e->Message); } | |
try | |
{ | |
fNoise.SetGradientPerturbAmp(Convert::ToSingle(warpAmpBox->Text, format)); | |
perturbNoise.SetGradientPerturbAmp(Convert::ToSingle(warpAmpBox->Text, format)); | |
} | |
catch (System::FormatException^ e) { MessageBox::Show("Warp amplitude: " + e->Message); } | |
try { perturbNoise.SetFrequency(Convert::ToSingle(perturbFreqBox->Text, format)); } | |
catch (System::FormatException^ e) { MessageBox::Show("Perturb frequency: " + e->Message); } | |
fNoise.SetCellularDistanceFunction((FastNoise::CellularDistanceFunction)distanceFunctionBox->SelectedIndex); | |
fNoise.SetCellularReturnType((FastNoise::CellularReturnType)cellReturnTypeBox->SelectedIndex); | |
fNoise.SetCellularDistance2Indices(Convert::ToInt32(distance2index0->Value), Convert::ToInt32(distance2index1->Value)); | |
try { fNoise.SetCellularJitter(Convert::ToSingle(jitterBox->Text, format)); } | |
catch (System::FormatException^ e) { MessageBox::Show("Cellular jitter: " + e->Message); } | |
FastNoise* lookupNoise = new FastNoise(); | |
lookupNoise->SetFrequency(0.2f); | |
lookupNoise->SetNoiseType(FastNoise::Simplex); | |
fNoise.SetCellularNoiseLookup(lookupNoise); | |
Bitmap^ bitmap = (gcnew Bitmap(size, size)); | |
FN_DECIMAL noise; | |
FN_DECIMAL minN = 99999; | |
FN_DECIMAL maxN = -99999; | |
FN_DECIMAL avg = 0; | |
LARGE_INTEGER ticks; | |
LARGE_INTEGER start; | |
LARGE_INTEGER end; | |
LONGLONG current = 0; | |
QueryPerformanceFrequency(&ticks); | |
bool get3d = checkBox3D->Checked; | |
int halfSize = size / 2; | |
int index = 0; | |
if (!noiseTypeList->Text->Contains("Perturb")) | |
{ | |
FN_DECIMAL* noiseValues = new FN_DECIMAL[size*size]; | |
int warpIndex = positionWarpBox->SelectedIndex; | |
QueryPerformanceCounter(&start); | |
if (get3d) | |
{ | |
for (int x = 0; x < size; x++) | |
{ | |
for (int y = 0; y < size; y++) | |
{ | |
FN_DECIMAL xf = FN_DECIMAL(x - halfSize); | |
FN_DECIMAL yf = FN_DECIMAL(y - halfSize); | |
FN_DECIMAL zf = FN_DECIMAL(zPos); | |
switch (warpIndex) | |
{ | |
case 1: | |
perturbNoise.GradientPerturb(xf, yf, zf); | |
break; | |
case 2: | |
perturbNoise.GradientPerturbFractal(xf, yf, zf); | |
break; | |
} | |
noise = fNoise.GetNoise(xf, yf, zf); | |
avg += noise; | |
maxN = fmax(maxN, noise); | |
minN = fmin(minN, noise); | |
noiseValues[index++] = noise; | |
} | |
} | |
} | |
else | |
{ | |
for (int x = 0; x < size; x++) | |
{ | |
for (int y = 0; y < size; y++) | |
{ | |
FN_DECIMAL xf = FN_DECIMAL(x - halfSize); | |
FN_DECIMAL yf = FN_DECIMAL(y - halfSize); | |
switch (warpIndex) | |
{ | |
case 1: | |
perturbNoise.GradientPerturb(xf, yf); | |
break; | |
case 2: | |
perturbNoise.GradientPerturbFractal(xf, yf); | |
break; | |
} | |
noise = fNoise.GetNoise(xf, yf); | |
avg += noise; | |
maxN = fmax(maxN, noise); | |
minN = fmin(minN, noise); | |
noiseValues[index++] = noise; | |
} | |
} | |
} | |
QueryPerformanceCounter(&end); | |
current += end.QuadPart - start.QuadPart; | |
avg /= index - 1; | |
index = 0; | |
FN_DECIMAL scale = 255 / (maxN - minN); | |
for (int x = 0; x < size; x++) | |
{ | |
for (int y = 0; y < size; y++) | |
{ | |
noise = noiseValues[index++]; | |
unsigned char value = (unsigned char)fmax(0, fmin(255, (noise - minN) * scale)); | |
if (invertBox->Checked) | |
value = 255 - value; | |
bitmap->SetPixel(x, y, Color::FromArgb(255, value, value, value)); | |
} | |
} | |
delete[] noiseValues; | |
} | |
else | |
{ | |
FN_DECIMAL* noiseValues = new FN_DECIMAL[size*size * 3]; | |
bool fractal = noiseTypeList->Text->Contains("Fractal"); | |
QueryPerformanceCounter(&start); | |
if (get3d) | |
{ | |
for (int x = 0; x < size; x++) | |
{ | |
for (int y = 0; y < size; y++) | |
{ | |
FN_DECIMAL xf = (FN_DECIMAL)x; | |
FN_DECIMAL yf = (FN_DECIMAL)y; | |
FN_DECIMAL zf = (FN_DECIMAL)zPos; | |
if (fractal) | |
fNoise.GradientPerturbFractal(xf, yf, zf); | |
else | |
fNoise.GradientPerturb(xf, yf, zf); | |
xf -= x; | |
yf -= y; | |
zf -= zPos; | |
avg += xf + yf + zf; | |
maxN = fmax(maxN, fmax(fmax(xf, yf), zf)); | |
minN = fmin(minN, fmin(fmin(xf, yf), zf)); | |
noiseValues[index++] = xf; | |
noiseValues[index++] = yf; | |
noiseValues[index++] = zf; | |
} | |
} | |
} | |
else | |
{ | |
for (int x = 0; x < size; x++) | |
{ | |
for (int y = 0; y < size; y++) | |
{ | |
FN_DECIMAL xf = (FN_DECIMAL)x; | |
FN_DECIMAL yf = (FN_DECIMAL)y; | |
if (fractal) | |
fNoise.GradientPerturbFractal(xf, yf); | |
else | |
fNoise.GradientPerturb(xf, yf); | |
xf -= x; | |
yf -= y; | |
avg += xf + yf; | |
maxN = fmax(maxN, fmax(xf, yf)); | |
minN = fmin(minN, fmin(xf, yf)); | |
noiseValues[index++] = xf; | |
noiseValues[index++] = yf; | |
} | |
} | |
} | |
QueryPerformanceCounter(&end); | |
current += end.QuadPart - start.QuadPart; | |
if (get3d) | |
avg /= (index - 1) * 3; | |
else | |
avg /= (index - 1) * 2; | |
index = 0; | |
FN_DECIMAL scale = 255 / (maxN - minN); | |
for (int x = 0; x < size; x++) | |
{ | |
for (int y = 0; y < size; y++) | |
{ | |
unsigned char red; | |
unsigned char green; | |
unsigned char blue; | |
if (get3d) | |
{ | |
red = (unsigned char)fmax(0, fmin(255, (noiseValues[index++] - minN) * scale)); | |
green = (unsigned char)fmax(0, fmin(255, (noiseValues[index++] - minN) * scale)); | |
blue = (unsigned char)fmax(0, fmin(255, (noiseValues[index++] - minN) * scale)); | |
} | |
else | |
{ | |
RGB rgb = HSV2RGB(HSV{ (unsigned char)((noiseValues[index++] - minN) * scale), 255, (unsigned char)((noiseValues[index++] - minN) * scale) }); | |
red = rgb.r; | |
green = rgb.g; | |
blue = rgb.b; | |
} | |
if (invertBox->Checked) | |
{ | |
red = 255 - red; | |
green = 255 - green; | |
blue = 255 - blue; | |
} | |
bitmap->SetPixel(x, y, Color::FromArgb(255, red, green, blue)); | |
} | |
} | |
delete noiseValues; | |
} | |
delete pictureBox1->Image; | |
pictureBox1->Image = bitmap; | |
maxLabel->Text = maxN.ToString(); | |
minLabel->Text = minN.ToString(); | |
meanLabel->Text = avg.ToString(); | |
timeLabel->Text = long(current / (ticks.QuadPart * 0.001)).ToString(); | |
} | |
void MyForm::MyForm_Load(System::Object^ sender, System::EventArgs^ e) | |
{ | |
UpdateBoxes(nullptr, nullptr); | |
} | |
void MyForm::UpdateBoxes(System::Object^ sender, System::EventArgs^ e) | |
{ | |
distance2index0->Value = min( | |
Convert::ToInt32(distance2index0->Value), | |
Convert::ToInt32(distance2index1->Value) - 1); | |
bool fractal = noiseTypeList->Text->Contains("Fractal"); | |
bool position = noiseTypeList->Text->Contains("Perturb"); | |
fractalTypeBox->Enabled = fractal && !position; | |
octavesBox->Enabled = fractal; | |
lacunarityBox->Enabled = fractal; | |
gainBox->Enabled = fractal; | |
bool cellular = noiseTypeList->Text->Contains("Cellular"); | |
bool white = noiseTypeList->Text->Contains("White"); | |
bool simplex = noiseTypeList->Text->Contains("Simplex"); | |
bool cubic = noiseTypeList->Text->Contains("Cubic"); | |
bool distance2 = cellular && cellReturnTypeBox->Text->Contains("Distance2"); | |
interpBox->Enabled = !(cellular || white || simplex || cubic); | |
distanceFunctionBox->Enabled = cellular; | |
cellReturnTypeBox->Enabled = cellular; | |
jitterBox->Enabled = cellular; | |
distance2index0->Enabled = distance2; | |
distance2index1->Enabled = distance2; | |
upButton->Enabled = checkBox3D->Checked; | |
downButton->Enabled = checkBox3D->Checked; | |
positionWarpBox->Enabled = !position; | |
warpAmpBox->Enabled = positionWarpBox->SelectedIndex > 0 && !position; | |
perturbFreqBox->Enabled = positionWarpBox->SelectedIndex > 0 && !position; | |
if (position) | |
{ | |
if (checkBox3D->Checked) | |
noteLabel->Text = "Visualisation of gradient perturb:\nRed = X offset, Green = Y offset, Blue = Z offset"; | |
else | |
noteLabel->Text = "Visualisation of gradient perturb:\nHue = X offset, Brightness = Y offset"; | |
} | |
else | |
noteLabel->Text = ""; | |
RebuildBitmap(nullptr, nullptr); | |
} | |
void MyForm::upButton_Click(System::Object^ sender, System::EventArgs^ e) | |
{ | |
zPos += Convert::ToSingle(frequencyBox->Text) * 100.f; | |
RebuildBitmap(nullptr, nullptr); | |
} | |
void MyForm::downButton_Click(System::Object^ sender, System::EventArgs^ e) | |
{ | |
zPos -= Convert::ToSingle(frequencyBox->Text) * 100.f; | |
RebuildBitmap(nullptr, nullptr); | |
} | |
static RGB HSV2RGB(HSV hsv) | |
{ | |
RGB rgb; | |
unsigned char region, remainder, p, q, t; | |
if (hsv.s == 0) | |
{ | |
rgb.r = hsv.v; | |
rgb.g = hsv.v; | |
rgb.b = hsv.v; | |
return rgb; | |
} | |
region = hsv.h / 43; | |
remainder = (hsv.h - (region * 43)) * 6; | |
p = (hsv.v * (255 - hsv.s)) >> 8; | |
q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8; | |
t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8; | |
switch (region) | |
{ | |
case 0: | |
rgb.r = hsv.v; rgb.g = t; rgb.b = p; | |
break; | |
case 1: | |
rgb.r = q; rgb.g = hsv.v; rgb.b = p; | |
break; | |
case 2: | |
rgb.r = p; rgb.g = hsv.v; rgb.b = t; | |
break; | |
case 3: | |
rgb.r = p; rgb.g = q; rgb.b = hsv.v; | |
break; | |
case 4: | |
rgb.r = t; rgb.g = p; rgb.b = hsv.v; | |
break; | |
default: | |
rgb.r = hsv.v; rgb.g = p; rgb.b = q; | |
break; | |
} | |
return rgb; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment