BALL.CPP

//==========================================================================; 
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;

#include <streams.h>
#include "ball.h"

//
//
// What this samples illustrates
//
// A simple source filter that produces decompressed images showing a ball
// bouncing around. Each movement of the ball is done by generating a new
// image. We use the CSource and CSourceStream base classes to manage a
// source filter - we are a live source and so do not support any seeking.
//
//
// Summary
//
// This is a sample source filter - we produce a never ending stream of images
// that show a coloured ball bouncing around the window. Depending on the bit
// depth of the current display device we colour the ball differently. As we
// are effectively a live video stream we do not offer any seeking interfaces.
// We can supply 32,24,16 (555 and 565) as well as eight bit palettised types
//
//
// Implementation
//
// We use the CSource and CSourceStream base classes from the SDK which look
// after some of the grunge associated with source filters, in particular the
// starting the stopping of workers threads as we're activated and stopped.
// The worker thread sits in a loop asking for buffers and then calling the
// PURE virtual FillBuffer method when it has a buffer for us to fill up.
//
// For an example we also have a simple quality management implementation in
// this filter, quality management of everyone except renderers (who are the
// ones normally to initiate it) is controlled through IQualityControl. This
// is called on each frame to say how we are getting on, because this filter
// is pretty straightforward we can control the spacing of samples we send
// downstream so that we always run flat out with whatever CPU is available
//
//
// Demonstration instructions
//
// Start GRAPHEDT available in the ActiveMovie SDK tools. Click on the Graph
// menu and select "Insert Filters". From the dialog box double click on
// "Bouncing ball" and then dismiss the dialog. Go to the right hand pin of
// the filter box and right click, select Render. A video renderer will be
// inserted and connected up (on some displays there may be a colour space
// convertor put between them to get the pictures into a suitable format).
// Then click run on GRAPHEDT and see the ball bounce around the window...
//
//
// Files
//
// ball.cpp Looks after drawing a moving bouncing ball
// ball.def What APIs the DLL imports and exports
// ball.h Class definition for the ball drawing object
// ball.rc Version and title information resources
// ball.reg What goes in the registry to make us work
// balluids.h The CLSIDs for the bouncing ball filter
// fball.cpp The real filter class implementation
// fball.h Class definition for the main filter object
// makefile How to build it...
// resource.h A couple of identifiers for our resources
//
//
// Base classes used
//
// CSource Base class for a generic source filter
// CSourceStream A base class for a source filters stream
//
//


//
// Constructor
//
// The default arguments provide a reasonable image and ball size
//
CBall::CBall(int iImageWidth, int iImageHeight, int iBallSize) :
m_iImageWidth(iImageWidth),
m_iImageHeight(iImageHeight),
m_iBallSize(iBallSize),
m_iAvailableWidth(iImageWidth - iBallSize),
m_iAvailableHeight(iImageHeight - iBallSize),
m_x(0),
m_y(0),
m_xDir(RIGHT),
m_yDir(UP)
{
// Check we have some (arbitrary) space to bounce in.
ASSERT(iImageWidth > 2*iBallSize);
ASSERT(iImageHeight > 2*iBallSize);

// Random position for showing off a video mixer
m_iRandX = rand();
m_iRandY = rand();

} // (Constructor)


//
// PlotBall
//
// Assumes the image buffer is arranged row 1,row 2,...,row n
// in memory and that the data is contiguous.
//
void CBall::PlotBall(BYTE pFrame[], BYTE BallPixel[], int iPixelSize)
{
ASSERT(m_x >= 0);
ASSERT(m_x <= m_iAvailableWidth);
ASSERT(m_y >= 0);
ASSERT(m_y <= m_iAvailableHeight);

// The current byte of interest in the frame
BYTE *pBack = pFrame;

// Plot the ball into the correct location
BYTE *pBall = pFrame + ( m_y * m_iImageWidth * iPixelSize) + m_x * iPixelSize;

for (int row = 0; row < m_iBallSize; row++) {

for (int col = 0; col < m_iBallSize; col++) {

// For each byte fill its value from BallPixel[]
for (int i = 0; i < iPixelSize; i++) {
if (WithinCircle(col, row)) {
*pBall = BallPixel[i];
}
pBall++;
}
}
pBall += m_iAvailableWidth * iPixelSize;
}

} // PlotBall


//
// BallPosition
//
// Return the 1-dimensional position of the ball at time t millisecs
// (note that millisecs runs out after about a month!)
//
int CBall::BallPosition(int iPixelTime, // Millisecs per pixel
int iLength, // Distance between the bounce points
int time, // Time in millisecs
int iOffset) // For a bit of randomness
{
// Calculate the position of an unconstrained ball (no walls)
// then fold it back and forth to calculate the actual position

int x = time / iPixelTime;
x += iOffset;
x %= 2*iLength;

// check it is still in bounds
if (x>iLength) {
x = 2*iLength - x;
}
return x;

} // BallPosition


//
// MoveBall
//
// Set (m_x, m_y) to the new position of the ball. move diagonally
// with speed m_v in each of x and y directions.
// Guarantees to keep the ball in valid areas of the frame.
// When it hits an edge the ball bounces in the traditional manner!.
// The boundaries are (0..m_iAvailableWidth, 0..m_iAvailableHeight)
//
void CBall::MoveBall(CRefTime rt)
{
m_x = BallPosition( 10, m_iAvailableWidth, rt.Millisecs(), m_iRandX );
m_y = BallPosition( 10, m_iAvailableHeight, rt.Millisecs(), m_iRandY );

} // MoveBall


//
// WithinCircle
//
// Return TRUE if (x,y) is within a circle radius S/2, centre (S/2, S/2)
// where S is m_iBallSize else return FALSE
//
inline BOOL CBall::WithinCircle(int x, int y)
{
unsigned int r = m_iBallSize / 2;

if ( (x-r)*(x-r) + (y-r)*(y-r) < r*r) {
return TRUE;
} else {
return FALSE;
}

} // WithinCircle