GLImageModifier.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <vector>
00022 #include <math.h>
00023 #include <GLEXT/GLImageItterator.h>
00024 #include <GLEXT/GLImageModifier.h>
00025 #include <image/ImageHandle.h>
00026 #include <image/ImageFactory.h>
00027 #include <engine/ScorchedContext.h>
00028 #include <landscape/Landscape.h>
00029 #include <landscapemap/LandscapeMaps.h>
00030 #include <client/ScorchedClient.h>
00031 #include <lang/LangResource.h>
00032 #include <common/OptionsTransient.h>
00033 #include <common/Defines.h>
00034 
00035 bool ImageModifier::findIntersection(HeightMap &hMap,
00036                                                                                 Vector start,
00037                                                                                 Vector end,
00038                                                                                 float &dist,
00039                                                                                 float stopDist)
00040 {
00041         bool result = false;
00042         dist = 0.0f;
00043         Vector point = start;
00044         Vector direction = end - start;
00045         float &pt0 = point[0];
00046         float &pt1 = point[1];
00047         float &pt2 = point[2];
00048         int width = hMap.getMapWidth();
00049         int height = hMap.getMapHeight();
00050 
00051         // Calculate how many pixels to jump for each itteration
00052         if (fabsf(direction[0]) > fabsf(direction[1])) direction /= fabsf(direction[0]);
00053         else direction /= fabsf(direction[1]);
00054 
00055         while (pt0 >= 0.0f && pt1 >= 0.0f &&
00056                 pt0 <= width && pt1 <= height)
00057         {
00058                 float height = hMap.getHeight(int(point[0]), int(point[1])).asFloat() - 0.1f;
00059                 float rayHeight = height - pt2;
00060                 if (rayHeight > 0.0f)
00061                 {
00062                         if (rayHeight > dist) dist = rayHeight;
00063                         result = true;
00064                         if (dist > stopDist) return result;
00065                 }
00066 
00067                 point += direction;
00068         }
00069 
00070         return result;
00071 }
00072 
00073 void ImageModifier::tileBitmap(Image &src, Image &dest)
00074 {
00075         GLubyte *destBytes = dest.getBits();
00076         for (int j=0; j<dest.getHeight(); j++)
00077         {
00078                 for (int i=0; i<dest.getWidth();i++, destBytes+=3)
00079                 {
00080                         int srcX = i % src.getWidth();
00081                         int srcY = j % src.getHeight();
00082 
00083                         GLubyte *srcBytes = src.getBits() + (3 * srcX) +
00084                                 (3 * src.getWidth() * srcY);
00085 
00086                         destBytes[0] = srcBytes[0];
00087                         destBytes[1] = srcBytes[1];
00088                         destBytes[2] = srcBytes[2];
00089                 }
00090         }
00091 }
00092 
00093 void ImageModifier::addLightMapToBitmap(Image &destBitmap, 
00094         HeightMap &hMap,
00095         Vector &sunPos,
00096         Vector &ambience,
00097         Vector &diffuse,
00098         ProgressCounter *counter)
00099 {
00100         const float softShadow = 3.0f;
00101         const int sideFade = 16;
00102         const int lightMapWidth = 256; // Resolution of the light map
00103 
00104         if (counter) counter->setNewOp(LANG_RESOURCE("LIGHT_MAP", "Light Map"));
00105 
00106         // Itterate the dest bitmap pixels
00107         GLfloat *bitmap = new GLfloat[lightMapWidth * lightMapWidth * 3];
00108         GLfloat *bitmapBits = bitmap;
00109         int y;
00110         for (y=0; y<lightMapWidth; y++)
00111         {
00112                 if (counter) counter->setNewPercentage(100.0f * float(y) / float(lightMapWidth));
00113 
00114                 for (int x=0; x<lightMapWidth; x++)
00115                 {
00116                         float dx = float(x)/float(lightMapWidth)*float(hMap.getMapWidth());
00117                         float dy = float(y)/float(lightMapWidth)*float(hMap.getMapHeight());
00118                         float dz = hMap.getInterpHeight(
00119                                 fixed::fromFloat(dx), fixed::fromFloat(dy)).asFloat();
00120                         
00121                         Vector testPosition(dx, dy, dz);
00122                         FixedVector fixedTestNormal;
00123                         hMap.getInterpNormal(
00124                                 fixed::fromFloat(dx), fixed::fromFloat(dy), fixedTestNormal);
00125                         Vector testNormal = fixedTestNormal.asVector();
00126                         Vector sunDirection = (sunPos - testPosition).Normalize();
00127 
00128                         // Calculate light based on whether obejcts in path
00129                         float diffuseLightMult = 
00130                                 (((testNormal.dotP(sunDirection)) / 2.0f) + 0.5f);
00131                         float dist = 0.0f;
00132                         if (findIntersection(hMap, 
00133                                 testPosition, sunPos, dist, softShadow))
00134                         {
00135                                 // An object is in the path
00136                                 if (dist < softShadow)
00137                                 {
00138                                         // The object is only just in the path
00139                                         // Create soft shadow
00140                                         diffuseLightMult *= 1.0f - (dist / softShadow);
00141                                 }
00142                                 else
00143                                 {
00144                                         // Totaly in path, dark shadow
00145                                         diffuseLightMult = 0.0f;
00146                                 }
00147                         }
00148 
00149                         Vector diffuseLight = diffuse * diffuseLightMult;
00150                         Vector ambientLight = ambience;
00151                         Vector lightColor = diffuseLight + ambientLight;
00152                         lightColor[0] = MIN(1.0f, lightColor[0]);
00153                         lightColor[1] = MIN(1.0f, lightColor[1]);
00154                         lightColor[2] = MIN(1.0f, lightColor[2]);
00155 
00156                         bitmapBits[0] = lightColor[0];
00157                         bitmapBits[1] = lightColor[1];
00158                         bitmapBits[2] = lightColor[2];
00159                         bitmapBits +=3;
00160                 }
00161         }
00162 
00163         GLfloat *copyDest = new GLfloat[destBitmap.getWidth() * destBitmap.getHeight() * 3];
00164         gluScaleImage(
00165                 GL_RGB, 
00166                 lightMapWidth, lightMapWidth, 
00167                 GL_FLOAT, bitmap,
00168                 destBitmap.getWidth(), destBitmap.getHeight(), 
00169                 GL_FLOAT, copyDest);
00170         
00171         GLfloat *srcBits = copyDest;
00172         GLubyte *destBits = destBitmap.getBits();
00173         for (y=0; y<destBitmap.getHeight(); y++)
00174         {
00175                 for (int x=0; x<destBitmap.getWidth(); x++)
00176                 {
00177                         destBits[0] = GLubyte(MIN(float(destBits[0]) * (srcBits[0] * 1.2f), 255.0f));
00178                         destBits[1] = GLubyte(MIN(float(destBits[1]) * (srcBits[1] * 1.2f), 255.0f));
00179                         destBits[2] = GLubyte(MIN(float(destBits[2]) * (srcBits[2] * 1.2f), 255.0f));
00180 
00181                         srcBits += 3;
00182                         destBits += 3;
00183                 }
00184         }
00185 
00186         delete [] copyDest;
00187         delete [] bitmap;
00188 }
00189 
00190 void ImageModifier::addHeightToBitmap(HeightMap &hMap,
00191                                                                                  Image &destBitmap, 
00192                                                                                  Image &destSplat1Bitmap,
00193                                                                                  Image &destSplat2Bitmap,
00194                                                                                  Image &slopeBitmap,
00195                                                                                  Image &shoreBitmap,
00196                                                                                  Image **origHeightBitmaps,
00197                                                                                  int numberSources,
00198                                                                                  int destBitmapScaleSize,
00199                                                                                  ProgressCounter *counter)
00200 {
00201         const float maxHeight = 30.0f; // Last texture ends at height 30
00202         const float blendHeightFactor = 0.4f; // Ends blend when 40% into height band
00203         const float blendNormalSlopeStart = 0.8f; // Starts blending slope at .80
00204         const float blendNormalSlopeLength = 0.3f; // Blends when 30% more slope
00205         const float blendNormalShoreStart = 0.8f; // Starts the sand
00206         const float blendNormalShoreLength = 0.1f; // Amount of sand
00207         const float noiseMax = 0.4f;
00208 
00209         float hMapMaxHeight = 0;
00210         for (int ma=0; ma<hMap.getMapWidth(); ma++)
00211         {
00212                 for (int mb=0;mb<hMap.getMapHeight(); mb++)
00213                 {
00214                         float height = hMap.getHeight(ma, mb).asFloat();
00215                         if (height > hMapMaxHeight) hMapMaxHeight = height;
00216                 }
00217         }
00218 
00219         // Create new bitmaps with the bitmap scaled to the correct size
00220         Image **heightBitmaps = new Image*[numberSources];
00221         ImageItterator ** bitmapItors = new ImageItterator*[numberSources+2];
00222         float bitmapScale = float(destBitmap.getWidth()) / float(destBitmapScaleSize);
00223 
00224         // Create a bitmap iterator for each bitmap
00225         // Create a bitmap correctly scaled to the scene
00226         int i;
00227         for (i=0; i<numberSources; i++)
00228         {
00229                 if (bitmapScale != 1.0f)
00230                 {
00231                         // Create the newly scaled bitmaps
00232                         heightBitmaps[i] = new ImageHandle(ImageFactory::createBlank(
00233                                 int(bitmapScale * origHeightBitmaps[i]->getWidth()),
00234                                 int(bitmapScale * origHeightBitmaps[i]->getHeight())));
00235 
00236                         // Scale bitmap
00237                         gluScaleImage(
00238                                 GL_RGB, 
00239                                 origHeightBitmaps[i]->getWidth(), origHeightBitmaps[i]->getHeight(), 
00240                                 GL_UNSIGNED_BYTE, origHeightBitmaps[i]->getBits(),
00241                                 heightBitmaps[i]->getWidth(), heightBitmaps[i]->getHeight(), 
00242                                 GL_UNSIGNED_BYTE, heightBitmaps[i]->getBits());
00243                 }
00244                 else
00245                 {
00246                         heightBitmaps[i] = origHeightBitmaps[i];
00247                 }
00248 
00249                 // Create iterator
00250                 bitmapItors[i] = new ImageItterator(
00251                         *heightBitmaps[i], 
00252                         destBitmap.getWidth(), 
00253                         destBitmap.getHeight(), 
00254                         ImageItterator::wrap);
00255         }
00256         // Add shore and slopt itterators
00257         bitmapItors[numberSources] = 
00258                 new ImageItterator(
00259                         slopeBitmap, 
00260                         destBitmap.getWidth(), 
00261                         destBitmap.getHeight(), 
00262                         ImageItterator::wrap);
00263         bitmapItors[numberSources + 1] = 
00264                 new ImageItterator(
00265                         shoreBitmap, 
00266                         destBitmap.getWidth(), 
00267                         destBitmap.getHeight(), 
00268                         ImageItterator::wrap);
00269         
00270         GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
00271         GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
00272 
00273         GLubyte *destBits = destBitmap.getBits();
00274         GLubyte *destSplat1Bits = destSplat1Bitmap.getBits();
00275         GLubyte *destSplat2Bits = destSplat2Bitmap.getBits();
00276 
00277         GLfloat hy = 0.0f;
00278         for (int by=0; by<destBitmap.getHeight(); by++, hy+=hdy)
00279         {
00280                 if (counter) counter->setNewPercentage((100.0f * float (by)) / float(destBitmap.getHeight()));
00281 
00282                 GLfloat hx = 0.0f;
00283                 for (int bx=0; bx<destBitmap.getWidth(); bx++, destBits+=3, destSplat1Bits+=4, destSplat2Bits+=4, hx+=hdx)
00284                 {
00285                         static FixedVector fixedNormal;
00286                         hMap.getInterpNormal(fixed::fromFloat(hx), fixed::fromFloat(hy), fixedNormal);
00287                         Vector &normal = fixedNormal.asVector();
00288                         float height = hMap.getInterpHeight(fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
00289                         float offSetHeight = hMap.getInterpHeight(
00290                                 fixed::fromFloat((float)hMap.getMapWidth() - hx), 
00291                                 fixed::fromFloat((float)hMap.getMapHeight() - hy)).asFloat();
00292                         height *= (1.0f - (noiseMax/2.0f)) + ((offSetHeight*noiseMax)/hMapMaxHeight);
00293 
00294                         // Find the index of the current texture by deviding the height into strips
00295                         float heightPer = (height / maxHeight) * (float) numberSources;
00296                         int heightIndex = (int) heightPer;
00297                         if (heightIndex >= numberSources) 
00298                         {
00299                                 heightIndex = numberSources - 1;
00300                         }
00301 
00302                         // Check if we are in a blending transition phase
00303                         float blendFirstAmount = 1.0f;
00304                         float blendSecondAmount = 0.0f;
00305                         if (heightIndex < numberSources - 1)
00306                         {
00307                                 float remainderIndex = heightPer - heightIndex;
00308                                 if (remainderIndex > blendHeightFactor)
00309                                 {
00310                                         // We need to do some blending, figure how much
00311                                         remainderIndex -= blendHeightFactor;
00312                                         blendSecondAmount = remainderIndex / (1.0f - blendHeightFactor);
00313                                         blendFirstAmount = 1.0f - blendSecondAmount;
00314                                 }
00315                         }
00316 
00317                         // Check to see if we need to blend in the side texture
00318                         float blendSideAmount = 0.0f;
00319                         float blendShoreAmount = 0.0f;
00320                         if (normal[2] < blendNormalSlopeStart)
00321                         {
00322                                 if (normal[2] < blendNormalSlopeStart - blendNormalSlopeLength)
00323                                 {
00324                                         // Only use the side texture
00325                                         blendSideAmount = 1.0f;
00326                                         blendFirstAmount = 0.0f;
00327                                         blendSecondAmount = 0.0f;
00328                                 }
00329                                 else
00330                                 {
00331                                         // Blend in the side texture
00332                                         float remainderIndex = normal[2] - (blendNormalSlopeStart - blendNormalSlopeLength);
00333                                         remainderIndex /= blendNormalSlopeLength;
00334                                 
00335                                         blendSideAmount = (1.0f - remainderIndex);
00336                                         blendFirstAmount *= remainderIndex;
00337                                         blendSecondAmount *= remainderIndex;
00338                                 }
00339                         } 
00340                         else if (normal[2] > blendNormalShoreStart && 
00341                                 height > 3.5f && height < 5.5f)
00342                         {
00343                                 if (normal[2] > blendNormalShoreStart + blendNormalShoreLength)
00344                                 {
00345                                         // Only use the side texture
00346                                         blendShoreAmount = 1.0f;
00347                                         blendFirstAmount = 0.0f;
00348                                         blendSecondAmount = 0.0f;
00349                                 }
00350                                 else
00351                                 {
00352                                         // Blend in the side texture
00353                                         float remainderIndex = normal[2] - blendNormalSlopeStart;
00354                                         remainderIndex /= blendNormalSlopeLength;
00355                                 
00356                                         blendShoreAmount = (1.0f - remainderIndex);
00357                                         blendFirstAmount *= remainderIndex;
00358                                         blendSecondAmount *= remainderIndex;
00359                                 }
00360                         }
00361 
00362                         // Add first height component
00363                         GLubyte *sourceBits1 = bitmapItors[heightIndex]->getPos();
00364                         destBits[0] = (GLubyte) ((float) sourceBits1[0] * blendFirstAmount);
00365                         destBits[1] = (GLubyte) ((float) sourceBits1[1] * blendFirstAmount);
00366                         destBits[2] = (GLubyte) ((float) sourceBits1[2] * blendFirstAmount);
00367                 
00368                         if (heightIndex < 4) destSplat1Bits[heightIndex] = (GLubyte) (255.0f * blendFirstAmount);
00369                         else destSplat2Bits[heightIndex-4] = (GLubyte) (255.0f * blendFirstAmount);
00370 
00371                         if (blendSecondAmount > 0.0f)
00372                         {
00373                                 // Add second height component (if blending)
00374                                 GLubyte *sourceBits2 = bitmapItors[heightIndex + 1]->getPos();
00375                                 destBits[0] += (GLubyte) ((float) sourceBits2[0] * blendSecondAmount);
00376                                 destBits[1] += (GLubyte) ((float) sourceBits2[1] * blendSecondAmount);
00377                                 destBits[2] += (GLubyte) ((float) sourceBits2[2] * blendSecondAmount);
00378 
00379                                 if (heightIndex + 1 < 4) destSplat1Bits[heightIndex + 1] = (GLubyte) (255.0f * blendSecondAmount);
00380                                 else destSplat2Bits[heightIndex + 1 - 4] = (GLubyte) (255.0f * blendSecondAmount);
00381                         }
00382 
00383                         if (blendSideAmount > 0.0f)
00384                         {
00385                                 // Add side component (if blending normals)
00386                                 GLubyte *sourceBits3 = bitmapItors[numberSources]->getPos();
00387                                 destBits[0] += (GLubyte) ((float) sourceBits3[0] * blendSideAmount);
00388                                 destBits[1] += (GLubyte) ((float) sourceBits3[1] * blendSideAmount);
00389                                 destBits[2] += (GLubyte) ((float) sourceBits3[2] * blendSideAmount);
00390 
00391                                 destSplat2Bits[0] = (GLubyte) (255.0f * blendSideAmount);
00392                         }
00393 
00394                         if (blendShoreAmount > 0.0f)
00395                         {
00396                                 // Add side component (if blending normals)
00397                                 GLubyte *sourceBits4 = bitmapItors[numberSources + 1]->getPos();
00398                                 destBits[0] += (GLubyte) ((float) sourceBits4[0] * blendShoreAmount);
00399                                 destBits[1] += (GLubyte) ((float) sourceBits4[1] * blendShoreAmount);
00400                                 destBits[2] += (GLubyte) ((float) sourceBits4[2] * blendShoreAmount);
00401 
00402                                 destSplat2Bits[1] = (GLubyte) (255.0f * blendShoreAmount);
00403                         }
00404 
00405                         for (i=0; i<numberSources+2; i++) bitmapItors[i]->incX();
00406                 }
00407 
00408                 for (i=0; i<numberSources+2; i++) bitmapItors[i]->incY();
00409         }
00410 
00411         // Cleanup iterator and extra bitmaps   
00412         for (i=0; i<numberSources+2; i++)
00413         {
00414                 delete bitmapItors[i];
00415         }
00416         delete [] bitmapItors;
00417         for (i=0; i<numberSources; i++)
00418         {
00419                 if (bitmapScale != 1.0f)
00420                 {
00421                         delete heightBitmaps[i];
00422                 }
00423         }
00424         delete [] heightBitmaps;
00425 }
00426 
00427 void ImageModifier::redBitmap(
00428                 Image &destBitmap)
00429 {
00430         unsigned char *destBits = destBitmap.getBits();
00431         for (int y=0; y<destBitmap.getHeight(); y++)
00432         {
00433                 for (int x=0; x<destBitmap.getWidth(); x++, destBits += 4)
00434                 {
00435                         destBits[0] = 255;
00436                         destBits[1] = 0;
00437                         destBits[2] = 0;
00438                         destBits[3] = 0;
00439                 }
00440         }
00441 }
00442 
00443 void ImageModifier::addTexturesToBitmap(
00444                 Image &destBitmap,
00445                 Image &slopeBitmap,
00446                 Image &shoreBitmap,
00447                 Image **heightBitmaps,
00448                 int numberSources)
00449 {
00450         std::vector<Image *> sources;
00451         for (int i=0; i<numberSources; i++)
00452         {
00453                 sources.push_back(heightBitmaps[i]);
00454         }
00455         sources.push_back(&slopeBitmap);
00456         sources.push_back(&shoreBitmap);
00457 
00458         int currentCount = sources.size();
00459         for (int i=currentCount; i<9; i++)
00460         {
00461                 sources.push_back(&shoreBitmap);
00462         }
00463         
00464         unsigned char *destBits = destBitmap.getBits();
00465         for (int y=0; y<destBitmap.getHeight(); y++)
00466         {
00467                 for (int x=0; x<destBitmap.getWidth(); x++, destBits += 3)
00468                 {
00469                         int texx = x / (destBitmap.getWidth() / 3);
00470                         int texy = y / (destBitmap.getHeight() / 3);
00471                         texx = MIN(2, texx);
00472                         texy = MIN(2, texy);
00473 
00474                         Image *src = sources[texx + texy * 3];
00475                         int srcx = x % src->getWidth();
00476                         int srcy = y % src->getHeight();
00477                         
00478                         unsigned char *srcBits = &src->getBits()[srcx * 3 + srcy * src->getWidth() * 3];
00479                         destBits[0] = srcBits[0];
00480                         destBits[1] = srcBits[1];
00481                         destBits[2] = srcBits[2];
00482                 }
00483         }
00484 }
00485 
00486 void ImageModifier::removeWaterFromBitmap(HeightMap &hMap,
00487                                                         Image &srcBitmap,
00488                                                         Image &destBitmap,
00489                                                         Image &alphaBitmap,
00490                                                         float waterHeight)
00491 {
00492         DIALOG_ASSERT(srcBitmap.getWidth() == destBitmap.getWidth() &&
00493                 srcBitmap.getWidth() == alphaBitmap.getWidth());
00494         DIALOG_ASSERT(srcBitmap.getHeight() == destBitmap.getHeight() &&
00495                 srcBitmap.getHeight() == alphaBitmap.getHeight());
00496 
00497         GLubyte *destBits = destBitmap.getBits();
00498         GLubyte *srcBits = srcBitmap.getBits();
00499         GLubyte *alphaBits = alphaBitmap.getBits();
00500 
00501         GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
00502         GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
00503 
00504         GLfloat hy = 0.0f;
00505         for (int y=0; y<srcBitmap.getHeight(); y++, hy+=hdy)
00506         {
00507                 GLfloat hx = 0.0f;
00508                 for (int x=0; x<srcBitmap.getWidth(); x++, hx+=hdx, 
00509                         destBits+=4, srcBits+=3, alphaBits+=3)
00510                 {
00511                         GLubyte alpha = 255 - alphaBits[0];
00512                         if (alpha > 0)
00513                         {
00514                                 float height = hMap.getInterpHeight(
00515                                         fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
00516                                 if (height > waterHeight - 0.3)
00517                                 {
00518                                         alpha = 128;
00519                                         if (height > waterHeight)
00520                                         {
00521                                                 alpha = 255;
00522                                         }
00523                                 }
00524                                 else alpha = 0;
00525                         }
00526 
00527                         destBits[0] = srcBits[0];
00528                         destBits[1] = srcBits[1];
00529                         destBits[2] = srcBits[2];
00530                         destBits[3] = alpha;
00531                 }
00532         }
00533 }
00534 
00535 void ImageModifier::addWaterToBitmap(HeightMap &hMap,
00536                                                                                 Image &destBitmap,
00537                                                                                 Image &waterBitmap,
00538                                                                                 float waterHeight)
00539 {
00540         const float waterPercentage = 0.75f;
00541         const float oneMinusPercentage = 1.0f - waterPercentage;
00542 
00543         ImageItterator bitmapItor(waterBitmap,
00544                                                                 destBitmap.getWidth(), 
00545                                                                 destBitmap.getHeight(), 
00546                                                                 ImageItterator::wrap);
00547 
00548         GLfloat hdx = (GLfloat) hMap.getMapWidth() / (GLfloat) destBitmap.getWidth();
00549         GLfloat hdy = (GLfloat) hMap.getMapHeight() / (GLfloat) destBitmap.getHeight();
00550 
00551         GLubyte *destBits = destBitmap.getBits();
00552 
00553         GLfloat hy = 0.0f;
00554         for (int by=0; by<destBitmap.getHeight(); by++, hy+=hdy, bitmapItor.incY())
00555         {
00556                 GLfloat hx = 0.0f;
00557                 for (int bx=0; bx<destBitmap.getWidth(); bx++, destBits+=3, hx+=hdx, bitmapItor.incX())
00558                 {
00559                         float height = hMap.getInterpHeight(
00560                                 fixed::fromFloat(hx), fixed::fromFloat(hy)).asFloat();
00561 
00562                         if (height <= waterHeight)
00563                         {
00564                                 if (height <= waterHeight - 0.3)
00565                                 {
00566                                         GLubyte *sourceBits = bitmapItor.getPos();
00567 
00568                                         destBits[0] = GLubyte(
00569                                                 (waterPercentage * float(sourceBits[0])) + 
00570                                                 (oneMinusPercentage * float(destBits[0])));
00571                                         destBits[1] = GLubyte(
00572                                                 (waterPercentage * float(sourceBits[1])) + 
00573                                                 (oneMinusPercentage * float(destBits[1])));
00574                                         destBits[2] = GLubyte(
00575                                                 (waterPercentage * float(sourceBits[2])) + 
00576                                                 (oneMinusPercentage * float(destBits[2])));
00577                                 }
00578                                 else
00579                                 {
00580                                         destBits[0] = 200;
00581                                         destBits[1] = 200;
00582                                         destBits[2] = 200;
00583                                 }
00584                         }
00585                 }
00586         }
00587 }
00588 
00589 ImageHandle ImageModifier::makeArenaBitmap()
00590 {
00591         Vector &wallColor = ScorchedClient::instance()->getOptionsTransient().getWallColor();
00592         ImageHandle handle = ImageFactory::createBlank(128, 128, true, 0);
00593 
00594         int arenaX = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaX();
00595         int arenaY = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaY();
00596         int arenaWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaWidth();
00597         int arenaHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaHeight();
00598         int landscapeWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeWidth();
00599         int landscapeHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeHeight();
00600 
00601         int lx = arenaX * handle.getWidth() / landscapeWidth;
00602         int ly = arenaY * handle.getHeight() / landscapeHeight;
00603         int lw = lx + (arenaWidth * handle.getWidth() / landscapeWidth);
00604         int lh = ly + (arenaHeight * handle.getHeight() / landscapeHeight);
00605 
00606         unsigned char *bits = handle.getBits();
00607         for (int y=0; y<handle.getHeight(); y++)
00608         {
00609                 for (int x=0; x<handle.getWidth(); x++, bits+=4)
00610                 {
00611                         if (x >= lx && x < lw &&
00612                                 y >= ly && y < lh)
00613                         {
00614                                 bits[3] = 0;
00615                         }
00616                         else 
00617                         {
00618                                 bits[3] = 255;
00619                         }
00620                 }
00621         }
00622 
00623         return handle;
00624 }
00625 
00626 ImageHandle ImageModifier::makeArenaSurroundBitmap()
00627 {
00628         Vector &wallColor = ScorchedClient::instance()->getOptionsTransient().getWallColor();
00629         ImageHandle handle = ImageFactory::createBlank(128, 128, true, 0);
00630 
00631         unsigned char *bits = handle.getBits();
00632         for (int y=0; y<handle.getHeight(); y++)
00633         {
00634                 for (int x=0; x<handle.getWidth(); x++, bits+=4)
00635                 {
00636                         bits[3] = 255;
00637                 }
00638         }
00639 
00640         return handle;
00641 }
00642 
00643 void ImageModifier::addBorderToBitmap(Image &destBitmap,
00644         int borderSize,
00645         float colors[3])
00646 {
00647         int arenaX = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaX();
00648         int arenaY = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaY();
00649         int arenaWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaWidth();
00650         int arenaHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getArenaHeight();
00651         int landscapeWidth = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeWidth();
00652         int landscapeHeight = ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeHeight();
00653 
00654         int borderX = int(float(arenaX) / float(landscapeWidth) * float(destBitmap.getWidth()));
00655         int borderY = int(float(arenaY) / float(landscapeHeight) * float(destBitmap.getHeight()));
00656         int borderWidth = int(float(arenaWidth) / float(landscapeWidth) * float(destBitmap.getWidth()));
00657         int borderHeight = int(float(arenaHeight) / float(landscapeHeight) * float(destBitmap.getHeight()));
00658         if (borderWidth + borderX >= destBitmap.getWidth()) borderWidth = destBitmap.getWidth() - borderX - 1;
00659         if (borderHeight + borderY >= destBitmap.getHeight()) borderHeight = destBitmap.getHeight() - borderY - 1;
00660 
00661         DIALOG_ASSERT(destBitmap.getComponents() == 3);
00662 
00663         for (int x=borderX; x<=borderX+borderWidth; x++)
00664         {
00665                 for (int i=0; i<borderSize; i++)
00666                 {
00667                         int pos = (x * 3) + ((borderY + i) * destBitmap.getWidth() * 3);
00668                         GLubyte *destBits = destBitmap.getBitsOffset(pos);
00669                         destBits[0] = GLubyte(colors[0] * 255.0f);
00670                         destBits[1] = GLubyte(colors[1] * 255.0f);
00671                         destBits[2] = GLubyte(colors[2] * 255.0f);
00672 
00673                         pos = (x * 3) + ((borderY + borderHeight - i) * destBitmap.getWidth() * 3);
00674                         destBits = destBitmap.getBitsOffset(pos);
00675                         destBits[0] = GLubyte(colors[0] * 255.0f);
00676                         destBits[1] = GLubyte(colors[1] * 255.0f);
00677                         destBits[2] = GLubyte(colors[2] * 255.0f);
00678                 }
00679         }
00680 
00681         for (int y=borderY; y<=borderY+borderHeight; y++)
00682         {
00683                 for (int i=0; i<borderSize; i++)
00684                 {
00685                         int pos = ((borderX + i) * 3) + (y * destBitmap.getWidth() * 3);
00686                         GLubyte *destBits = destBitmap.getBitsOffset(pos);
00687                         destBits[0] = GLubyte(colors[0] * 255.0f);
00688                         destBits[1] = GLubyte(colors[1] * 255.0f);
00689                         destBits[2] = GLubyte(colors[2] * 255.0f);
00690 
00691                         pos = ((borderX + borderWidth - i) * 3) + (y * destBitmap.getWidth() * 3);
00692                         destBits = destBitmap.getBitsOffset(pos);
00693                         destBits[0] = GLubyte(colors[0] * 255.0f);
00694                         destBits[1] = GLubyte(colors[1] * 255.0f);
00695                         destBits[2] = GLubyte(colors[2] * 255.0f);
00696                 }
00697         }
00698 }
00699 
00700 void ImageModifier::makeBitmapTransparent(Image &output,
00701                 Image &input,
00702                 Image &mask)
00703 {
00704         GLubyte *outputBits = output.getBits();
00705         GLubyte *maskBits = mask.getBits();
00706         GLubyte *inputBits = input.getBits();
00707 
00708         for (int i=0; i<output.getWidth() * output.getHeight(); i++)
00709         {
00710                 outputBits[0] = inputBits[0];
00711                 outputBits[1] = inputBits[1];
00712                 outputBits[2] = inputBits[2];
00713                 outputBits[3] = maskBits[3];
00714 
00715                 inputBits += 3;
00716                 outputBits += 4;
00717                 maskBits += 4;
00718         }
00719 }
00720 
00721 void ImageModifier::addCircleToLandscape(
00722         ScorchedContext &context,
00723         float sx, float sy, float sw, float opacity)
00724 {
00725         float shadowMultWidth = (float) Landscape::instance()->getMainMap().getWidth() / 
00726                 context.getLandscapeMaps().getGroundMaps().getLandscapeWidth();
00727         float shadowMultHeight = (float) Landscape::instance()->getMainMap().getHeight() / 
00728                 context.getLandscapeMaps().getGroundMaps().getLandscapeHeight();
00729 
00730         addCircle(Landscape::instance()->getMainMap(),
00731                 sx * shadowMultWidth, sy * shadowMultHeight, 
00732                 sw * shadowMultWidth, opacity);
00733 }
00734 
00735 void ImageModifier::addCircle(Image &destBitmap, 
00736                                                                  float sx, float sy, float sw, float opacity)
00737 {
00738         int decrement = int(opacity * 125.0f);
00739         float halfW = sw / 2.0f;
00740 
00741         float minX = sx - halfW;
00742         float minY = sy - halfW;
00743         float maxX = sx + halfW;
00744         float maxY = sy + halfW;
00745         /*minX /= 2.0f;
00746         minY /= 2.0f;
00747         maxX /= 2.0f;
00748         maxY /= 2.0f;*/
00749 
00750         minX = MAX(minX, 0.0f);
00751         minY = MAX(minY, 0.0f);
00752         maxX = MIN(maxX, destBitmap.getWidth() - 1.0f);
00753         maxY = MIN(maxY, destBitmap.getHeight() - 1.0f);
00754 
00755         int xStart = int(minX);
00756         int yStart = int(minY);
00757         int xWidth = int(maxX - minX);
00758         int yWidth = int(maxY - minY);
00759         int yInc = (destBitmap.getWidth() - xWidth) * 3;
00760 
00761         if (xWidth <= 0 || yWidth <= 0) return;
00762         double degMult = (1 / double(yWidth)) * 3.14;
00763 
00764         GLubyte *start = &destBitmap.getBits()[(yStart * destBitmap.getWidth() * 3) + xStart * 3];
00765         for (int y=0; y<yWidth; y++, start += yInc)
00766         {
00767                 double deg = double(y) * degMult;
00768                 int realXSize = int(sin(deg) * double(xWidth));
00769                 int halfSize = (xWidth - realXSize) / 2;
00770 
00771                 start+=halfSize * 3;
00772                 int x;
00773                 for (x=0; x<realXSize; x++, start+=3)
00774                 {
00775                         start[0] = start[0] / 2;
00776                         start[1] = start[1] / 2;
00777                         start[2] = start[2] / 2;
00778                 }
00779                 start+=(xWidth - (halfSize + x)) * 3;
00780         }
00781 }
00782 
00783 
00784 void ImageModifier::addBitmapToLandscape(
00785         ScorchedContext &context,
00786         Image &srcBitmap,
00787         float sx, float sy, float scalex, float scaley, 
00788         bool commit)
00789 {
00790         float shadowMultWidth = (float) Landscape::instance()->getMainMap().getWidth() / 
00791                 context.getLandscapeMaps().getGroundMaps().getLandscapeWidth();
00792         float shadowMultHeight = (float) Landscape::instance()->getMainMap().getHeight() / 
00793                 context.getLandscapeMaps().getGroundMaps().getLandscapeHeight();
00794 
00795         addBitmap(
00796                 Landscape::instance()->getMainMap(),
00797                 srcBitmap,
00798                 sx * shadowMultWidth, 
00799                 sy * shadowMultHeight,
00800                 shadowMultWidth * scalex,
00801                 shadowMultHeight * scaley,
00802                 commit);
00803 }
00804 
00805 void ImageModifier::addBitmap(Image &destBitmap,
00806         Image &srcBitmap,
00807         float sx, float sy, float scalex, float scaley, 
00808         bool commit)
00809 {
00810         int srcScaleWidth = int(float(srcBitmap.getWidth()) * scalex);
00811         int srcScaleHeight = int(float(srcBitmap.getHeight()) * scaley);
00812 
00813         float minX = sx - srcScaleWidth / 2;
00814         float minY = sy - srcScaleHeight / 2;
00815         float maxX = sx + srcScaleWidth / 2;
00816         float maxY = sy + srcScaleHeight / 2;
00817 
00818         minX = MAX(minX, 0.0f);
00819         minY = MAX(minY, 0.0f);
00820         maxX = MIN(maxX, destBitmap.getWidth() - 1.0f);
00821         maxY = MIN(maxY, destBitmap.getHeight() - 1.0f);
00822 
00823         int xStart = int(minX);
00824         int yStart = int(minY);
00825         int xWidth = int(maxX - minX);
00826         int yWidth = int(maxY - minY);
00827 
00828         if (xWidth <= 0 || yWidth <= 0) return;
00829 
00830         int yDestInc = (destBitmap.getWidth() * 3);
00831 
00832         GLubyte *dest = &destBitmap.getBits()[
00833                 (yStart * destBitmap.getWidth() * 3) + xStart * 3];
00834         for (int y=0; y<yWidth; y++, dest += yDestInc)
00835         {
00836                 GLubyte *tmpDest = dest;
00837                 for (int x=0; x<xWidth; x++)
00838                 {
00839                         int srcX = int(float(x) / scalex);
00840                         srcX = MIN(srcX, srcBitmap.getWidth());
00841                         int srcY = int(float(y) / scaley);
00842                         srcY = MIN(srcY, srcBitmap.getHeight());
00843 
00844                         GLubyte *tmpSrc = srcBitmap.getBits() +
00845                                 srcX * srcBitmap.getComponents() +
00846                                 srcY * srcBitmap.getComponents() * srcBitmap.getWidth();
00847 
00848                         float alpha = 1.0f;
00849                         float invAlpha = 0.0f;
00850                         if (srcBitmap.getComponents() == 4)
00851                         {
00852                                 alpha = float(tmpSrc[3]) / 255.0f;
00853                                 invAlpha = 1.0f - alpha;
00854                         }
00855 
00856                         tmpDest[0] = GLubyte(float(tmpSrc[0]) * alpha + float(tmpDest[0]) * invAlpha);
00857                         tmpDest[1] = GLubyte(float(tmpSrc[1]) * alpha + float(tmpDest[1]) * invAlpha);
00858                         tmpDest[2] = GLubyte(float(tmpSrc[2]) * alpha + float(tmpDest[2]) * invAlpha);
00859 
00860                         tmpDest += 3;
00861                 }
00862         }
00863 
00864         if (commit)
00865         {
00866                 int landscapeWidth = Landscape::instance()->getMainMap().getWidth();
00867                 int width = 3 * landscapeWidth;
00868                 width   = (width + 3) & ~3;     
00869 
00870                 GLubyte *bytes = 
00871                         Landscape::instance()->getMainMap().getBits() + ((width * yStart) + xStart * 3);
00872 
00873                 GLState currentState(GLState::TEXTURE_ON);
00874                 Landscape::instance()->getMainTexture().draw(true);
00875 
00876                 glPixelStorei(GL_UNPACK_ROW_LENGTH, landscapeWidth);
00877                 glTexSubImage2D(GL_TEXTURE_2D, 0, 
00878                                                 xStart, yStart, 
00879                                                 xWidth, yWidth, 
00880                                                 GL_RGB, GL_UNSIGNED_BYTE, 
00881                                                 bytes);
00882                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00883         }
00884 }
00885 
00886 void ImageModifier::scalePlanBitmap(Image &destBitmap,
00887         Image &srcIncBitmap,
00888         int landscapeX, int landscapeY)
00889 {
00890         int maxSize = MAX(landscapeX, landscapeY);
00891         float xScale = landscapeX / float(maxSize);
00892         float yScale = landscapeY / float(maxSize);
00893 
00894         int newX = int(float(destBitmap.getWidth()) / xScale);
00895         int newY = int(float(destBitmap.getHeight()) / yScale);
00896         int offsetX = (newX - destBitmap.getWidth()) / 2;
00897         int offsetY = (newY - destBitmap.getHeight()) / 2;
00898 
00899         ImageHandle srcBitmap = 
00900                 srcIncBitmap.createResize(newX, newY);
00901 
00902         GLubyte *dest = destBitmap.getBits();
00903         for (int y=0; y<destBitmap.getHeight(); y++)
00904         {
00905                 for (int x=0; x<destBitmap.getWidth(); x++, dest+=destBitmap.getComponents())
00906                 {
00907                         int srcX = MIN(x + offsetX, srcBitmap.getWidth() - 1);
00908                         int srcY = MIN(y + offsetY, srcBitmap.getHeight() - 1);
00909                         GLubyte *src = srcBitmap.getBits() +
00910                                 srcX * srcBitmap.getComponents() +
00911                                 srcY * srcBitmap.getComponents() * srcBitmap.getWidth();                        
00912 
00913                         dest[0] = src[0];
00914                         dest[1] = src[1];
00915                         dest[2] = src[2];
00916                 }
00917         }
00918 }

Generated on Mon Feb 16 15:14:44 2009 for Scorched3D by  doxygen 1.5.3