/*@@ Wedit generated application. Written Thu Oct 26 12:28:52 2000
 @@header: d:\lcc\basicres.h
 @@resources: d:\lcc\basic.rc
 Do not edit outside the indicated areas */
/*<---------------------------------------------------------------------->*/
/*<---------------------------------------------------------------------->*/
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <string.h>
#include "basicres.h"
/*<---------------------------------------------------------------------->*/
HINSTANCE hInst;		// Instance handle
HWND hwndMain;		//Main window handle

LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
/* --- The following code comes from d:\lcc\lib\wizard\statbar.tpl. */

// Global Variables for the status bar control.

HWND  hWndStatusbar;

/*------------------------------------------------------------------------
 Procedure:     UpdateStatusBar ID:1
 Purpose:       Updates the statusbar control with the appropiate
                text
 Input:         lpszStatusString: Charactar string that will be shown
                partNumber: index of the status bar part number.
                displayFlags: Decoration flags
 Output:        none
 Errors:        none

------------------------------------------------------------------------*/
void UpdateStatusBar(LPSTR lpszStatusString, WORD partNumber, WORD displayFlags)
{
    SendMessage(hWndStatusbar,
                SB_SETTEXT,
                partNumber | displayFlags,
                (LPARAM)lpszStatusString);
}


/*------------------------------------------------------------------------
 Procedure:     MsgMenuSelect ID:1
 Purpose:       Shows in the status bar a descriptive explaation of
                the purpose of each menu item.The message
                WM_MENUSELECT is sent when the user starts browsing
                the menu for each menu item where the mouse passes.
 Input:         Standard windows.
 Output:        The string from the resources string table is shown
 Errors:        If the string is not found nothing will be shown.
------------------------------------------------------------------------*/
LRESULT MsgMenuSelect(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
{
    static char szBuffer[256];
    UINT   nStringID = 0;
    UINT   fuFlags = GET_WM_MENUSELECT_FLAGS(wparam, lparam) & 0xffff;
    UINT   uCmd    = GET_WM_MENUSELECT_CMD(wparam, lparam);
    HMENU  hMenu   = GET_WM_MENUSELECT_HMENU(wparam, lparam);

    szBuffer[0] = 0;                            // First reset the buffer
    if (fuFlags == 0xffff && hMenu == NULL)     // Menu has been closed
        nStringID = 0;

    else if (fuFlags & MFT_SEPARATOR)           // Ignore separators
        nStringID = 0;

    else if (fuFlags & MF_POPUP)                // Popup menu
    {
        if (fuFlags & MF_SYSMENU)               // System menu
            nStringID = IDS_SYSMENU;
        else
            // Get string ID for popup menu from idPopup array.
            nStringID = 0;
    }  // for MF_POPUP
    else                                        // Must be a command item
        nStringID = uCmd;                       // String ID == Command ID

    // Load the string if we have an ID
    if (0 != nStringID)
        LoadString(hInst, nStringID, szBuffer, sizeof(szBuffer));
    // Finally... send the string to the status bar
    UpdateStatusBar(szBuffer, 0, 0);
    return 0;
}


/*------------------------------------------------------------------------
 Procedure:     InitializeStatusBar ID:1
 Purpose:       Initialize the status bar
 Input:         hwndParent: the parent window
                nrOfParts: The status bar can contain more than one
                part. What is difficult, is to figure out how this
                should be drawn. So, for the time being only one is
                being used...
 Output:        The status bar is created
 Errors:
------------------------------------------------------------------------*/
void InitializeStatusBar(HWND hwndParent,int nrOfParts)
{
    const cSpaceInBetween = 8;
    int   ptArray[40];   // Array defining the number of parts/sections
    RECT  rect;
    HDC   hDC;

   /* * Fill in the ptArray...  */

    hDC = GetDC(hwndParent);
    GetClientRect(hwndParent, &rect);

    ptArray[nrOfParts-1] = rect.right;
    //---TODO--- Add code to calculate the size of each part of the status
    // bar here.

    ReleaseDC(hwndParent, hDC);
    SendMessage(hWndStatusbar,
                SB_SETPARTS,
                nrOfParts,
                (LPARAM)(LPINT)ptArray);

    UpdateStatusBar("Ready", 0, 0);
    //---TODO--- Add code to update all fields of the status bar here.
    // As an example, look at the calls commented out below.

//    UpdateStatusBar("Cursor Pos:", 1, SBT_POPOUT);
//    UpdateStatusBar("Time:", 3, SBT_POPOUT);
}


/*------------------------------------------------------------------------
 Procedure:     CreateSBar ID:1
 Purpose:       Calls CreateStatusWindow to create the status bar
 Input:         hwndParent: the parent window
                initial text: the initial contents of the status bar
 Output:
 Errors:
------------------------------------------------------------------------*/
static BOOL CreateSBar(HWND hwndParent,char *initialText,int nrOfParts)
{
    hWndStatusbar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_BORDER|SBARS_SIZEGRIP,
                                       initialText,
                                       hwndParent,
                                       IDM_STATUSBAR);
    if(hWndStatusbar)
    {
        InitializeStatusBar(hwndParent,nrOfParts);
        return TRUE;
    }

    return FALSE;
}

/*<---------------------------------------------------------------------->*/
/*@@0->@@*/
static BOOL InitApplication(void)
{
	WNDCLASS wc;

	memset(&wc,0,sizeof(WNDCLASS));
	wc.style = CS_BYTEALIGNCLIENT |CS_BYTEALIGNWINDOW |CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS ;
	wc.style = CS_BYTEALIGNCLIENT |CS_BYTEALIGNWINDOW |CS_DBLCLKS ;
	wc.lpfnWndProc = (WNDPROC)MainWndProc;
	wc.hInstance = hInst;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszClassName = "basicWndClass";
	wc.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU);
	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
	if (!RegisterClass(&wc))
		return 0;
/*@@0<-@@*/
	// ---TODO--- Call module specific initialization routines here

	return 1;
}

/*<---------------------------------------------------------------------->*/
/*@@1->@@*/
HWND CreatebasicWndClassWnd(void)
{
	return CreateWindow("basicWndClass","basic",
		WS_MINIMIZEBOX|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZEBOX|WS_CAPTION|WS_BORDER|WS_SYSMENU|WS_THICKFRAME,
		CW_USEDEFAULT,0,CW_USEDEFAULT,0,
		NULL,
		NULL,
		hInst,
		NULL);
}
/*@@1<-@@*/
/*<---------------------------------------------------------------------->*/
/* --- The following code comes from d:\lcc\lib\wizard\defOnCmd.tpl. */
void MainWndProc_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
	switch(id) {
		// ---TODO--- Add new menu commands here
		/*@@NEWCOMMANDS@@*/
		case IDM_NEW:
			create_balls(hwnd);
		break;
		case IDM_EXIT:
		PostMessage(hwnd,WM_CLOSE,0,0);
		break;
	}
}

/*<---------------------------------------------------------------------->*/
/*AT LAST MY CODE */

int dispx,dispy;
float accx = 0.0;
float accy = 0.01;
float e = 0.97;
int numballs = 0;
float tc;
float xmin,xmax,ymin,ymax;
float dee2,dee;
HBRUSH	brush1,brush2,brush3;
HPEN pen1, pen2,pen3;
#define SS 5000
float r[SS],nvx[SS],nvy[SS],vx[SS],vy[SS],px[SS],py[SS],m[SS],opx[SS],opy[SS];
float fabs(),sqrt();
int got_one;
long btime,bperiod,ncollisions;

/* windows cruft */

void init_things(HWND wh)
{
LOGBRUSH lb;
lb.lbStyle = BS_HOLLOW;

brush1 = CreateBrushIndirect(&lb);
brush2 = CreateBrushIndirect(&lb);
brush3 = CreateBrushIndirect(&lb);

pen2 = CreatePen(PS_SOLID,0,0);
pen1 = CreatePen(PS_SOLID,0,0xffffff);
pen3 = CreatePen(PS_SOLID,0,0xff);
}

void release_things(HWND wh)
{
DeleteObject(brush1);
DeleteObject(brush2);
DeleteObject(pen1);
DeleteObject(pen2);
DeleteObject(brush3);
DeleteObject(pen3);
}


void disp_rec(HWND wh)
{
char bb[100];
long x,y;
RECT r;
POINT p;
GetCursorPos(&p);
GetWindowRect(wh,&r);
x = r.right - r.left;
y = r.bottom - r.top;
sprintf(bb,"%ld collisions, %ld ms  ",ncollisions,bperiod);
UpdateStatusBar(bb,0,0);
xmin = (float)r.left;
ymin = (float)r.top;
xmax = (float)r.right-8;
ymax = (float)r.bottom-64;
}


float frand()
{
float t;
int rand();
t = rand()/32768.0;
t = t*2.0-1.0;
return t;
}


void create_balls(HWND wh)
{
int i;
float extx,exty;
RECT rec;
GetWindowRect(wh,&rec);
extx = (float)rec.right - (float)rec.left;
exty = (float)rec.bottom - (float)rec.top;
numballs =300;
dee =7.0;
got_one=0;
tc = 1.0;
for (i=1; i<=numballs; i++)
	{
	px[i]=frand()*extx;
	py[i]=frand()*exty;
	vx[i]=frand()*0.2;
	vy[i]=frand()*0.2;
	r[i]=dee;
	}
dee2 = dee*dee*4;
btime = GetTickCount();
bperiod = 0;
}

void display_balls(HWND hwnd)
{
int a,x1,x2,y1,y2;
HDC dc;
dc = GetDC(hwnd);
for(a=1; a<=numballs; a++)
	{
    x1 = (int)(opx[a] - r[a] - xmin);
    y1 = (int)(opy[a] - r[a] - ymin);
    x2 = (int)(opx[a] + r[a] - xmin);
    y2 = (int)(opy[a] + r[a] - ymin);
	SelectObject(dc,brush1);
	SelectObject(dc,pen1);
	Ellipse(dc,x1,y1,x2,y2);
    x1 = (int)(px[a] - r[a] - xmin);
    y1 = (int)(py[a] - r[a] - ymin);
    x2 = (int)(px[a] + r[a] - xmin);
    y2 = (int)(py[a] + r[a] - ymin);
	if(got_one == a)
		{
		SelectObject(dc,brush3);
		SelectObject(dc,pen3);
		}
	else
		{
		SelectObject(dc,brush2);
		SelectObject(dc,pen2);
		}
	Ellipse(dc,x1,y1,x2,y2);
	opx[a]=px[a];
	opy[a]=py[a];
	}
ReleaseDC(hwnd, dc);
bperiod = GetTickCount() - btime;
btime = GetTickCount();
}



void update_balls(HWND hwnd)
{
int a,b;
float d,nx,ny,m,vxa,vya,vxb,vyb,dd,cdx,cdy,cosa,cosam;
POINT p;
ncollisions = 0;
if(got_one != 0)
	{
	GetCursorPos(&p);
	px[got_one] = (float)p.x;
	py[got_one] = (float)(p.y-32);
	vx[got_one] = 0.1*(px[got_one] - opx[got_one])*tc ;
	vy[got_one] = 0.1*(py[got_one] - opy[got_one])*tc ;
	}

for(a=1; a<=numballs; a++)
	if(a != got_one)
	for(b=1; b<=numballs; b++)
		if(a != b)
		{
		d = (px[a]-px[b])*(px[a]-px[b])+(py[a]-py[b])*(py[a]-py[b]);
			if (d < dee2)
				{
				ncollisions++;
				d = sqrt(d);
				vxa= vx[a];vya=vy[a];vxb=vx[b];vyb=vy[b];
				nx=px[b]-px[a];
				ny=py[b]-py[a];
				if (fabs(d)>0.0001)
					{
					cdx=nx/d;cdy=ny/d;
					dd=r[a]+r[b]-d;
					px[a] -= dd*cdx;   /* just move them apart */
					py[a] -= dd*cdy;   /* no physical rationale, sorry */
					px[b] += dd*cdx;
					py[b] += dd*cdy;
					m = sqrt(vx[a]*vx[a]+vy[a]*vy[a]);
					if (fabs(m)>0.0001)		/* A's velocity > 0 ? */
						{
						cosam = (cdx*vx[a]+cdy*vy[a]) * e;
						vxa -= cdx*cosam;
						vya -= cdy*cosam; /* conserve momentum */
						vxb += cdx*cosam;
						vyb += cdy*cosam;
						}
					m = sqrt(vx[b]*vx[b]+vy[b]*vy[b]);
					if (fabs(m) >0.0001)
						{
						cosam = (cdx*vx[b]+cdy*vy[b]) * e;
						vxa += cdx*cosam;
						vya += cdy*cosam;
						vxb -= cdx*cosam;
						vyb -= cdy*cosam;
						}
					}
				vx[a]=vxa;vy[a]=vya;vx[b]=vxb;vy[b]=vyb;
			}
		}
	for(a=1; a<=numballs; a++)
		{
		if (px[a]<= (xmin+r[a]))
			{
			px[a]=xmin+r[a];
			vx[a] = -vx[a] * e;
			}
		if (px[a]>= (xmax-r[a]))
			{
			px[a]=xmax-r[a];
			vx[a] = -vx[a] * e;
			}
		if (py[a]<= (ymin+r[a]))
			{
			py[a]=ymin+r[a];
			vy[a] = -vy[a] * e;
			}
		if (py[a]>= (ymax-r[a]))
			{
			py[a]=ymax-r[a];
			vy[a] = -vy[a] * e;
			}
		}
	for(a=1; a<=numballs; a++)
		if(a != got_one)
			{
			vx[a] += accx*tc;
			vy[a] += accy*tc;
			px[a] += vx[a]*tc;
			py[a] += vy[a]*tc;
			}
}


void got_drop_one()
{
int i;
POINT p;
float d,fmx,fmy;
GetCursorPos(&p);
fmx = (float)p.x;
fmy = (float)(p.y-32);
if(got_one != 0)
	got_one = 0;
else
	for(i=1; i <= numballs;i++)
		{
		d = (px[i]-fmx)*(px[i]-fmx)+(py[i]-fmy)*(py[i]-fmy);
		if(d < (2.0*dee))
			{
			got_one = i;
			break;
			}
		}
}


LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{

	switch (msg) {
	case WM_LBUTTONUP:
		got_drop_one();
		break;
	case WM_SIZE:
	case WM_MOVE:
		SendMessage(hWndStatusbar,msg,wParam,lParam);
		InitializeStatusBar(hWndStatusbar,1);
		break;
	case WM_PAINT:
		disp_rec(hwnd);
		display_balls(hwnd);
		update_balls(hwnd);
		break;
	case WM_MENUSELECT:
		return MsgMenuSelect(hwnd,msg,wParam,lParam);
	case WM_COMMAND:
		HANDLE_WM_COMMAND(hwnd,wParam,lParam,MainWndProc_OnCommand);
		break;
	case WM_CREATE:
		create_balls(hwnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;


	default:
		return DefWindowProc(hwnd,msg,wParam,lParam);
	}
/*@@3<-@@*/
	return 0;
}
/*@@2<-@@*/

/*<---------------------------------------------------------------------->*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
	MSG msg;
	HANDLE hAccelTable;

	hInst = hInstance;
	if (!InitApplication())
		return 0;
	hAccelTable = LoadAccelerators(hInst,MAKEINTRESOURCE(IDACCEL));
	if ((hwndMain = CreatebasicWndClassWnd()) == (HWND)0)
		return 0;
	CreateSBar(hwndMain,"Ready",1);
	ShowWindow(hwndMain,SW_SHOW);
	init_things(hwndMain);
	while (GetMessage(&msg,NULL,0,0)) {
		if (!TranslateAccelerator(msg.hwnd,hAccelTable,&msg)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	release_things(hwndMain);
	return msg.wParam;
}
 

