/*
* Copyright 2010-2016 OpenXcom Developers.
*
* This file is part of OpenXcom.
*
* OpenXcom is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenXcom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SurfaceSet.h"
#include <fstream>
#include <climits>
#include "Surface.h"
#include "Exception.h"
namespace OpenXcom
{
/**
* Sets up a new empty surface set for frames of the specified size.
* @param width Frame width in pixels.
* @param height Frame height in pixels.
*/
SurfaceSet::SurfaceSet(int width, int height) : _width(width), _height(height), _sharedFrames(INT_MAX)
{
}
/**
* Performs a deep copy of an existing surface set.
* @param other Surface set to copy from.
*/
SurfaceSet::SurfaceSet(const SurfaceSet& other)
{
_width = other._width;
_height = other._height;
_sharedFrames = other._sharedFrames;
for (std::map<int, Surface*>::const_iterator f = other._frames.begin(); f != other._frames.end(); ++f)
{
_frames[f->first] = new Surface(*f->second);
}
}
/**
* Deletes the images from memory.
*/
SurfaceSet::~SurfaceSet()
{
for (std::map<int, Surface*>::iterator i = _frames.begin(); i != _frames.end(); ++i)
{
delete i->second;
}
}
/**
* Loads the contents of an X-Com set of PCK/TAB image files
* into the surface. The PCK file contains an RLE compressed
* image, while the TAB file contains the offsets to each
* frame in the image.
* @param pck Filename of the PCK image.
* @param tab Filename of the TAB offsets.
* @sa http://www.ufopaedia.org/index.php?title=Image_Formats#PCK
*/
void SurfaceSet::loadPck(const std::string &pck, const std::string &tab)
{
int nframes = 0;
// Load TAB and get image offsets
if (!tab.empty())
{
std::ifstream offsetFile(tab.c_str(), std::ios::in | std::ios::binary);
if (!offsetFile)
{
throw Exception(tab + " not found");
}
std::streampos begin, end;
begin = offsetFile.tellg();
int off;
offsetFile.read((char*)&off, sizeof(off));
offsetFile.seekg(0, std::ios::end);
end = offsetFile.tellg();
int size = end - begin;
// 16-bit offsets
if (off != 0)
{
nframes = size / 2;
}
// 32-bit offsets
else
{
nframes = size / 4;
}
offsetFile.close();
for (int frame = 0; frame < nframes; ++frame)
{
_frames[frame] = new Surface(_width, _height);
}
}
else
{
nframes = 1;
_frames[0] = new Surface(_width, _height);
}
// Load PCK and put pixels in surfaces
std::ifstream imgFile (pck.c_str(), std::ios::in | std::ios::binary);
if (!imgFile)
{
throw Exception(pck + " not found");
}
Uint8 value;
for (int frame = 0; frame < nframes; ++frame)
{
int x = 0, y = 0;
// Lock the surface
_frames[frame]->lock();
imgFile.read((char*)&value, 1);
for (int i = 0; i < value; ++i)
{
for (int j = 0; j < _width; ++j)
{
_frames[frame]->setPixelIterative(&x, &y, 0);
}
}
while (imgFile.read((char*)&value, 1) && value != 255)
{
if (value == 254)
{
imgFile.read((char*)&value, 1);
for (int i = 0; i < value; ++i)
{
_frames[frame]->setPixelIterative(&x, &y, 0);
}
}
else
{
_frames[frame]->setPixelIterative(&x, &y, value);
}
}
// Unlock the surface
_frames[frame]->unlock();
}
imgFile.close();
}
/**
* Loads the contents of an X-Com DAT image file into the
* surface. Unlike the PCK, a DAT file is an uncompressed
* image with no offsets so these have to be figured out
* manually, usually by splitting the image into equal portions.
* @param filename Filename of the DAT image.
* @sa http://www.ufopaedia.org/index.php?title=Image_Formats#SCR_.26_DAT
*/
void SurfaceSet::loadDat(const std::string &filename)
{
int nframes = 0;
// Load file and put pixels in surface
std::ifstream imgFile (filename.c_str(), std::ios::in | std::ios::binary);
if (!imgFile)
{
throw Exception(filename + " not found");
}
imgFile.seekg(0, std::ios::end);
std::streamoff size = imgFile.tellg();
imgFile.seekg(0, std::ios::beg);
nframes = (int)size / (_width * _height);
for (int i = 0; i < nframes; ++i)
{
Surface *surface = new Surface(_width, _height);
_frames[i] = surface;
}
Uint8 value;
int x = 0, y = 0, frame = 0;
// Lock the surface
_frames[frame]->lock();
while (imgFile.read((char*)&value, 1))
{
_frames[frame]->setPixelIterative(&x, &y, value);
if (y >= _height)
{
// Unlock the surface
_frames[frame]->unlock();
frame++;
x = 0;
y = 0;
if (frame >= nframes)
break;
else
_frames[frame]->lock();
}
}
imgFile.close();
}
/**
* Returns a particular frame from the surface set.
* @param i Frame number in the set.
* @return Pointer to the respective surface.
*/
Surface *SurfaceSet::getFrame(int i)
{
if (_frames.find(i) != _frames.end())
{
return _frames[i];
}
return 0;
}
/**
* Creates and returns a particular frame in the surface set.
* @param i Frame number in the set.
* @return Pointer to the respective surface.
*/
Surface *SurfaceSet::addFrame(int i)
{
_frames[i] = new Surface(_width, _height);
return _frames[i];
}
/**
* Returns the full width of a frame in the set.
* @return Width in pixels.
*/
int SurfaceSet::getWidth() const
{
return _width;
}
/**
* Returns the full height of a frame in the set.
* @return Height in pixels.
*/
int SurfaceSet::getHeight() const
{
return _height;
}
/**
* Set number of shared frame indexs that are accessible for all mods.
*/
void SurfaceSet::setMaxSharedFrames(int i)
{
if (i >= 0)
{
_sharedFrames = i;
}
else
{
_sharedFrames = 0;
}
}
/**
* Gets number of shared frame indexs that are accessible for all mods.
*/
int SurfaceSet::getMaxSharedFrames() const
{
return _sharedFrames;
}
/**
* Returns the total amount of frames currently
* stored in the set.
* @return Number of frames.
*/
size_t SurfaceSet::getTotalFrames() const
{
return _frames.size();
}
/**
* Replaces a certain amount of colors in all of the frames.
* @param colors Pointer to the set of colors.
* @param firstcolor Offset of the first color to replace.
* @param ncolors Amount of colors to replace.
*/
void SurfaceSet::setPalette(SDL_Color *colors, int firstcolor, int ncolors)
{
for (std::map<int, Surface*>::iterator i = _frames.begin(); i != _frames.end(); ++i)
{
(*i).second->setPalette(colors, firstcolor, ncolors);
}
}
std::map<int, Surface*> *SurfaceSet::getFrames()
{
return &_frames;
}
}
↑ V1020 The function exited without calling the '_frames[frame]->unlock' function. Check lines: 220, 198.
↑ V1020 The function exited without calling the '_frames[frame]->unlock' function. Check lines: 220, 216.