www.pudn.com > Sterren_ASe_Explorer.rar > aseView.cpp
/* Copyright (C) William van der Sterren, 2002.
* All rights reserved worldwide.
*
* This software is provided "as is" without express or implied
* warranties. You may freely copy and compile this source into
* applications you distribute provided that the copyright text
* below is included in the resulting source code, for example:
* "Portions Copyright (C) William van der Sterren, 2002"
*/
/* Copyright (C) James Matthews, 2001.
* All rights reserved worldwide.
*
* This software is provided "as is" without express or implied
* warranties. You may freely copy and compile this source into
* applications you distribute provided that the copyright text
* below is included in the resulting source code, for example:
* "Portions Copyright (C) James Matthews, 2001"
*/
// aseView.cpp : implementation of the CAseView class
//
#include "stdafx.h"
#include "ase.h"
#include "aseDoc.h"
#include "aseView.h"
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define ci(x,y) x*ASE_BOARDY+y
/////////////////////////////////////////////////////////////////////////////
// CAseView
IMPLEMENT_DYNCREATE(CAseView, CView)
BEGIN_MESSAGE_MAP(CAseView, CView)
//{{AFX_MSG_MAP(CAseView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_ERASEBKGND()
ON_WM_RBUTTONDBLCLK()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAseView construction/destruction
//! \todo remove first 4 entries
static COLORREF crBrushes [] = {
RGB(255,000,000), // start
RGB(000,255,000) // end
};
CAseView::CAseView()
{
m_bDragging = false;
m_uBrushType = 0;
}
CAseView::~CAseView()
{
}
BOOL CAseView::PreCreateWindow(CREATESTRUCT& cs)
{
return CView::PreCreateWindow(cs);
}
void CAseView::DisplayWaitCursor()
{
BeginWaitCursor();
}
void CAseView::DisplayDefaultCursor()
{
EndWaitCursor();
}
/////////////////////////////////////////////////////////////////////////////
// CAseView drawing
void CAseView::OnDraw(CDC* pDC)
{
CAseDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rect;
GetClientRect(rect);
CDC memdc;
CBitmap bmp, *oldbmp;
CPen *oldpen, pen(PS_SOLID, 1, RGB(255,0,255));
memdc.CreateCompatibleDC(GetDC());
bmp.CreateDiscardableBitmap(pDC, rect.Width(), rect.Height());
oldbmp = memdc.SelectObject(&bmp);
oldpen = memdc.SelectObject(&pen);
memdc.FillSolidRect(rect, RGB(255,255,255));
int i;
int dx = rect.Width();
int dy = rect.Height();
bool bSearch = pDoc->DoesDisplaySearchSpace();
bool bThreat = pDoc->DoesDisplayThreatPositions();
bool bLOF = pDoc->DoesDisplayThreatLinesOfFire();
bool bApproxLOF = pDoc->DoesDisplayApproximatedLinesOfFire();
// Cycle through the board and draw any squares
const ASE_TerrainBoard* terrain;
const ASE_ThreatBoard* threats;
const ASE_SearchBoard* searchspace;
const ASE_LOSApproximationBoard* losapprox;
terrain = pDoc->GetTerrainBoard();
threats = pDoc->GetThreatBoard();
searchspace = pDoc->GetSearchSpaceBoard();
losapprox = pDoc->GetLOSApproximationBoard();
// first draw non-boxed contents (lof, search space)
unsigned int row;
unsigned int col;
for ( row = 0; row < terrain->GetNumberOfRows(); ++row )
{
for ( col = 0; col < terrain->GetNumberOfColumns(); ++col )
{
unsigned int idx;
idx = terrain->GetIndexForRowColumn(row, col);
// ignore boxed terrain here
if ( !terrain->IsEmptyCell(idx) )
continue;
ASE_Board::CellValue threattype;
// clip to threat lof
threattype = min(1, threats->GetCellValue(idx));
if ( ( bSearch )
&& ( !searchspace->IsEmptyCell(idx) )
)
{
// empty terrain, so solely look at lof
if ( bApproxLOF )
{
threattype = losapprox->GetCellValue(idx);
threattype = min(2, threattype);
}
else
if ( !bLOF )
{
threattype = 0;
}
DrawRectangleNB(row, col, &memdc,
searchspace->GetCellColorForOffset(idx, threattype)
);
}
else
if ( ( bApproxLOF )
&& ( !losapprox->IsEmptyCell(idx) )
)
{
// empty terrain, only display approx lof here (even if it might be a threat position)
DrawRectangleNB(row, col, &memdc, losapprox->GetCellColorForOffset(idx, 0));
}
else
if ( ( bLOF )
&& ( !threats->IsEmptyCell(idx) )
)
{
// empty terrain, only display lof here (even if it might be a threat position)
DrawRectangleNB(row, col, &memdc, threats->GetCellColorForOffset(idx, 0));
}
}
}
for ( row = 0; row < terrain->GetNumberOfRows(); ++row )
{
for ( col = 0; col < terrain->GetNumberOfColumns(); ++col )
{
unsigned int idx;
idx = terrain->GetIndexForRowColumn(row, col);
// ignore non-boxed terrain here
if ( ( terrain->IsEmptyCell(idx) )
&& ( !threats->IsThreatPosition(idx) )
)
continue;
if ( ( bSearch )
&& ( !searchspace->IsEmptyCell(idx) )
)
{
ASE_Board::CellValue terraintype;
terraintype = terrain->GetCellValue(idx);
ASE_Board::CellValue threattype;
threattype = threats->GetCellValue(idx);
if ( ( threattype != 0 )
&& ( ( ( !bLOF )
&& ( !threats->IsThreatPosition(idx) )
)
|| ( ( !bThreat )
&& ( threats->IsThreatPosition(idx) )
)
)
)
{
threattype = 0;
}
else
{
threattype = 1;
}
ASE_Board::CellValue offset;
offset = max(terraintype, threattype);
DrawRectangleNB(row, col, &memdc,
searchspace->GetCellColorForOffset(idx, offset)
);
}
else
if ( ( !threats->IsEmptyCell(idx) )
&& ( ( ( bThreat )
&& ( threats->IsThreatPosition(idx) )
)
|| ( ( bLOF )
&& ( !terrain->IsEmptyCell(idx) )
)
)
)
{
ASE_Board::CellValue terraintype;
terraintype = terrain->GetCellValue(idx);
DrawRectangle(row, col, &memdc,
threats->GetCellColorForOffset(idx, terraintype)
);
}
else
if ( !terrain->IsEmptyCell(idx) )
{
DrawRectangle(row, col, &memdc, terrain->GetCellColor(idx));
}
}
}
// Draw start, end and debug points
if (m_cStart.x != -1) DrawRectangle(m_cStart.x, m_cStart.y, &memdc, crBrushes[0]);
if (m_cEnd.x != -1) DrawRectangle(m_cEnd.x, m_cEnd.y, &memdc, crBrushes[1]);
// set pen for grid
CPen gridpen(PS_SOLID, 0, RGB(192, 192, 192));
CPen* oldgridpen;
oldgridpen = memdc.SelectObject(&gridpen);
// Draw the grid...
for (i=0; iDoesDisplayRoute() )
DrawRoute(&memdc);
if (m_cHilight.x != -1) {
DrawRectangle(m_cHilight.x, m_cHilight.y, &memdc, RGB(0,0,255));
CPoint centre;
centre.x = m_cHilight.x*ASE_GRIDSIZE+(ASE_GRIDSIZE/2);
centre.y = m_cHilight.y*ASE_GRIDSIZE+(ASE_GRIDSIZE/2);
memdc.MoveTo(centre);
unsigned int numchildren = m_cHilightNode->GetNumberOfChildren();
_asNode *temp;
for ( unsigned int i=0; iGetChild(i);
memdc.LineTo(temp->GetX() * ASE_GRIDSIZE + (ASE_GRIDSIZE/2),
temp->GetY() * ASE_GRIDSIZE + (ASE_GRIDSIZE/2));
memdc.MoveTo(centre);
}
}
CPoint bp = pDoc->GetBreakpoint();
if (bp.x != -1) DrawCircle(bp.x, bp.y, &memdc, RGB(128,0,0));
pDC->BitBlt(0,0,rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY);
memdc.SelectObject(oldpen);
memdc.SelectObject(oldbmp);
}
void CAseView::DrawRectangle(int x, int y, CDC *pDC, COLORREF cr)
{
CBrush br(RGB(0,0,0));
CRect rect(x*ASE_GRIDSIZE, y*ASE_GRIDSIZE,
x*ASE_GRIDSIZE+ASE_GRIDSIZE+1,
y*ASE_GRIDSIZE+ASE_GRIDSIZE+1);
pDC->FillSolidRect(rect, cr);
pDC->FrameRect(&rect, &br);
}
void CAseView::DrawRectangleNB(int x, int y, CDC *pDC, COLORREF cr)
{
CRect rect(x*ASE_GRIDSIZE, y*ASE_GRIDSIZE,
x*ASE_GRIDSIZE+ASE_GRIDSIZE+1,
y*ASE_GRIDSIZE+ASE_GRIDSIZE+1);
pDC->FillSolidRect(rect, cr);
}
void CAseView::DrawCircle(int x, int y, CDC *pDC, COLORREF cr)
{
CBrush br(cr), *oldbrush;
CPen pen(PS_SOLID, 0, RGB(0,0,0)), *oldpen;
CRect rect(x*ASE_GRIDSIZE, y*ASE_GRIDSIZE,
x*ASE_GRIDSIZE+ASE_GRIDSIZE+1,
y*ASE_GRIDSIZE+ASE_GRIDSIZE+1);
oldbrush = pDC->SelectObject(&br);
oldpen = pDC->SelectObject(&pen);
pDC->Ellipse(rect);
pDC->SelectObject(oldbrush);
pDC->SelectObject(oldpen);
}
void CAseView::DrawRoute(CDC *pDC)
{
CAseDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CPen pen(PS_SOLID,1,RGB(0,0,0)),*oldpen;
oldpen = pDC->SelectObject(&pen);
CAStar *astar = pDoc->GetPathFinder();
_asNode *best = astar->GetBestNode();
int x,y,px,py;
if (best) {
x = best->GetX();
y = best->GetY();
px = x * ASE_GRIDSIZE + (ASE_GRIDSIZE / 2);
py = y * ASE_GRIDSIZE + (ASE_GRIDSIZE / 2);
pDC->MoveTo(px,py);
best = best->GetParent();
}
while (best) {
x = best->GetX();
y = best->GetY();
px = x * ASE_GRIDSIZE + (ASE_GRIDSIZE / 2);
py = y * ASE_GRIDSIZE + (ASE_GRIDSIZE / 2);
pDC->LineTo(px,py);
best = best->GetParent();
}
pDC->SetPixel(px,py, RGB(0,0,128));
pDC->SelectObject(oldpen);
}
void CAseView::HighlightNode(_asNode *node, bool drawKidsConnections)
{
if (!node) {
m_cHilight.x = -1;
m_cHilightNode = NULL;
} else {
m_cHilight.x = node->GetX();
m_cHilight.y = node->GetY();
m_cHilightNode = node;
}
Invalidate(false);
}
void CAseView::RemoveHighlight()
{
m_cHilight.x = -1;
m_cHilightNode = NULL;
}
void CAseView::OnInitialUpdate()
{
CView::OnInitialUpdate();
m_cHilight.x = -1;
m_cHilightNode = NULL;
GetDocument()->GetStartEnd(m_cStart, m_cEnd);
}
/////////////////////////////////////////////////////////////////////////////
// CAseView diagnostics
#ifdef _DEBUG
void CAseView::AssertValid() const
{
CView::AssertValid();
}
void CAseView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CAseDoc* CAseView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CAseDoc)));
return (CAseDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CAseView message handlers
void CAseView::OnLButtonDown(UINT nFlags, CPoint point)
{
CAseDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
MouseToPoint(point, m_uBrushType);
if (m_uBrushType < 4) m_bDragging = true;
CView::OnLButtonDown(nFlags, point);
}
void CAseView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bDragging = false;
GetDocument()->NotifyClick();
CView::OnLButtonUp(nFlags, point);
}
void CAseView::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bDragging) {
MouseToPoint(point, m_uBrushType);
}
CView::OnMouseMove(nFlags, point);
}
void CAseView::MouseToPoint(CPoint point, UINT brush)
{
CClientDC dc(this);
int px = point.x/8, py = point.y/8;
CPoint round(px*ASE_GRIDSIZE, py*ASE_GRIDSIZE),temp;
GetDocument()->GetStartEnd(m_cStart, m_cEnd);
// If start or end
if (brush == 4) {
temp.x = m_cStart.x * ASE_GRIDSIZE;
temp.y = m_cStart.y * ASE_GRIDSIZE;
m_cStart.x = px;
m_cStart.y = py;
InvalidateRect(CRect(round,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
InvalidateRect(CRect(temp,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
} else if (brush == 5) {
temp.x = m_cEnd.x * ASE_GRIDSIZE;
temp.y = m_cEnd.y * ASE_GRIDSIZE;
m_cEnd.x = px;
m_cEnd.y = py;
InvalidateRect(CRect(round,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
InvalidateRect(CRect(temp,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
}
else if (brush == -1)
{
CPoint bp = GetDocument()->GetBreakpoint();
temp.x = bp.x * ASE_GRIDSIZE;
temp.y = bp.y * ASE_GRIDSIZE;
bp.x = px;
bp.y = py;
GetDocument()->SetBreakpoint(bp);
InvalidateRect(CRect(round,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
InvalidateRect(CRect(temp,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
}
else if (brush == 6) // threat position
{
GetDocument()->GetThreatBoard()->MarkThreatPosition(px, py);
GetDocument()->GetLOSApproximationBoard()->ApplyThreatModification(px, py);
if ( GetDocument()->DoesDisplayApproximatedLinesOfFire() )
{
DisplayWaitCursor();
GetDocument()->GetLOSApproximationBoard()->ComputeLinesOfFireApproximation();
DisplayDefaultCursor();
}
//! \todo make a bit smarter, since only the rectangles within a radius are affected
Invalidate();
}
else if (brush == 0) // clearing position
{
// check whether threats are visible and if threat needs to be removed (first)
if ( ( GetDocument()->DoesDisplayThreatPositions() )
&& ( GetDocument()->GetThreatBoard()->IsThreatPosition(px, py) )
)
{
GetDocument()->GetThreatBoard()->ClearThreatPosition(px, py);
GetDocument()->GetLOSApproximationBoard()->ApplyThreatModification(px, py);
if ( GetDocument()->DoesDisplayApproximatedLinesOfFire() )
{
DisplayWaitCursor();
GetDocument()->GetLOSApproximationBoard()->ComputeLinesOfFireApproximation();
DisplayDefaultCursor();
}
//! \todo make a bit smarter, since only the rectangles within a radius are affected
Invalidate();
}
else
{
bool bFullRedraw;
bFullRedraw = GetDocument()->GetTerrainBoard()->IsLocationImpassable(px, py);
GetDocument()->GetTerrainBoard()->SetCellValue(px, py, 0);
if ( bFullRedraw )
{
DisplayWaitCursor();
GetDocument()->GetThreatBoard()->ComputeLinesOfFire();
GetDocument()->GetLOSApproximationBoard()->ApplyTerrainModification(px, py);
if ( GetDocument()->DoesDisplayApproximatedLinesOfFire() )
{
GetDocument()->GetLOSApproximationBoard()->ComputeLinesOfFireApproximation();
}
DisplayDefaultCursor();
Invalidate();
}
else
{
InvalidateRect(CRect(round,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
}
}
}
else if (brush == 3) // impassable terrain
{
// clear threat, if necessary
GetDocument()->GetTerrainBoard()->SetCellValue(px, py, 3);
GetDocument()->GetThreatBoard()->ClearThreatPosition(px, py);
GetDocument()->GetLOSApproximationBoard()->ApplyTerrainModification(px, py);
if ( GetDocument()->DoesDisplayApproximatedLinesOfFire() )
{
DisplayWaitCursor();
GetDocument()->GetLOSApproximationBoard()->ComputeLinesOfFireApproximation();
DisplayDefaultCursor();
}
Invalidate();
}
else // terrain weights
{
//! \todo handle invalidation after painting impassable terrain, since
// it may block lof
GetDocument()->GetTerrainBoard()->SetCellValue(px, py, brush);
GetDocument()->GetLOSApproximationBoard()->ApplyTerrainModification(px, py);
if ( GetDocument()->DoesDisplayApproximatedLinesOfFire() )
{
DisplayWaitCursor();
GetDocument()->GetLOSApproximationBoard()->ComputeLinesOfFireApproximation();
DisplayDefaultCursor();
}
assert( GetDocument()->GetTerrainBoard()->GetCellValue(px, py) == brush );
InvalidateRect(CRect(round,CSize(ASE_GRIDSIZE+1,ASE_GRIDSIZE+1)), false);
}
GetDocument()->SetModifiedFlag();
GetDocument()->SetStartEnd(m_cStart, m_cEnd);
}
BOOL CAseView::OnEraseBkgnd(CDC* pDC)
{
return false;
return CView::OnEraseBkgnd(pDC);
}
void CAseView::OnRButtonDblClk(UINT nFlags, CPoint point)
{
MouseToPoint(point, -1);
CView::OnRButtonDblClk(nFlags, point);
}