Skip to content

Instantly share code, notes, and snippets.

@hotwatermorning
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hotwatermorning/f23841dcee3f77b1419a to your computer and use it in GitHub Desktop.
Save hotwatermorning/f23841dcee3f77b1419a to your computer and use it in GitHub Desktop.
perlin_noise
// 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