Code:
//January 10, 2010
#include <windows.h>
#include <ddraw.h>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <string>
#include <iostream>
#include <vector>
HDC _hOffscreenDC;
HBITMAP _hOffscreenBitmap;
void BuildSky(HDC hDC, HWND hWnd, RECT windowrect)
{
int endx = windowrect.right;
int endy = windowrect.bottom;
int startx = 0;
int starty = 0;
float r1 = 0;
float g1 = 0;
float b1 = 10;
float r2 = 0;
float g2 = 2;
float b2 = 30;
float rs = r2/endy;
float gs = g2/endy;
float bs = b2/endy;
for (int i=0; i<=endy; i++)
{
//rs = r2/endy;
//gs = g2/endy;
//bs = b2/endy;
r1 = r1 + rs;
g1 = g1 + gs;
b1 = b1 + bs;
HPEN pen = CreatePen(PS_SOLID, 1, RGB(r1, g1, b1));
SelectObject(hDC, pen);
MoveToEx(hDC, 0, i, NULL);
LineTo(hDC, endx, i);
SelectObject(hDC, pen);
DeleteObject(pen);
}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
using namespace std;
struct Point
{
int x,y;
};
//Point points(5);
vector<Point> points;
void SetupMountains(RECT windowrect)
{
Point p;
/*for(int i=1; i<=20; i++)
{
p.x = i*25;
p.y = rand() % 150 + 50;
points.push_back(p);
}*/
p.x = 0;
p.y = 0;
points.push_back(p);
p.x = 1080;
p.y = 0;
points.push_back(p);
}
void Complex()
{
if (points.size()-1 >= 1000) //Quit so that it doesn't freeze!
return;
int tx,ty,tx1,ty1,midx,midy,miny;
float Complexity = 1;
Point tp;
float range = 1;
int mass = 500;
if(true) //(points.size() > 2)
{
for(int i=0; i<=points.size()-2; i++)
{
tx = points[i].x;
ty = points[i].y;
tx1 = points[i+1].x;
ty1 = points[i+1].x;
midx = (tx + tx1)/2; //Midpoint of x
midy = (ty + ty1)/2; //Midpoitn of y
miny = ty; //Minimum point of y
tp.x = midx;
tp.y = miny + (rand() % (int)floor(range*mass*2+1)); //- range*mass*0.5; //Displace the y value by a random amount
if(abs(tp.y - miny) > (mass*range*0.7)) //Smoothing?
tp.y = tp.y * 0.4;
points.insert(points.begin()+i+1,tp); //Break the segment into two. (aka Add a new point in between)
range *= 0.3; //Deplete the range by half
//if(range <= 0.001)
// range = 0.001;
i += 1;
if(i >= points.size()-1)
break;
}
} else {
int i=0;
tx = points[i].x;
ty = points[i].y;
tx1 = points[i+1].x;
ty1 = points[i+1].x;
midx = (tx + tx1)/2;
midy = (ty + ty1)/2;
miny = ty;
tp.x = midx;
tp.y = miny + rand() % (int)(range*mass) + range*mass;
points.insert(points.begin()+i+1,tp);
//range = range*0.7;
}
}
void DrawMountains(HDC hDC, HWND hWnd, RECT windowrect)
{
HPEN pen = CreatePen(PS_SOLID, 1, RGB(255,20,20));
SelectObject(hDC, pen);
for(int i=0; i<=points.size()-2; i++)
{
MoveToEx(hDC, points[i].x, 1080 - points[i].y, NULL);
LineTo(hDC, points[i+1].x, 1080 - points[i+1].y);
}
for(int i=0; i<=points.size()-1; i++)//Mark points or elbows of mountain
{
SetPixel(hDC, points[i].x, 1080 - points[i].y, RGB(255,255,100));
}
SelectObject(hDC, pen);
DeleteObject(pen);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPreInst,
LPSTR lpszCmdLine, int nCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASSEX wc;
//fill the WNDCLASSEX structure with the appropriate values
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW; //CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "wndClass";
wc.hIconSm = LoadIcon(NULL, IDI_EXCLAMATION);
//register the new class
RegisterClassEx(&wc);
//create a window
hWnd = CreateWindowEx(
NULL,
"wndClass",
"Fractal Terrain",
WS_POPUP | WS_VISIBLE,
0, //Position x
0, //Position y
1920, //Size x
1080, //Size y
NULL,
NULL,
hInst,
NULL
);
//event loop - handle all messages
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//standard return value
return (msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam,
LPARAM lParam)
{
HDC hDC;
HBRUSH brush;
RECT windowrect;
srand((int)time(0));
switch(nMsg)
{
case WM_CREATE:
hDC = GetDC(hWnd);
GetClientRect(hWnd, &windowrect);
srand(time(0));
SetCursor(NULL);
SetTimer(hWnd, 1, 250, NULL);
SetupMountains(windowrect);
ReleaseDC(hWnd, hDC);
break;
case WM_PAINT:
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &windowrect);
//BuildEarth(hDC, hWnd, windowrect);
DrawMountains(hDC, hWnd, windowrect);
EndPaint(hWnd, &ps);
break;
case WM_MOUSEMOVE:
SetCursor(NULL);
break;
case WM_TIMER:
hDC = GetDC(hWnd);
brush = CreateSolidBrush(RGB(0,10,25));
GetClientRect(hWnd, &windowrect);
RECT temp;
temp.left = 0;
temp.top = 0;
temp.right = windowrect.right;
temp.bottom = windowrect.bottom;
_hOffscreenDC = CreateCompatibleDC(GetDC(hWnd));
_hOffscreenBitmap = CreateCompatibleBitmap(GetDC(hWnd),windowrect.right,windowrect.bottom);
SelectObject(_hOffscreenDC, _hOffscreenBitmap);
BuildSky(_hOffscreenDC, hWnd, windowrect);
DrawMountains(_hOffscreenDC, hWnd, windowrect);
BitBlt(hDC, 0, 0, windowrect.right, windowrect.bottom, _hOffscreenDC, 0, 0, SRCCOPY);
DeleteObject(_hOffscreenBitmap);
DeleteDC(_hOffscreenDC);
SelectObject(hDC, brush);
DeleteObject(brush);
ReleaseDC(hWnd, hDC);
break;
case WM_DESTROY:
KillTimer(hWnd, 1);
PostQuitMessage(0);
break;
case WM_KEYUP:
switch (wParam)
{
case VK_ESCAPE:
//destroy the timer
KillTimer(hWnd, 1);
//end the program
PostQuitMessage(0);
break;
case VK_UP:
Complex(); //Make the terrain more complex
break;
}
break;
default:
//let Windows handle every other message
return(DefWindowProc(hWnd, nMsg, wParam, lParam));
}
return 0;
}
The main thing that needs to be focused on is the Complex() function....