friendly scottish programmer
|
||||
|
|
|
||
BOOL CSlideWnd::GenerateFractal(int nWidth, int nHeight, BOOL bFullScreen=FALSE)
{
// Tests every point in the current subset of
// the complex plane, and colours it according
// to it's escape behaviour
// If bFullScreen is TRUE, we don't want to display the fractal
// as it generates. Instead, we generate behind the scenes,
// and display progress lights
CFractopiaApp* pApp = (CFractopiaApp*)AfxGetApp();
CFractopiaDlg* pParent = (CFractopiaDlg*)GetParent();
// If the Formula dialog is active,
// refresh its controls with current fractal data
pParent->RefreshFormulaDialog();
// First, we're generating, so set the "generating" flag
// We use this flag to ensure that only one fractal image is
// generated at a time
SetGenerating(TRUE);
// Next, initialise the quit flag. This may be set to true later,
// if the user decides to interrupt fractal generation, or if we
// need to end the app cleanly.
SetQuitFlag(FALSE);
// Change to a "wait" cursor
// Note: the CWaitCursor object will be deleted when it goes out of scope
CWaitCursor wait;
if (bFullScreen) // we're generating a full screen fractal image
{
// ask the user to wait
pParent->WriteToStatusArea("please wait...");
}
// Now we need a new fractal image bitmap
if (!bFullScreen)
{
// delete the old thumbnail image...
delete m_pDoc->m_pFractalImage;
// and construct a new one
m_pDoc->m_pFractalImage = new CDIBitmap(nWidth, nHeight, m_pDoc->m_hLogicalPalette);
// Now clear the screen by painting the new (blank) bitmap
// (we don't do this if we're generating a full screen image,
// in which case we want to leave the old thumnail image
// on screen while we generate)
Invalidate(TRUE);
// We are about to create a virgin, unsaved new fractal.
// If it won't have been saved, we won't be in a position
// to Preview it, so disable the CFractopiaDlg Preview button.
// (and do this before the fractal is generated)
pParent->m_btnPreview.EnableWindow(FALSE);
// While we're at it, don't forget to update the iterations
// spin control on the CFractopiaSSFormView.
pParent->RefreshFormulaDialog();
}
// Specify our starting co-ordinates
// in the complex plane...
double x = m_pDoc->m_pFractalData->Z_Origin().X(),
yi = m_pDoc->m_pFractalData->Z_Origin().Y();
// ... and the distance between each point
// in the plane, at the current zoom level
double dGrainWidth = m_pDoc->m_pFractalData->Z_Width() / nWidth;
double dGrainHeight = m_pDoc->m_pFractalData->Z_Height() / nHeight;
// Colour all the (complex) points
for (int nRow = 0; nRow < nHeight; nRow++)
{
for (int nCol = 0; nCol < nWidth; nCol++)
{
m_cpTestPoint.SetX(x);
m_cpTestPoint.SetY(yi);
// find the escape orbit for this point
int nEscapeOrbit = m_pDoc->TestPoint(m_cpTestPoint);
// map the escape orbit to a colour value
switch (nEscapeOrbit)
{
case -1: m_nColourValue = 10; // lake colour
break;
default: m_nColourValue = (nEscapeOrbit
% m_pDoc->m_nPaletteEntries)
+ 11; // other colours
}
// store colour value directly in the fractal image bitmap
if (!bFullScreen)
{
m_pDoc->m_pFractalImage->PaintBit(nCol, nRow, m_nColourValue);
}
else
{
m_pDoc->m_pBigFractalImage->PaintBit(nCol, nRow, m_nColourValue);
}
x += dGrainWidth; // advance along x axis
}
// Interrupt app to process *any* messages in the queue.
// This allows the "Rendering" dialog box to be freely moved,
// minimised or closed.
if (!PeekAndPump()) return FALSE;
// If the user has interrupted fractal generation, or even
// terminated the program mid generation, exit the loop
if (m_bQuit)
{
// We aren't generating anymore. Reset the flag
OutputDebugString("*** Quitting mid fractal generation ***\n");
SetGenerating(FALSE);
return FALSE;
}
if (bFullScreen)
{
// if we're generating a full screen fractal image,
// *don't* paint the line we just generated
// - update the progress lights instead
int nPercent = int(nRow / (float)nHeight * 16); //100);
pParent->ShowBuildProgress(nPercent);
}
else
{
// Paint the line we just generated (immediately)
CRect rOneLine(0, nRow, nWidth, nRow + 1);
InvalidateRect(rOneLine, FALSE);
UpdateWindow();
}
// we (may) have lost the wait cursor, so restore it.
wait.Restore();
x = m_pDoc->m_pFractalData->Z_Origin().X(); // return to leftmost x position
yi -= dGrainHeight; // go down to next yi position
}
// The fractal image has been generated. Now tidy up.
if (bFullScreen)
{
// if we're generating a full screen fractal image...
// reset Regenerated flag which will have been set if
// CFractopiaDlg::OnRegenerate() was previously invoked
m_pDoc->SetRegeneratedFlag(FALSE);
// Beep to let the user know we've finished calculating at last!
// (on full screen render only)
MessageBeep(MB_OK);
// turn off all the progress lights, and take down status message
pParent->ResetBuildProgress();
pParent->WriteToStatusArea(" ");
}
if (!bFullScreen)
{
// The "document" has been modified. Set the flag.
m_pDoc->SetModifiedFlag(TRUE);
// Save the new fractal to the undo list,
// in case the user wants to UNDO later
((CFractopiaDlg*)GetParent())->SaveToUndoList();
}
// We aren't generating anymore. Reset the flag
SetGenerating(FALSE);
// reenable previews
pParent->m_btnPreview.EnableWindow(TRUE);
// Note that the default + cursor is restored at the end of this
// function, when "wait" (the CWaitCursor object), goes out of scope.
return TRUE;
}