Changed launcher to not have S3D_SERVER #defined to allow visible dialog messages
[scorched3d.git] / src / client / GLEXT / GLImageModifier.cpp
blobcee5eed13658bff2046587c4483321ee6c4f11f3
1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2009
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/OptionsTransient.h>
33 #include <common/Defines.h>
35 bool ImageModifier::findIntersection(HeightMap &hMap,
36 Vector start,
37 Vector end,
38 float &dist,
39 float stopDist)
41 bool result = false;
42 dist = 0.0f;
43 Vector point = start;
44 Vector direction = end - start;
45 float &pt0 = point[0];
46 float &pt1 = point[1];
47 float &pt2 = point[2];
48 int width = hMap.getMapWidth();
49 int height = hMap.getMapHeight();
51 // Calculate how many pixels to jump for each itteration
52 if (fabsf(direction[0]) > fabsf(direction[1])) direction /= fabsf(direction[0]);
53 else direction /= fabsf(direction[1]);
55 while (pt0 >= 0.0f && pt1 >= 0.0f &&
56 pt0 <= width && pt1 <= height)
58 float height = hMap.getHeight(int(point[0]), int(point[1])).asFloat() - 0.1f;
59 float rayHeight = height - pt2;
60 if (rayHeight > 0.0f)
62 if (rayHeight > dist) dist = rayHeight;
63 result = true;
64 if (dist > stopDist) return result;
67 point += direction;
70 return result;
73 void ImageModifier::tileBitmap(Image &src, Image &dest)
75 GLubyte *destBytes = dest.getBits();
76 for (int j=0; j<dest.getHeight(); j++)
78 for (int i=0; i<dest.getWidth();i++, destBytes+=3)
80 int srcX = i % src.getWidth();
81 int srcY = j % src.getHeight();
83 GLubyte *srcBytes = src.getBits() + (3 * srcX) +
84 (3 * src.getWidth() * srcY);
86 destBytes[0] = srcBytes[0];
87 destBytes[1] = srcBytes[1];
88 destBytes[2] = srcBytes[2];
93 void ImageModifier::addLightMapToBitmap(Image &destBitmap,
94 HeightMap &hMap,
95 Vector &sunPos,
96 Vector &ambience,
97 Vector &diffuse,
98 ProgressCounter *counter)
100 const float softShadow = 3.0f;
101 const int sideFade = 16;
102 const int lightMapWidth = 256; // Resolution of the light map
104 if (counter) counter->setNewOp(LANG_RESOURCE("LIGHT_MAP", "Light Map"));
106 // Itterate the dest bitmap pixels
107 GLfloat *bitmap = new GLfloat[lightMapWidth * lightMapWidth * 3];
108 GLfloat *bitmapBits = bitmap;
109 int y;
110 for (y=0; y<lightMapWidth; y++)
112 if (counter) counter->setNewPercentage(100.0f * float(y) / float(lightMapWidth));
114 for (int x=0; x<lightMapWidth; x++)
116 float dx = float(x)/float(lightMapWidth)*float(hMap.getMapWidth());
117 float dy = float(y)/float(lightMapWidth)*float(hMap.getMapHeight());
118 float dz = hMap.getInterpHeight(
119 fixed::fromFloat(dx), fixed::fromFloat(dy)).asFloat();
121 Vector testPosition(dx, dy, dz);
122 FixedVector fixedTestNormal;
123 hMap.getInterpNormal(
124 fixed::fromFloat(dx), fixed::fromFloat(dy), fixedTestNormal);
125 Vector testNormal = fixedTestNormal.asVector();
126 Vector sunDirection = (sunPos - testPosition).Normalize();
128 // Calculate light based on whether obejcts in path
129 float diffuseLightMult =
130 (((testNormal.dotP(sunDirection)) / 2.0f) + 0.5f);
131 float dist = 0.0f;
132 if (findIntersection(hMap,
133 testPosition, sunPos, dist, softShadow))
135 // An object is in the path
136 if (dist < softShadow)
138 // The object is only just in the path
139 // Create soft shadow
140 diffuseLightMult *= 1.0f - (dist / softShadow);
142 else
144 // Totaly in path, dark shadow
145 diffuseLightMult = 0.0f;
149 Vector diffuseLight = diffuse * diffuseLightMult;
150 Vector ambientLight = ambience;
151 Vector lightColor = diffuseLight + ambientLight;
152 lightColor[0] = MIN(1.0f, lightColor[0]);
153 lightColor[1] = MIN(1.0f, lightColor[1]);
154 lightColor[2] = MIN(1.0f, lightColor[2]);
156 bitmapBits[0] = lightColor[0];
157 bitmapBits[1] = lightColor[1];
158 bitmapBits[2] = lightColor[2];
159 bitmapBits +=3;
163 GLfloat *copyDest = new GLfloat[destBitmap.getWidth() * destBitmap.getHeight() * 3];
164 gluScaleImage(
165 GL_RGB,
166 lightMapWidth, lightMapWidth,
167 GL_FLOAT, bitmap,
168 destBitmap.getWidth(), destBitmap.getHeight(),
169 GL_FLOAT, copyDest);
171 GLfloat *srcBits = copyDest;
172 GLubyte *destBits = destBitmap.getBits();
173 for (y=0; y<destBitmap.getHeight(); y++)
175 for (int x=0; x<destBitmap.getWidth(); x++)
177 destBits[0] = GLubyte(MIN(float(destBits[0]) * (srcBits[0] * 1.2f), 255.0f));
178 destBits[1] = GLubyte(MIN(float(destBits[1]) * (srcBits[1] * 1.2f), 255.0f));
179 destBits[2] = GLubyte(MIN(float(destBits[2]) * (srcBits[2] * 1.2f), 255.0f));
181 srcBits += 3;
182 destBits += 3;
186 delete [] copyDest;
187 delete [] bitmap;
190 void ImageModifier::addHeightToBitmap(HeightMap &hMap,
191 Image &destBitmap,
192 Image &destSplat1Bitmap,
193 Image &destSplat2Bitmap,
194 Image &slopeBitmap,
195 Image &shoreBitmap,
196 Image **origHeightBitmaps,
197 int numberSources,
198 int destBitmapScaleSize,
199 ProgressCounter *counter)
201 const float maxHeight = 30.0f; // Last texture ends at height 30
202 const float blendHeightFactor = 0.4f; // Ends blend when 40% into height band
203 const float blendNormalSlopeStart = 0.8f; // Starts blending slope at .80
204 const float blendNormalSlopeLength = 0.3f; // Blends when 30% more slope
205 const float blendNormalShoreStart = 0.8f; // Starts the sand
206 const float blendNormalShoreLength = 0.1f; // Amount of sand
207 const float noiseMax = 0.4f;
209 float hMapMaxHeight = 0;
210 for (int ma=0; ma<hMap.getMapWidth(); ma++)
212 for (int mb=0;mb<hMap.getMapHeight(); mb++)
214 float height = hMap.getHeight(ma, mb).asFloat();
215 if (height > hMapMaxHeight) hMapMaxHeight = height;
219 // Create new bitmaps with the bitmap scaled to the correct size
220 Image **heightBitmaps = new Image*[numberSources];
221 ImageItterator ** bitmapItors = new ImageItterator*[numberSources+2];
222 float bitmapScale = float(destBitmap.getWidth()) / float(destBitmapScaleSize);
224 // Create a bitmap iterator for each bitmap
225 // Create a bitmap correctly scaled to the scene
226 int i;
227 for (i=0; i<numberSources; i++)
229 if (bitmapScale != 1.0f)
231 // Create the newly scaled bitmaps
232 heightBitmaps[i] = new ImageHandle(ImageFactory::createBlank(
233 int(bitmapScale * origHeightBitmaps[i]->getWidth()),
234 int(bitmapScale * origHeightBitmaps[i]->getHeight())));
236 // Scale bitmap
237 gluScaleImage(
238 GL_RGB,
239 origHeightBitmaps[i]->getWidth(), origHeightBitmaps[i]->getHeight(),
240 GL_UNSIGNED_BYTE, origHeightBitmaps[i]->getBits(),
241 heightBitmaps[i]->getWidth(), heightBitmaps[i]->getHeight(),
242 GL_UNSIGNED_BYTE, heightBitmaps[i]->getBits());
244 else
246 heightBitmaps[i] = origHeightBitmaps[i];
249 // Create iterator
250 bitmapItors[i] = new ImageItterator(
251 *heightBitmaps[i],
252 destBitmap.getWidth(),
253 destBitmap.getHeight(),
254 ImageItterator::wrap);
256 // Add shore and slopt itterators
257 bitmapItors[numberSources] =
258 new ImageItterator(
259 slopeBitmap,
260 destBitmap.getWidth(),
261 destBitmap.getHeight(),
262 ImageItterator::wrap);
263 bitmapItors[numberSources + 1] =
264 new ImageItterator(
265 shoreBitmap,
266 destBitmap.getWidth(),
267 destBitmap.getHeight(),
268 ImageItterator::wrap);
270 GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
271 GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
273 GLubyte *destBits = destBitmap.getBits();
274 GLubyte *destSplat1Bits = destSplat1Bitmap.getBits();
275 GLubyte *destSplat2Bits = destSplat2Bitmap.getBits();
277 GLfloat hy = 0.0f;
278 for (int by=0; by<destBitmap.getHeight(); by++, hy+=hdy)
280 if (counter) counter->setNewPercentage((100.0f * float (by)) / float(destBitmap.getHeight()));
282 GLfloat hx = 0.0f;
283 for (int bx=0; bx<destBitmap.getWidth(); bx++, destBits+=3, destSplat1Bits+=4, destSplat2Bits+=4, hx+=hdx)
285 static FixedVector fixedNormal;
286 hMap.getInterpNormal(fixed::fromFloat(hx), fixed::fromFloat(hy), fixedNormal);
287 Vector &normal = fixedNormal.asVector();
288 float height = hMap.getInterpHeight(fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
289 float offSetHeight = hMap.getInterpHeight(
290 fixed::fromFloat((float)hMap.getMapWidth() - hx),
291 fixed::fromFloat((float)hMap.getMapHeight() - hy)).asFloat();
292 height *= (1.0f - (noiseMax/2.0f)) + ((offSetHeight*noiseMax)/hMapMaxHeight);
294 // Find the index of the current texture by deviding the height into strips
295 float heightPer = (height / maxHeight) * (float) numberSources;
296 int heightIndex = (int) heightPer;
297 if (heightIndex >= numberSources)
299 heightIndex = numberSources - 1;
302 // Check if we are in a blending transition phase
303 float blendFirstAmount = 1.0f;
304 float blendSecondAmount = 0.0f;
305 if (heightIndex < numberSources - 1)
307 float remainderIndex = heightPer - heightIndex;
308 if (remainderIndex > blendHeightFactor)
310 // We need to do some blending, figure how much
311 remainderIndex -= blendHeightFactor;
312 blendSecondAmount = remainderIndex / (1.0f - blendHeightFactor);
313 blendFirstAmount = 1.0f - blendSecondAmount;
317 // Check to see if we need to blend in the side texture
318 float blendSideAmount = 0.0f;
319 float blendShoreAmount = 0.0f;
320 if (normal[2] < blendNormalSlopeStart)
322 if (normal[2] < blendNormalSlopeStart - blendNormalSlopeLength)
324 // Only use the side texture
325 blendSideAmount = 1.0f;
326 blendFirstAmount = 0.0f;
327 blendSecondAmount = 0.0f;
329 else
331 // Blend in the side texture
332 float remainderIndex = normal[2] - (blendNormalSlopeStart - blendNormalSlopeLength);
333 remainderIndex /= blendNormalSlopeLength;
335 blendSideAmount = (1.0f - remainderIndex);
336 blendFirstAmount *= remainderIndex;
337 blendSecondAmount *= remainderIndex;
340 else if (normal[2] > blendNormalShoreStart &&
341 height > 3.5f && height < 5.5f)
343 if (normal[2] > blendNormalShoreStart + blendNormalShoreLength)
345 // Only use the side texture
346 blendShoreAmount = 1.0f;
347 blendFirstAmount = 0.0f;
348 blendSecondAmount = 0.0f;
350 else
352 // Blend in the side texture
353 float remainderIndex = normal[2] - blendNormalSlopeStart;
354 remainderIndex /= blendNormalSlopeLength;
356 blendShoreAmount = (1.0f - remainderIndex);
357 blendFirstAmount *= remainderIndex;
358 blendSecondAmount *= remainderIndex;
362 // Add first height component
363 GLubyte *sourceBits1 = bitmapItors[heightIndex]->getPos();
364 destBits[0] = (GLubyte) ((float) sourceBits1[0] * blendFirstAmount);
365 destBits[1] = (GLubyte) ((float) sourceBits1[1] * blendFirstAmount);
366 destBits[2] = (GLubyte) ((float) sourceBits1[2] * blendFirstAmount);
368 if (heightIndex < 4) destSplat1Bits[heightIndex] = (GLubyte) (255.0f * blendFirstAmount);
369 else destSplat2Bits[heightIndex-4] = (GLubyte) (255.0f * blendFirstAmount);
371 if (blendSecondAmount > 0.0f)
373 // Add second height component (if blending)
374 GLubyte *sourceBits2 = bitmapItors[heightIndex + 1]->getPos();
375 destBits[0] += (GLubyte) ((float) sourceBits2[0] * blendSecondAmount);
376 destBits[1] += (GLubyte) ((float) sourceBits2[1] * blendSecondAmount);
377 destBits[2] += (GLubyte) ((float) sourceBits2[2] * blendSecondAmount);
379 if (heightIndex + 1 < 4) destSplat1Bits[heightIndex + 1] = (GLubyte) (255.0f * blendSecondAmount);
380 else destSplat2Bits[heightIndex + 1 - 4] = (GLubyte) (255.0f * blendSecondAmount);
383 if (blendSideAmount > 0.0f)
385 // Add side component (if blending normals)
386 GLubyte *sourceBits3 = bitmapItors[numberSources]->getPos();
387 destBits[0] += (GLubyte) ((float) sourceBits3[0] * blendSideAmount);
388 destBits[1] += (GLubyte) ((float) sourceBits3[1] * blendSideAmount);
389 destBits[2] += (GLubyte) ((float) sourceBits3[2] * blendSideAmount);
391 destSplat2Bits[0] = (GLubyte) (255.0f * blendSideAmount);
394 if (blendShoreAmount > 0.0f)
396 // Add side component (if blending normals)
397 GLubyte *sourceBits4 = bitmapItors[numberSources + 1]->getPos();
398 destBits[0] += (GLubyte) ((float) sourceBits4[0] * blendShoreAmount);
399 destBits[1] += (GLubyte) ((float) sourceBits4[1] * blendShoreAmount);
400 destBits[2] += (GLubyte) ((float) sourceBits4[2] * blendShoreAmount);
402 destSplat2Bits[1] = (GLubyte) (255.0f * blendShoreAmount);
405 for (i=0; i<numberSources+2; i++) bitmapItors[i]->incX();
408 for (i=0; i<numberSources+2; i++) bitmapItors[i]->incY();
411 // Cleanup iterator and extra bitmaps
412 for (i=0; i<numberSources+2; i++)
414 delete bitmapItors[i];
416 delete [] bitmapItors;
417 for (i=0; i<numberSources; i++)
419 if (bitmapScale != 1.0f)
421 delete heightBitmaps[i];
424 delete [] heightBitmaps;
427 void ImageModifier::redBitmap(
428 Image &destBitmap)
430 unsigned char *destBits = destBitmap.getBits();
431 for (int y=0; y<destBitmap.getHeight(); y++)
433 for (int x=0; x<destBitmap.getWidth(); x++, destBits += 4)
435 destBits[0] = 255;
436 destBits[1] = 0;
437 destBits[2] = 0;
438 destBits[3] = 0;
443 void ImageModifier::addTexturesToBitmap(
444 Image &destBitmap,
445 Image &slopeBitmap,
446 Image &shoreBitmap,
447 Image **heightBitmaps,
448 int numberSources)
450 std::vector<Image *> sources;
451 for (int i=0; i<numberSources; i++)
453 sources.push_back(heightBitmaps[i]);
455 sources.push_back(&slopeBitmap);
456 sources.push_back(&shoreBitmap);
458 int currentCount = sources.size();
459 for (int i=currentCount; i<9; i++)
461 sources.push_back(&shoreBitmap);
464 unsigned char *destBits = destBitmap.getBits();
465 for (int y=0; y<destBitmap.getHeight(); y++)
467 for (int x=0; x<destBitmap.getWidth(); x++, destBits += 3)
469 int texx = x / (destBitmap.getWidth() / 3);
470 int texy = y / (destBitmap.getHeight() / 3);
471 texx = MIN(2, texx);
472 texy = MIN(2, texy);
474 Image *src = sources[texx + texy * 3];
475 int srcx = x % src->getWidth();
476 int srcy = y % src->getHeight();
478 unsigned char *srcBits = &src->getBits()[srcx * 3 + srcy * src->getWidth() * 3];
479 destBits[0] = srcBits[0];
480 destBits[1] = srcBits[1];
481 destBits[2] = srcBits[2];
486 void ImageModifier::removeWaterFromBitmap(HeightMap &hMap,
487 Image &srcBitmap,
488 Image &destBitmap,
489 Image &alphaBitmap,
490 float waterHeight)
492 DIALOG_ASSERT(srcBitmap.getWidth() == destBitmap.getWidth() &&
493 srcBitmap.getWidth() == alphaBitmap.getWidth());
494 DIALOG_ASSERT(srcBitmap.getHeight() == destBitmap.getHeight() &&
495 srcBitmap.getHeight() == alphaBitmap.getHeight());
497 GLubyte *destBits = destBitmap.getBits();
498 GLubyte *srcBits = srcBitmap.getBits();
499 GLubyte *alphaBits = alphaBitmap.getBits();
501 GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
502 GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
504 GLfloat hy = 0.0f;
505 for (int y=0; y<srcBitmap.getHeight(); y++, hy+=hdy)
507 GLfloat hx = 0.0f;
508 for (int x=0; x<srcBitmap.getWidth(); x++, hx+=hdx,
509 destBits+=4, srcBits+=3, alphaBits+=3)
511 GLubyte alpha = 255 - alphaBits[0];
512 if (alpha > 0)
514 float height = hMap.getInterpHeight(
515 fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
516 if (height > waterHeight - 0.3)
518 alpha = 128;
519 if (height > waterHeight)
521 alpha = 255;
524 else alpha = 0;
527 destBits[0] = srcBits[0];
528 destBits[1] = srcBits[1];
529 destBits[2] = srcBits[2];
530 destBits[3] = alpha;
535 void ImageModifier::addWaterToBitmap(HeightMap &hMap,
536 Image &destBitmap,
537 Image &waterBitmap,
538 float waterHeight)
540 const float waterPercentage = 0.75f;
541 const float oneMinusPercentage = 1.0f - waterPercentage;
543 ImageItterator bitmapItor(waterBitmap,
544 destBitmap.getWidth(),
545 destBitmap.getHeight(),
546 ImageItterator::wrap);
548 GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
549 GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
551 GLubyte *destBits = destBitmap.getBits();
553 GLfloat hy = 0.0f;
554 for (int by=0; by<destBitmap.getHeight(); by++, hy+=hdy, bitmapItor.incY())
556 GLfloat hx = 0.0f;
557 for (int bx=0; bx<destBitmap.getWidth(); bx++, destBits+=3, hx+=hdx, bitmapItor.incX())
559 float height = hMap.getInterpHeight(
560 fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
562 if (height <= waterHeight)
564 if (height <= waterHeight - 0.3)
566 GLubyte *sourceBits = bitmapItor.getPos();
568 destBits[0] = GLubyte(
569 (waterPercentage * float(sourceBits[0])) +
570 (oneMinusPercentage * float(destBits[0])));
571 destBits[1] = GLubyte(
572 (waterPercentage * float(sourceBits[1])) +
573 (oneMinusPercentage * float(destBits[1])));
574 destBits[2] = GLubyte(
575 (waterPercentage * float(sourceBits[2])) +
576 (oneMinusPercentage * float(destBits[2])));
578 else
580 destBits[0] = 200;
581 destBits[1] = 200;
582 destBits[2] = 200;
589 ImageHandle ImageModifier::makeArenaBitmap()
591 Vector &wallColor = ScorchedClient::instance()->getOptionsTransient().getWallColor();
592 ImageHandle handle = ImageFactory::createBlank(128, 128, true, 0);
594 int arenaX = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaX();
595 int arenaY = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaY();
596 int arenaWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaWidth();
597 int arenaHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaHeight();
598 int landscapeWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeWidth();
599 int landscapeHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeHeight();
601 int lx = arenaX * handle.getWidth() / landscapeWidth;
602 int ly = arenaY * handle.getHeight() / landscapeHeight;
603 int lw = lx + (arenaWidth * handle.getWidth() / landscapeWidth);
604 int lh = ly + (arenaHeight * handle.getHeight() / landscapeHeight);
606 unsigned char *bits = handle.getBits();
607 for (int y=0; y<handle.getHeight(); y++)
609 for (int x=0; x<handle.getWidth(); x++, bits+=4)
611 if (x >= lx && x < lw &&
612 y >= ly && y < lh)
614 bits[3] = 0;
616 else
618 bits[3] = 255;
623 return handle;
626 ImageHandle ImageModifier::makeArenaSurroundBitmap()
628 Vector &wallColor = ScorchedClient::instance()->getOptionsTransient().getWallColor();
629 ImageHandle handle = ImageFactory::createBlank(128, 128, true, 0);
631 unsigned char *bits = handle.getBits();
632 for (int y=0; y<handle.getHeight(); y++)
634 for (int x=0; x<handle.getWidth(); x++, bits+=4)
636 bits[3] = 255;
640 return handle;
643 void ImageModifier::addBorderToBitmap(Image &destBitmap,
644 int borderSize,
645 float colors[3])
647 int arenaX = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaX();
648 int arenaY = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaY();
649 int arenaWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaWidth();
650 int arenaHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaHeight();
651 int landscapeWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeWidth();
652 int landscapeHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeHeight();
654 int borderX = int(float(arenaX) / float(landscapeWidth) * float(destBitmap.getWidth()));
655 int borderY = int(float(arenaY) / float(landscapeHeight) * float(destBitmap.getHeight()));
656 int borderWidth = int(float(arenaWidth) / float(landscapeWidth) * float(destBitmap.getWidth()));
657 int borderHeight = int(float(arenaHeight) / float(landscapeHeight) * float(destBitmap.getHeight()));
658 if (borderWidth + borderX >= destBitmap.getWidth()) borderWidth = destBitmap.getWidth() - borderX - 1;
659 if (borderHeight + borderY >= destBitmap.getHeight()) borderHeight = destBitmap.getHeight() - borderY - 1;
661 DIALOG_ASSERT(destBitmap.getComponents() == 3);
663 for (int x=borderX; x<=borderX+borderWidth; x++)
665 for (int i=0; i<borderSize; i++)
667 int pos = (x * 3) + ((borderY + i) * destBitmap.getWidth() * 3);
668 GLubyte *destBits = destBitmap.getBitsOffset(pos);
669 destBits[0] = GLubyte(colors[0] * 255.0f);
670 destBits[1] = GLubyte(colors[1] * 255.0f);
671 destBits[2] = GLubyte(colors[2] * 255.0f);
673 pos = (x * 3) + ((borderY + borderHeight - i) * destBitmap.getWidth() * 3);
674 destBits = destBitmap.getBitsOffset(pos);
675 destBits[0] = GLubyte(colors[0] * 255.0f);
676 destBits[1] = GLubyte(colors[1] * 255.0f);
677 destBits[2] = GLubyte(colors[2] * 255.0f);
681 for (int y=borderY; y<=borderY+borderHeight; y++)
683 for (int i=0; i<borderSize; i++)
685 int pos = ((borderX + i) * 3) + (y * destBitmap.getWidth() * 3);
686 GLubyte *destBits = destBitmap.getBitsOffset(pos);
687 destBits[0] = GLubyte(colors[0] * 255.0f);
688 destBits[1] = GLubyte(colors[1] * 255.0f);
689 destBits[2] = GLubyte(colors[2] * 255.0f);
691 pos = ((borderX + borderWidth - i) * 3) + (y * destBitmap.getWidth() * 3);
692 destBits = destBitmap.getBitsOffset(pos);
693 destBits[0] = GLubyte(colors[0] * 255.0f);
694 destBits[1] = GLubyte(colors[1] * 255.0f);
695 destBits[2] = GLubyte(colors[2] * 255.0f);
700 void ImageModifier::makeBitmapTransparent(Image &output,
701 Image &input,
702 Image &mask)
704 GLubyte *outputBits = output.getBits();
705 GLubyte *maskBits = mask.getBits();
706 GLubyte *inputBits = input.getBits();
708 for (int i=0; i<output.getWidth() * output.getHeight(); i++)
710 outputBits[0] = inputBits[0];
711 outputBits[1] = inputBits[1];
712 outputBits[2] = inputBits[2];
713 outputBits[3] = maskBits[3];
715 inputBits += 3;
716 outputBits += 4;
717 maskBits += 4;
721 void ImageModifier::addCircleToLandscape(
722 ScorchedContext &context,
723 float sx, float sy, float sw, float opacity)
725 float shadowMultWidth = (float) Landscape::instance()->getMainMap().getWidth() /
726 context.getLandscapeMaps().getGroundMaps().getLandscapeWidth();
727 float shadowMultHeight = (float) Landscape::instance()->getMainMap().getHeight() /
728 context.getLandscapeMaps().getGroundMaps().getLandscapeHeight();
730 addCircle(Landscape::instance()->getMainMap(),
731 sx * shadowMultWidth, sy * shadowMultHeight,
732 sw * shadowMultWidth, opacity);
735 void ImageModifier::addCircle(Image &destBitmap,
736 float sx, float sy, float sw, float opacity)
738 int decrement = int(opacity * 125.0f);
739 float halfW = sw / 2.0f;
741 float minX = sx - halfW;
742 float minY = sy - halfW;
743 float maxX = sx + halfW;
744 float maxY = sy + halfW;
745 /*minX /= 2.0f;
746 minY /= 2.0f;
747 maxX /= 2.0f;
748 maxY /= 2.0f;*/
750 minX = MAX(minX, 0.0f);
751 minY = MAX(minY, 0.0f);
752 maxX = MIN(maxX, destBitmap.getWidth() - 1.0f);
753 maxY = MIN(maxY, destBitmap.getHeight() - 1.0f);
755 int xStart = int(minX);
756 int yStart = int(minY);
757 int xWidth = int(maxX - minX);
758 int yWidth = int(maxY - minY);
759 int yInc = (destBitmap.getWidth() - xWidth) * 3;
761 if (xWidth <= 0 || yWidth <= 0) return;
762 double degMult = (1 / double(yWidth)) * 3.14;
764 GLubyte *start = &destBitmap.getBits()[(yStart * destBitmap.getWidth() * 3) + xStart * 3];
765 for (int y=0; y<yWidth; y++, start += yInc)
767 double deg = double(y) * degMult;
768 int realXSize = int(sin(deg) * double(xWidth));
769 int halfSize = (xWidth - realXSize) / 2;
771 start+=halfSize * 3;
772 int x;
773 for (x=0; x<realXSize; x++, start+=3)
775 start[0] = start[0] / 2;
776 start[1] = start[1] / 2;
777 start[2] = start[2] / 2;
779 start+=(xWidth - (halfSize + x)) * 3;
784 void ImageModifier::addBitmapToLandscape(
785 ScorchedContext &context,
786 Image &srcBitmap,
787 float sx, float sy, float scalex, float scaley,
788 bool commit)
790 float shadowMultWidth = (float) Landscape::instance()->getMainMap().getWidth() /
791 context.getLandscapeMaps().getGroundMaps().getLandscapeWidth();
792 float shadowMultHeight = (float) Landscape::instance()->getMainMap().getHeight() /
793 context.getLandscapeMaps().getGroundMaps().getLandscapeHeight();
795 addBitmap(
796 Landscape::instance()->getMainMap(),
797 srcBitmap,
798 sx * shadowMultWidth,
799 sy * shadowMultHeight,
800 shadowMultWidth * scalex,
801 shadowMultHeight * scaley,
802 commit);
805 void ImageModifier::addBitmap(Image &destBitmap,
806 Image &srcBitmap,
807 float sx, float sy, float scalex, float scaley,
808 bool commit)
810 int srcScaleWidth = int(float(srcBitmap.getWidth()) * scalex);
811 int srcScaleHeight = int(float(srcBitmap.getHeight()) * scaley);
813 float minX = sx - srcScaleWidth / 2;
814 float minY = sy - srcScaleHeight / 2;
815 float maxX = sx + srcScaleWidth / 2;
816 float maxY = sy + srcScaleHeight / 2;
818 minX = MAX(minX, 0.0f);
819 minY = MAX(minY, 0.0f);
820 maxX = MIN(maxX, destBitmap.getWidth() - 1.0f);
821 maxY = MIN(maxY, destBitmap.getHeight() - 1.0f);
823 int xStart = int(minX);
824 int yStart = int(minY);
825 int xWidth = int(maxX - minX);
826 int yWidth = int(maxY - minY);
828 if (xWidth <= 0 || yWidth <= 0) return;
830 int yDestInc = (destBitmap.getWidth() * 3);
832 GLubyte *dest = &destBitmap.getBits()[
833 (yStart * destBitmap.getWidth() * 3) + xStart * 3];
834 for (int y=0; y<yWidth; y++, dest += yDestInc)
836 GLubyte *tmpDest = dest;
837 for (int x=0; x<xWidth; x++)
839 int srcX = int(float(x) / scalex);
840 srcX = MIN(srcX, srcBitmap.getWidth());
841 int srcY = int(float(y) / scaley);
842 srcY = MIN(srcY, srcBitmap.getHeight());
844 GLubyte *tmpSrc = srcBitmap.getBits() +
845 srcX * srcBitmap.getComponents() +
846 srcY * srcBitmap.getComponents() * srcBitmap.getWidth();
848 float alpha = 1.0f;
849 float invAlpha = 0.0f;
850 if (srcBitmap.getComponents() == 4)
852 alpha = float(tmpSrc[3]) / 255.0f;
853 invAlpha = 1.0f - alpha;
856 tmpDest[0] = GLubyte(float(tmpSrc[0]) * alpha + float(tmpDest[0]) * invAlpha);
857 tmpDest[1] = GLubyte(float(tmpSrc[1]) * alpha + float(tmpDest[1]) * invAlpha);
858 tmpDest[2] = GLubyte(float(tmpSrc[2]) * alpha + float(tmpDest[2]) * invAlpha);
860 tmpDest += 3;
864 if (commit)
866 int landscapeWidth = Landscape::instance()->getMainMap().getWidth();
867 int width = 3 * landscapeWidth;
868 width = (width + 3) & ~3;
870 GLubyte *bytes =
871 Landscape::instance()->getMainMap().getBits() + ((width * yStart) + xStart * 3);
873 GLState currentState(GLState::TEXTURE_ON);
874 Landscape::instance()->getMainTexture().draw(true);
876 glPixelStorei(GL_UNPACK_ROW_LENGTH, landscapeWidth);
877 glTexSubImage2D(GL_TEXTURE_2D, 0,
878 xStart, yStart,
879 xWidth, yWidth,
880 GL_RGB, GL_UNSIGNED_BYTE,
881 bytes);
882 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
886 void ImageModifier::scalePlanBitmap(Image &destBitmap,
887 Image &srcIncBitmap,
888 int landscapeX, int landscapeY)
890 int maxSize = MAX(landscapeX, landscapeY);
891 float xScale = landscapeX / float(maxSize);
892 float yScale = landscapeY / float(maxSize);
894 int newX = int(float(destBitmap.getWidth()) / xScale);
895 int newY = int(float(destBitmap.getHeight()) / yScale);
896 int offsetX = (newX - destBitmap.getWidth()) / 2;
897 int offsetY = (newY - destBitmap.getHeight()) / 2;
899 ImageHandle srcBitmap =
900 srcIncBitmap.createResize(newX, newY);
902 GLubyte *dest = destBitmap.getBits();
903 for (int y=0; y<destBitmap.getHeight(); y++)
905 for (int x=0; x<destBitmap.getWidth(); x++, dest+=destBitmap.getComponents())
907 int srcX = MIN(x + offsetX, srcBitmap.getWidth() - 1);
908 int srcY = MIN(y + offsetY, srcBitmap.getHeight() - 1);
909 GLubyte *src = srcBitmap.getBits() +
910 srcX * srcBitmap.getComponents() +
911 srcY * srcBitmap.getComponents() * srcBitmap.getWidth();
913 dest[0] = src[0];
914 dest[1] = src[1];
915 dest[2] = src[2];