1 /*
2  * Copyright 2010-2014 OpenXcom Developers.
3  *
4  * This file is part of OpenXcom.
5  *
6  * OpenXcom is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * OpenXcom is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with OpenXcom.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "Palette.h"
20 #include <fstream>
21 #include "Exception.h"
22 
23 namespace OpenXcom
24 {
25 
26 /**
27  * Initializes a brand new palette.
28  */
Palette()29 Palette::Palette() : _colors(0), _count(0)
30 {
31 }
32 
33 /**
34  * Deletes any colors contained within.
35  */
~Palette()36 Palette::~Palette()
37 {
38 	delete[] _colors;
39 }
40 
41 /**
42  * Loads an X-Com palette from a file. X-Com palettes are just a set
43  * of RGB colors in a row, on a 0-63 scale, which have to be adjusted
44  * for modern computers (0-255 scale).
45  * @param filename Filename of the palette.
46  * @param ncolors Number of colors in the palette.
47  * @param offset Position of the palette in the file (in bytes).
48  * @sa http://www.ufopaedia.org/index.php?title=PALETTES.DAT
49  */
loadDat(const std::string & filename,int ncolors,int offset)50 void Palette::loadDat(const std::string &filename, int ncolors, int offset)
51 {
52 	if(_colors != 0)
53 		throw Exception("loadDat can be run only once");
54 	_count = ncolors;
55 	_colors = new SDL_Color[_count];
56 	memset(_colors, 0, sizeof(SDL_Color) * _count);
57 
58 	// Load file and put colors in pallete
59 	std::ifstream palFile (filename.c_str(), std::ios::in | std::ios::binary);
60 	if (!palFile)
61 	{
62 		throw Exception(filename + " not found");
63 	}
64 
65 	// Move pointer to proper pallete
66 	palFile.seekg(offset, std::ios::beg);
67 
68 	Uint8 value[3];
69 
70 	for (int i = 0; i < _count && palFile.read((char*)value, 3); ++i)
71 	{
72 		// Correct X-Com colors to RGB colors
73 		_colors[i].r = value[0] * 4;
74 		_colors[i].g = value[1] * 4;
75 		_colors[i].b = value[2] * 4;
76 		_colors[i].unused = 255;
77 	}
78 	_colors[0].unused = 0;
79 
80 	palFile.close();
81 }
82 
83 /**
84  * Provides access to colors contained in the palette.
85  * @param offset Offset to a specific color.
86  * @return Pointer to the requested SDL_Color.
87  */
getColors(int offset) const88 SDL_Color *Palette::getColors(int offset) const
89 {
90 	return _colors + offset;
91 }
92 
93 /**
94  * Converts an SDL_Color struct into an hexadecimal RGBA color value.
95  * Mostly used for operations with SDL_gfx that require colors in this format.
96  * @param pal Requested palette.
97  * @param color Requested color in the palette.
98  * @return Hexadecimal RGBA value.
99  */
getRGBA(SDL_Color * pal,Uint8 color)100 Uint32 Palette::getRGBA(SDL_Color* pal, Uint8 color)
101 {
102 	return ((Uint32) pal[color].r << 24) | ((Uint32) pal[color].g << 16) | ((Uint32) pal[color].b << 8) | (Uint32) 0xFF;
103 }
104 
savePal(const std::string & file) const105 void Palette::savePal(const std::string &file) const
106 {
107 	std::ofstream out(file.c_str(), std::ios::out | std::ios::binary);
108 	short count = _count;
109 
110 	// RIFF header
111 	out << "RIFF";
112 	int length = 4 + 4 + 4 + 4 + 2 + 2 + count * 4;
113 	out.write((char*) &length, sizeof(length));
114 	out << "PAL ";
115 
116 	// Data chunk
117 	out << "data";
118 	int data = count * 4 + 4;
119 	out.write((char*) &data, sizeof(data));
120 	short version = 0x0300;
121 	out.write((char*) &version, sizeof(version));
122 	out.write((char*) &count, sizeof(count));
123 
124 	// Colors
125 	SDL_Color *color = getColors();
126 	for (short i = 0; i < count; ++i)
127 	{
128 		char c = 0;
129 		out.write((char*) &color->r, 1);
130 		out.write((char*) &color->g, 1);
131 		out.write((char*) &color->b, 1);
132 		out.write(&c, 1);
133 		color++;
134 	}
135 	out.close();
136 }
137 
138 }
139