1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2009
4 // This file is part of Scorched3D.
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 ////////////////////////////////////////////////////////////////////////////////
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
,
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
;
62 if (rayHeight
> dist
) dist
= rayHeight
;
64 if (dist
> stopDist
) 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
,
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
;
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
);
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
);
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];
163 GLfloat
*copyDest
= new GLfloat
[destBitmap
.getWidth() * destBitmap
.getHeight() * 3];
166 lightMapWidth
, lightMapWidth
,
168 destBitmap
.getWidth(), destBitmap
.getHeight(),
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
));
190 void ImageModifier::addHeightToBitmap(HeightMap
&hMap
,
192 Image
&destSplat1Bitmap
,
193 Image
&destSplat2Bitmap
,
196 Image
**origHeightBitmaps
,
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
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())));
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());
246 heightBitmaps
[i
] = origHeightBitmaps
[i
];
250 bitmapItors
[i
] = new ImageItterator(
252 destBitmap
.getWidth(),
253 destBitmap
.getHeight(),
254 ImageItterator::wrap
);
256 // Add shore and slopt itterators
257 bitmapItors
[numberSources
] =
260 destBitmap
.getWidth(),
261 destBitmap
.getHeight(),
262 ImageItterator::wrap
);
263 bitmapItors
[numberSources
+ 1] =
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();
278 for (int by
=0; by
<destBitmap
.getHeight(); by
++, hy
+=hdy
)
280 if (counter
) counter
->setNewPercentage((100.0f
* float (by
)) / float(destBitmap
.getHeight()));
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
;
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
;
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(
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)
443 void ImageModifier::addTexturesToBitmap(
447 Image
**heightBitmaps
,
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);
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
,
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();
505 for (int y
=0; y
<srcBitmap
.getHeight(); y
++, hy
+=hdy
)
508 for (int x
=0; x
<srcBitmap
.getWidth(); x
++, hx
+=hdx
,
509 destBits
+=4, srcBits
+=3, alphaBits
+=3)
511 GLubyte alpha
= 255 - alphaBits
[0];
514 float height
= hMap
.getInterpHeight(
515 fixed::fromFloat(hx
), fixed::fromFloat(hy
)).asFloat();
516 if (height
> waterHeight
- 0.3)
519 if (height
> waterHeight
)
527 destBits
[0] = srcBits
[0];
528 destBits
[1] = srcBits
[1];
529 destBits
[2] = srcBits
[2];
535 void ImageModifier::addWaterToBitmap(HeightMap
&hMap
,
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();
554 for (int by
=0; by
<destBitmap
.getHeight(); by
++, hy
+=hdy
, bitmapItor
.incY())
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])));
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
&&
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)
643 void ImageModifier::addBorderToBitmap(Image
&destBitmap
,
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
,
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];
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
;
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;
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
,
787 float sx
, float sy
, float scalex
, float scaley
,
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();
796 Landscape::instance()->getMainMap(),
798 sx
* shadowMultWidth
,
799 sy
* shadowMultHeight
,
800 shadowMultWidth
* scalex
,
801 shadowMultHeight
* scaley
,
805 void ImageModifier::addBitmap(Image
&destBitmap
,
807 float sx
, float sy
, float scalex
, float scaley
,
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();
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
);
866 int landscapeWidth
= Landscape::instance()->getMainMap().getWidth();
867 int width
= 3 * landscapeWidth
;
868 width
= (width
+ 3) & ~3;
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,
880 GL_RGB
, GL_UNSIGNED_BYTE
,
882 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
886 void ImageModifier::scalePlanBitmap(Image
&destBitmap
,
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();