//-mwindows -lgdi32
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>

#define WIDTH  1200
#define HEIGHT 800

#define OCTAVES 8
#define PERSIST 0.55f
#define LACUNARITY 2.0f

float seedOffset;
// 按钮ID
#define IDC_GENERATE_BUTTON 1001
// 全局窗口句柄
HWND hGenerateButton;

static int perm[512] = {
    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
};

float fade(float t) {
    return t * t * t * (t * (t * 6 - 15) + 10);
}

float lerp(float t, float a, float b) {
    return a + t * (b - a);
}

float grad(int hash, float x, float y) {
    int h = hash & 15;
    float u = h < 8 ? x : y;
    float v = h < 4 ? y : (h == 12 || h == 14 ? x : 0);
    return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}

float perlin2d(float x, float y) {
    x += seedOffset;
    y += seedOffset;

    int X = (int)floor(x) & 255;
    int Y = (int)floor(y) & 255;
    x -= floor(x);
    y -= floor(y);
    float u = fade(x);
    float v = fade(y);

    int A = perm[X] + Y;
    int AA = perm[A];
    int AB = perm[A + 1];
    int B = perm[X + 1] + Y;
    int BA = perm[B];
    int BB = perm[B + 1];

    return lerp(v,
        lerp(u, grad(perm[AA], x, y),
                 grad(perm[BA], x-1, y)),
        lerp(u, grad(perm[AB], x, y-1),
                 grad(perm[BB], x-1, y-1)));
}

float fbm(float x, float y) {
    float total = 0;
    float amp = 1;
    float freq = 1;
    float max = 0;
    for (int i = 0; i < OCTAVES; i++) {
        total += perlin2d(x * freq, y * freq) * amp;
        max += amp;
        amp *= PERSIST;
        freq *= LACUNARITY;
    }
    return total / max;
}

// 海洋 ≈ 65%,地形过渡更自然
COLORREF GetBiomeColor(float h) {
    if (h < 0.41f)      return RGB(25, 55, 110);    // 深海
    else if (h < 0.50f) return RGB(38, 95, 170);    // 海洋
    else if (h < 0.52f) return RGB(235, 218, 138);  // 沙滩
    else if (h < 0.57f) return RGB(155, 195, 98);   // 平原
    else if (h < 0.66f) return RGB(55, 135, 55);    // 森林
    else if (h < 0.74f) return RGB(218, 198, 98);   // 沙漠
    else if (h < 0.84f) return RGB(115, 115, 115);  // 石头山
    else                return RGB(245, 245, 255);  // 雪山
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    HDC hdc;
    PAINTSTRUCT ps;
    int x, y;
    float height;

    switch (msg) {
        case WM_CREATE:
            // 创建按钮
            hGenerateButton = CreateWindow(
                "BUTTON",
                "重新生成地形",
                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                10, 10, 120, 35,
                hwnd,
                (HMENU)IDC_GENERATE_BUTTON,
                ((LPCREATESTRUCT)lParam)->hInstance,
                NULL
            );
            break;

        case WM_COMMAND:
            // 按钮点击事件
            if (LOWORD(wParam) == IDC_GENERATE_BUTTON) {
                // 重新生成随机种子
                srand((unsigned)time(NULL));
                seedOffset = (float)(rand() % 20000) / 100.0f;
                // 强制重绘窗口
                InvalidateRect(hwnd, NULL, TRUE);
                UpdateWindow(hwnd);
            }
            break;

        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            for (y = 0; y < HEIGHT; y++) {
                for (x = 0; x < WIDTH; x++) {
                    height = fbm((float)x / 220.0f, (float)y / 220.0f);
                    height = (height + 1.0f) * 0.5f;
                    SetPixel(hdc, x, y, GetBiomeColor(height));
                }
            }
            EndPaint(hwnd, &ps);
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR cmd, int nShow) {
    srand((unsigned)time(NULL));
    seedOffset = (float)(rand() % 20000) / 100.0f;

    const char CLASS_NAME[] = "PerlinMap";
    WNDCLASS wc = {0};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0, CLASS_NAME, "自然地形 - 点击按钮重新生成",
        WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
        CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT,
        NULL, NULL, hInstance, NULL
    );

    if (!hwnd) return 0;
    ShowWindow(hwnd, nShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}