Merge from development branch heightmap to main.
[scorched3d.git] / src / client / GLEXT / GLImageModifier.cpp
blob006f7ecb850c532f7f4ad062b2c014cd8ff30c42
1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2003
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.
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.
16 // You should have received a copy of the GNU General Public License
17 // along with Scorched3D; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ////////////////////////////////////////////////////////////////////////////////
21 #include <vector>
22 #include <math.h>
23 #include <GLEXT/GLImageItterator.h>
24 #include <GLEXT/GLImageModifier.h>
25 #include <image/ImageHandle.h>
26 #include <image/ImageFactory.h>
27 #include <engine/ScorchedContext.h>
28 #include <landscape/Landscape.h>
29 #include <landscapemap/LandscapeMaps.h>
30 #include <client/ScorchedClient.h>
31 #include <lang/LangResource.h>
32 #include <common/Defines.h>
34 bool ImageModifier::findIntersection(HeightMap &hMap,
35 Vector start,
36 Vector end,
37 float &dist,
38 float stopDist)
40 bool result = false;
41 dist = 0.0f;
42 Vector point = start;
43 Vector direction = end - start;
44 float &pt0 = point[0];
45 float &pt1 = point[1];
46 float &pt2 = point[2];
47 int width = hMap.getMapWidth();
48 int height = hMap.getMapHeight();
50 // Calculate how many pixels to jump for each itteration
51 if (fabsf(direction[0]) > fabsf(direction[1])) direction /= fabsf(direction[0]);
52 else direction /= fabsf(direction[1]);
54 while (pt0 >= 0.0f && pt1 >= 0.0f &&
55 pt0 <= width && pt1 <= height)
57 float height = hMap.getHeight(int(point[0]), int(point[1])).asFloat() - 0.1f;
58 float rayHeight = height - pt2;
59 if (rayHeight > 0.0f)
61 if (rayHeight > dist) dist = rayHeight;
62 result = true;
63 if (dist > stopDist) return result;
66 point += direction;
69 return result;
72 void ImageModifier::tileBitmap(Image &src, Image &dest)
74 GLubyte *destBytes = dest.getBits();
75 for (int j=0; j<dest.getHeight(); j++)
77 for (int i=0; i<dest.getWidth();i++, destBytes+=3)
79 int srcX = i % src.getWidth();
80 int srcY = j % src.getHeight();
82 GLubyte *srcBytes = src.getBits() + (3 * srcX) +
83 (3 * src.getWidth() * srcY);
85 destBytes[0] = srcBytes[0];
86 destBytes[1] = srcBytes[1];
87 destBytes[2] = srcBytes[2];
92 void ImageModifier::addLightMapToBitmap(Image &destBitmap,
93 HeightMap &hMap,
94 Vector &sunPos,
95 Vector &ambience,
96 Vector &diffuse,
97 ProgressCounter *counter)
99 const float softShadow = 3.0f;
100 const int sideFade = 16;
101 const int lightMapWidth = 256; // Resolution of the light map
103 if (counter) counter->setNewOp(LANG_RESOURCE("LIGHT_MAP", "Light Map"));
105 // Itterate the dest bitmap pixels
106 GLfloat *bitmap = new GLfloat[lightMapWidth * lightMapWidth * 3];
107 GLfloat *bitmapBits = bitmap;
108 int y;
109 for (y=0; y<lightMapWidth; y++)
111 if (counter) counter->setNewPercentage(100.0f * float(y) / float(lightMapWidth));
113 for (int x=0; x<lightMapWidth; x++)
115 float dx = float(x)/float(lightMapWidth)*float(hMap.getMapWidth());
116 float dy = float(y)/float(lightMapWidth)*float(hMap.getMapHeight());
117 float dz = hMap.getInterpHeight(
118 fixed::fromFloat(dx), fixed::fromFloat(dy)).asFloat();
120 Vector testPosition(dx, dy, dz);
121 FixedVector fixedTestNormal;
122 hMap.getInterpNormal(
123 fixed::fromFloat(dx), fixed::fromFloat(dy), fixedTestNormal);
124 Vector testNormal = fixedTestNormal.asVector();
125 Vector sunDirection = (sunPos - testPosition).Normalize();
127 // Calculate light based on whether obejcts in path
128 float diffuseLightMult =
129 (((testNormal.dotP(sunDirection)) / 2.0f) + 0.5f);
130 float dist = 0.0f;
131 if (findIntersection(hMap,
132 testPosition, sunPos, dist, softShadow))
134 // An object is in the path
135 if (dist < softShadow)
137 // The object is only just in the path
138 // Create soft shadow
139 diffuseLightMult *= 1.0f - (dist / softShadow);
141 else
143 // Totaly in path, dark shadow
144 diffuseLightMult = 0.0f;
148 Vector diffuseLight = diffuse * diffuseLightMult;
149 Vector ambientLight = ambience;
150 Vector lightColor = diffuseLight + ambientLight;
151 lightColor[0] = MIN(1.0f, lightColor[0]);
152 lightColor[1] = MIN(1.0f, lightColor[1]);
153 lightColor[2] = MIN(1.0f, lightColor[2]);
155 bitmapBits[0] = lightColor[0];
156 bitmapBits[1] = lightColor[1];
157 bitmapBits[2] = lightColor[2];
158 bitmapBits +=3;
162 GLfloat *copyDest = new GLfloat[destBitmap.getWidth() * destBitmap.getHeight() * 3];
163 gluScaleImage(
164 GL_RGB,
165 lightMapWidth, lightMapWidth,
166 GL_FLOAT, bitmap,
167 destBitmap.getWidth(), destBitmap.getHeight(),
168 GL_FLOAT, copyDest);
170 GLfloat *srcBits = copyDest;
171 GLubyte *destBits = destBitmap.getBits();
172 for (y=0; y<destBitmap.getHeight(); y++)
174 for (int x=0; x<destBitmap.getWidth(); x++)
176 destBits[0] = GLubyte(MIN(float(destBits[0]) * (srcBits[0] * 1.2f), 255.0f));
177 destBits[1] = GLubyte(MIN(float(destBits[1]) * (srcBits[1] * 1.2f), 255.0f));
178 destBits[2] = GLubyte(MIN(float(destBits[2]) * (srcBits[2] * 1.2f), 255.0f));
180 srcBits += 3;
181 destBits += 3;
185 delete [] copyDest;
186 delete [] bitmap;
189 void ImageModifier::addHeightToBitmap(HeightMap &hMap,
190 Image &destBitmap,
191 Image &destSplat1Bitmap,
192 Image &destSplat2Bitmap,
193 Image &slopeBitmap,
194 Image &shoreBitmap,
195 Image **origHeightBitmaps,
196 int numberSources,
197 int destBitmapScaleSize,
198 ProgressCounter *counter)
200 const float maxHeight = 30.0f; // Last texture ends at height 30
201 const float blendHeightFactor = 0.4f; // Ends blend when 40% into height band
202 const float blendNormalSlopeStart = 0.8f; // Starts blending slope at .80
203 const float blendNormalSlopeLength = 0.3f; // Blends when 30% more slope
204 const float blendNormalShoreStart = 0.8f; // Starts the sand
205 const float blendNormalShoreLength = 0.1f; // Amount of sand
206 const float noiseMax = 0.4f;
208 float hMapMaxHeight = 0;
209 for (int ma=0; ma<hMap.getMapWidth(); ma++)
211 for (int mb=0;mb<hMap.getMapHeight(); mb++)
213 float height = hMap.getHeight(ma, mb).asFloat();
214 if (height > hMapMaxHeight) hMapMaxHeight = height;
218 // Create new bitmaps with the bitmap scaled to the correct size
219 Image **heightBitmaps = new Image*[numberSources];
220 ImageItterator ** bitmapItors = new ImageItterator*[numberSources+2];
221 float bitmapScale = float(destBitmap.getWidth()) / float(destBitmapScaleSize);
223 // Create a bitmap iterator for each bitmap
224 // Create a bitmap correctly scaled to the scene
225 int i;
226 for (i=0; i<numberSources; i++)
228 if (bitmapScale != 1.0f)
230 // Create the newly scaled bitmaps
231 heightBitmaps[i] = new ImageHandle(ImageFactory::createBlank(
232 int(bitmapScale * origHeightBitmaps[i]->getWidth()),
233 int(bitmapScale * origHeightBitmaps[i]->getHeight())));
235 // Scale bitmap
236 gluScaleImage(
237 GL_RGB,
238 origHeightBitmaps[i]->getWidth(), origHeightBitmaps[i]->getHeight(),
239 GL_UNSIGNED_BYTE, origHeightBitmaps[i]->getBits(),
240 heightBitmaps[i]->getWidth(), heightBitmaps[i]->getHeight(),
241 GL_UNSIGNED_BYTE, heightBitmaps[i]->getBits());
243 else
245 heightBitmaps[i] = origHeightBitmaps[i];
248 // Create iterator
249 bitmapItors[i] = new ImageItterator(
250 *heightBitmaps[i],
251 destBitmap.getWidth(),
252 destBitmap.getHeight(),
253 ImageItterator::wrap);
255 // Add shore and slopt itterators
256 bitmapItors[numberSources] =
257 new ImageItterator(
258 slopeBitmap,
259 destBitmap.getWidth(),
260 destBitmap.getHeight(),
261 ImageItterator::wrap);
262 bitmapItors[numberSources + 1] =
263 new ImageItterator(
264 shoreBitmap,
265 destBitmap.getWidth(),
266 destBitmap.getHeight(),
267 ImageItterator::wrap);
269 GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
270 GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
272 GLubyte *destBits = destBitmap.getBits();
273 GLubyte *destSplat1Bits = destSplat1Bitmap.getBits();
274 GLubyte *destSplat2Bits = destSplat2Bitmap.getBits();
276 GLfloat hy = 0.0f;
277 for (int by=0; by<destBitmap.getHeight(); by++, hy+=hdy)
279 if (counter) counter->setNewPercentage((100.0f * float (by)) / float(destBitmap.getHeight()));
281 GLfloat hx = 0.0f;
282 for (int bx=0; bx<destBitmap.getWidth(); bx++, destBits+=3, destSplat1Bits+=4, destSplat2Bits+=4, hx+=hdx)
284 static FixedVector fixedNormal;
285 hMap.getInterpNormal(fixed::fromFloat(hx), fixed::fromFloat(hy), fixedNormal);
286 Vector &normal = fixedNormal.asVector();
287 float height = hMap.getInterpHeight(fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
288 float offSetHeight = hMap.getInterpHeight(
289 fixed::fromFloat((float)hMap.getMapWidth() - hx),
290 fixed::fromFloat((float)hMap.getMapHeight() - hy)).asFloat();
291 height *= (1.0f - (noiseMax/2.0f)) + ((offSetHeight*noiseMax)/hMapMaxHeight);
293 // Find the index of the current texture by deviding the height into strips
294 float heightPer = (height / maxHeight) * (float) numberSources;
295 int heightIndex = (int) heightPer;
296 if (heightIndex >= numberSources)
298 heightIndex = numberSources - 1;
301 // Check if we are in a blending transition phase
302 float blendFirstAmount = 1.0f;
303 float blendSecondAmount = 0.0f;
304 if (heightIndex < numberSources - 1)
306 float remainderIndex = heightPer - heightIndex;
307 if (remainderIndex > blendHeightFactor)
309 // We need to do some blending, figure how much
310 remainderIndex -= blendHeightFactor;
311 blendSecondAmount = remainderIndex / (1.0f - blendHeightFactor);
312 blendFirstAmount = 1.0f - blendSecondAmount;
316 // Check to see if we need to blend in the side texture
317 float blendSideAmount = 0.0f;
318 float blendShoreAmount = 0.0f;
319 if (normal[2] < blendNormalSlopeStart)
321 if (normal[2] < blendNormalSlopeStart - blendNormalSlopeLength)
323 // Only use the side texture
324 blendSideAmount = 1.0f;
325 blendFirstAmount = 0.0f;
326 blendSecondAmount = 0.0f;
328 else
330 // Blend in the side texture
331 float remainderIndex = normal[2] - (blendNormalSlopeStart - blendNormalSlopeLength);
332 remainderIndex /= blendNormalSlopeLength;
334 blendSideAmount = (1.0f - remainderIndex);
335 blendFirstAmount *= remainderIndex;
336 blendSecondAmount *= remainderIndex;
339 else if (normal[2] > blendNormalShoreStart &&
340 height > 3.5f && height < 5.5f)
342 if (normal[2] > blendNormalShoreStart + blendNormalShoreLength)
344 // Only use the side texture
345 blendShoreAmount = 1.0f;
346 blendFirstAmount = 0.0f;
347 blendSecondAmount = 0.0f;
349 else
351 // Blend in the side texture
352 float remainderIndex = normal[2] - blendNormalSlopeStart;
353 remainderIndex /= blendNormalSlopeLength;
355 blendShoreAmount = (1.0f - remainderIndex);
356 blendFirstAmount *= remainderIndex;
357 blendSecondAmount *= remainderIndex;
361 // Add first height component
362 GLubyte *sourceBits1 = bitmapItors[heightIndex]->getPos();
363 destBits[0] = (GLubyte) ((float) sourceBits1[0] * blendFirstAmount);
364 destBits[1] = (GLubyte) ((float) sourceBits1[1] * blendFirstAmount);
365 destBits[2] = (GLubyte) ((float) sourceBits1[2] * blendFirstAmount);
367 if (heightIndex < 4) destSplat1Bits[heightIndex] = (GLubyte) (255.0f * blendFirstAmount);
368 else destSplat2Bits[heightIndex-4] = (GLubyte) (255.0f * blendFirstAmount);
370 if (blendSecondAmount > 0.0f)
372 // Add second height component (if blending)
373 GLubyte *sourceBits2 = bitmapItors[heightIndex + 1]->getPos();
374 destBits[0] += (GLubyte) ((float) sourceBits2[0] * blendSecondAmount);
375 destBits[1] += (GLubyte) ((float) sourceBits2[1] * blendSecondAmount);
376 destBits[2] += (GLubyte) ((float) sourceBits2[2] * blendSecondAmount);
378 if (heightIndex + 1 < 4) destSplat1Bits[heightIndex + 1] = (GLubyte) (255.0f * blendSecondAmount);
379 else destSplat2Bits[heightIndex + 1 - 4] = (GLubyte) (255.0f * blendSecondAmount);
382 if (blendSideAmount > 0.0f)
384 // Add side component (if blending normals)
385 GLubyte *sourceBits3 = bitmapItors[numberSources]->getPos();
386 destBits[0] += (GLubyte) ((float) sourceBits3[0] * blendSideAmount);
387 destBits[1] += (GLubyte) ((float) sourceBits3[1] * blendSideAmount);
388 destBits[2] += (GLubyte) ((float) sourceBits3[2] * blendSideAmount);
390 destSplat2Bits[0] = (GLubyte) (255.0f * blendSideAmount);
393 if (blendShoreAmount > 0.0f)
395 // Add side component (if blending normals)
396 GLubyte *sourceBits4 = bitmapItors[numberSources + 1]->getPos();
397 destBits[0] += (GLubyte) ((float) sourceBits4[0] * blendShoreAmount);
398 destBits[1] += (GLubyte) ((float) sourceBits4[1] * blendShoreAmount);
399 destBits[2] += (GLubyte) ((float) sourceBits4[2] * blendShoreAmount);
401 destSplat2Bits[1] = (GLubyte) (255.0f * blendShoreAmount);
404 for (i=0; i<numberSources+2; i++) bitmapItors[i]->incX();
407 for (i=0; i<numberSources+2; i++) bitmapItors[i]->incY();
410 // Cleanup iterator and extra bitmaps
411 for (i=0; i<numberSources+2; i++)
413 delete bitmapItors[i];
415 delete [] bitmapItors;
416 for (i=0; i<numberSources; i++)
418 if (bitmapScale != 1.0f)
420 delete heightBitmaps[i];
423 delete [] heightBitmaps;
426 void ImageModifier::redBitmap(
427 Image &destBitmap)
429 unsigned char *destBits = destBitmap.getBits();
430 for (int y=0; y<destBitmap.getHeight(); y++)
432 for (int x=0; x<destBitmap.getWidth(); x++, destBits += 4)
434 destBits[0] = 255;
435 destBits[1] = 0;
436 destBits[2] = 0;
437 destBits[3] = 0;
442 void ImageModifier::addTexturesToBitmap(
443 Image &destBitmap,
444 Image &slopeBitmap,
445 Image &shoreBitmap,
446 Image **heightBitmaps,
447 int numberSources)
449 std::vector<Image *> sources;
450 for (int i=0; i<numberSources; i++)
452 sources.push_back(heightBitmaps[i]);
454 sources.push_back(&slopeBitmap);
455 sources.push_back(&shoreBitmap);
457 int currentCount = sources.size();
458 for (int i=currentCount; i<9; i++)
460 sources.push_back(&shoreBitmap);
463 unsigned char *destBits = destBitmap.getBits();
464 for (int y=0; y<destBitmap.getHeight(); y++)
466 for (int x=0; x<destBitmap.getWidth(); x++, destBits += 3)
468 int texx = x / (destBitmap.getWidth() / 3);
469 int texy = y / (destBitmap.getHeight() / 3);
470 texx = MIN(2, texx);
471 texy = MIN(2, texy);
473 Image *src = sources[texx + texy * 3];
474 int srcx = x % src->getWidth();
475 int srcy = y % src->getHeight();
477 unsigned char *srcBits = &src->getBits()[srcx * 3 + srcy * src->getWidth() * 3];
478 destBits[0] = srcBits[0];
479 destBits[1] = srcBits[1];
480 destBits[2] = srcBits[2];
485 void ImageModifier::removeWaterFromBitmap(HeightMap &hMap,
486 Image &srcBitmap,
487 Image &destBitmap,
488 Image &alphaBitmap,
489 float waterHeight)
491 DIALOG_ASSERT(srcBitmap.getWidth() == destBitmap.getWidth() &&
492 srcBitmap.getWidth() == alphaBitmap.getWidth());
493 DIALOG_ASSERT(srcBitmap.getHeight() == destBitmap.getHeight() &&
494 srcBitmap.getHeight() == alphaBitmap.getHeight());
496 GLubyte *destBits = destBitmap.getBits();
497 GLubyte *srcBits = srcBitmap.getBits();
498 GLubyte *alphaBits = alphaBitmap.getBits();
500 GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
501 GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
503 GLfloat hy = 0.0f;
504 for (int y=0; y<srcBitmap.getHeight(); y++, hy+=hdy)
506 GLfloat hx = 0.0f;
507 for (int x=0; x<srcBitmap.getWidth(); x++, hx+=hdx,
508 destBits+=4, srcBits+=3, alphaBits+=3)
510 GLubyte alpha = 255 - alphaBits[0];
511 if (alpha > 0)
513 float height = hMap.getInterpHeight(
514 fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
515 if (height > waterHeight - 0.3)
517 alpha = 128;
518 if (height > waterHeight)
520 alpha = 255;
523 else alpha = 0;
526 destBits[0] = srcBits[0];
527 destBits[1] = srcBits[1];
528 destBits[2] = srcBits[2];
529 destBits[3] = alpha;
534 void ImageModifier::addWaterToBitmap(HeightMap &hMap,
535 Image &destBitmap,
536 Image &waterBitmap,
537 float waterHeight)
539 const float waterPercentage = 0.75f;
540 const float oneMinusPercentage = 1.0f - waterPercentage;
542 ImageItterator bitmapItor(waterBitmap,
543 destBitmap.getWidth(),
544 destBitmap.getHeight(),
545 ImageItterator::wrap);
547 GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
548 GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
550 GLubyte *destBits = destBitmap.getBits();
552 GLfloat hy = 0.0f;
553 for (int by=0; by<destBitmap.getHeight(); by++, hy+=hdy, bitmapItor.incY())
555 GLfloat hx = 0.0f;
556 for (int bx=0; bx<destBitmap.getWidth(); bx++, destBits+=3, hx+=hdx, bitmapItor.incX())
558 float height = hMap.getInterpHeight(
559 fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
561 if (height <= waterHeight)
563 if (height <= waterHeight - 0.3)
565 GLubyte *sourceBits = bitmapItor.getPos();
567 destBits[0] = GLubyte(
568 (waterPercentage * float(sourceBits[0])) +
569 (oneMinusPercentage * float(destBits[0])));
570 destBits[1] = GLubyte(
571 (waterPercentage * float(sourceBits[1])) +
572 (oneMinusPercentage * float(destBits[1])));
573 destBits[2] = GLubyte(
574 (waterPercentage * float(sourceBits[2])) +
575 (oneMinusPercentage * float(destBits[2])));
577 else
579 destBits[0] = 200;
580 destBits[1] = 200;
581 destBits[2] = 200;
588 void ImageModifier::addBorderToBitmap(Image &destBitmap,
589 int borderSize,
590 float colors[3])
592 int arenaX = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaX();
593 int arenaY = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaY();
594 int arenaWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaWidth();
595 int arenaHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaHeight();
596 int landscapeWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeWidth();
597 int landscapeHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeHeight();
599 int borderX = int(float(arenaX) / float(landscapeWidth) * float(destBitmap.getWidth()));
600 int borderY = int(float(arenaY) / float(landscapeHeight) * float(destBitmap.getHeight()));
601 int borderWidth = int(float(arenaWidth) / float(landscapeWidth) * float(destBitmap.getWidth()));
602 int borderHeight = int(float(arenaHeight) / float(landscapeHeight) * float(destBitmap.getHeight()));
603 if (borderWidth + borderX >= destBitmap.getWidth()) borderWidth = destBitmap.getWidth() - borderX - 1;
604 if (borderHeight + borderY >= destBitmap.getHeight()) borderHeight = destBitmap.getHeight() - borderY - 1;
606 DIALOG_ASSERT(destBitmap.getComponents() == 3);
608 for (int x=borderX; x<=borderX+borderWidth; x++)
610 for (int i=0; i<borderSize; i++)
612 int pos = (x * 3) + ((borderY + i) * destBitmap.getWidth() * 3);
613 GLubyte *destBits = destBitmap.getBitsOffset(pos);
614 destBits[0] = GLubyte(colors[0] * 255.0f);
615 destBits[1] = GLubyte(colors[1] * 255.0f);
616 destBits[2] = GLubyte(colors[2] * 255.0f);
618 pos = (x * 3) + ((borderY + borderHeight - i) * destBitmap.getWidth() * 3);
619 destBits = destBitmap.getBitsOffset(pos);
620 destBits[0] = GLubyte(colors[0] * 255.0f);
621 destBits[1] = GLubyte(colors[1] * 255.0f);
622 destBits[2] = GLubyte(colors[2] * 255.0f);
626 for (int y=borderY; y<=borderY+borderHeight; y++)
628 for (int i=0; i<borderSize; i++)
630 int pos = ((borderX + i) * 3) + (y * destBitmap.getWidth() * 3);
631 GLubyte *destBits = destBitmap.getBitsOffset(pos);
632 destBits[0] = GLubyte(colors[0] * 255.0f);
633 destBits[1] = GLubyte(colors[1] * 255.0f);
634 destBits[2] = GLubyte(colors[2] * 255.0f);
636 pos = ((borderX + borderWidth - i) * 3) + (y * destBitmap.getWidth() * 3);
637 destBits = destBitmap.getBitsOffset(pos);
638 destBits[0] = GLubyte(colors[0] * 255.0f);
639 destBits[1] = GLubyte(colors[1] * 255.0f);
640 destBits[2] = GLubyte(colors[2] * 255.0f);
645 void ImageModifier::makeBitmapTransparent(Image &output,
646 Image &input,
647 Image &mask)
649 GLubyte *outputBits = output.getBits();
650 GLubyte *maskBits = mask.getBits();
651 GLubyte *inputBits = input.getBits();
653 for (int i=0; i<output.getWidth() * output.getHeight(); i++)
655 outputBits[0] = inputBits[0];
656 outputBits[1] = inputBits[1];
657 outputBits[2] = inputBits[2];
658 outputBits[3] = maskBits[3];
660 inputBits += 3;
661 outputBits += 4;
662 maskBits += 4;
666 void ImageModifier::addCircleToLandscape(
667 ScorchedContext &context,
668 float sx, float sy, float sw, float opacity)
670 float shadowMultWidth = (float) Landscape::instance()->getMainMap().getWidth() /
671 context.getLandscapeMaps().getGroundMaps().getLandscapeWidth();
672 float shadowMultHeight = (float) Landscape::instance()->getMainMap().getHeight() /
673 context.getLandscapeMaps().getGroundMaps().getLandscapeHeight();
675 addCircle(Landscape::instance()->getMainMap(),
676 sx * shadowMultWidth, sy * shadowMultHeight,
677 sw * shadowMultWidth, opacity);
680 void ImageModifier::addCircle(Image &destBitmap,
681 float sx, float sy, float sw, float opacity)
683 int decrement = int(opacity * 125.0f);
684 float halfW = sw / 2.0f;
686 float minX = sx - halfW;
687 float minY = sy - halfW;
688 float maxX = sx + halfW;
689 float maxY = sy + halfW;
690 /*minX /= 2.0f;
691 minY /= 2.0f;
692 maxX /= 2.0f;
693 maxY /= 2.0f;*/
695 minX = MAX(minX, 0.0f);
696 minY = MAX(minY, 0.0f);
697 maxX = MIN(maxX, destBitmap.getWidth() - 1.0f);
698 maxY = MIN(maxY, destBitmap.getHeight() - 1.0f);
700 int xStart = int(minX);
701 int yStart = int(minY);
702 int xWidth = int(maxX - minX);
703 int yWidth = int(maxY - minY);
704 int yInc = (destBitmap.getWidth() - xWidth) * 3;
706 if (xWidth <= 0 || yWidth <= 0) return;
707 double degMult = (1 / double(yWidth)) * 3.14;
709 GLubyte *start = &destBitmap.getBits()[(yStart * destBitmap.getWidth() * 3) + xStart * 3];
710 for (int y=0; y<yWidth; y++, start += yInc)
712 double deg = double(y) * degMult;
713 int realXSize = int(sin(deg) * double(xWidth));
714 int halfSize = (xWidth - realXSize) / 2;
716 start+=halfSize * 3;
717 int x;
718 for (x=0; x<realXSize; x++, start+=3)
720 start[0] = start[0] / 2;
721 start[1] = start[1] / 2;
722 start[2] = start[2] / 2;
724 start+=(xWidth - (halfSize + x)) * 3;
729 void ImageModifier::addBitmapToLandscape(
730 ScorchedContext &context,
731 Image &srcBitmap,
732 float sx, float sy, float scalex, float scaley,
733 bool commit)
735 float shadowMultWidth = (float) Landscape::instance()->getMainMap().getWidth() /
736 context.getLandscapeMaps().getGroundMaps().getLandscapeWidth();
737 float shadowMultHeight = (float) Landscape::instance()->getMainMap().getHeight() /
738 context.getLandscapeMaps().getGroundMaps().getLandscapeHeight();
740 addBitmap(
741 Landscape::instance()->getMainMap(),
742 srcBitmap,
743 sx * shadowMultWidth,
744 sy * shadowMultHeight,
745 shadowMultWidth * scalex,
746 shadowMultHeight * scaley,
747 commit);
750 void ImageModifier::addBitmap(Image &destBitmap,
751 Image &srcBitmap,
752 float sx, float sy, float scalex, float scaley,
753 bool commit)
755 int srcScaleWidth = int(float(srcBitmap.getWidth()) * scalex);
756 int srcScaleHeight = int(float(srcBitmap.getHeight()) * scaley);
758 float minX = sx - srcScaleWidth / 2;
759 float minY = sy - srcScaleHeight / 2;
760 float maxX = sx + srcScaleWidth / 2;
761 float maxY = sy + srcScaleHeight / 2;
763 minX = MAX(minX, 0.0f);
764 minY = MAX(minY, 0.0f);
765 maxX = MIN(maxX, destBitmap.getWidth() - 1.0f);
766 maxY = MIN(maxY, destBitmap.getHeight() - 1.0f);
768 int xStart = int(minX);
769 int yStart = int(minY);
770 int xWidth = int(maxX - minX);
771 int yWidth = int(maxY - minY);
773 if (xWidth <= 0 || yWidth <= 0) return;
775 int yDestInc = (destBitmap.getWidth() * 3);
777 GLubyte *dest = &destBitmap.getBits()[
778 (yStart * destBitmap.getWidth() * 3) + xStart * 3];
779 for (int y=0; y<yWidth; y++, dest += yDestInc)
781 GLubyte *tmpDest = dest;
782 for (int x=0; x<xWidth; x++)
784 int srcX = int(float(x) / scalex);
785 srcX = MIN(srcX, srcBitmap.getWidth());
786 int srcY = int(float(y) / scaley);
787 srcY = MIN(srcY, srcBitmap.getHeight());
789 GLubyte *tmpSrc = srcBitmap.getBits() +
790 srcX * srcBitmap.getComponents() +
791 srcY * srcBitmap.getComponents() * srcBitmap.getWidth();
793 float alpha = 1.0f;
794 float invAlpha = 0.0f;
795 if (srcBitmap.getComponents() == 4)
797 alpha = float(tmpSrc[3]) / 255.0f;
798 invAlpha = 1.0f - alpha;
801 tmpDest[0] = GLubyte(float(tmpSrc[0]) * alpha + float(tmpDest[0]) * invAlpha);
802 tmpDest[1] = GLubyte(float(tmpSrc[1]) * alpha + float(tmpDest[1]) * invAlpha);
803 tmpDest[2] = GLubyte(float(tmpSrc[2]) * alpha + float(tmpDest[2]) * invAlpha);
805 tmpDest += 3;
809 if (commit)
811 int landscapeWidth = Landscape::instance()->getMainMap().getWidth();
812 int width = 3 * landscapeWidth;
813 width = (width + 3) & ~3;
815 GLubyte *bytes =
816 Landscape::instance()->getMainMap().getBits() + ((width * yStart) + xStart * 3);
818 GLState currentState(GLState::TEXTURE_ON);
819 Landscape::instance()->getMainTexture().draw(true);
821 glPixelStorei(GL_UNPACK_ROW_LENGTH, landscapeWidth);
822 glTexSubImage2D(GL_TEXTURE_2D, 0,
823 xStart, yStart,
824 xWidth, yWidth,
825 GL_RGB, GL_UNSIGNED_BYTE,
826 bytes);
827 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
831 void ImageModifier::scalePlanBitmap(Image &destBitmap,
832 Image &srcIncBitmap,
833 int landscapeX, int landscapeY)
835 int maxSize = MAX(landscapeX, landscapeY);
836 float xScale = landscapeX / float(maxSize);
837 float yScale = landscapeY / float(maxSize);
839 int newX = int(float(destBitmap.getWidth()) / xScale);
840 int newY = int(float(destBitmap.getHeight()) / yScale);
841 int offsetX = (newX - destBitmap.getWidth()) / 2;
842 int offsetY = (newY - destBitmap.getHeight()) / 2;
844 ImageHandle srcBitmap =
845 srcIncBitmap.createResize(newX, newY);
847 GLubyte *dest = destBitmap.getBits();
848 for (int y=0; y<destBitmap.getHeight(); y++)
850 for (int x=0; x<destBitmap.getWidth(); x++, dest+=destBitmap.getComponents())
852 int srcX = MIN(x + offsetX, srcBitmap.getWidth() - 1);
853 int srcY = MIN(y + offsetY, srcBitmap.getHeight() - 1);
854 GLubyte *src = srcBitmap.getBits() +
855 srcX * srcBitmap.getComponents() +
856 srcY * srcBitmap.getComponents() * srcBitmap.getWidth();
858 dest[0] = src[0];
859 dest[1] = src[1];
860 dest[2] = src[2];