/*
 | PONGBALL.C
 |
 | Graphics Driver for SieFuzzy Pongball demo.
 |
 | Copyright (c) Siemens ZFE ST SN 42 1993.
 | All rights reserved.
 |
 | $Header:   P:/VCS/TSEX/PONGBALL/PONGBALL.C_V   1.1   10 Dec 1993 17:42:34   ror  $
 */

#pragma warning (disable:4001)
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <fpl.h>
#include <ts.h>
#include "tssim.h"

// Local Macros.
//
#define TITLE           "Pongball"
#define TUBEPENSIZE     (2)
#define NOTEQUAL(a,b)   (fabs(a-b) > 0.5)

// Create the graphic output window.
//
// Returns NULL if initialization errors, otherwise non-NULL GLOBALHANDLE.
//
GLOBALHANDLE FAR PASCAL TSSimGraphicInit(LPGRAPHICINIT pInit)
{
    HCURSOR hCurOrg;
    MDICREATESTRUCT cs;

    hWndFrame = pInit->hWndFrame;

    if (hWndGraphic)
    {
	ShowWindow (hWndGraphic, SW_SHOW);
	return (GLOBALHANDLE) 1;
    }

    hCurOrg = SetCursor (LoadCursor (NULL, IDC_WAIT));

    // Load MDI create struct with sent data.
    //
    cs.szClass    = (LPSTR) CLASS;
    cs.szTitle    = (LPSTR) TITLE;
    cs.style      = CS_DBLCLKS | WS_CLIPCHILDREN;
    cs.x          = CW_USEDEFAULT;
    cs.y          = CW_USEDEFAULT;
    cs.cx         = CW_USEDEFAULT;
    cs.cy         = CW_USEDEFAULT;
    cs.hOwner     = hInst;
    cs.lParam     = 0L;

    hWndGraphic = (HWND) (UINT) SendMessage (pInit->hWndMDIClient, WM_MDICREATE, 0, (LPARAM) (LPMDICREATESTRUCT) &cs);

    // Error if no memory or mega problem
    //
    if (hWndGraphic == NULL)
    {
	SetCursor (hCurOrg);
	return NULL;
    }

    // If there is a window, show it.
    //
    else
    {
	ShowWindow (hWndGraphic, SW_SHOW);
	UpdateWindow (hWndGraphic);
    }

    SetCursor (hCurOrg);

    SetWindowText (hWndGraphic, (LPCSTR) TITLE);

    // This window doesn't require any allocated memory, but we must return
    // a non-NULL GLOBALHANDLE to SieFuzzy so it knows that initialization
    // was successful
    //
    return (GLOBALHANDLE) 1;
}


// Called when the user screen should be updated.
//
// Returns 0 if no errors, else non-zero.
//
int FAR PASCAL TSSimGraphic(GLOBALHANDLE hMem, LPSTR paramfmt, LPIOVALUE params)
{
    PWINDATA pWinData;

    NOTUSED(hMem);

    if (!hWndGraphic)
	return 0;

    // Verify parameters are 3(6) FLOAT values, otherwise, return a bad completion.
    //
    if (lstrcmp (paramfmt, (LPSTR) "AAA") != 0)
	return 1;

    // Get the input parameters
    //
    pWinData              = (PWINDATA) GetWinMem (hWndGraphic);
/*  pWinData->tube_width  = params++->float_value;
    pWinData->tube_height = params++->float_value;
    pWinData->ball_radius = params++->float_value;
*/  pWinData->setpoint    = params++->float_value;
    pWinData->pos         = params++->float_value;
    pWinData->current     = params++->float_value;

    // if the setpoint changed, redraw all        
    if NOTEQUAL(pWinData->setpoint, pWinData->oldsetpoint) {
	pWinData->oldsetpoint = pWinData->setpoint;
	pWinData->oldpos = pWinData->pos;
	pWinData->oldcurrent = pWinData->current;
	InvalidateRect (pWinData->hWnd, NULL, TRUE);
    } else {
    // if the pos/current changed, redraw appropriate region        
	if NOTEQUAL(pWinData->pos, pWinData->oldpos) {
	    pWinData->oldpos = pWinData->pos;
	    InvalidateRect (pWinData->hWnd, &pWinData->rt, TRUE);
	}
	if (pWinData->current > pWinData->oldcurrent) {
	    pWinData->oldcurrent = pWinData->current;
	    InvalidateRect (pWinData->hWnd, &pWinData->rc, FALSE);
	}
	if (pWinData->current < pWinData->oldcurrent - 400) {
	    pWinData->oldcurrent = pWinData->current;
	    InvalidateRect (pWinData->hWnd, &pWinData->rc, TRUE);
	}
    }
    UpdateWindow (pWinData->hWnd);

    // Return a good completion
    //
    return 0;
}


// Called by SieFuzzy when the simulation is reset.
//
// Returns 0 if no errors, else non-zero.
//
int FAR PASCAL TSSimGraphicReset(GLOBALHANDLE hMem)
{
    NOTUSED(hMem);

    // Reset internal flags and memory structures.
    //

    // Return a good completion
    //
    return 0;
}


// Called by SieFuzzy when the simulation is terminated.
//
void FAR PASCAL TSSimGraphicClean(GLOBALHANDLE hMem)
{
    NOTUSED(hMem);

    // This window does not require allocated memory, so we don't
    // have to deallocate the hMem handle.
    //
    SendMessage (hWndGraphic, WM_CLOSE, 0, 0L);
}


// Initialize window data.
//
void SimGraphic_InitWindowData(PWINDATA pWinData)
{
    int cx;
    RECT r;

	 pWinData->tube_width  = 10;
	 pWinData->tube_height = 100;
	 pWinData->ball_radius = 8;
	 pWinData->setpoint    = 60;
	 pWinData->oldsetpoint = pWinData->setpoint;
	 pWinData->pos         = 30;
	 pWinData->oldpos      = pWinData->pos;
	 pWinData->current     = 0;
	 pWinData->oldcurrent  = pWinData->current;
    
    // Resize our window.
    //
    if (hWndMDIClient)
    {
	GetWindowRect (pWinData->hWnd, &r);
	ScreenToClient (hWndMDIClient, (POINT FAR *) &r);
	ScreenToClient (hWndMDIClient, (POINT FAR *) &r.right);
	cx = (r.bottom-r.top)/2;
	MoveWindow (pWinData->hWnd, r.left, r.top, cx, cx, TRUE);
    }
}


// Paint the window.
//
void SimGraphic_OnPaint(PWINDATA pWinData)
{
    RECT r;
    int cx;
    int cy;
    HDC hDC;
    RECT b1;
    FLOAT cradius;
    FLOAT cpos;
    PAINTSTRUCT ps;
    HPEN hPenColor, hPenOrg;
    HBRUSH hBrushColor, hBrushOrg;
    POINT poly[3];

    if (!hWndGraphic)
	return;

    // Intialize hDC for painting.
    //
    hDC = BeginPaint (pWinData->hWnd, &ps);

    // Set up ISOTROPIC mapping mode for four quatrant system.
    //
//    FillRect (hDC, (LPRECT) &ps.rcPaint, GetStockObject (WHITE_BRUSH));
    GetClientRect (pWinData->hWnd, &r);

    cx = r.right  - r.left;
    cy = r.bottom - r.top;
	 SetMapMode (hDC, MM_ISOTROPIC);
	 SetWindowExt (hDC, (int) (0.7 * pWinData->tube_height), (int) (1.5 * pWinData->tube_height));
	 SetViewportExt (hDC, cx, -cy);
	 SetViewportOrg (hDC, cx/2, cy*4/5);

    SetRect (&pWinData->rt, (int)-pWinData->tube_width/2,(int)pWinData->tube_height,(int)pWinData->tube_width/2,0);
    LPtoDP (hDC, (LPPOINT) &pWinData->rt, 2);

    SetRect (&pWinData->rc, (int)(-3*pWinData->tube_width),0,(int)(3*pWinData->tube_width),(int)(-1.5*pWinData->tube_width));
    LPtoDP (hDC, (LPPOINT) &pWinData->rc, 2);

	 // Draw tube.
	 //
	 hPenColor = CreatePen (PS_SOLID, TUBEPENSIZE, RGB(0,0,0));
	 hPenOrg   = SelectPen (hDC, hPenColor);
	 MoveTo (hDC, (int) -pWinData->tube_width/2-TUBEPENSIZE, (int) 0);
	 LineTo (hDC, (int) -pWinData->tube_width/2-TUBEPENSIZE, (int) pWinData->tube_height);
	 MoveTo (hDC, (int) pWinData->tube_width/2+TUBEPENSIZE, (int) 0);
	 LineTo (hDC, (int) pWinData->tube_width/2+TUBEPENSIZE, (int) pWinData->tube_height);

	 // Draw setpoint.
	 //
	 MoveTo (hDC, (int) -pWinData->tube_width-TUBEPENSIZE, (int) pWinData->setpoint);
	 LineTo (hDC, (int) -pWinData->tube_width/2-TUBEPENSIZE, (int) pWinData->setpoint);
	 MoveTo (hDC, (int) pWinData->tube_width+TUBEPENSIZE, (int) pWinData->setpoint);
	 LineTo (hDC, (int) pWinData->tube_width/2+TUBEPENSIZE, (int) pWinData->setpoint);
	 SelectPen (hDC, hPenOrg);
	 DeleteObject (hPenColor);

	 // Draw pongball.
    //
    SelectPen (hDC, GetStockObject (NULL_PEN));
	 hBrushColor = CreateSolidBrush (RGB(0, 0, 255));
    hBrushOrg   = SelectBrush (hDC, hBrushColor);

    SetRect (&r, 0, 0, 2, 2);
	 DPtoLP  (hDC, (LPPOINT) &r, 2);
	 cpos       = pWinData->pos;
	 cradius    = pWinData->ball_radius;
	 b1.left    = (int) (-cradius/2);
	 b1.right   = (int) (cradius/2)+(r.right-r.left);
	 b1.top     = (int) (cpos-cradius/2);
	 b1.bottom  = (int) (cpos+cradius/2)+(r.bottom-r.top);
    Ellipse (hDC, b1.left, b1.top, b1.right, b1.bottom);

    SelectBrush (hDC, hBrushOrg);
    DeleteObject (hBrushColor);

    // Draw representation of new current.
    //
    hBrushColor = CreateSolidBrush (RGB(128, 128, 128));
    hBrushOrg   = SelectBrush (hDC, hBrushColor);
    SelectPen (hDC, GetStockObject (BLACK_PEN));

    cpos = 3 * pWinData->tube_width * (pWinData->current + 55000) / 90000;
    poly[0].x = (int) (-cpos);
    poly[0].y = (int) (-cpos/2);
    poly[1].x = 0;
    poly[1].y = 0;
    poly[2].x = (int) (cpos);
    poly[2].y = (int) (-cpos/2);
    Polygon (hDC, (LPPOINT) &poly, 3);

    SelectBrush (hDC, hBrushOrg);
    DeleteObject (hBrushColor);

    // Done Painting.
    //
    EndPaint (pWinData->hWnd, &ps);
}
