1 ////////////////////////////////////////////////////////////////////////////////
2 //    Scorched3D (c) 2000-2011
3 //
4 //    This file is part of Scorched3D.
5 //
6 //    Scorched3D 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 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    Scorched3D 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 along
17 //    with this program; if not, write to the Free Software Foundation, Inc.,
18 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20 
21 #include <image/Image.h>
22 #include <image/ImageFactory.h>
23 #include <common/DefinesAssert.h>
24 #include <SDL/SDL.h>
25 #include "string.h"
26 
Image()27 Image::Image()
28 {
29 	data_ = new ImageData();
30 	data_->reference();
31 }
32 
Image(int width,int height,bool alpha)33 Image::Image(int width, int height, bool alpha)
34 {
35 	data_ = new ImageData(width, height, alpha?4:3, 255);
36 	data_->reference();
37 }
38 
Image(int width,int height,int components,unsigned char fill)39 Image::Image(int width, int height, int components, unsigned char fill)
40 {
41 	data_ = new ImageData(width, height, components, fill);
42 	data_->reference();
43 }
44 
Image(const Image & other)45 Image::Image(const Image &other)
46 {
47 	data_ = other.data_;
48 	data_->reference();
49 }
50 
~Image()51 Image::~Image()
52 {
53 	data_->dereference();
54 }
55 
operator =(const Image & other)56 Image &Image::operator=(const Image &other)
57 {
58 	data_->dereference();
59 	data_ = other.data_;
60 	data_->reference();
61 
62 	return *this;
63 }
64 
getBitsPos(int x,int y)65 unsigned char *Image::getBitsPos(int x, int y)
66 {
67 	DIALOG_ASSERT(x >= 0 && y >= 0 && x < getWidth() && y < getHeight());
68 	return &getBits()[(x * getComponents()) + (y * getWidth() * getComponents())];
69 }
70 
getBitsOffset(int offset)71 unsigned char *Image::getBitsOffset(int offset)
72 {
73 	DIALOG_ASSERT(offset >=0 && offset < getComponents() * getWidth() * getHeight());
74 	return &getBits()[offset];
75 }
76 
writeToFile(const std::string & filename)77 bool Image::writeToFile(const std::string &filename)
78 {
79 	if (!getBits() || getComponents() == 4) return false;
80 
81 	unsigned char *brgbits = new unsigned char[getWidth() * getHeight() * 3];
82 
83 	// Convert the returned bits from RGB to BGR
84 	// and flip the verticle scan lines
85 	unsigned char *from = (unsigned char *) getBits();
86 	for (int i=0; i<getHeight(); i ++)
87 	{
88 		unsigned char *destRow = ((unsigned char *) brgbits) +
89 			((getHeight() - i - 1) * (getWidth() * 3));
90 		for (int j=0; j<getWidth(); j++)
91 		{
92 			unsigned char *dest = destRow + (j * getComponents());
93 
94 			dest[0] = from[0];
95 			dest[1] = from[1];
96 			dest[2] = from[2];
97 			from+=getComponents();
98 		}
99 	}
100 
101     /* SDL interprets each pixel as a 32-bit number, so our masks must depend
102        on the endianness (byte order) of the machine */
103     Uint32 rmask, gmask, bmask;
104 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
105     rmask = 0xff000000;
106     gmask = 0x00ff0000;
107     bmask = 0x0000ff00;
108 #else
109     rmask = 0x000000ff;
110     gmask = 0x0000ff00;
111     bmask = 0x00ff0000;
112 #endif
113 
114 	SDL_Surface *image = SDL_CreateRGBSurface(
115 		SDL_SWSURFACE, getWidth(), getHeight(), 24, rmask, gmask, bmask, 0);
116 	memcpy(image->pixels, brgbits, getWidth() * getHeight() * 3);
117 
118 	if (!image) return false;
119 
120 	SDL_SaveBMP(image, filename.c_str());
121     SDL_FreeSurface (image);
122 
123 	delete [] brgbits;
124 	return true;
125 }
126 
127 #ifndef S3D_SERVER
128 
129 #include <GLEXT/GLState.h>
130 #include <common/Defines.h>
131 
createAlphaMult(float mult)132 Image Image::createAlphaMult(float mult)
133 {
134 	if (getComponents() != 4) return Image();
135 
136 	Image map(getWidth(), getHeight(), true);
137 
138 	unsigned char *srcBits = getBits();
139 	unsigned char *destBits = map.getBits();
140 	for (int y=0; y<getHeight(); y++)
141 	{
142 		for (int x=0; x<getWidth(); x++, srcBits += 3, destBits += 3)
143 		{
144 			float a = float(srcBits[3]) * mult;
145 			a = MAX(a, 255);
146 			a = MIN(a, 0);
147 
148 			destBits[0] = srcBits[0];
149 			destBits[1] = srcBits[1];
150 			destBits[2] = srcBits[2];
151 			destBits[3] = (unsigned char)(a);
152 		}
153 	}
154 
155 	return map;
156 }
157 
createResize(int newWidth,int newHeight)158 Image Image::createResize(int newWidth, int newHeight)
159 {
160 	if (!getBits()) return Image();
161 
162 	Image map(newWidth, newHeight, getComponents(), 0);
163 
164 	// Odd hack to fix a seeming memory corruption with gluScaleImage
165 	map.setBits(new unsigned char[newWidth * 2 * newHeight * map.getComponents()]);
166 
167 	if (getWidth() != newWidth || getHeight() != newHeight)
168 	{
169 		GLenum format = GL_RGBA;
170 		if (getComponents() == 4) format = GL_RGBA;
171 		else if (getComponents() == 3) format = GL_RGB;
172 		else if (getComponents() == 2) format = GL_LUMINANCE_ALPHA;
173 		else if (getComponents() == 1) format = GL_LUMINANCE;
174 
175 		int result = gluScaleImage(
176 			format,
177 			getWidth(), getHeight(),
178 			GL_UNSIGNED_BYTE, getBits(),
179 			newWidth, newHeight,
180 			GL_UNSIGNED_BYTE, map.getBits());
181 		if (result != 0)
182 		{
183 			const char *error = (const char *) gluErrorString(result);
184 			S3D::dialogExit("gluScaleImage", error);
185 		}
186 	}
187 	else
188 	{
189 		memcpy(map.getBits(), getBits(), getComponents() * getWidth() * getHeight());
190 	}
191 
192 	return map;
193 }
194 #endif
195