// File: sprite.cxx // Written by: Michael Main (main@colorado.edu) // Version: Nov 3, 2005 // This file implements the Sprite class. Please see sprite.h for // the documentation on how to use the class. #include "sprite.h" // Provides Sprite class definition #include // Provides winbgim functions #include // Provides assert macro #include // Provides sprintf #include // Provides size_t #include // Provides string class #include // Provides vector class #include using namespace std; namespace edu_colorado_main_intro { /////////////////////////////////////////////////////////////////////////// static string itos(int n) { char s[30]; sprintf(s, "%d", n); return s; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// Sprite::Sprite( ) { // Note that the _images vector is initially size zero, so we can // call the clear function and it won't return any images to the // heap. It will set all other member variables to their defaults. clear( ); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// Sprite::Sprite( int side_length, std::string filebase, int many_frames, int many_angles ) { clear( ); set_images(side_length, filebase, many_frames, many_angles); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// Sprite:: ~Sprite( ) { clear( ); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::approach(double amount, double x, double y) { double dx = x - _x; double dy = y - _y; double d = sqrt( dx*dx + dy*dy); double percent; if (d <= fabs(amount)) percent = (amount >= 0) ? 1 : -1; else percent = amount/d; _x += percent * dx; _y += percent * dy; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::approach_mouse(double amount) { approach(amount, mousex( ), mousey( )); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::change_frame(int frame) { assert(static_cast(frame) < _images.size( )); _frame = frame; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::clear( ) { // First return memory used by the images: for (_frame = 0; static_cast(_frame) < _images.size( ); ++_frame) { for (_angle_number = 0; _angle_number < _many_angles; ++_angle_number) free (_images[_frame][_angle_number]); } _images.clear( ); // Then clear all member variables: _many_angles = 0; _side_length = 0; _half_length = 0; _frame = 0; _angle_number = 0; _x = 0; _y = 0; _angle_in_radians = 0; _mode = COPY_PUT; _bytes_per_image = 0; _scalex = 1; _translatex = 0; _scaley = -1; _translatey = 0; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::compute_coordinates (int newx, int newy, double r, int& x, int& y) { double cart_newx = newx - _half_length; double cart_newy = _half_length - newy; double theta = -(r - M_PI/2); double cos_theta = cos(theta); double sin_theta = sin(theta); double cart_x = cos_theta * cart_newx - sin_theta * cart_newy; double cart_y = sin_theta * cart_newx + cos_theta * cart_newy; x = static_cast(cart_x) + _half_length; if (x < 0) x = 0; else if (x >= static_cast(_side_length)) x = _side_length-1; y = _half_length - static_cast(cart_y); if (y < 0) y = 0; else if (y >= static_cast(_side_length)) y = _side_length-1; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::draw( ) const { int x, y; // Pixel coordinates of center of image if (_mode != INVISIBLE_PUT) { x = static_cast(_scalex*_x + _translatex); y = static_cast(_scaley*_y + _translatey); putimage(x, y, _images[_frame][_angle_number], _mode); } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::jump( ) { _x = rand( ) % getmaxx( ); _y = rand( ) % getmaxy( ); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::operator =(const Sprite& source) { if (this == &source) return; // Release the memory currently used by this sprite. clear( ); // Copy the member variables _many_angles = source._many_angles; _side_length = source._side_length; _half_length = source._half_length; _frame = source._frame; _angle_number = source._angle_number; _x = source._x; _y = source._y; _angle_in_radians = source._angle_in_radians; _mode = source._mode; _bytes_per_image = source._bytes_per_image; _scalex = source._scalex; _translatex = source._translatex; _scaley = source._scaley; _translatex = source._translatex; // Set the new images for each frame. _images.resize(source._images.size( )); for (_frame = 0; static_cast(_frame) < source._images.size( ); ++_frame) { _images[_frame].resize(_many_angles); for (_angle_number = 0; _angle_number < _many_angles; ++_angle_number) { // Create the image for buffer[image_index][angle_number] memcpy( _images[_frame][_angle_number], source._images[_frame][_angle_number], _bytes_per_image ); } } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::set_angle_in_radians(double angle_in_radians) { // The control angle is a little bit more than the actual angle. // For example, if we have four images, then an actual angle // between -M_PI/4 and +M_PI/4 will result in a control angle // between 0 and +M_PI/2, which gives an angle number of zero. double control; _angle_in_radians = angle_in_radians; control = _angle_in_radians + M_PI / _many_angles; _angle_number = static_cast(control*_many_angles/(2*M_PI)) % _many_angles; if (_angle_number < 0) _angle_number += _many_angles; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::set_images( int side_length, std::string filebase, int many_frames, int many_angles ) { string filename; // The name of a bmp file int frame; // Which of several frames are we working with? int angle_number; // Which of several angle numbers are we working with? double r; // An angle in radians int x, y; // Coordinates in an existing image int newx, newy; // Corresponding coordinates in a new, rotated image int color; // Color number of a single pixel // Clear out any old images that were in this sprite: clear( ); // Reset the vector of images to the new size, and set other // member variables: _images.resize(many_frames); _many_angles = many_angles; _side_length = side_length; _half_length = side_length/2; _frame = 0; _bytes_per_image = imagesize(0, 0, side_length-1, side_length-1); // We don't change the angle, but we might need to compute a new angle // number, which will be done in this function: set_angle_in_radians(_angle_in_radians); // Read the new images for each frame. for (frame = 0; static_cast(frame) < _images.size( ); ++frame) { filename = filebase + itos(frame) + ".bmp"; clearviewport( ); bgiout << "Loading image " << filename; outstreamxy(10,10); swapbuffers( ); clearviewport( ); readimagefile(filename.c_str(), 0, 0, side_length-1, side_length-1); _images[frame].resize(many_angles); for (angle_number = 0; angle_number < many_angles; ++angle_number) { // Create the image for buffer[image_index][angle_number] r = angle_number * 2 * M_PI / many_angles; for (newx = 0; newx < static_cast(side_length); newx++) { for (newy = 0; newy < static_cast(side_length); newy++) { compute_coordinates(newx, newy, r, x, y); color = getpixel(x,y); putpixel(newx + side_length, newy + side_length, color); } } _images[frame][angle_number] = (char *)malloc(_bytes_per_image); getimage( side_length, side_length, 2*side_length-1, 2*side_length-1, _images[frame][angle_number] ); } } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Sprite::set_drawing_transformations (double scalex, double translatex, double scaley, double translatey) { _scalex = scalex; _scaley = scaley; _translatex = translatex; _translatey = translatey; } }