1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2003
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/Defines.h>
34 bool ImageModifier::findIntersection(HeightMap
&hMap
,
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
;
61 if (rayHeight
> dist
) dist
= rayHeight
;
63 if (dist
> stopDist
) 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
,
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
;
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
);
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
);
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];
162 GLfloat
*copyDest
= new GLfloat
[destBitmap
.getWidth() * destBitmap
.getHeight() * 3];
165 lightMapWidth
, lightMapWidth
,
167 destBitmap
.getWidth(), destBitmap
.getHeight(),
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
));
189 void ImageModifier::addHeightToBitmap(HeightMap
&hMap
,
191 Image
&destSplat1Bitmap
,
192 Image
&destSplat2Bitmap
,
195 Image
**origHeightBitmaps
,
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
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())));
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());
245 heightBitmaps
[i
] = origHeightBitmaps
[i
];
249 bitmapItors
[i
] = new ImageItterator(
251 destBitmap
.getWidth(),
252 destBitmap
.getHeight(),
253 ImageItterator::wrap
);
255 // Add shore and slopt itterators
256 bitmapItors
[numberSources
] =
259 destBitmap
.getWidth(),
260 destBitmap
.getHeight(),
261 ImageItterator::wrap
);
262 bitmapItors
[numberSources
+ 1] =
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();
277 for (int by
=0; by
<destBitmap
.getHeight(); by
++, hy
+=hdy
)
279 if (counter
) counter
->setNewPercentage((100.0f
* float (by
)) / float(destBitmap
.getHeight()));
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
;
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
;
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(
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)
442 void ImageModifier::addTexturesToBitmap(
446 Image
**heightBitmaps
,
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);
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
,
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();
504 for (int y
=0; y
<srcBitmap
.getHeight(); y
++, hy
+=hdy
)
507 for (int x
=0; x
<srcBitmap
.getWidth(); x
++, hx
+=hdx
,
508 destBits
+=4, srcBits
+=3, alphaBits
+=3)
510 GLubyte alpha
= 255 - alphaBits
[0];
513 float height
= hMap
.getInterpHeight(
514 fixed::fromFloat(hx
), fixed::fromFloat(hy
)).asFloat();
515 if (height
> waterHeight
- 0.3)
518 if (height
> waterHeight
)
526 destBits
[0] = srcBits
[0];
527 destBits
[1] = srcBits
[1];
528 destBits
[2] = srcBits
[2];
534 void ImageModifier::addWaterToBitmap(HeightMap
&hMap
,
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();
553 for (int by
=0; by
<destBitmap
.getHeight(); by
++, hy
+=hdy
, bitmapItor
.incY())
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])));
588 void ImageModifier::addBorderToBitmap(Image
&destBitmap
,
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
,
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];
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
;
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;
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
,
732 float sx
, float sy
, float scalex
, float scaley
,
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();
741 Landscape::instance()->getMainMap(),
743 sx
* shadowMultWidth
,
744 sy
* shadowMultHeight
,
745 shadowMultWidth
* scalex
,
746 shadowMultHeight
* scaley
,
750 void ImageModifier::addBitmap(Image
&destBitmap
,
752 float sx
, float sy
, float scalex
, float scaley
,
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();
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
);
811 int landscapeWidth
= Landscape::instance()->getMainMap().getWidth();
812 int width
= 3 * landscapeWidth
;
813 width
= (width
+ 3) & ~3;
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,
825 GL_RGB
, GL_UNSIGNED_BYTE
,
827 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
831 void ImageModifier::scalePlanBitmap(Image
&destBitmap
,
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();