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