657 lines
19 KiB
C++
657 lines
19 KiB
C++
// Clouds.cpp: Implementaion of the class CClouds.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "Clouds.h"
|
|
#include "Util\DynamicArray2D.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction / destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
IMPLEMENT_SERIAL (CClouds, CObject, 1)
|
|
|
|
CClouds::CClouds()
|
|
{
|
|
// Init member variables
|
|
m_iWidth = 0;
|
|
m_iHeight = 0;
|
|
m_sLastParam.bValid = false;
|
|
}
|
|
|
|
CClouds::~CClouds()
|
|
{
|
|
|
|
}
|
|
|
|
bool CClouds::GenerateClouds(SNoiseParams *sParam, CWnd *pWndStatus)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Generate the clouds
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
assert(sParam);
|
|
|
|
// Free all old data
|
|
CleanUp();
|
|
|
|
// Save the width & height
|
|
m_iWidth = sParam->iWidth;
|
|
m_iHeight = sParam->iHeight;
|
|
|
|
// Create a new DC
|
|
m_dcClouds.CreateCompatibleDC(NULL);
|
|
|
|
// Create a new bitmap
|
|
VERIFY(m_bmpClouds.CreateBitmap(512, 512, 1, 32, NULL));
|
|
m_dcClouds.SelectObject(m_bmpClouds);
|
|
|
|
// Hold the last used parameters
|
|
memcpy(&m_sLastParam, sParam, sizeof(SNoiseParams));
|
|
m_sLastParam.bValid = true;
|
|
|
|
// Call the generation function function with the supplied parameters
|
|
CalcCloudsPerlin(sParam, pWndStatus);
|
|
|
|
return true;
|
|
}
|
|
|
|
void CClouds::DrawClouds(CDC *pDC, LPRECT prcPosition)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Draw the generated cloud texture
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
assert(pDC);
|
|
assert(prcPosition);
|
|
|
|
// Prevents that the overall apperance of the image changes when it
|
|
// is stretched
|
|
pDC->SetStretchBltMode(HALFTONE);
|
|
|
|
if (m_dcClouds.m_hDC)
|
|
{
|
|
// Blit it to the destination rectangle
|
|
pDC->StretchBlt(prcPosition->left, prcPosition->top, prcPosition->right,
|
|
prcPosition->bottom, &m_dcClouds, 0, 0, m_iWidth, m_iHeight, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
// Just draw a black rectangle
|
|
pDC->StretchBlt(prcPosition->left, prcPosition->top, prcPosition->right,
|
|
prcPosition->bottom, &m_dcClouds, 0, 0, m_iWidth, m_iHeight, BLACKNESS);
|
|
}
|
|
}
|
|
|
|
void CClouds::CalcCloudsPerlin(SNoiseParams *sParam, CWnd *pWndStatus)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Generate perlin noise based clouds
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned int i, j, h;
|
|
COLORREF clrfColor;
|
|
float fValueRange;
|
|
CDynamicArray2D cCloud(sParam->iWidth, sParam->iHeight);
|
|
float fLowestPoint = 256000.0f, fHighestPoint = -256000.0f;
|
|
float fScaledCol;
|
|
CNoise cNoise;
|
|
float fYScale = 255;
|
|
char szStatus[128];
|
|
|
|
assert(!IsBadReadPtr(sParam, sizeof(SNoiseParams)));
|
|
assert(sParam->fFrequency);
|
|
assert(sParam->iWidth && sParam->iHeight);
|
|
assert(pWndStatus);
|
|
assert(::IsWindow(pWndStatus->m_hWnd));
|
|
assert(m_dcClouds.m_hDC);
|
|
assert(m_bmpClouds.m_hObject);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Generate the noise array
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Set the random value
|
|
srand(sParam->iRandom);
|
|
|
|
// Process layers
|
|
for (i=0; i<sParam->iPasses; i++)
|
|
{
|
|
// Show status
|
|
sprintf(szStatus, "Calculating pass %i of %i...", i + 1, sParam->iPasses);
|
|
pWndStatus->SetWindowText(szStatus);
|
|
|
|
// Apply the fractal noise function to the array
|
|
cNoise.FracSynthPass(&cCloud, sParam->fFrequency, fYScale,
|
|
sParam->iWidth, sParam->iHeight, FALSE);
|
|
|
|
// Modify noise generation parameters
|
|
sParam->fFrequency *= sParam->fFrequencyStep;
|
|
fYScale *= sParam->fFade;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Paint the clouds into the bitmap
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Apply the exponential function and find the value range
|
|
for (i=0; i<sParam->iWidth; i++)
|
|
for (j=0; j<sParam->iHeight; j++)
|
|
{
|
|
// Apply an exponential function to get separated clouds
|
|
cCloud.m_Array[i][j] = CloudExpCurve(cCloud.m_Array[i][j],
|
|
sParam->iCover, sParam->iSharpness);
|
|
|
|
fHighestPoint = __max(fHighestPoint, cCloud.m_Array[i][j]);
|
|
fLowestPoint = __min(fLowestPoint, cCloud.m_Array[i][j]);
|
|
}
|
|
|
|
// Prepare some renormalisation values
|
|
fValueRange = fHighestPoint - fLowestPoint;
|
|
|
|
// Smooth the clouds
|
|
for (h=0; h<sParam->iSmoothness; h++)
|
|
for (i=1; i<sParam->iWidth-1; i++)
|
|
for (j=1; j<sParam->iHeight-1; j++)
|
|
{
|
|
cCloud.m_Array[i][j] =
|
|
(cCloud.m_Array[i][j] + cCloud.m_Array[i+1][j] + cCloud.m_Array[i][j+1] +
|
|
cCloud.m_Array[i+1][j+1] + cCloud.m_Array[i-1][j] + cCloud.m_Array[i][j-1] +
|
|
cCloud.m_Array[i-1][j-1] + cCloud.m_Array[i+1][j-1] + cCloud.m_Array[i-1][j+1])
|
|
/ 9.0f;
|
|
}
|
|
|
|
for (i=0; i<sParam->iWidth; i++)
|
|
for (j=0; j<sParam->iHeight; j++)
|
|
{
|
|
// Normalize it first
|
|
cCloud.m_Array[i][j] += fLowestPoint;
|
|
cCloud.m_Array[i][j] = cCloud.m_Array[i][j] / fValueRange * 255.0f;
|
|
if (cCloud.m_Array[i][j] > 255)
|
|
cCloud.m_Array[i][j] = 255;
|
|
|
|
// Get the 0-255 index from the array, convert it into 0x00BBGGRR format, (add the
|
|
// blue sky) and draw the pixel it into the bitmap
|
|
if (sParam->bBlueSky)
|
|
{
|
|
fScaledCol = cCloud.m_Array[i][j] / 255.0f;
|
|
clrfColor = ((int) (fScaledCol * 255 + (1 - fScaledCol) * 40)) |
|
|
((int) (fScaledCol * 255 + (1 - fScaledCol) * 90)) << 8 |
|
|
((int) (fScaledCol * 255 + (1 - fScaledCol) * 180)) << 16;
|
|
}
|
|
else
|
|
{
|
|
fScaledCol = cCloud.m_Array[i][j] / 255.0f;
|
|
clrfColor = ((int) (fScaledCol * 255 + (1 - fScaledCol))) |
|
|
((int) (fScaledCol * 255 + (1 - fScaledCol))) << 8 |
|
|
((int) (fScaledCol * 255 + (1 - fScaledCol))) << 16;
|
|
}
|
|
|
|
// Set the pixel
|
|
m_dcClouds.SetPixelV(i, j, clrfColor);
|
|
}
|
|
}
|
|
|
|
void CClouds::CleanUp()
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Free all data
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// The cloud DC
|
|
if (m_dcClouds.m_hDC)
|
|
m_dcClouds.DeleteDC();
|
|
|
|
// Bitmap
|
|
if (m_bmpClouds.m_hObject)
|
|
m_bmpClouds.DeleteObject();
|
|
}
|
|
|
|
|
|
float CClouds::CloudExpCurve(float v, unsigned int iCover, float fSharpness)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Exponential function to generate separated clouds
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
float CloudDensity;
|
|
float c;
|
|
|
|
c = v - iCover;
|
|
|
|
if (c < 0)
|
|
c = 0;
|
|
|
|
CloudDensity = 255.f - (float) ((pow(fSharpness, c)) * 255.0f);
|
|
|
|
return CloudDensity;
|
|
}
|
|
|
|
void CClouds::Serialize(CArchive& ar)
|
|
{
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Save or restore the class
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
CObject::Serialize (ar);
|
|
|
|
if (ar.IsStoring())
|
|
{
|
|
// Storing
|
|
ar << m_iWidth << m_iHeight;
|
|
ar.Write(&m_sLastParam, sizeof(m_sLastParam));
|
|
}
|
|
else
|
|
{
|
|
// Loading
|
|
ar >> m_iWidth >> m_iHeight;
|
|
ar.Read(&m_sLastParam, sizeof(m_sLastParam));
|
|
}
|
|
}
|
|
|
|
void CClouds::Serialize( CXmlArchive &xmlAr )
|
|
{
|
|
if (xmlAr.bLoading)
|
|
{
|
|
//Load
|
|
XmlNodeRef clouds = xmlAr.root->findChild( "Clouds" );
|
|
if (clouds)
|
|
{
|
|
clouds->getAttr( "Width",m_iWidth );
|
|
clouds->getAttr( "Height",m_iHeight );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Save
|
|
XmlNodeRef clouds = xmlAr.root->newChild( "Clouds" );
|
|
clouds->setAttr( "Width",(int)m_iWidth );
|
|
clouds->setAttr( "Height",(int)m_iHeight );
|
|
}
|
|
}
|
|
|
|
/*
|
|
void CClouds::CalcCloudsBezierFault(CLOUDPARAM *sParam, CWnd *pWndStatus)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Generate new clouds. We are using quadric Bezier curves
|
|
// instead of simple lines to smooth out the image. The point in front
|
|
// of line test is done by using a simple Bresenham algorithm to find
|
|
// the intersection points with each scanline. Use the titel of
|
|
// the supplied window to provide status informations
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned int i, j, h, iScanline, iScanlineCurX;
|
|
uint8 iColor;
|
|
COLORREF clrfColor;
|
|
POINT p1, p2, p3;
|
|
float fValueRange;
|
|
CDynamicArray2D cCloud(sParam->iWidth, sParam->iHeight);
|
|
unsigned int *pScanlineIntersection = new unsigned int [m_iHeight];
|
|
float fLowestPoint = 65536.0f, fHighestPoint = -65536.0f;
|
|
float fIncreasement = 1.0f;
|
|
KeyPoint sKeyPoints[MAX_KEY_POINTS];
|
|
unsigned int iKeyPointCount;
|
|
int iDeltaX, iDeltaY;
|
|
int iUDeltaX, iUDeltaY;
|
|
char szWindowTitel[32];
|
|
unsigned int iStatus, iLastStatus = 0;
|
|
|
|
assert(sParam);
|
|
assert(sParam->iIterations);
|
|
|
|
// Paint it black first
|
|
m_dcClouds.BitBlt(0, 0, m_iWidth, m_iHeight, &m_dcClouds, 0, 0, BLACKNESS);
|
|
|
|
// Do the iterations
|
|
for (i=0; i<sParam->iIterations; i++)
|
|
{
|
|
// Update status (if necessary)
|
|
iStatus = (int) (i / (float) sParam->iIterations * 100);
|
|
if (iStatus != iLastStatus)
|
|
{
|
|
sprintf(szWindowTitel, "%i%% Done", iStatus);
|
|
pWndStatus->SetWindowText(szWindowTitel);
|
|
iLastStatus = iStatus;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Generate the curve
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Pick two random points on the border
|
|
RandomPoints(&p1, &p2);
|
|
|
|
iDeltaX = p2.x - p1.x; // Work out X delta
|
|
iDeltaY = p2.y - p1.y; // Work out Y delta
|
|
iUDeltaX = abs(iDeltaX); // iUDeltaX is the unsigned X delta
|
|
iUDeltaY = abs(iDeltaY); // iUDeltaY is the unsigned Y delta
|
|
|
|
// Subdivide the line, use a random point in the heightmap as third control point
|
|
p3.x = (long) (rand() / (float) RAND_MAX * m_iWidth);
|
|
p3.y = (long) (rand() / (float) RAND_MAX * m_iHeight);
|
|
|
|
// Get the keypoints of the Bezier curve
|
|
iKeyPointCount = QuadricSubdivide(&p1, &p3, &p2,
|
|
BEZIER_SUBDIVISON_LEVEL, sKeyPoints, true);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Trace each curve segment into the scanline intersection array
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
for (j=0; j<iKeyPointCount - 1; j++)
|
|
{
|
|
// Get the start / endpoints of the segment
|
|
p1.x = (long) sKeyPoints[j].fX;
|
|
p1.y = (long) sKeyPoints[j].fY;
|
|
p2.x = (long) sKeyPoints[j + 1].fX;
|
|
p2.y = (long) sKeyPoints[j + 1].fY;
|
|
|
|
TraceCurveSegment(&p1, &p2, iUDeltaX, iUDeltaY, pScanlineIntersection);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Process all scanlines and raise / lower the terrain
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// This ensures a good distribution of vallies and mountains
|
|
if (rand() % 2)
|
|
{
|
|
if (iDeltaX > 0)
|
|
iDeltaX = -iDeltaX;
|
|
else
|
|
iDeltaX = abs(iDeltaX);
|
|
}
|
|
|
|
// We have to approach the two delta cases different to make sure we are
|
|
// processing all pixels
|
|
if (iUDeltaX < iUDeltaY)
|
|
{
|
|
// This is necessary because the direction of the line is important for the
|
|
// raising / lowering. Doing it here safes us from using a branch in the
|
|
// inner loop
|
|
if (iDeltaX > 0)
|
|
fIncreasement = (float) fabs(fIncreasement);
|
|
else
|
|
fIncreasement = (float) -fabs(fIncreasement);
|
|
|
|
for (iScanline=0; iScanline<m_iHeight; iScanline++)
|
|
{
|
|
// Loop trough each pixel in the scanline
|
|
for (iScanlineCurX=0; iScanlineCurX<m_iWidth; iScanlineCurX++)
|
|
{
|
|
// Raise / lower the terrain on each side of the line
|
|
if (iScanlineCurX > pScanlineIntersection[iScanline])
|
|
cCloud.m_Array[iScanlineCurX][iScanline] += fIncreasement;
|
|
else
|
|
cCloud.m_Array[iScanlineCurX][iScanline] -= fIncreasement;
|
|
|
|
// Do we have a new highest / lowest value ?
|
|
fLowestPoint = __min(fLowestPoint, cCloud.m_Array[iScanlineCurX][iScanline]);
|
|
fHighestPoint = __max(fHighestPoint, cCloud.m_Array[iScanlineCurX][iScanline]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This is necessary because the direction of the line is important for the
|
|
// raising / lowering. Doing it here safes us from using a branch in the
|
|
// inner loop
|
|
if (iDeltaY > 0)
|
|
fIncreasement = (float) fabs(fIncreasement);
|
|
else
|
|
fIncreasement = (float) -fabs(fIncreasement);
|
|
|
|
// Loop trough each pixel in the scanline
|
|
for (iScanlineCurX=0; iScanlineCurX<m_iWidth; iScanlineCurX++)
|
|
{
|
|
for (iScanline=0; iScanline<m_iHeight; iScanline++)
|
|
{
|
|
// Raise / lower the terrain on each side of the line
|
|
if (iScanline > pScanlineIntersection[iScanlineCurX])
|
|
cCloud.m_Array[iScanlineCurX][iScanline] += fIncreasement;
|
|
else
|
|
cCloud.m_Array[iScanlineCurX][iScanline] -= fIncreasement;
|
|
|
|
// Do we have a new highest / lowest value ?
|
|
fLowestPoint = __min(fLowestPoint, cCloud.m_Array[iScanlineCurX][iScanline]);
|
|
fHighestPoint = __max(fHighestPoint, cCloud.m_Array[iScanlineCurX][iScanline]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Paint the clouds into the bitmap
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Prepare some renormalisation values. Shorten the value range to get
|
|
// higher contrast clouds
|
|
fValueRange = (fHighestPoint - fLowestPoint) / 1.3f;
|
|
|
|
if (fLowestPoint < 0)
|
|
{
|
|
fLowestPoint = (float) fabs(fLowestPoint);
|
|
fHighestPoint += (float) fabs(fLowestPoint);
|
|
}
|
|
|
|
// Smooth the clouds
|
|
for (h=0; h<sParam->iSmoothness; h++)
|
|
for (i=1; i<m_iWidth-1; i++)
|
|
for (j=1; j<m_iHeight-1; j++)
|
|
{
|
|
cCloud.m_Array[i][j] =
|
|
(cCloud.m_Array[i][j] + cCloud.m_Array[i+1][j] + cCloud.m_Array[i][j+1] +
|
|
cCloud.m_Array[i+1][j+1] + cCloud.m_Array[i-1][j] + cCloud.m_Array[i][j-1] +
|
|
cCloud.m_Array[i-1][j-1] + cCloud.m_Array[i+1][j-1] + cCloud.m_Array[i-1][j+1])
|
|
/ 9.0f;
|
|
}
|
|
|
|
for (i=0; i<m_iWidth; i++)
|
|
for (j=0; j<m_iHeight; j++)
|
|
{
|
|
// Normalize it first
|
|
cCloud.m_Array[i][j] += fLowestPoint;
|
|
cCloud.m_Array[i][j] = cCloud.m_Array[i][j] / fValueRange * 255.0f;
|
|
if (cCloud.m_Array[i][j] > 255)
|
|
cCloud.m_Array[i][j] = 255;
|
|
|
|
// Apply an exponetial function to get separated clouds
|
|
cCloud.m_Array[i][j] = CloudExpCurve(cCloud.m_Array[i][j]);
|
|
|
|
// Get the 0-255 index from the array, convert it into 0x00BBGGRR grayscale
|
|
// and draw it into the bitmap
|
|
iColor = (int8) cCloud.m_Array[i][j];
|
|
clrfColor = iColor | iColor << 8 | iColor << 16;
|
|
m_dcClouds.SetPixelV(i, j, clrfColor);
|
|
}
|
|
|
|
// Free the scanline intersection data
|
|
delete [] pScanlineIntersection;
|
|
pScanlineIntersection = 0;
|
|
}
|
|
|
|
unsigned int CClouds::QuadricSubdivide(LPPOINT p1, LPPOINT p2, LPPOINT p3, unsigned int iLevel,
|
|
KeyPoint *pKeyPointArray, bool bFirstSubdivision)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Add a line (one key point). If level is 0 use the end points. If
|
|
// this is the first subdivision, you have to pass true for
|
|
// bFirstSubdivision. The number of keypoints is returned
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
POINT pGl[3];
|
|
POINT pGr[3];
|
|
static int iCurKeyPoint = 0;
|
|
|
|
// Start with the first keypoint when doing the first subdivision
|
|
if (bFirstSubdivision)
|
|
iCurKeyPoint = 0;
|
|
|
|
if (iLevel == 0)
|
|
{
|
|
// Add it to the list
|
|
pKeyPointArray[iCurKeyPoint].fX = (float) p1->x;
|
|
pKeyPointArray[iCurKeyPoint].fY = (float) p1->y;
|
|
|
|
// Advance to the next
|
|
iCurKeyPoint++;
|
|
|
|
return iCurKeyPoint;
|
|
}
|
|
|
|
// New geometry vectors for the left and right halves of the curve
|
|
|
|
// Subdivide
|
|
|
|
memcpy(&pGl[0], p1, sizeof(POINT));
|
|
|
|
pGl[1].x = (p1->x + p2->x) >> 1;
|
|
pGl[1].y = (p1->y + p2->y) >> 1;
|
|
|
|
pGr[1].x = (p2->x + p3->x) >> 1;
|
|
pGr[1].y = (p2->y + p3->y) >> 1;
|
|
|
|
pGl[2].x = pGr[0].x = (pGl[1].x + pGr[1].x) >> 1;
|
|
pGl[2].y = pGr[0].y = (pGl[1].y + pGr[1].y) >> 1;
|
|
|
|
memcpy(&pGr[2], p3, sizeof(POINT));
|
|
|
|
// Call recursively for left and right halves
|
|
QuadricSubdivide(&pGl[0], &pGl[1], &pGl[2], --iLevel, pKeyPointArray, false);
|
|
QuadricSubdivide(&pGr[0], &pGr[1], &pGr[2], iLevel, pKeyPointArray, false);
|
|
|
|
// Add the end of the curve to the keypoint list if this is the first
|
|
// recursion level
|
|
if (bFirstSubdivision)
|
|
{
|
|
pKeyPointArray[iCurKeyPoint].fX = (float) p3->x;
|
|
pKeyPointArray[iCurKeyPoint].fY = (float) p3->y;
|
|
|
|
iCurKeyPoint++;
|
|
}
|
|
|
|
return iCurKeyPoint;
|
|
}
|
|
|
|
void CClouds::TraceCurveSegment(LPPOINT p1, LPPOINT p2, int iUCurveDeltaX,
|
|
int iUCurveDeltaY, unsigned int *pScanlineIntersection)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Use the Bresenham line drawing algorithm to find the scanline
|
|
// intersection points
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
int iDeltaX, iDeltaY;
|
|
int iUDeltaX, iUDeltaY;
|
|
int iXAdd, iYAdd;
|
|
int iError, iLoop;
|
|
|
|
iDeltaX = p2->x - p1->x; // Work out X delta
|
|
iDeltaY = p2->y - p1->y; // Work out Y delta
|
|
|
|
iUDeltaX = abs(iDeltaX); // iUDeltaX is the unsigned X delta
|
|
iUDeltaY = abs(iDeltaY); // iUDeltaY is the unsigned Y delta
|
|
|
|
// Work out direction to step in the Y direction
|
|
if (iDeltaX < 0)
|
|
iXAdd = -1;
|
|
else
|
|
iXAdd = 1;
|
|
|
|
// Work out direction to step in the Y direction
|
|
if (iDeltaY < 0)
|
|
iYAdd = -1;
|
|
else
|
|
iYAdd = 1;
|
|
|
|
iError = 0;
|
|
iLoop = 0;
|
|
|
|
if (iUDeltaX > iUDeltaY)
|
|
{
|
|
// Delta X > Delta Y
|
|
do
|
|
{
|
|
iError += iUDeltaY;
|
|
|
|
// Time to move up / down ?
|
|
if (iError >= iUDeltaX)
|
|
{
|
|
iError -= iUDeltaX;
|
|
p1->y += iYAdd;
|
|
}
|
|
|
|
iLoop++;
|
|
|
|
// Save scanline intersection
|
|
if (iUCurveDeltaX < iUCurveDeltaY)
|
|
pScanlineIntersection[p1->y] = p1->x;
|
|
else
|
|
pScanlineIntersection[p1->x] = p1->y;
|
|
|
|
// Move horizontally
|
|
p1->x += iXAdd;
|
|
}
|
|
while (iLoop < iUDeltaX); // Repeat for x length of line
|
|
}
|
|
else
|
|
{
|
|
// Delta Y > Delta X
|
|
do
|
|
{
|
|
iError += iUDeltaX;
|
|
|
|
// Time to move left / right?
|
|
if (iError >= iUDeltaY)
|
|
{
|
|
iError -= iUDeltaY;
|
|
// Move across
|
|
p1->x += iXAdd;
|
|
}
|
|
|
|
iLoop++;
|
|
|
|
// Save scanline intersection
|
|
if (iUCurveDeltaX < iUCurveDeltaY)
|
|
pScanlineIntersection[p1->y] = p1->x;
|
|
else
|
|
pScanlineIntersection[p1->x] = p1->y;
|
|
|
|
// Move up / down a row
|
|
p1->y += iYAdd;
|
|
}
|
|
while (iLoop < iUDeltaY); // Repeat for y length of line
|
|
}
|
|
}
|
|
|
|
void CClouds::RandomPoints(LPPOINT p1, LPPOINT p2)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Make two random points that lay on the bitmap's boundaries
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
bool bSwapSides;
|
|
|
|
assert(p1 && p2);
|
|
|
|
bSwapSides = (rand() % 2) ? true : false;
|
|
|
|
if (rand() % 2)
|
|
{
|
|
p1->x = (long) (rand() / (float) RAND_MAX * m_iWidth);
|
|
p1->y = bSwapSides ? 0 : m_iHeight - 1;
|
|
p2->x = (long) (rand() / (float) RAND_MAX * m_iWidth);
|
|
p2->y = bSwapSides ? m_iHeight - 1 : 0;
|
|
}
|
|
else
|
|
{
|
|
p1->x = bSwapSides ? m_iWidth - 1 : 0;
|
|
p1->y = (long) (rand() / (float) RAND_MAX * m_iHeight);
|
|
p2->x = bSwapSides ? 0 : m_iWidth - 1;
|
|
p2->y = (long) (rand() / (float) RAND_MAX * m_iHeight);
|
|
}
|
|
}
|
|
*/
|