﻿#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <d2d1.h> // put d2d1.lib in Project -Properties -Linker -AllOptions -Additional Dependencies
#include <d2d1helper.h>
#define PI 3.141592653589793
#define EARTHRADIUS 6371 // kilometers
double PI2 = PI /  2.0;
double radius = 6371000.0;
//double R2PI360 = radius * 2.0 * PI / 360.0;
double number, LON2, lowest, widest;
DWORD LatMeters, LonMeters;
int End = 0, f3;
bool GOTIT = false, xlakes, done = false;
float xl, yl;
float X0, X90, X180, X270;
float Sin0[10800], Cos0[10800];
float Sin90[10800], Cos90[10800];
DWORD latlon[2];// 40036.456777348325030967927276514
HWND hwnd;
HDC hdc, hdcMem, hdcMem2, hdcMem3, hdcMem5;
HBITMAP hBitmap, hBitmap2, hBitmap3, hBitmap5;
RECT rect;
PAINTSTRUCT ps;
HBRUSH hBrush, hWhiteBrush, hBrush7, hHollowBrush;
HANDLE hFile, hFilea, hFileb, hFilec, hFiled, hFilee, hFilef, hFileg, hFileh, hFilei, hFilej, hFilek, hFilel, hAllCitiesFile, hMyCitiesFile, hCountriesFile, hCountryNamesFile, hStatesFile, hStateNames, hCountryNames, hIslandsFile, hLakesFile, hRiversFile, hProvincesFile;
HGDIOBJ hOldBrush, hOldPen, hRiverPen, hGridPen, hHeavyPen, hOldFont;
COLORREF rgbBlue = 0x00FFD000;
HFONT hFont;
LOGFONT lf; // to rotate city names
ID2D1DCRenderTarget* pRT;
ID2D1Factory* pD2DFactory = NULL;
ID2D1SolidColorBrush *mybrush1 = 0, *mybrush2 = 0, *mybrush3 = 0;
D2D1_RECT_F Rect;
HRESULT hr;
short *ElevData;
char szAppName[] = "Globe";
char SansSerif[] = TEXT("Microsoft Sans Serif");
char letter, String[256], String2[256], String3[256];
bool rbutton = false, rbuttondown = false, rbuttondown2 = false, fuc, xlake;
bool first = true, gotit = false, gotit2, gotit4 = false, alt = false, newscreen = true;
bool neg, fook, gotstates, showrivers = false, showcities = false, showcounties = false;
short V3[1802][1802], H3[1802][1802];
short Elevs[18000][12000];
short V2[13000][12000];
short H2[13000][12000];
float lats[1800], lons[1800];
int yLoc, X2, Y2, bigl, bigr, bigt, bigb, rivernamesize, xelev, yelev, Rotate, pixels, xz;
int city, citysize, citiesx, citiesy, incr, incrint, closestx, closesty, closestz, xLoc, col, colinc, rowinc;
int smallv, smallw, column, endo, chars, shift, ctrl, row, Number = 3, oldx, oldy, xs = 2000, ys = 2000, latrow;
int h, i, j, t, u, v, w, v2, w2, v2x, w2x, vv, ww, x, y, z, xx, yy, zz, xy, yx, cx, ix, CountriesSize, CountriesFileSize, namesize;
float latitude, longitude, prevlat, prevlon, lat2, lon2;
double topLat, bottomLat, leftLon, rightLon, top, bottom, left, right, latloninc, latloninc120;
double LON = 270.0, LON3 = 270.0, rotate = 0.0, deltaRadLon, RadLat, rad;
double lat, lon, Lat, Lon, RotateUpDown, xlen, ylen, west, north, PIdiv2;
double conversion = 500.0 / 6371000.0, Conversion, minus90, plus90, Minus90, Plus90;
double elevlat = 0.0, elevlon = 0.0, coslat, sinlat, coslon, sinlon, metersperlat, metersperlon;
double U, U2, V, W, X, Y, Z, X1, Y1, Z1,  Smallest, zoom = 0.0, oldX, oldZ;
double Ninty = 90.0 * PI / 180.0;
double deg2rad = PI / 180.0;
double rad2deg = 180.0 / PI;
double rad90 = 90.0 * deg2rad;
double kilometers, myLon, myRadLat, bearing;
char CountriesData[9000000];
struct {
	float lat;
	float lon;
} allcities[20];

struct EVENT {
	char name[24];
	float lat;
	float lon;
	int population;
} cities[38450]; // 36 bytes/city
struct {
	float lat;
	float lon;
	char name[24]; // 32 bytes total
} states[50];
struct {
	float lat;
	float lon;
} countries[4000000];
struct {
	float lat;
	float lon;
	char name[48];
} countrynames[512];
struct {
	float lat;
	float lon;
	char name[24];
} provincenames[13];
struct {
	float lat;
	float lon;
	char name[24];
} britishcounties[217];
char FullFilename[MAX_PATH] = "C:\\Users\\Public\\temp.dta";
char AllElevations[MAX_PATH] = "C:\\Users\\Public\\AllElevations.dta";
char Elevations[] = "C:\\Users\\Public\\All10g\\x10g";
char CountriesFilename[] = "C:\\Users\\Public\\countries.csv";
//char ProvincesFilename[] = "C:\\Users\\Public\\CanadaProvinces.dta";
char ProvinceNamesFile[] = "C:\\Users\\Public\\ProvinceNames.dta";
char BritishCounties[] = "C:\\Users\\Public\\EnglishCounties.dta";
char CountryNamesFile[] = "C:\\Users\\Public\\CountryNames.dta";
//char CitiesFilename[] = "C:\\Users\\Public\\cities.csv";
char CityData[] = "C:\\Users\\Public\\Cities.dta";
char IslandFile[] = "C:\\Users\\Public\\Islands.txt";
char LakesFile[] = "C:\\Users\\Public\\Lakes.txt";
char RiversFile2[] = "C:\\Users\\Public\\Rivers2.dta";
char StatesFilename[] = "C:\\Users\\Public\\States.txt";
char StateNames2[] = "C:\\Users\\Public\\StateNames.dta";
DWORD fileSize, dwBytesRead, dwBytesWritten, CitiesSize, StatesfileSize;
char StatesData[34595];
int statesize = 1690;
float States[1690];
char AllStates[1814];
int namenum;
struct {
	float lat;
	float lon;
	char name[48];
} IslandsData[60];
char Islands[5000];
int islandsize;
int lakes;
bool lake;
char Lakes[4000];
struct {
	int elev;
	float lat1;
	float lon1;
	float lat2;
	float lon2;
} LakesData[300];
int rivers, rx1, ry1, rx2, ry2;
struct {
	float fromlon;
	float fromlat;
	float tolon;
	float tolat;
	char name[24];
	char name2[23];
	byte Strahler;
} RiverData2[3600000];
double centerlat = 0.0, centerlon = 0.0, thiscenterlon;
double centerX, centerY, centerZ;
int Population = 250000, biggest = 0, smallest, downsmall, rightsmall;
char badCitiesData[4800000]; // 44692 cities * 36 = 1,608,912
char CitiesData[4800000]; // 44692 cities * 36 = 1,608,912
int colors[256] = { 0x29FEB2,0x26FEAD,0x24FEA6,0x23FDA0,0x20FD9B,0x1EFC95,0x1DFC8F,0x1AFC89,0x19FA82,0x17F87B,0x17F675,0x16F36F,0x14F068,0x13EE62,0x12EB5B,0x12E956,0x11E64F,0x11E449,0x10E144,0x10DF3E,0x0FDC39,0x0FDA33,0x10D82F,0x10D72A,0x11D526,0x12D422,0x12D21E,0x12D11A,0x13CF16,0x16D014,0x17D112,0x1AD210,0x1CD30E,0x1ED40C,0x21D507,0x23D600,0x27D800,0x2BDB00,0x30DD00,0x33DF00,0x38E200,0x3DE400,0x41E600,0x47E900,0x4BEC00,0x51EE00,0x57F200,0x5CF500,0x62F700,0x68FA00,0x6FFA00,0x75FB00,0x7CFC00,0x83FD00,0x8AFD00,0x91FE00,0x98FF00,0x9EFF00,0xA3FF00,0xA9FF00,0xAFFF00,0xB6FF00,0xBCFF00,0xC2FF00,0xC7FF00,0xCBFF00,0xD0FF00,0xD5FF00,0xDAFF00,0xDFFF00,0xE2FE00,0xE5FC00,0xE8FA00,0xEAF900,0xEDF700,0xF1F500,0xF3F400,0xF5EF00,0xF7EB00,0xF8E700,0xFAE300,0xFBDF04,0xFDDB04,0xFED704,0xFED204,0xFECD04,0xFEC704,0xFEC204,0xFEBC04,0xFEB604,0xFEB107,0xFFAB04,0xFFA604,0xFFA003,0xFF9C00,0xFF9600,0xFF9000,0xFE8B00,0xFD8500,0xFD8000,0xFC7B00,0xFB7500,0xFA7000,0xF96C00,0xF86600,0xF76200,0xF55D00,0xF45800,0xF35400,0xF15000,0xEF4B00,0xEF4800,0xEC4400,0xEA4100,0xE93D00,0xE73B00,0xE53800,0xE43400,0xE23200,0xE03107,0xDF2F0C,0xDD2E0D,0xDC2C0F,0xDA2A11,0xD82813,0xD72915,0xD62A17,0xD62A1B,0xDA291C,0xD42B20,0xD32C22,0xD32C26,0xD32E29,0xD3322D,0xD43431,0xD43734,0xD53B38,0xD53D3C,0xD64040,0xD74544,0xD94A49,0xDA504D,0xDC5652,0xDE5A57,0xDF605B,0xE16660,0xE36C64,0xE67260,0xE8786B,0xEA7F6F,0xED8572,0xEF8C75,0xF39279,0xF5987B,0xF69E7C,0xF8A37D,0xFAA97F,0xFBAF80,0xE796FE,0xE58EFE,0xE386FD,0xE17DFD,0xE075FD,0xDE6DFD,0xDC65FD,0xDA5DFD,0xD755FC,0xD44DFC,0xD145FC,0xCE3DFC,0xCB36FB,0xC82EFB,0xC428FB,0xC023FA,0xBB1FFA,0xB61BF9,0xB116F8,0xAD12F8,0xA80DF7,0xA403F7,0xA003F6,0x9D03F5,0x9900F4,0x9500F3,0x9000F2,0x8C00F1,0x8900EF,0x8500EF,0x8200ED,0x7F00ED,0x7B00EC,0x7800EB,0x7500EA, 0x7203E9,0x700CE9,0x6E0FE8,0x6C11E7,0x6A14E7,0x6816E6,0x6619E5,0x641CE5,0x6320E5,0x6224E6,0x6128E6,0x5F2DE5,0x5E30E6,0x5D34E6,0x5C39E7,0x5B3DE7,0x5B42E7,0x5A47E9,0x594BEA,0x5950EB,0x5754E8,0x5859ED,0x585FEF,0x5765EF,0x576BF2,0x5670F3,0x5675F4,0x557BF6,0x5582F7,0x5588F8,0x548EF9,0x5494FB,0x549BFC,0x53A0FD,0x53A6FE,0x52ACFE,0x52B1FE,0x51B7FE,0x50BDFE,0x50C3FE,0x4FC9FE,0x4FCEFE,0x4DD2FC,0x4CD6F9,0x4BDAF7,0x4ADEF5,0x49E2F3,0x49E6F1,0x47EAEF,0x45EDEA,0x43EFE6,0x40F3E2,0x3EF5DE,0x3DF8DA,0x3AFBD6,0x38FCD2,0x35FDCD,0x33FDC8,0x30FDC2,0x2EFEBD,0x2BFEB8,0,0 };

void GetLatLon(void);
void Deg2Meters(double Lat, double Lon, double myLat, double myLon); // from Wikipedia Earth Radius
void DistBearing(double RadLat, double Lon);
void GetEndo(void);
DWORD Atoi(char* ptr);
void ShowTopo(void);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
 {
	hBrush = CreateSolidBrush(0xFFFFFF); // (0x302010);
	MSG msg;
	WNDCLASS wndclass;
	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = hBrush;
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;
	if (!RegisterClass(&wndclass))
		return 0;
	hwnd = CreateWindow(szAppName, szAppName,
		WS_OVERLAPPEDWINDOW,
		0, 0, 1920, 1060,
		NULL, NULL, hInstance, NULL);
	ShowWindow(hwnd, SW_SHOWNORMAL);
	UpdateWindow(hwnd);
	while (GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return (int) msg.wParam;
}
// to move point on a circle, where A = center of circle:
//Cx = Ax + (Bx−Ax)cos(α)−(By−Ay)sin(α)
//Cy = Ay + (Bx−Ax)sin(α) + (By−Ay)cos(α)
void Draw(void)
{	double X, Y, Z;
//	Sin0[30*v2] = sin(Lat);
//	Sin0[10800 - (30 * v2)] = cos(Lat);
X = cos(Lat) * cos(Lon);
Y = cos(Lat) * sin(Lon);// 926.62438870465610 meters per 1/20th of a degree latitude
Z = (Y * U) + (sin(Lat) * V); // U = sin(RotateUpDown) V = cos(RotateUpDown); // if (RotateUpDown == 0.0) Z = sin(Lat)
//	X = Sin0[10800 - (30 * v2)] * Sin0[30 * w2];
//	Y = Sin0[10800 - (30 * v2)] * Sin0[10800 + (30 * w2)]; // 926.62438870465610 meters per 1/20th of a degree latitude
//	Z = (Y * U) + (Sin0[colinc * v2] * V); // U = sin(RotateUpDown) V = cos(RotateUpDown); // if (RotateUpDown == 0.0) Z = sin(Lat)
	xx = 960 + (int)(X * W); // W = (zoom + 1.0) * 500.0;
	yy = 510 + (int)(Z * W);
}
void Line(int w)
{
	if ((countries[w].lon >= minus90) && (countries[w].lon <= plus90) && (countries[w].lat >= Minus90) && (countries[w].lat <= Plus90)) {
		Lat = - countries[w].lat * deg2rad;
		Lon = (countries[w].lon + LON) * deg2rad;
		Draw();
		if (!gotit)
			x = LineTo(hdcMem3, xx, yy);
		else {
			gotit = false;
			x = MoveToEx(hdcMem3, xx, yy, NULL);
		}
	}
}
static void ShowCountries()
{
	RotateUpDown = -rotate * deg2rad; // from 90° LAT (0° true)
	U = sin(RotateUpDown);
	V = cos(RotateUpDown);
	W = (zoom + 1.0) * 500.0;
	Plus90 = centerlat + 90.0;
	Minus90 = centerlat - 90.0;
	plus90 = centerlon + 90.0;
	minus90 = centerlon - 90.0;
	gotit = true;
	for (x = 0; x < statesize-1; x += 2) {
		if (States[x] == 0.0) {
			gotit = true;
			x++; // past second 0.0
		}
		if ((States[x] >= Minus90) && (States[x] <= Plus90) && (-States[x + 1] >= minus90) && (-States[x + 1] <= plus90)) {
			Lat = -States[x] * deg2rad;
			Lon = (-States[x + 1] + LON) * deg2rad;
			Draw();
 			if (!gotit)
				LineTo(hdcMem3, xx, yy);
			else {
				gotit = false;
				MoveToEx(hdcMem3, xx, yy, NULL);
			}
		}
	}
	Minus90 = centerlat - 90.0;
	Plus90 = centerlat + 90.0;
	gotit = true;
//	hOldPen = SelectObject(hdcMem3, hHeavyPen);
	for (w = 0; w < CountriesSize; w++) {
		if ((countries[w].lon == 0.0) && (countries[w].lat == 0.0)) { // new country
			gotit = true;
			w++;
			Line(w);
		}
		else {
			plus90 = centerlon + 90.0;
			minus90 = centerlon - 90.0;
			Line(w);
			if ((minus90 < -180.0)) { // circling to left 
				minus90 = 180.0 + plus90; // trick
				plus90 = 180.0;
				Line(w);
			}
			else if (plus90 > 180.0) { // circling to right
				plus90 = -180.0 + minus90;
				minus90 = -180;
				Line(w);
			}
		}
	}
//	SelectObject(hdcMem3, hOldPen);
	if (zoom >= 1.0) {
		plus90 = centerlon + 90.0;
		minus90 = centerlon - 90.0;
		SetTextColor(hdcMem3, 0x404040);
		SetBkMode(hdcMem3, TRANSPARENT);
		for (x = 0; x < 50; x++) {
			if ((states[x].lon >= minus90) && (states[x].lon <= plus90) && (states[x].lat >= Minus90) && (states[x].lat <= Plus90)) {
				Lat = -states[x].lat * deg2rad;
				Lon = (states[x].lon + LON) * deg2rad;
				Draw();
				TextOut(hdcMem3, xx, yy, states[x].name, (int)strlen(states[x].name));
			}
		}
		for (x = 0; x < 13; x++) {
			if ((provincenames[x].lon >= minus90) && (provincenames[x].lon <= plus90) && (provincenames[x].lat >= Minus90) && (provincenames[x].lat <= Plus90)) {
				Lat = -provincenames[x].lat * deg2rad;
				Lon = (provincenames[x].lon + LON) * deg2rad;
				Draw();
				y = (int)strlen(provincenames[x].name);
				if (y > 24)
					y = 24;
				TextOut(hdcMem3, xx, yy, provincenames[x].name, y);
				if (x == 12) // fix bug
					TextOut(hdcMem3, xx+96, yy, "ia", 2);
			}
		}

		for (x = 256; x < 512; x++) {
			if ((countrynames[x].name[0] != ' ') && (countrynames[x].lon >= minus90) && (countrynames[x].lon <= plus90) && (countrynames[x].lat >= Minus90) && (countrynames[x].lat <= Plus90)) {
				Lat = -countrynames[x].lat * (float)deg2rad;
				Lon = (countrynames[x].lon + (float)LON) * (float)deg2rad;
				Draw();
				y = (int)strlen(countrynames[x].name);
				TextOut(hdcMem3, xx, yy, countrynames[x].name, y);
			}
		}
		if (islandsize) {
			for (x = 0; IslandsData[x].lat != 0.0; x++) {
				if ((IslandsData[x].lon >= minus90) && (IslandsData[x].lon <= plus90) && (IslandsData[x].lat >= Minus90) && (IslandsData[x].lat <= Plus90)) {
					Lat = -IslandsData[x].lat * deg2rad;
					Lon = (IslandsData[x].lon + LON) * deg2rad;
					Draw();
					TextOut(hdcMem3, xx, yy, IslandsData[x].name, (int)strlen(IslandsData[x].name));
				}
			}
		}
		SetBkMode(hdcMem3, OPAQUE);
		SetTextColor(hdcMem3, 0);
	}
}

DWORD Atoi(char* ptr)
{
	DWORD x;
	for (x = 0; (*ptr == '.') || ((*ptr >= char('0')) && (*ptr <= char('9'))); ptr++) {
		if (*ptr == '.')
			continue;
		x *= 10;
		x += *ptr - '0';
	}
	return x;
}

double parseDouble(char* p)
{
	int s = 1;
	if (*p == '-') {
		s = -1; p++;
	}

	double acc = 0;
	while (*p >= '0' && *p <= '9')
		acc = acc * 10 + *p++ - '0';

	if (*p == '.') {
		double k = 0.1;
		p++;
		while (*p >= '0' && *p <= '9') {
			acc += (*p++ - '0') * k;
			k *= 0.1;
		}
	}
	return s * acc;
}

void GetCountries(void)
{
	int num = 0; // x, y, z, 
	if (hCountriesFile != INVALID_HANDLE_VALUE) {
		fileSize = GetFileSize(hCountriesFile, NULL);
		ReadFile(hCountriesFile, &CountriesData, fileSize, &dwBytesRead, NULL);
		CountriesFileSize = dwBytesRead;
		CountriesSize = 0;
		if (!gotit4)
			CountriesFileSize = dwBytesRead;
 	}
	if (CountriesData[0] && fileSize) { // delete anything around 49.5lat and -95.0lon
		for (xy = 0; *(DWORD*)&CountriesData[xy] != 0x5B5B5B20; xy++) // [[[ or [[[[
			;
		xy += 4; // to first longitude
		for (; xy < CountriesFileSize; xy++) {
		if (*(DWORD*)&CountriesData[xy + 4] != 0x34312D65) // if "5.68e-14" <bad data>	0x652D3134
				countries[yx].lon = (float)parseDouble(&CountriesData[xy]);
			else
				countries[yx].lon = (float)0.000001;
			for (; CountriesData[xy] != ','; xy++)
				;
			xy += 2;
			if (*(DWORD*)&CountriesData[xy + 4] != 0x34312D65) // if "5.68e-14" <bad data>	0x652D3134
				countries[yx].lat = (float)parseDouble(&CountriesData[xy]); // latitude
			else
				countries[yx].lat = (float)0.000001;
			for (; (CountriesData[xy] != ',') && (*(DWORD*)&CountriesData[xy] != 0x2C5D5D5D); xy++) // ]]],
				;
			if (*(DWORD*)&CountriesData[xy] != 0x2C5D5D5D) { //]]],
				xy += 2; // past comma and space (increment it to '[')
				yx++;
			}
			else { // end of closed loop or end of country
				for (; (xy < CountriesFileSize) && (*(DWORD*)&CountriesData[xy] != 0x5B5B5B20); xy++)// [[[
					;
				yx++;
				countries[yx].lon = (float)0.0; // to end loop and start a new one
				countries[yx].lat = (float)0.0;
				yx++;
				if (xy >= CountriesFileSize)
					break;
				xy += 4;
				if (CountriesData[xy] != '[')
					xy--; // incremented in loop
			}
		} // end of for (; xy < CountriesFileSize; xy++)
		CountriesSize = yx;
	}
}

static void ShowTopo(void) // uses the All10g (All ten g) 30-secondth Latitude and Longitude elevation data
{
// comment the following to not show colored elevations
	for (v2 = 0; v2 < 13000; v2++) {
		for (w2 = 0; w2 < 12000; w2++) {
			V2[v2][w2] = 0;
			H2[v2][w2] = -30000;
		}
	}
	SetCursor(LoadCursor(NULL, IDC_NO));
	elevlat = centerlat;
	lowest = -50.0;
	widest = 180.0;
//	if (zoom == 0.0) number = 4.0;
	if (zoom < 1.0) number = 4.0;
	else if (zoom == 1.0) number = 8.0;
	else if (zoom == 2.0) number = 12.0;
	else if (zoom <= 3.0) number = 15.0;
	else if (zoom <= 5.0) number = 24.0;
	else if (zoom <= 7.0) number = 30.0;
	else if (zoom <= 9.0) number = 40.0;
	else if (zoom < 30.0) number = 60.0;
	else if (zoom >= 30.0) {
		if (centerlat > -10.0) {
			number = 120.0;
			lowest = -10.0;
			widest = 100.0;
		}
		else
			number = 60;
	}

	if (zoom) {
		yLoc = 0;
		xLoc = 960;
		GetLatLon();
		topLat = lat2;
		if (topLat == centerlat)
			topLat = 90.0;
		yLoc = 1040;
		xLoc = 960;
		GetLatLon();
		bottomLat = lat2;
	}
	else {
		topLat = centerlat + 90.0;
		bottomLat = centerlat - 90.0;
		leftLon = centerlon - 90.0;
		rightLon = centerlon + 90.0;
	}
	pRT->BeginDraw();
	pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
	hr = pRT->CreateSolidColorBrush(D2D1::ColorF(0x29FEB2, 1.0f), &mybrush3); // below sea level
	hr = pRT->CreateSolidColorBrush(D2D1::ColorF(0x18A8F8, 1.0f), &mybrush1); // blue
	//	120 columns and rows per degree
	colinc = 120 / (int)number;
	rowinc = 43200 * colinc;
	latloninc = 1.0 / number;
	latloninc120 = 1.0 / (120.0 * number);
	v2 = 0;
	row = (int)(120.0 * centerlon); elevlat = 90.0; // + (centerlat * latloninc120);
	for (elevlat = 90.0; elevlat > lowest; elevlat -= latloninc, row += rowinc, v2++) {//150 degrees * 120 = 18,000 rows
		if (!zoom || ((elevlat < topLat) && (elevlat > bottomLat))) {
			Lat = elevlat * deg2rad; // ********43,200 words across times4 16,800 lines down********
			w2 = 0; col = 10800; elevlon = centerlon * latloninc120;
			for (elevlon = 0.0; elevlon < 180.0; col += colinc, elevlon += latloninc, w2++) {
//				if (!zoom || (elevlon >= leftLon) && (elevlon <= rightLon)) {
					Lon = elevlon * deg2rad;
					Draw();
					if ((yy >= 0) && (yy < 1040) && (xx >= 0) && (xx < 1920)) {
						V2[v2][w2] = (1023 - yy);
						H2[v2][w2] = (1923 - xx);
						y = row + col; // for ElevData
						if (y < 0) y = -y;
						Elevs[v2][w2] = ElevData[y]; // for showing elevations
						for (xlakes = false, h = 0; h < lakes; h++) {
							if ((ElevData[y] == LakesData[h].elev) && (elevlat <= LakesData[h].lat1) && (elevlat >= LakesData[h].lat2) && ((elevlon - 90.0 + centerlon) >= LakesData[h].lon1) && ((elevlon - 90.0 + centerlon) <= LakesData[h].lon2)) {
								xlakes = true; break;
							}
						}
						if ((v2 > 1) && (w2 > 1)) {
							Rect = D2D1::RectF((float)H2[v2][w2 - 2], (float)V2[v2 - 2][w2], (float)(H2[v2][w2]), (float)(V2[v2][w2]));
							if ((ElevData[y] <= -500) || xlakes)
								pRT->FillRectangle(&Rect, mybrush1);
							else if ((ElevData[y] >= 0) && (ElevData[y] < 9144)) { // 30000 * 0.3048
								j = (int)(ElevData[y] * (float)0.0328984); // feet / 100
								hr = pRT->CreateSolidColorBrush(D2D1::ColorF(colors[j], 1.0f), &mybrush2);
								pRT->FillRectangle(&Rect, mybrush2);
							}
							else if ((ElevData[y] > -500) && (ElevData[y] < 0))
								pRT->FillRectangle(&Rect, mybrush3);
						}
					}
//				}
			}
		}
	}
//
//	pRT->BeginDraw();
//	pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
	pRT->EndDraw();
	SetCursor(LoadCursor(NULL, IDC_ARROW));
	if (hr != S_OK)
		PostMessage(hwnd, WM_DESTROY, 0, 0);
}

void GetEndo(void)
{
	for (endo = 0; endo < citysize; endo++) { // get end of cities > Population
		if (cities[endo].population < Population)
			break;
	}
	if (Population < 10000)
		Population = 10000;
}

double Haversine(double LAT1, double LON1, double LAT2, double LON2)
{
	double a, b, d;

	b = sin(((LON2 - LON1) * deg2rad) / 2.0);
	d = sin(((LAT1 - LAT2) * deg2rad) / 2.0);
	a = (d * d) + (cos(LAT1 * deg2rad) * cos(LAT2 * deg2rad) * b * b);
	X = EARTHRADIUS * 2.0 * atan2(sqrt(a), sqrt(1 - a));
	return X;
}

void GetLatLon(void)
{
	v = 0;
	w = 0;
	for (v = 0, elevlat = 90.0; elevlat < 270.0; elevlat += 0.1, v++) {
		lats[v] = (float)elevlat;
		Lat = elevlat * deg2rad;
		for (w = 0, elevlon = 0.0; elevlon < 180.0; elevlon += 0.1, w++) {
			lons[w] = (float)elevlon;
			Lon = elevlon * deg2rad;
			Draw();
			V3[v][w] = yy;
			H3[v][w] = xx;
			if ((yy < 1080) && (v >= 2) && (w >= 2) && (yLoc >= V3[v][w]) && (yLoc <= V3[v - 2][w]) && (xLoc >= H3[v][w - 2]) && (xLoc <= H3[v][w])) {
				vv = v-1;
 				ww = w-1;
				lat2 = (lats[vv] - (float)180.0);
				LON3 = LON - ((double)lons[ww] - 90.0); // from center lon
				if ((270.0 - LON3) < -180.0)
					LON3 = LON3 - 360.0;
				else if ((270.0 - LON3) > 180.0)
					LON3 = LON3 + 360.0;
				lon2 = (float)(270.0 - LON3);
				return;
			}
		}
	}
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CREATE:
		yl = (float)26.1; //lat
		xl = (float)50.5; //lon
		latlon[0] = *(DWORD*)&yl;
		latlon[1] = *(DWORD*)&xl;
		xl = *(float*)&latlon[0];
		yl = *(float*)&latlon[1];
//		zoom = 21000.0; // zoomed out fully
//		Lat = 89.9;
//		LatMeters = Lat * R2PI360 / zoom;
//		Lon = 0.9;
//		LonMeters = R2PI360 * cos(Lat * deg2rad) * Lon / zoom;
//
//		for (x = 0; x < 10800; x++)
//			Cos0[x] = Sin0[10800 - x];
		for (x = 0, X = 90.0; x < 10800; x++, X += xl)
			Sin90[x] = (float)sin(X * deg2rad);
//		for (x = 0; x < 10800; x++)
//			Cos90[x] = Sin90[10800 - x];
		//		Lat = 12.34;
//		X0 = (float)sin(Lat * deg2rad);
//		X90 = (float)sin((90 + Lat) * deg2rad);
//		X180 = (float)sin((180.0 + Lat) * deg2rad);
//		X270 = (float)sin((270.0 + Lat) * deg2rad);
// X180 == -X0 and X270 == -X90
// X0 == X90 and X90 == -X0 from above
//		X0 = (float)cos(Lat * deg2rad);
//		X90 = (float)cos((90.0 + Lat) * deg2rad);
//		X180 = (float)cos((180.0 + Lat) * deg2rad);
//		X270 = (float)cos((270.0 + Lat) * deg2rad);
// X180 == -X0 and X270 == -X90
//
		rect.top = 0;
		rect.left = 0;
		rect.right = 1920;
		rect.bottom = 1080;// 1060
		InvalidateRect(hwnd, &rect, false); // to show it sooner
		hHeavyPen = CreatePen(PS_SOLID, 2, 0);
		hGridPen = CreatePen(PS_SOLID, 1, 0xC8C040); // RGB(120, 220, 220));
		lf.lfHeight = -16;
		lf.lfWeight = 400;
		lf.lfEscapement = 0;
		lf.lfOrientation = 0;
		lf.lfItalic = 0;
		lf.lfUnderline = 0;
		lf.lfStrikeOut = 0;
		lf.lfCharSet = 0;
		lf.lfOutPrecision = 3;
		lf.lfClipPrecision = 2;
		lf.lfQuality = 1;
		lf.lfPitchAndFamily = 0x22;
		for (x = 0; SansSerif[x] != 0; x++)
			lf.lfFaceName[x] = SansSerif[x];
		lf.lfFaceName[x] = 0;
		ElevData = (short*)malloc(14515200000); // ********43,200 words across times 16,800 lines down times 10********
		hFile = CreateFile(AllElevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
		ReadFile(hFile, ElevData, 1451520000, &dwBytesRead, NULL);
		CloseHandle(hFile);
		if (dwBytesRead != 1451520000) {
			fileSize = 21600; // width in bytes of each line of All10g files
			column = 0;
			Elevations[23] = 'a'; // "C:\\Users\\Public\\All10g\\x10g"
			hFilea = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'b';
			hFileb = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'c';
			hFilec = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'd';
			hFiled = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'e';
			hFilee = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'f';
			hFilef = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'g';
			hFileg = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'h';
			hFileh = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'i';
			hFilei = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'j';
			hFilej = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'k';
			hFilek = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			Elevations[23] = 'l';
			hFilel = CreateFile(Elevations, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);// every 1/120th of lat down and 1/120 of lon across
			for (x = 0; x < 4800; x++) { // x reads rows down (90 to 50 degrees lat)
				y = ReadFile(hFilea, &ElevData[column], fileSize, &dwBytesRead, NULL);// y reads columns across
				column += 10800;
				y = ReadFile(hFileb, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFilec, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFiled, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;// 10800*4 = 43,200 words (86,400 bytes) across each line
			}//207,360,000 words
			for (x = 0; x < 6000; x++) { // rows (50 to 0 degrees lat)
				y = ReadFile(hFilee, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFilef, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFileg, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFileh, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
			}//259,200,000 words
			for (x = 0; x < 6000; x++) { // rows (0 to -50 degrees lat)
				y = ReadFile(hFilei, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFilej, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFilek, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
				y = ReadFile(hFilel, &ElevData[column], fileSize, &dwBytesRead, NULL);
				column += 10800;
			}//259,200,000 words
			if (dwBytesRead)
				GOTIT = true;
			CloseHandle(hFilea);//725,760,000 total words		16,800 rows
			CloseHandle(hFileb);
			CloseHandle(hFilec);
			CloseHandle(hFiled);
			CloseHandle(hFilee);
			CloseHandle(hFilef);
			CloseHandle(hFileg);
			CloseHandle(hFileh);
			CloseHandle(hFilei);
			CloseHandle(hFilej);
			CloseHandle(hFilek);
			CloseHandle(hFilel);
			hFile = CreateFile(AllElevations, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
			WriteFile(hFile, ElevData, 1451530000, &dwBytesWritten, NULL);
			CloseHandle(hFile);
		}
		else
			GOTIT = true;
		hBrush7 = CreateSolidBrush(0xF8FFF8);
		hWhiteBrush = CreateSolidBrush(0xFFFFFF);//further into ElevData[1451530000-799200] is empty
		hHollowBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
		hStatesFile = CreateFile(StatesFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hStatesFile != INVALID_HANDLE_VALUE) {
			StatesfileSize = GetFileSize(hStatesFile, NULL);
			ReadFile(hStatesFile, &StatesData, StatesfileSize, &dwBytesRead, NULL);
			CloseHandle(hStatesFile);
		}
		if (!gotstates) {
			for (x = 0, z = 1; x < (int)StatesfileSize; x++) {
				w = atoi(&StatesData[x]);
				if (z != w)
					States[y++] = 0.0; // end of line
				z = w;
				for (; StatesData[x] != ','; x++)
					;
				x++;
				for (; StatesData[x] != ','; x++)
					;
				x++;
				for (; StatesData[x] != ','; x++)
					;
				x++;
				States[y++] = (float)atof(&StatesData[x]); // latitude
				for (; StatesData[x] != ','; x++)
					;
				x++;
				States[y++] = (float)atof(&StatesData[x]); // longitude
				for (; StatesData[x] != '\n'; x++)
					;
			}
			gotstates = true;
		}
		hStateNames = CreateFile(StateNames2, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hStateNames != INVALID_HANDLE_VALUE) {
			fileSize = GetFileSize(hStateNames, NULL);
			ReadFile(hStateNames, states, fileSize, &dwBytesRead, NULL);
			CloseHandle(hStateNames);
		}
		hFile = CreateFile(CityData, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE) {
			fileSize = GetFileSize(hFile, NULL);
			ReadFile(hFile, &cities, fileSize, &dwBytesRead, NULL);
			CloseHandle(hFile);
			citysize = 38450;
			GetEndo();
		}

		hCountriesFile = CreateFile(CountriesFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE) {
			yx = 0;
			GetCountries();
			CloseHandle(hCountriesFile);
		}
//		hCountriesFile = CreateFile(ProvincesFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
//		hCountriesFile = CreateFile("C:\\Users\\Public\\BritishCounties.dta", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		GetCountries();
		gotit4 = false;
		CountriesSize = yx;
		hCountryNamesFile = CreateFile(CountryNamesFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		fileSize = GetFileSize(hCountryNamesFile, NULL);
		ReadFile(hCountryNamesFile, countrynames, fileSize, &dwBytesRead, NULL);
		CloseHandle(hCountryNamesFile);
		namesize = dwBytesRead;
		for (x = 0, y = 256; x < 256; x++, y++)
			countrynames[y] = countrynames[x];// fixes bug

		hProvincesFile = CreateFile(ProvinceNamesFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		fileSize = GetFileSize(hProvincesFile, NULL);
		if (fileSize)
			ReadFile(hProvincesFile, provincenames, 406, &dwBytesRead, NULL); // 406 is trick!
		CloseHandle(hProvincesFile);

		hFile = CreateFile(BritishCounties, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE) {
			fileSize = GetFileSize(hFile, NULL);
			ReadFile(hFile, britishcounties, fileSize, &dwBytesRead, NULL);
			CloseHandle(hFile);
		}
		hIslandsFile = CreateFile(IslandFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hIslandsFile != INVALID_HANDLE_VALUE) {
			fileSize = GetFileSize(hIslandsFile, NULL);
			ReadFile(hIslandsFile, Islands, fileSize, &dwBytesRead, NULL);
			islandsize = dwBytesRead;
			CloseHandle(hIslandsFile);
			for (z = 0, x = 0; x < islandsize; x++, z++) {
				IslandsData[z].lat = (float)parseDouble(&Islands[x]);
				for (; Islands[x] != ' '; x++)
					;
				x++;
				IslandsData[z].lon = (float)parseDouble(&Islands[x]);
				for (; Islands[x] != ' '; x++)
					;
				x++;
				for (y = 0; (x < islandsize) && (Islands[x] != '\r'); x++, y++)
					IslandsData[z].name[y] = Islands[x];
				IslandsData[z].name[y] = 0;
				x++; // to '\n'
			}
		}
		hLakesFile = CreateFile(LakesFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hLakesFile != INVALID_HANDLE_VALUE) {
			fileSize = GetFileSize(hLakesFile, NULL);
			ReadFile(hLakesFile, Lakes, fileSize, &dwBytesRead, NULL);
			CloseHandle(hLakesFile);
			if (Lakes[fileSize == 0]) {
				fileSize++;
				Lakes[fileSize] = '\r';
			}
			neg = false;
			if (Lakes[0] == '-')
				neg = true;
			for (x = 0, lakes = 0; x < (int)fileSize; x++, lakes++) {
				if (neg) {
					neg = false;
					LakesData[lakes].elev = Atoi(&Lakes[x + 1]);
					LakesData[lakes].elev = -LakesData[lakes].elev;
				}
				else
					LakesData[lakes].elev = Atoi(&Lakes[x]);
				for (; (Lakes[x] != 0) && (Lakes[x] != ' ') && (Lakes[x] != '\r'); x++)
					;
				if (Lakes[x] == ' ') {
					x++;
					LakesData[lakes].lat1 = (float)atof(&Lakes[x]);
					for (; Lakes[x] != ' '; x++)
						;
					x++;
					LakesData[lakes].lon1 = (float)atof(&Lakes[x]);
					for (; Lakes[x] != ' '; x++)
						;
					x++;
					LakesData[lakes].lat2 = (float)atof(&Lakes[x]);
					for (; Lakes[x] != ' '; x++)
						;
					x++;
					LakesData[lakes].lon2 = (float)atof(&Lakes[x]);
					for (; Lakes[x] != '\r'; x++)
						;
					if (Lakes[x + 2] == '-')
						neg = true;
				}
				x++;
			}
		}
		hRiversFile = CreateFile(RiversFile2, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hRiversFile != INVALID_HANDLE_VALUE) {
			fileSize = GetFileSize(hRiversFile, NULL);
			ReadFile(hRiversFile, RiverData2, fileSize, &dwBytesRead, NULL);
			rivers = fileSize / 64; // 4 floats & 48 bytes in RiverData2[x]
			CloseHandle(hRiversFile);
		}
		break; // end of case WM_CREATE


	case WM_KEYDOWN:// number or number + 48
		if (GetKeyState(VK_CONTROL) & 0x8000) ctrl = TRUE;
		else ctrl = FALSE;
		if (GetKeyState(VK_SHIFT) & 0x8000) shift = TRUE;
		else shift = FALSE;// && vv && ww  && ((int)lats[vv] != 90)
		Rotate = 0;
		if ((wParam == VK_F3)) {// && String3[0]
			if (allcities[f3].lat != 0.0) {
				thiscenterlon = centerlon;
				lat2 = allcities[f3].lat;
				lon2 = allcities[f3].lon;
				Rotate = 0;
				newscreen = true;
				rotate = lat2;
				latitude = lat2;
				centerlat = lat2;
				longitude = lon2;
				centerlon = lon2;
				LON = LON + (thiscenterlon - centerlon);
				f3++;
			}
		}
		if (((wParam >= (96 - 48)) && (wParam <= (105 - 48))) || ((wParam >= 96) && (wParam <= 105))) { // num pad numbers 0-9 are 96-105
			newscreen = true;
			rotate = lat2;
			latitude = lat2;
			centerlat = lat2;
			longitude = lon2;
			centerlon = lon2;
			LON = LON3;
			if ((wParam >= 96) && (wParam <= 105))
				zoom = (double)(wParam - 96);
			else //if ((wParam >= (96 - 48)) && (wParam <= (105 - 48)))
				zoom = (double)(wParam - 96 + 48); // for ShowTopo & ShowCountries
			if (ctrl) {
				if (zoom == 0.0) zoom = 100.0;
				else zoom *= 10.0;
			}
			Conversion = conversion * (zoom + 1.0); // conversion = 500.0 / radius
		}
		else if ((wParam == 107) || (wParam == 187)) // '+'
			Rotate = 1;
		else if ((wParam == 109) || (wParam == 189)) // '-'
			Rotate = -1;
		else if ((wParam == 82) && (shift || ctrl)) { // 'R'
			if (showrivers == false)
				showrivers = true;
			else
				showrivers = false;
		}
		else if ((wParam == 67) && (shift || ctrl)) { // 'C'
			if (!showcities)
				showcities = true;
			else
				showcities = false;
		}
		else if ((wParam == 69) && (shift || ctrl)) { // 'E'
			if (!showcounties)
				showcounties = true;
			else
				showcounties = false;
		}
		else if (wParam == VK_UP) {
			Population -= 10000;
			GetEndo();
		}
		else if (wParam == VK_DOWN) {
			Population += 10000;
			GetEndo();
		}

		else if (wParam == VK_LEFT) {
			centerlon -= 90.0;
			if (centerlon < -180.0)
				centerlon += 360.0;
			LON = 270 - centerlon;
			newscreen = true;
			InvalidateRect(hwnd, &rect, false);
		}
		else if (wParam == VK_RIGHT) {
			centerlon += 90.0;
			if (centerlon > 180.0)
				centerlon -= 360.0;
			LON = -90.0 - centerlon;
			newscreen = true;
			InvalidateRect(hwnd, &rect, false);
		}
		else if ((wParam >= 65) && (wParam <= 90) || (wParam == VK_SPACE)) { // A or a thru Z or z
			String3[End] = (int)wParam;
			End++;
			String3[End] = '\0';
		}
		else if (wParam == VK_RETURN) {
			if (String3[0]) { // search for it in countrynames and cities
				for (x = 0; x < 20; x++) {
					allcities[x].lat = 0.0;
					allcities[x].lon = 0.0;
				}
				End = 0;
				for (x = 0; x < 512; x++) {
					for (y = 0; String3[y] != 0; y++) {
						if ((INT)countrynames[x].name[y] > 90)
							countrynames[x].name[y] -= 32;
						if (String3[y] != countrynames[x].name[y])
							break;
						else if ((countrynames[x].name[y + 1] == 0) && (String3[y + 1] == 0)) {
							thiscenterlon = centerlon;
							lat2 = countrynames[x].lat;
							lon2 = countrynames[x].lon;
							cx = x;
							Rotate = 0;
							newscreen = true;
							rotate = lat2;
							latitude = lat2;
							centerlat = lat2;
							longitude = lon2;
							centerlon = lon2;
							LON = LON + (thiscenterlon - centerlon);
							done = true;
							break;
						}
					}
					if (done) {
						break;
					}
				}
				End = 0;
				for (x = 0; x < 60; x++) {
					if (x == 52)
						x = x;
					for (y = 0; String3[y] != 0; y++) {
						if ((INT)IslandsData[x].name[y] > 90)
							IslandsData[x].name[y] -= 32;
						if (String3[y] != IslandsData[x].name[y])
							break;
						else if ((IslandsData[x].name[y + 1] == 0) && (String3[y + 1] == 0)) {
							thiscenterlon = centerlon;
							lat2 = IslandsData[x].lat;
							lon2 = IslandsData[x].lon;
							ix = x;
							Rotate = 0;
							newscreen = true;
							rotate = lat2;
							latitude = lat2;
							centerlat = lat2;
							longitude = lon2;
							centerlon = lon2;
							LON = LON + (thiscenterlon - centerlon);
							done = true;
							break;
						}
					}
					if (done) {
						break;
					}
				}
				End = 0;
				for (x = 0; x < 50; x++) {
					for (y = 0; String3[y] != 0; y++) {
						if ((INT)states[x].name[y] > 90)
							states[x].name[y] -= 32;
						if (String3[y] != states[x].name[y])
							break;
						else if ((states[x].name[y + 1] == 0) && (String3[y + 1] == 0)) {
							thiscenterlon = centerlon;
							lat2 = states[x].lat;
							lon2 = states[x].lon;
							Rotate = 0;
							newscreen = true;
							rotate = lat2;
							latitude = lat2;
							centerlat = lat2;
							longitude = lon2;
							centerlon = lon2;
							LON = LON + (thiscenterlon - centerlon);
							done = true;
							break;
						}
					}
					if (done) {
						break;
					}
				}
				End = 0;
				for (x = 0; x < 38450; x++) {
					for (y = 0; String3[y] != 0; y++) {
						if ((INT)cities[x].name[y] > 90)
							cities[x].name[y] -= 32;
						if (String3[y] != cities[x].name[y])
							break;
						else if ((cities[x].name[y + 1] == 0) && (String3[y + 1] == 0)) {
							thiscenterlon = centerlon;
							lat2 = cities[x].lat;// cities[x].lat;
							lon2 = cities[x].lon;// cities[x].lon;
							Rotate = 0;
							newscreen = true;
							rotate = lat2;
							latitude = lat2;
							centerlat = lat2;
							longitude = lon2;
							centerlon = lon2;
							LON = LON + (thiscenterlon - centerlon);
							allcities[f3].lat = cities[x].lat;
							allcities[f3].lon = cities[x].lon;
							f3++;
							if (0 == strcmp(cities[x].name, countrynames[cx].name)) {
								allcities[f3].lat = countrynames[cx].lat;
								allcities[f3].lon = countrynames[cx].lon;
								f3++;
							}
							if (0 == strcmp(cities[x].name, IslandsData[ix].name)) {
								allcities[f3].lat = IslandsData[ix].lat;
								allcities[f3].lon = IslandsData[ix].lon;
								f3++;
							}
						}
					}
				}
				f3 = 0;
				End = 0;
				done = false;
			}
			x = x;
		}
		else if ((wParam == VK_BACK) && (End != 0))
			End--;
		else if (wParam == VK_ESCAPE) {
			DestroyWindow(hwnd);
			break;
		}
		InvalidateRect(hwnd, &rect, false);
		break;
	case WM_LBUTTONDOWN:
		Rotate = 0;
		newscreen = true;
		rotate = lat2;
		latitude = lat2;
		centerlat = lat2;
		longitude = lon2;
		centerlon = lon2;
		LON = LON3;
		InvalidateRect(hwnd, &rect, false);
		break;
	case WM_RBUTTONDOWN:
		rbuttondown = rbuttondown2 = true;
		InvalidateRect(hwnd, &rect, false);
		break;
	case WM_MOUSEMOVE:
		xLoc = LOWORD(lParam); // pixels from left of screen
		yLoc = HIWORD(lParam); // pixels from top of screen
		Rotate = 0;
		newscreen = false;
		GetLatLon();/////////////
		break;
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		if (first) {
			rect = ps.rcPaint;
			hdcMem = CreateCompatibleDC(hdc);
			hBitmap = CreateCompatibleBitmap(hdc, 1920, 1080);
			SelectObject(hdcMem, hBitmap);
			hdcMem3 = CreateCompatibleDC(hdc);
			hBitmap3 = CreateCompatibleBitmap(hdc, 1920, 1080);
			SelectObject(hdcMem3, hBitmap3);
			hdcMem5 = CreateCompatibleDC(hdc); // for ShowTopo
			hBitmap5 = CreateCompatibleBitmap(hdc, 1920, 1080);
			SelectObject(hdcMem5, hBitmap5);
			D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
			D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), 0, 0, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT);
			pD2DFactory->CreateDCRenderTarget(&props, &pRT);
			pRT->BindDC(hdcMem5, &rect); // for ShowTopo
			hFont = CreateFontIndirect(&lf);
			hOldFont = SelectObject(hdcMem, hFont);
		}
		FillRect(hdcMem, &rect, hBrush7);
		if (newscreen) {
			FillRect(hdcMem3, &rect, hBrush7);
			if (CountriesSize)
				ShowCountries();
			if (GOTIT)
				ShowTopo();
			SetCursorPos(968, 540);
			newscreen = false;
		}
		if (zoom < 10.0) { // draw 10° grid
			if (centerlat < 0.0)
				Y = rotate;
			else
				Y = 0.0;
			zz = (int)centerlon % 10;
			hOldPen = SelectObject(hdcMem, hGridPen);
			for (v = 0, elevlat = 130.0; elevlat < 270.0 + Y; elevlat += 10.0, v++) {
				Lat = elevlat * deg2rad;
				fuc = true;
				for (w = 0, elevlon = 0.0 - zz; elevlon < 180.0 - zz; elevlon += 5.0, w++) {
					Lon = elevlon * deg2rad;
					Draw();
					if ((xx >= 0) && (xx < 1920) && (yy >= 0) && (yy < 1080)) {
						if (fuc) {
							fuc = false;
							MoveToEx(hdcMem, xx, yy, NULL);
						}
						LineTo(hdcMem, xx, yy);
					}
				}
			}
			for (w = 0, elevlon = 0.0 - zz; elevlon < 180.0 - zz; elevlon += 10.0, w++) {
				Lon = elevlon * deg2rad;
				fuc = true;
				for (v = 0, elevlat = 130.0; elevlat < 270.0 + Y; elevlat += 5.0, v++) {
					Lat = elevlat * deg2rad;
					Draw();
					if ((xx >= 0) && (xx < 1920) && (yy >= 0) && (yy < 1080)) {
						if (fuc) {
							fuc = false;
							MoveToEx(hdcMem, xx, yy, NULL);
						}
						LineTo(hdcMem, xx, yy);
					}
				}
			}
			SelectObject(hdcMem, hOldPen);
		}
		if (showrivers) {
			hRiverPen = GetStockObject(DC_PEN);
			SetDCPenColor(hdcMem, 0xFFC000);
			hOldPen = SelectObject(hdcMem, hRiverPen);
			for (x = 1; x < rivers; x++) {
				if ((RiverData2[x].fromlon >= minus90) && (RiverData2[x].fromlon <= plus90) && (RiverData2[x].fromlat >= Minus90) && (RiverData2[x].fromlat <= Plus90)) {
					Lat = -RiverData2[x].fromlat * deg2rad;
					Lon = (RiverData2[x].fromlon + LON) * deg2rad;
					Draw();
					if ((xx > 0) && (xx < 1920) && (yy > 0) && (yy < 1080)) {
						ry1 = yy;
						rx1 = xx;
						Lat = -RiverData2[x].tolat * deg2rad;
						Lon = (RiverData2[x].tolon + LON) * deg2rad;
						Draw();
						if ((xx > 0) && (xx < 1920) && (yy > 0) && (yy < 1080)) {
							ry2 = yy;
							rx2 = xx;
							MoveToEx(hdcMem, rx1, ry1, NULL);
							LineTo(hdcMem, rx2, ry2);
						}
					}
				}
			}
			SelectObject(hdcMem, hOldPen);
		}
		if (GOTIT)
			BitBlt(hdcMem, 0, 0, rect.right, rect.bottom, hdcMem5, 0, 0, SRCAND); // elevation colors
		if (CountriesSize)
			BitBlt(hdcMem, 0, 0, rect.right, rect.bottom, hdcMem3, 0, 0, SRCAND); // boundaries
//		if (GOTIT)
//			BitBlt(hdcMem, 0, 0, rect.right, rect.bottom, hdcMem5, 0, 0, SRCAND); // elevation colors
		if (zoom && showcities) {
			if ((Rotate) && !shift && !ctrl) { // CreateFontIndirect to rotate name
				DeleteObject(hFont);
				lf.lfHeight = -14;
				if (Rotate > 0) {
					lf.lfEscapement -= 100;
					lf.lfOrientation -= 100;
				}
				else {
					lf.lfEscapement += 100;
					lf.lfOrientation += 100;
				}
			}
			else { // horizontal cities
				DeleteObject(hFont);
				lf.lfHeight = -14;
			}
			hFont = CreateFontIndirect(&lf);
			SetTextColor(hdcMem, 0xE0);
			hOldFont = SelectObject(hdcMem, hFont);
			SetBkMode(hdcMem, TRANSPARENT);
			for (x = 0; x < endo; x++) {
				if ((cities[x].lon >= minus90) && (cities[x].lon <= plus90) && (cities[x].lat >= Minus90) && (cities[x].lat <= Plus90)) {
					Lat = -cities[x].lat * deg2rad;
					Lon = (cities[x].lon + LON) * deg2rad;
					Draw();
					SetPixel(hdcMem, xx, yy, 0);
					TextOut(hdcMem, xx, yy, cities[x].name, (int)strlen(cities[x].name));
				}
			}
			SetTextColor(hdcMem, 0);
			SetBkMode(hdcMem, TRANSPARENT);
			chars = sprintf_s(String, 64, "cities with population > %i", Population);
			TextOut(hdcMem, 20, 50, String, chars);
			DeleteObject(hFont);
			lf.lfHeight = -16;
			hFont = CreateFontIndirect(&lf);
			SelectObject(hdcMem, hFont);
			SetBkMode(hdcMem, OPAQUE);
 		}
		if (showcounties) {
			SetBkMode(hdcMem3, TRANSPARENT);
			for (x = 0; x < 218; x++) {
				if ((britishcounties[x].name[0] != 'X') && (britishcounties[x].lon >= minus90) && (britishcounties[x].lon <= plus90) && (britishcounties[x].lat >= Minus90) && (britishcounties[x].lat <= Plus90)) {
					Lat = -britishcounties[x].lat * deg2rad;
					Lon = (britishcounties[x].lon + LON) * deg2rad;
					Draw();
					y = (int)strlen(britishcounties[x].name);
					if (y > 24)
						y = 24;
					TextOut(hdcMem, xx, yy, britishcounties[x].name, y);
				}
			}
			SetBkMode(hdcMem3, OPAQUE);
		}
		SetBkMode(hdcMem, TRANSPARENT);
		if (zoom)
			chars = sprintf_s(String, 64, "zoom = %i", (int)zoom);
		TextOut(hdcMem, 20, 35, String, chars);
		MoveToEx(hdcMem, 957, 505, NULL); // create x in center
		LineTo(hdcMem, 968, 516);
		MoveToEx(hdcMem, 967, 505, NULL);
		LineTo(hdcMem, 956, 516);
		SelectObject(hdcMem, hOldPen);
		SetBkMode(hdcMem, OPAQUE);

		if (zoom == 0.0) {
			if (first)
			SetTextColor(hdcMem, 0xD0);
			TextOut(hdcMem, 3, 0, "Press the left mouse button to center the location the pointer is over.", 72);
			TextOut(hdcMem, 3, 20, "Press a number to zoom to that number AND center the location the pointer is over.", 83);
			TextOut(hdcMem, 100, 36, "(hold the Ctrl key down to zoom to 10 times that number)", 56);
			TextOut(hdcMem, 3, 52, "Press left / right arrow key to rotate the globe 90°.", 54);
			TextOut(hdcMem, 3, 72, "Press the right mouse button to see the latitude/longitude and altitude at the pointer.", 88);
			if (first) {
				first = false;
				SetTextColor(hdcMem, 0);
			}
			TextOut(hdcMem, 3, 110, "Press Control-C key to show / not show cities.", 47);
			TextOut(hdcMem, 3, 130, "Press the up / down arrow key to increase / decrease cities by 10,000 population.", 82);
			TextOut(hdcMem, 3, 150, "If city names overlap, press the - or + key to rotate them.", 59);
			TextOut(hdcMem, 3, 190, "Press Control-R to show / not show rivers. Press the right mouse button", 72);
			TextOut(hdcMem, 3, 210, "when over a river junction / bend / source to see its name.", 59);
			TextOut(hdcMem, 3, 250, "Type in the name of a country, city, state  or island you want to move to", 74);
			TextOut(hdcMem, 3, 270, "and press Enter (press the Back key to erase last entered letter).", 67);
			TextOut(hdcMem, 3, 290, "Press F3 to see more cities/countries/islands with the same name.", 66);
		}
		if (String3[0])
			TextOut(hdcMem, 0, 460, String3, End);
		if (rbuttondown) {
			rbuttondown = false;
			gotit2 = false;
			if (showrivers) {
				for (x = 0; x < rivers; x++) {
					if ((Y != RiverData2[x].fromlat) || (X != RiverData2[x].fromlon)) {
						if ((lat2 <= RiverData2[x].fromlat + 0.2) && (lat2 >= RiverData2[x].fromlat - 0.2) && (lon2 <= RiverData2[x].fromlon + 0.2) && (lon2 >= RiverData2[x].fromlon - 0.2)) {
							SetBkMode(hdcMem, TRANSPARENT);
							TextOut(hdcMem, xLoc, yLoc, RiverData2[x].name, 24);
							if (RiverData2[x].tolat != RiverData2[x - 1].tolat) {
								TextOut(hdcMem, xLoc, yLoc + 12, RiverData2[x].name2, 23);
								Y = RiverData2[x].fromlat;
								X = RiverData2[x].fromlon;
								SetBkMode(hdcMem, OPAQUE);
							}
							gotit2 = true;
							break;
						}
					}
				}
			}
			if (!gotit2) { // show latitude longitude elevation
				SetBkMode(hdcMem, TRANSPARENT);
				SetPixel(hdcMem, xLoc, yLoc, 0);
				chars = sprintf_s(String, 64, "%.1f° lat", lat2);
				TextOut(hdcMem, xLoc, yLoc, String, chars);
				chars = sprintf_s(String2, 64, "%.1f° lon", lon2);
				TextOut(hdcMem, xLoc, yLoc + 16, String2, chars);
				if (prevlat != 0.0) {
					X = Haversine(lat2, lon2, prevlat, prevlon); // kilometersmeters
					chars = sprintf_s(String2, 64, "%.i Miles from previous", (int)(X / 1.60934));
					TextOut(hdcMem, xLoc, yLoc + 48, String2, chars);
				}
				prevlat = lat2;
				prevlon = lon2;
				for (y = 1; (y < v2); y++) {// && (y < 10000)
					for (x = 1; x < w2; x++) {// && (x < 10000)
						if (H2[y][x] != -30000) {
							if (rbuttondown2) { // compare xLoc with w2 and yLoc with v2 to get elevation there
								if ((xLoc >= H2[y][x - 2]) && (xLoc <= H2[y][x]) && (yLoc >= V2[y - 2][x]) && (yLoc <= V2[y][x])) {
									if ((Elevs[y][x] != -500)) {
										chars = sprintf_s(String2, 64, "%i ft.", (int)((double)Elevs[y][x] * 3.28084));
										TextOut(hdcMem, xLoc, yLoc + 32, String2, chars); // elevation
										rbuttondown2 = false;
										break;
									}
									rbuttondown2 = false;
									break;
								}
							}
						}
					}
					if (!rbuttondown2)
						break;
				}
				SetBkMode(hdcMem, OPAQUE);
			}
		} // end of if (rbuttondown)
		BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
		EndPaint(hwnd, &ps);
		break;
	case WM_DESTROY:
		hr = pD2DFactory->Release();
		hr = pRT->Release();
		free(ElevData);
		PostQuitMessage(0);
		break;
	} // end of switch (message)
	return DefWindowProc(hwnd, message, wParam, lParam);
} // end of WndProc
