00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <math.h>
00022 #include <string.h>
00023 #include <GLEXT/GLStateExtension.h>
00024 #include <landscape/ShadowMap.h>
00025 #include <landscapemap/LandscapeMaps.h>
00026 #include <client/ScorchedClient.h>
00027 #include <common/Defines.h>
00028 #include <graph/OptionsDisplay.h>
00029
00030 ShadowMap::ShadowMap() : size_(256), sizeSq_(256 *256), shadowCount_(0)
00031 {
00032 shadowBytes_ = new GLubyte[sizeSq_];
00033 memset(shadowBytes_, 255, sizeSq_);
00034 shadowTexture_.create(shadowBytes_, size_, size_, 1, 4, GL_LUMINANCE, false);
00035 }
00036
00037 ShadowMap::~ShadowMap()
00038 {
00039 delete [] shadowBytes_;
00040 }
00041
00042 void ShadowMap::setTexture()
00043 {
00044 shadowCount_ = 0;
00045
00046
00047 shadowTexture_.draw(true);
00048
00049 if (!GLStateExtension::getNoTexSubImage())
00050 {
00051
00052 glTexSubImage2D(GL_TEXTURE_2D, 0,
00053 0, 0,
00054 size_, size_,
00055 GL_LUMINANCE, GL_UNSIGNED_BYTE,
00056 shadowBytes_);
00057
00058
00059 memset(shadowBytes_, 255, sizeSq_);
00060
00061
00062
00063 }
00064 }
00065
00066 void ShadowMap::addSquare(float sx, float sy, float sw, float opacity)
00067 {
00068 addShadow(sx, sy, sw, opacity, false);
00069 }
00070
00071 void ShadowMap::addCircle(float sx, float sy, float sw, float opacity)
00072 {
00073 addShadow(sx, sy, sw, opacity, true);
00074 }
00075
00076 bool ShadowMap::shouldAddShadow()
00077 {
00078 if (!GLStateExtension::hasMultiTex() ||
00079 GLStateExtension::getNoTexSubImage() ||
00080 OptionsDisplay::instance()->getNoShadows() ||
00081 GLStateExtension::hasHardwareShadows()) return false;
00082 return true;
00083 }
00084
00085 void ShadowMap::addShadow(float mapx, float mapy, float mapw, float opacity, bool circle)
00086 {
00087 if (!shouldAddShadow()) return;
00088
00089 if (mapw > 10.0f) return;
00090
00091 int mapWidth =
00092 ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeWidth();
00093 int mapHeight =
00094 ScorchedClient::instance()->getLandscapeMaps().getGroundMaps().getLandscapeHeight();
00095
00096 float sx = mapx * size_ / float(mapWidth);
00097 float sy = mapy * size_ / float(mapHeight);
00098 float sw = mapw * size_ / float(mapWidth);
00099 if (sx < 0 || sx >= size_ || sy < 0 || sy >= size_)
00100 {
00101 return;
00102 }
00103
00104 shadowCount_++;
00105 const GLubyte minNum = 64;
00106 int decrement = int(opacity * 200.0f);
00107 float halfW = sw / 2.0f;
00108
00109 float minX = sx - halfW;
00110 float minY = sy - halfW;
00111 float maxX = sx + halfW;
00112 float maxY = sy + halfW;
00113
00114 minX = MAX(minX, 0.0f);
00115 minY = MAX(minY, 0.0f);
00116 maxX = MIN(maxX, size_ - 1.0f);
00117 maxY = MIN(maxY, size_ - 1.0f);
00118
00119 int iSize = int(size_);
00120 int xStart = int(minX);
00121 int yStart = int(minY);
00122 int xWidth = int(maxX - minX);
00123 int yWidth = int(maxY - minY);
00124 int yInc = size_ - xWidth;
00125 if (xWidth <= 0 || yWidth <= 0) return;
00126
00127 if (circle)
00128 {
00129 static float sintable[100];
00130 static bool sintablemade = false;
00131 if (!sintablemade)
00132 {
00133 sintablemade = true;
00134 float degMult = 0.0314f;
00135 for (int i=0; i<100; i++)
00136 {
00137 float deg = float(i) * degMult;
00138 sintable[i] = sinf(deg);
00139 }
00140 }
00141 GLubyte *start = &shadowBytes_[(yStart * iSize) + xStart];
00142 for (int y=0; y<yWidth; y++, start += yInc)
00143 {
00144 int deg = (y * 90) / yWidth;
00145 int realXSize = int(sintable[deg] * xWidth);
00146 int halfSize = (xWidth - realXSize) / 2;
00147
00148 start+=halfSize;
00149 int x;
00150 for (x=0; x<realXSize; x++, start++)
00151 {
00152 if (*start > decrement + minNum) (*start) -= (GLubyte) (decrement);
00153 else (*start = minNum);
00154 }
00155 start+=xWidth - (halfSize + x);
00156 }
00157 }
00158 else
00159 {
00160 GLubyte *start = &shadowBytes_[(yStart * iSize) + xStart];
00161 for (int y=0; y<yWidth; y++, start += yInc)
00162 {
00163 for (int x=0; x<xWidth; x++, start++)
00164 {
00165 if (*start > decrement + minNum) (*start) -= (GLubyte) decrement;
00166 else (*start = minNum);
00167 }
00168 }
00169 }
00170 }