image.cpp

Go to the documentation of this file.
00001 
00002 //            Copyright (C) 2004-2007 by The Allacrost Project
00003 //                         All Rights Reserved
00004 //
00005 // This code is licensed under the GNU GPL version 2. It is free software 
00006 // and you may modify it and/or redistribute it under the terms of this license.
00007 // See http://www.gnu.org/copyleft/gpl.html for details.
00009 
00010 #include "utils.h"
00011 #include <cassert>
00012 #include <cstdarg>
00013 #include "video.h"
00014 #include <math.h>
00015 #include "gui.h"
00016 
00017 using namespace std;
00018 using namespace hoa_video::private_video;
00019 using namespace hoa_video;
00020 using namespace hoa_utils;
00021 
00022 namespace hoa_video {
00023 
00024 namespace private_video {
00025 
00026 // *****************************************************************************
00027 // ********************************** Image ************************************
00028 // *****************************************************************************
00029 
00030 Image::Image(const std::string &fname, const std::string &tags_, int32 w, int32 h, bool grayscale_) :
00031   filename(fname),
00032   tags(tags_),
00033   width(w),
00034   height(h),
00035   grayscale(grayscale_)
00036 {
00037   texture_sheet = NULL;
00038   x = 0;
00039   y = 0;
00040   u1 = 0.0f;
00041   v1 = 0.0f;
00042   u2 = 1.0f;
00043   v2 = 1.0f;
00044   ref_count = 0;
00045 }
00046 
00047 
00048 
00049 Image::Image(TexSheet *sheet, const std::string &tags_, const std::string &fname, int32 x_, int32 y_, float u1_, float v1_,
00050   float u2_, float v2_, int32 w, int32 h, bool grayscale_) :
00051   texture_sheet(sheet),
00052   filename(fname),
00053   tags(tags_),
00054   x(x_),
00055   y(y_),
00056   u1(u1_),
00057   v1(v1_),
00058   u2(u2_),
00059   v2(v2_),
00060   width(w),
00061   height(h),
00062   grayscale(grayscale_)
00063 {
00064   ref_count = 0;
00065 }
00066 
00067 // *****************************************************************************
00068 // ****************************** ImageElement *********************************
00069 // *****************************************************************************
00070 
00071 ImageElement::ImageElement(Image *image_, float x_offset_, float y_offset_, float u1_, float v1_,
00072   float u2_, float v2_, float width_, float height_) :
00073   image(image_),
00074   x_offset(x_offset_),
00075   y_offset(y_offset_),
00076   u1(u1_),
00077   v1(v1_),
00078   u2(u2_),
00079   v2(v2_),
00080   width(width_),
00081   height(height_)
00082 {
00083   white = true;
00084   one_color = true;
00085   blend = false;
00086   color[0] = Color::white;
00087 }
00088 
00089 
00090 
00091 ImageElement::ImageElement(Image *image_, float x_offset_, float y_offset_, float u1_, float v1_, 
00092     float u2_, float v2_, float width_, float height_, Color color_[4]) :
00093   image(image_),
00094   x_offset(x_offset_),
00095   y_offset(y_offset_),
00096   u1(u1_),
00097   v1(v1_),
00098   u2(u2_),
00099   v2(v2_),
00100   width(width_),
00101   height(height_)
00102 {
00103   color[0] = color_[0];
00104 
00105   // If all colors are the same, then mark it so we don't have to process all vertex colors
00106   if (color_[1] == color[0] && color_[2] == color[0] && color_[3] == color[0]) {
00107     one_color = true;
00108 
00109     // If all vertex colors are white, set a flag so they don't have to be processed at all
00110     if (color[0] == Color::white) {
00111       white = true;
00112       blend = false;
00113     }
00114     // Set blend to true if alpha < 1.0f
00115     else {
00116       blend = (color[0][3] < 1.0f);
00117     }
00118   }
00119   else {
00120     color[0] = color_[0];
00121     color[1] = color_[1];
00122     color[2] = color_[2];
00123     color[3] = color_[3];
00124     // Set blend to true if any of the four colors have an alpha value < 1.0f
00125     blend = (color[0][3] < 1.0f || color[1][3] < 1.0f || color[2][3] < 1.0f || color[3][3] < 1.0f);
00126   }
00127 } // ImageElement::ImageElement()
00128 
00129 
00130 } // namespace private_video
00131 
00132 
00133 
00134 
00135 // *****************************************************************************
00136 // ***************************** ImageDescriptor *******************************
00137 // *****************************************************************************
00138 
00139 ImageDescriptor::ImageDescriptor() :
00140 _width (0.0f),
00141 _height (0.0f),
00142 _is_static (false),
00143 _grayscale (false),
00144 _animated (false),
00145 _loaded (false)
00146 {
00147   _color[0] = _color[1] = _color[2] = _color[3] = Color::white;
00148 }
00149 
00150 
00151 bool ImageDescriptor::Load()
00152 {
00153   return VideoManager->LoadImage(*this);
00154 }
00155 
00156 
00157 void ImageDescriptor::Draw()
00158 {
00159   VideoManager->DrawImage(*this);
00160 }
00161 
00162 
00163 bool ImageDescriptor::Save(const std::string filename) const
00164 {
00165   if (_animated)
00166     return VideoManager->SaveImage(filename, dynamic_cast<const AnimatedImage &>(*this));
00167   else
00168     return VideoManager->SaveImage(filename, dynamic_cast<const StillImage &>(*this));
00169 }
00170 
00171 
00172 void ImageDescriptor::_Clear()
00173 {
00174   _width = 0.0f;
00175   _height = 0.0f;
00176   _is_static = false;
00177   _grayscale = false;
00178   _color[0] = _color[1] = _color[2] = _color[3] = Color::white;
00179 
00180   _loaded = false;
00181 }
00182 
00183 
00184 // *****************************************************************************
00185 // ******************************** StillImage *********************************
00186 // *****************************************************************************
00187 
00188 StillImage::StillImage(const bool grayscale) {
00189   Clear();
00190   _animated = false;
00191   _grayscale = grayscale;
00192 }
00193 
00194 
00195 
00196 void StillImage::Clear() {
00197   _Clear();
00198   _filename.clear();
00199   _elements.clear();
00200 
00201   SetColor(Color::white);
00202 }
00203 
00204 
00205 void StillImage::SetWidth (const float width)
00206 {
00207   _width = width;
00208 
00209   for (std::vector <private_video::ImageElement>::iterator it=_elements.begin(); it<_elements.end(); ++it)
00210   {
00211     it->width = width;
00212   }
00213 }
00214 
00215 
00216 void StillImage::SetHeight (const float height)
00217 {
00218   _height = height;
00219 
00220   for (std::vector <private_video::ImageElement>::iterator it=_elements.begin(); it<_elements.end(); ++it)
00221   {
00222     it->height = height;
00223   }
00224 }
00225 
00226 
00227 void StillImage::SetDimensions (const float width, const float height)
00228 {
00229   _width = width;
00230   _height = height;
00231 
00232   for (std::vector <private_video::ImageElement>::iterator it=_elements.begin(); it<_elements.end(); ++it)
00233   {
00234     it->width = width;
00235     it->height = height;
00236   }
00237 }
00238 
00239 
00240 void StillImage::EnableGrayScale() {
00241   // If the image is already in grayscale mode, go back
00242   if (_grayscale)
00243     return;
00244   
00245   // Mark as grayscale
00246   _grayscale = true;
00247 
00248   // If the image is not yet loaded, go back (it will be made grayscale when loading)
00249   if (_elements.size() == 0)
00250     return;
00251 
00252   // Turn gray all the ImageElement components
00253   for (uint32 i=0; i<_elements.size(); i++)
00254   {
00255     Image *img = _elements[i].image;  // Color image
00256 
00257     if (img == NULL)
00258     {
00259       if (VIDEO_DEBUG)
00260         cerr << "VIDEO ERROR: Attemp to turn to grayscale mode a NULL Image" << endl;
00261       continue;
00262     }
00263 
00264     // Check first if there is a grayscale version already in the map
00265     if (VideoManager->_images.find(img->filename + img->tags + "<G>") != VideoManager->_images.end())
00266     {
00267       _elements[i].image = VideoManager->_images[img->filename + img->tags + "<G>"];
00268       ++(_elements[i].image->ref_count);
00269       continue;
00270     }
00271 
00272     // If we arrive here, it means we have to convert to grayscale the image
00273     hoa_video::private_video::ImageLoadInfo buffer;
00274     VideoManager->_GetBufferFromImage (buffer, img);
00275 
00276     VideoManager->_ConvertImageToGrayscale (buffer, buffer);
00277     
00278     Image* new_image_gray = new Image(img->filename, img->tags+"<G>", buffer.width, buffer.height, true);
00279 
00280     TexSheet *sheet = VideoManager->_InsertImageInTexSheet(new_image_gray, buffer, _is_static);
00281 
00282     if(!sheet)
00283     {
00284       if(VIDEO_DEBUG)
00285         cerr << "VIDEO_DEBUG: GameVideo::_InsertImageInTexSheet() returned NULL!" << endl;
00286 
00287       delete new_image_gray;
00288 
00289       if (buffer.pixels)
00290         free (buffer.pixels);
00291 
00292       return;
00293     }
00294 
00295     new_image_gray->ref_count = 1;
00296     VideoManager->_images[new_image_gray->filename + new_image_gray->tags] = new_image_gray;
00297     _elements[i].image = new_image_gray;
00298   }
00299 }
00300 
00301 
00302 
00303 void StillImage::DisableGrayScale() {
00304   // If the image is already in color mode, go back
00305   if (!_grayscale)
00306     return;
00307   
00308   // Mark as not grayscale
00309   _grayscale = false;
00310 
00311   // If the image is not yet loaded, go back
00312   if (_elements.size() == 0)
00313     return;
00314 
00315   // Turn to color all the ImageElement components
00316   for (uint32 i=0; i<_elements.size(); i++)
00317   {
00318     Image *img = _elements[i].image;  // Color image
00319 
00320     if (img == NULL)
00321     {
00322       if (VIDEO_DEBUG)
00323         cerr << "VIDEO ERROR: Attemp to turn to color mode a NULL Image" << endl;
00324       continue;
00325     }
00326 
00327     // Check for the color mode version of the image, already in the map
00328     if (VideoManager->_images.find(img->filename + img->tags.substr(0,img->tags.length()-3)) == VideoManager->_images.end())
00329     {
00330       if (VIDEO_DEBUG)
00331         cerr << "VIDEO ERROR: Color image not found in the map, while gray one was in it" << endl;
00332       continue;
00333     }
00334 
00335     _elements[i].image = VideoManager->_images[img->filename + img->tags.substr(0,img->tags.length()-3)];
00336     --(img->ref_count);
00337   }
00338 }
00339 
00340 //------------------------------------------------------------------------------
00341 // AddImage: this is the function that gives us the ability to form "compound images".
00342 // Call AddImage() on an existing image descriptor to place a new image at the desired offsets.
00343 //
00344 // NOTE: It is an error to pass in negative offsets to this function
00345 //
00346 // NOTE: When you create a compound image descriptor with AddImage(), remember to call DeleteImage()
00347 // on it when you're done. Even though it's not loading any new image from disk, it increases the
00348 // reference count.
00349 //------------------------------------------------------------------------------
00350 bool StillImage::AddImage(const StillImage &id, float x_offset, float y_offset, float u1, float v1, float u2, float v2)
00351 {
00352   // Negative offsets not allowed
00353   if (x_offset < 0.0f || y_offset < 0.0f) {
00354     if (VIDEO_DEBUG) 
00355       cerr << "VIDEO ERROR: passed negative offsets to StillImage::AddImage()" << endl;
00356     return false;
00357   }
00358   
00359   size_t num_elements = id._elements.size();
00360   if (num_elements == 0) {
00361     if (VIDEO_DEBUG) 
00362       cerr << "VIDEO ERROR: passed in an uninitialized image descriptor to StillImage::AddImage()!" << endl;
00363     
00364     return false;
00365   }
00366   
00367   for (uint32 i = 0; i < num_elements; ++i) {
00368     // Add the new image element to the descriptor
00369     ImageElement elem = id._elements[i];
00370     elem.x_offset += x_offset;
00371     elem.y_offset += y_offset;
00372     elem.u1 = u1;
00373     elem.v1 = v1;
00374     elem.u2 = u2;
00375     elem.v2 = v2;
00376     
00377     elem.width *= (elem.u2 - elem.u1);
00378     elem.height *= (elem.v2 - elem.v1);
00379 
00380     // TODO: This needs a comment here
00381     if (elem.image) {
00382       ++(elem.image->ref_count);
00383     }
00384     _elements.push_back(elem);
00385 
00386     // Recalculate the width and height of the descriptor as a whole. (This assumes that there are no negative offsets.)
00387     float max_x = elem.x_offset + elem.width;
00388     if (max_x > _width)
00389       _width = max_x;
00390       
00391     float max_y = elem.y_offset + elem.height;
00392     if (max_y > _height)
00393       _height = max_y;
00394   }
00395   
00396   return true;  
00397 } // bool StillImage::AddImage()
00398 
00399 // *****************************************************************************
00400 // ******************************* AnimatedImage *******************************
00401 // *****************************************************************************
00402 
00403 AnimatedImage::AnimatedImage(const bool grayscale) {
00404   Clear();
00405   _animated = true;
00406   _grayscale = grayscale;
00407   _number_loops = -1;
00408   _loop_counter = 0;
00409   _loops_finished = false;
00410 }
00411 
00412 
00413 
00414 void AnimatedImage::Clear() {
00415   _Clear();
00416   _frame_index = 0;
00417   _frame_counter = 0;
00418   _frames.clear();
00419   _number_loops = -1;
00420   _loop_counter = 0;
00421   _loops_finished = false;
00422 
00423   SetColor(Color::white);
00424 }
00425 
00426 
00427 
00428 void AnimatedImage::EnableGrayScale() {
00429   // Enable gray scale on all frames
00430   StillImage *img;
00431   for (uint32 i = 0; i < _frames.size(); i++) {
00432     img = GetFrame(i);
00433     img->EnableGrayScale();
00434   }
00435 }
00436 
00437 
00438 
00439 void AnimatedImage::DisableGrayScale() {
00440   // Disable gray scale on all frames
00441   StillImage *img;
00442   for (uint32 i = 0; i < _frames.size(); i++) {
00443     img = GetFrame(i);
00444     img->DisableGrayScale();
00445   }
00446 }
00447 
00448 
00449 
00450 void AnimatedImage::Update() {
00451   if (_frames.size() <= 1)
00452     return;
00453 
00454   if (_loops_finished)
00455     return;
00456 
00457   // Get the amount of time that expired since the last frame
00458   uint32 frame_change = VideoManager->GetFrameChange();
00459   _frame_counter += frame_change;
00460 
00461   // If the frame time has expired, update the frame index and counter.
00462   while (_frame_counter >= _frames[_frame_index].frame_time) {
00463     frame_change = _frame_counter - _frames[_frame_index].frame_time;
00464     _frame_index++;
00465     if (_frame_index >= _frames.size()) {
00466         // Check if the animation has looping enabled and if so, increment the loop counter
00467         // and cease the animation if the number of animation loops have finished
00468       if (_number_loops >= 0 && ++_loop_counter >= _number_loops) {
00469         _loops_finished = true;
00470         _frame_counter = 0;
00471         return;
00472       }
00473       _frame_index = 0;
00474     }
00475     _frame_counter = frame_change;
00476   }
00477 }
00478 
00479 
00480 
00481 bool AnimatedImage::AddFrame(const std::string &frame, uint32 frame_time) {
00482   StillImage img;
00483   img.SetFilename(frame); 
00484   img.SetDimensions(_width, _height);
00485   img.SetVertexColors(_color[0], _color[1], _color[2], _color[3]);
00486   img.SetStatic(_is_static);
00487   
00488   AnimationFrame new_frame;
00489   new_frame.frame_time = frame_time;
00490   new_frame.image = img;
00491   _frames.push_back(new_frame);
00492 
00493   return true;
00494 }
00495 
00496 
00497 
00498 bool AnimatedImage::AddFrame(const StillImage &frame, uint32 frame_time) {
00499   AnimationFrame new_frame;
00500   new_frame.image = frame;
00501   new_frame.frame_time = frame_time;
00502 
00503   // Check if the static image argument has been loaded yet.
00504   // If it has, then we have to increment the reference count
00505   uint32 num_elements = new_frame.image._elements.size();
00506   if (num_elements) {
00507     for (uint32 i = 0; i < num_elements; i++) {
00508       ++(new_frame.image._elements[i].image->ref_count);
00509     }
00510   }
00511   
00512   _frames.push_back(new_frame);
00513   return true;
00514 }
00515 
00516 
00517 
00518 void AnimatedImage::SetWidth(const float width) {
00519   _width = width;
00520 
00521   // Update the width of each frame image
00522   StillImage *img;
00523   for (uint32 i = 0; i < _frames.size(); ++i) {
00524     img = GetFrame(i);
00525     img->SetWidth(width);
00526   }
00527 }
00528 
00529 
00530 
00531 void AnimatedImage::SetHeight(const float height) {
00532   _height = height;
00533 
00534   // Update the height of each frame image
00535   StillImage *img;
00536   for (uint32 i = 0; i < _frames.size(); i++) {
00537     img = GetFrame(i);
00538     img->SetHeight(height);
00539   }
00540 }
00541 
00542 
00543 
00544 void AnimatedImage::SetDimensions(const float width, const float height) {
00545   _width = width;
00546   _height = height;
00547 
00548   // Update the width and height of each frame image
00549   StillImage *img;
00550   for (uint32 i = 0; i < _frames.size(); i++) {
00551     img = GetFrame(i);
00552     img->SetDimensions(width, height);
00553   }
00554 }
00555 
00556 
00557 
00558 void AnimatedImage::SetColor(const Color &color)
00559 {
00560   _color[0] = color;
00561   _color[1] = color;
00562   _color[2] = color;
00563   _color[3] = color;
00564 
00565   // Update the color of each frame image
00566   StillImage *img;
00567   for (uint32 i = 0; i < _frames.size(); i++) {
00568     img = GetFrame(i);
00569     img->SetColor(color);
00570   }
00571 }
00572 
00573 
00574 
00575 void AnimatedImage::SetVertexColors(const Color &tl, const Color &tr, const Color &bl, const Color &br) {
00576   _color[0] = tl;
00577   _color[1] = tr;
00578   _color[2] = bl;
00579   _color[3] = br;
00580 
00581   // Update the vertex colors of each frame image
00582   StillImage *img;
00583   for (uint32 i = 0; i < _frames.size(); i++) {
00584     img = GetFrame(i);
00585     img->SetVertexColors(tl, tr, bl, br);
00586   }
00587 }
00588 
00589 }  // namespace hoa_video

Generated on Fri Jul 6 23:11:16 2007 for Hero of Allacrost by  doxygen 1.5.1