//==========================================================================; // // 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 - 1998 Microsoft Corporation. All Rights Reserved. // //--------------------------------------------------------------------------; #include #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 // 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