Last active
August 29, 2015 14:16
-
-
Save hotwatermorning/f23841dcee3f77b1419a to your computer and use it in GitHub Desktop.
perlin_noise
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
// perlin_noise_cpp.cpp | |
// http://postd.cc/the-laws-of-shitty-dashboard-2/ | |
#include <cassert> | |
#include <cstdint> | |
#include <algorithm> | |
#include <memory> | |
#define UNICODE | |
#define WIN32_LEAN_AND_MEAN // Windows ヘッダーから使用されていない部分を除外します。 | |
// Windows ヘッダー ファイル: | |
#include <windows.h> | |
#include <tchar.h> | |
// グローバル変数: | |
HINSTANCE hInst; // 現在のインターフェイス | |
TCHAR szTitle[] = L"BITMAP_TEST_WINDOW"; // タイトル バーのテキスト | |
TCHAR szWindowClass[] = L"BITMAP_TEST_WINDOW_CLASS"; // メイン ウィンドウ クラス名 | |
// このコード モジュールに含まれる関数の宣言を転送します: | |
ATOM MyRegisterClass(HINSTANCE hInstance); | |
BOOL InitInstance(HINSTANCE, int); | |
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); | |
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); | |
int APIENTRY WinMain(_In_ HINSTANCE hInstance, | |
_In_opt_ HINSTANCE hPrevInstance, | |
_In_ LPSTR lpCmdLine, | |
_In_ int nCmdShow) | |
{ | |
UNREFERENCED_PARAMETER(hPrevInstance); | |
UNREFERENCED_PARAMETER(lpCmdLine); | |
MSG msg; | |
MyRegisterClass(hInstance); | |
// アプリケーションの初期化を実行します: | |
if (!InitInstance (hInstance, nCmdShow)) | |
{ | |
return FALSE; | |
} | |
// メイン メッセージ ループ: | |
while (GetMessage(&msg, NULL, 0, 0)) | |
{ | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
return (int) msg.wParam; | |
} | |
// | |
// 関数: MyRegisterClass() | |
// | |
// 目的: ウィンドウ クラスを登録します。 | |
// | |
ATOM MyRegisterClass(HINSTANCE hInstance) | |
{ | |
WNDCLASSEX wcex; | |
wcex.cbSize = sizeof(WNDCLASSEX); | |
wcex.style = CS_HREDRAW | CS_VREDRAW; | |
wcex.lpfnWndProc = WndProc; | |
wcex.cbClsExtra = 0; | |
wcex.cbWndExtra = 0; | |
wcex.hInstance = hInstance; | |
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); | |
wcex.hCursor = LoadCursor(NULL, IDC_ARROW); | |
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); | |
wcex.lpszMenuName = NULL; | |
wcex.lpszClassName = szWindowClass; | |
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); | |
return RegisterClassEx(&wcex); | |
} | |
// | |
// 関数: InitInstance(HINSTANCE, int) | |
// | |
// 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します。 | |
// | |
// コメント: | |
// | |
// この関数で、グローバル変数でインスタンス ハンドルを保存し、 | |
// メイン プログラム ウィンドウを作成および表示します。 | |
// | |
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) | |
{ | |
HWND hWnd; | |
hInst = hInstance; // グローバル変数にインスタンス処理を格納します。 | |
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, | |
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); | |
if (!hWnd) | |
{ | |
int x = GetLastError(); | |
assert(x == 0); | |
return FALSE; | |
} | |
ShowWindow(hWnd, nCmdShow); | |
UpdateWindow(hWnd); | |
return TRUE; | |
} | |
int const bitmap_height = 600; | |
int const bitmap_width = 600; | |
HWND src_window; | |
HDC back_dc; | |
HBITMAP old_bitmap; | |
BITMAPINFO bitmap_info; | |
std::unique_ptr<std::int32_t[]> bitmap_data; | |
void SetupBitmap(HWND hWnd, int cx, int cy); | |
void CleanupBitmap(); | |
void UpdateBitmap(std::int32_t *data, int cx, int cy); | |
// | |
// 関数: WndProc(HWND, UINT, WPARAM, LPARAM) | |
// | |
// 目的: メイン ウィンドウのメッセージを処理します。 | |
// | |
// WM_COMMAND - アプリケーション メニューの処理 | |
// WM_PAINT - メイン ウィンドウの描画 | |
// WM_DESTROY - 中止メッセージを表示して戻る | |
// | |
// | |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | |
{ | |
switch (message) | |
{ | |
case WM_CREATE: { | |
SetupBitmap(hWnd, bitmap_width, bitmap_height); | |
SetTimer(hWnd, 0, 10, NULL); | |
UpdateBitmap(bitmap_data.get(), bitmap_width, bitmap_height); | |
return 0; | |
} | |
case WM_TIMER: { | |
UpdateBitmap(bitmap_data.get(), bitmap_width, bitmap_height); | |
InvalidateRect(hWnd, NULL, FALSE); | |
break; | |
} | |
case WM_COMMAND: { | |
int wmId, wmEvent; | |
wmId = LOWORD(wParam); | |
wmEvent = HIWORD(wParam); | |
// 選択されたメニューの解析: | |
switch (wmId) | |
{ | |
case 0: | |
default: | |
return DefWindowProc(hWnd, message, wParam, lParam); | |
} | |
break; | |
} | |
case WM_PAINT: { | |
PAINTSTRUCT ps; | |
HDC hdc; | |
hdc = BeginPaint(hWnd, &ps); | |
RECT rc; | |
GetClientRect(hWnd, &rc); | |
StretchDIBits(hdc, 0, 0, rc.right, rc.bottom, 0, 0, bitmap_width, bitmap_height, bitmap_data.get(), &bitmap_info, DIB_RGB_COLORS, SRCCOPY); | |
EndPaint(hWnd, &ps); | |
break; | |
} | |
case WM_DESTROY: { | |
KillTimer(hWnd, 0); | |
CleanupBitmap(); | |
PostQuitMessage(0); | |
break; | |
} | |
default: | |
return DefWindowProc(hWnd, message, wParam, lParam); | |
} | |
return 0; | |
} | |
//====================================================================== | |
// Color functions | |
//====================================================================== | |
struct RGBColor | |
{ | |
double r_; | |
double g_; | |
double b_; | |
RGBColor(double r, double g, double b) | |
: r_(r) | |
, g_(g) | |
, b_(b) | |
{} | |
}; | |
struct HSVColor | |
{ | |
double hue_; | |
double saturation_; | |
double brightness_; | |
HSVColor(double hue, double saturation, double brightness) | |
: hue_(hue) | |
, saturation_(saturation) | |
, brightness_(brightness) | |
{} | |
}; | |
RGBColor HSVToRGB(double hue, double saturation, double brightness) | |
{ | |
assert(0 <= hue && hue <= 1.0); | |
assert(0 <= saturation && saturation <= 1.0); | |
assert(0 <= brightness && brightness <= 1.0); | |
double r = brightness; | |
double g = brightness; | |
double b = brightness; | |
if (saturation > 0.0f) { | |
hue *= 6.0f; | |
int const i = (int)hue; | |
double const f = hue - (float)i; | |
switch (i) { | |
default: | |
case 0: | |
g *= 1 - saturation * (1 - f); | |
b *= 1 - saturation; | |
break; | |
case 1: | |
r *= 1 - saturation * f; | |
b *= 1 - saturation; | |
break; | |
case 2: | |
r *= 1 - saturation; | |
b *= 1 - saturation * (1 - f); | |
break; | |
case 3: | |
r *= 1 - saturation; | |
g *= 1 - saturation * f; | |
break; | |
case 4: | |
r *= 1 - saturation * (1 - f); | |
g *= 1 - saturation; | |
break; | |
case 5: | |
g *= 1 - saturation; | |
b *= 1 - saturation * f; | |
break; | |
} | |
} | |
return RGBColor(r, g, b); | |
} | |
HSVColor RGBToHSV(double r, double g, double b) | |
{ | |
assert(0 <= r && r <= 1.0); | |
assert(0 <= g && g <= 1.0); | |
assert(0 <= b && b <= 1.0); | |
double max = r > g ? r : g; | |
max = max > b ? max : b; | |
double min = r < g ? r : g; | |
min = min < b ? min : b; | |
double h = max - min; | |
if (h > 0.0f) { | |
if (max == r) { | |
h = (g - b) / h; | |
if (h < 0.0f) { | |
h += 6.0f; | |
} | |
} else if (max == g) { | |
h = 2.0f + (b - r) / h; | |
} else { | |
h = 4.0f + (r - g) / h; | |
} | |
} | |
h /= 6.0f; | |
double s = (max - min); | |
if (max != 0.0f) | |
s /= max; | |
double v = max; | |
return HSVColor(h, s, v); | |
} | |
RGBColor HSVToRGB(HSVColor const &c) | |
{ | |
return HSVToRGB(c.hue_, c.saturation_, c.brightness_); | |
} | |
HSVColor RGBToHSV(RGBColor const &c) | |
{ | |
return RGBToHSV(c.r_, c.g_, c.b_); | |
} | |
//====================================================================== | |
// Bitmap functions | |
//====================================================================== | |
void SetupBitmap(HWND hWnd, int cx, int cy) | |
{ | |
src_window = hWnd; | |
HDC dc = GetDC(src_window); | |
back_dc = CreateCompatibleDC(dc); | |
HBITMAP back_bitmap = CreateCompatibleBitmap(dc, bitmap_width, bitmap_height); | |
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
bitmap_info.bmiHeader.biWidth = cx; | |
bitmap_info.bmiHeader.biHeight = cy; | |
bitmap_info.bmiHeader.biPlanes = 1; | |
bitmap_info.bmiHeader.biBitCount = 32; | |
bitmap_info.bmiHeader.biCompression = BI_RGB; | |
bitmap_data = std::make_unique<std::int32_t[]>(cx * cy); | |
GetDIBits(dc, back_bitmap, 0, cy, bitmap_data.get(), &bitmap_info, DIB_RGB_COLORS); | |
old_bitmap = (HBITMAP)SelectObject(back_dc, back_bitmap); | |
DeleteObject(back_bitmap); | |
ReleaseDC(src_window, dc); | |
} | |
void CleanupBitmap() | |
{ | |
SelectObject(back_dc, old_bitmap); | |
ReleaseDC(src_window, back_dc); | |
} | |
//void UpdateBitmap(std::int32_t *bitmap, int cx, int cy) | |
//{ | |
// for(int y = 0; y < cy; ++y) { | |
// for(int x = 0; x < cx; ++x) { | |
// double hue = (x + y * cx) / (double)(cx * cy - 1); | |
// auto rgb = HSVToRGB(hue, 1.0, 1.0); | |
// | |
// int r = std::min<int>(static_cast<int>(rgb.r_ * 256), 255); | |
// int g = std::min<int>(static_cast<int>(rgb.g_ * 256), 255); | |
// int b = std::min<int>(static_cast<int>(rgb.b_ * 256), 255); | |
// | |
// bitmap[x + y * cx] = r * (1 << 16) + g * (1 << 8) + b * (1 << 0); | |
// } | |
// } | |
//} | |
//====================================================================== | |
// Perlin noise | |
//====================================================================== | |
//! 格子点の勾配ベクトル生成用の乱数列(256個の点列を複製して512個にしている) | |
int const p[] = { | |
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, | |
140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, | |
247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, | |
57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, | |
74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, | |
60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, | |
65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, | |
200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, | |
52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, | |
207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, | |
119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, | |
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, | |
218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, | |
81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, | |
184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, | |
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, | |
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, | |
140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, | |
247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, | |
57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, | |
74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, | |
60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, | |
65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, | |
200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, | |
52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, | |
207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, | |
119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, | |
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, | |
218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, | |
81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, | |
184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, | |
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 | |
}; | |
double lerp(double a, double b, double x) | |
{ | |
return a + x * (b - a); | |
} | |
double fade(double t) | |
{ | |
return t * t * t * (t * (t * 6 - 15) + 10); | |
} | |
int repeat = 256; | |
int inc(int num) | |
{ | |
num++; | |
if(repeat > 0) { num %= repeat; } | |
return num; | |
} | |
//! 格子点の勾配ベクトルを返す | |
//! hashは、格子点の座標から得られる乱数値 | |
double grad(int hash, double x, double y) | |
{ | |
switch(hash & 3) | |
{ | |
case 0: return x + y; | |
case 1: return x - y; | |
case 2: return -x + y; | |
case 3: return -x - x; | |
default: return 0; | |
} | |
} | |
//! 格子点の勾配ベクトルを返す | |
//! hashは、格子点の座標から得られる乱数値 | |
double grad(int hash, double x, double y, double z) | |
{ | |
switch(hash & 0xF) | |
{ | |
case 0x0: return x + y; | |
case 0x1: return -x + y; | |
case 0x2: return x - y; | |
case 0x3: return -x - y; | |
case 0x4: return x + z; | |
case 0x5: return -x + z; | |
case 0x6: return x - z; | |
case 0x7: return -x - z; | |
case 0x8: return y + z; | |
case 0x9: return -y + z; | |
case 0xA: return y - z; | |
case 0xB: return -y - z; | |
case 0xC: return y + x; | |
case 0xD: return -y + z; | |
case 0xE: return y - x; | |
case 0xF: return -y - z; | |
default: return 0; // never happens | |
} | |
} | |
double perlin_2d(double x, double y /*, double z*/) { | |
if(repeat > 0) { | |
x = fmod(x, repeat); | |
y = fmod(y, repeat); | |
} | |
int xi = (int)x & 255; | |
int yi = (int)y & 255; | |
double xf = x - (int)x; | |
double yf = y - (int)y; | |
double u = fade(xf); | |
double v = fade(yf); | |
int aa, ab, ba, bb; | |
aa = p[p[xi] + yi]; | |
ab = p[p[xi] + inc(yi)]; | |
ba = p[p[inc(xi)] + yi]; | |
bb = p[p[inc(xi)] + inc(yi)]; | |
double x1, x2; | |
x1 = lerp( grad(aa, xf, yf), grad(ba, xf-1, yf), u ); | |
x2 = lerp( grad(ab, xf, yf-1), grad(bb, xf-1, yf-1), u ); | |
return (lerp(x1, x2, v) + 1) / 2; | |
} | |
double perlin_3d(double x, double y, double z) { | |
if(repeat > 0) { | |
x = fmod(x, repeat); | |
y = fmod(y, repeat); | |
z = fmod(z, repeat); | |
} | |
int xi = (int)x & 255; | |
int yi = (int)y & 255; | |
int zi = (int)z & 255; | |
double xf = x - (int)x; | |
double yf = y - (int)y; | |
double zf = z - (int)z; | |
double u = fade(xf); | |
double v = fade(yf); | |
double w = fade(zf); | |
int aaa, aab, aba, abb, baa, bab, bba, bbb; | |
aaa = p[p[p[xi] + yi] + zi]; | |
aab = p[p[p[xi] + yi] + inc(zi)]; | |
aba = p[p[p[xi] + inc(yi)] + zi]; | |
abb = p[p[p[xi] + inc(yi)] + inc(zi)]; | |
baa = p[p[p[inc(xi)] + yi] + zi]; | |
bab = p[p[p[inc(xi)] + yi] + inc(zi)]; | |
bba = p[p[p[inc(xi)] + inc(yi)] + zi]; | |
bbb = p[p[p[inc(xi)] + inc(yi)] + inc(zi)]; | |
double x1, x2, y1, y2; | |
//! 隣接する勾配ベクトル同士のドット積を計算 | |
x1 = lerp( grad (aaa, xf , yf , zf), // The gradient function calculates the dot product between a pseudorandom | |
grad (baa, xf-1, yf , zf), // gradient vector and the vector from the input coordinate to the 8 | |
u); // surrounding points in its unit cube. | |
x2 = lerp( grad (aba, xf , yf-1, zf), // This is all then lerped together as a sort of weighted average based on the faded (u,v,w) | |
grad (bba, xf-1, yf-1, zf), // values we made earlier. | |
u); | |
y1 = lerp(x1, x2, v); | |
x1 = lerp( grad (aab, xf , yf , zf-1), | |
grad (bab, xf-1, yf , zf-1), | |
u); | |
x2 = lerp( grad (abb, xf , yf-1, zf-1), | |
grad (bbb, xf-1, yf-1, zf-1), | |
u); | |
y2 = lerp (x1, x2, v); | |
return (lerp (y1, y2, w)+1)/2; | |
} | |
double octave_perlin_3d(double x, double y, double z, int octaves, double persistence) | |
{ | |
double total = 0; | |
double frequency = 1; | |
double amplitude = 1; | |
double max_value = 0; | |
for(int i = 0; i < octaves; ++i) { | |
total += perlin_3d(x * frequency, y * frequency, z * frequency) * amplitude; | |
max_value += amplitude; | |
amplitude *= persistence; | |
frequency *= 2; | |
} | |
return total / max_value; | |
} | |
double z_pos; | |
void UpdateBitmap(std::int32_t *bitmap, int cx, int cy) | |
{ | |
z_pos += 0.00617; | |
#pragma omp parallel for | |
for(int x = 0; x < cx; ++x) { | |
for(int y = 0; y < cy; ++y) { | |
double pixel = octave_perlin_3d(x * 0.01, y * 0.01, z_pos, 6, 0.45); | |
pixel = pixel / 3.0 + 0.45; | |
double fr; | |
double fg; | |
double fb; | |
RGBColor color = HSVToRGB(pixel, 1.0, 1.0); | |
fr = color.r_; | |
fg = color.g_; | |
fb = color.b_; | |
int r = (fr == 1.0) ? 255 : (int)(fr * 255); | |
int g = (fg == 1.0) ? 255 : (int)(fg * 255); | |
int b = (fb == 1.0) ? 255 : (int)(fb * 255); | |
bitmap[y * cx + x] = r * (1 << 16) + g * (1 << 8) + b * (1 << 0); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment