1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include <cstring>
4 #include "TerrainBase.h"
5 #include "Terrain.h"
6 #include "TerrainNode.h"
7 #include "Textures.h"
8 #include "Lightcalc.h"
9 #include "Map/ReadMap.h"
10 #include "Map/SM3/Vector3.h"
11 #include "Rendering/GL/myGL.h"
12 #include "System/Matrix44f.h"
13 #include "System/Util.h"
14 #include "System/Log/ILog.h"
15
16 #include <IL/il.h>
17 #include <assert.h>
18
19 #include "System/Misc/SpringTime.h"
20
21 namespace terrain {
22
23 using std::min;
24
BlurGrayscaleImage(int w,int h,uchar * data)25 void BlurGrayscaleImage(int w, int h, uchar* data)
26 {
27 uchar* nd = new uchar [w*h];
28
29 for (int y = 0; y < h; y++) {
30 for (int x = 0; x < w; x++) {
31 int l = x ? (x - 1) : x;
32 int r = x < (w - 1) ? (x + 1) : x;
33 int t = y ? (y - 1) : y;
34 int b = y < (h - 1) ? (y + 1) : y;
35
36 int result = 0;
37
38 #define AT(X,Y) result += data[w*(Y)+(X)]
39 AT(l, t);
40 AT(x, t);
41 AT(r, t);
42
43 AT(l, y);
44 AT(r, y);
45
46 AT(l, b);
47 AT(x, b);
48 AT(r, b);
49 #undef AT
50 nd[y*w + x] = (uchar)(result / 8);
51 }
52 }
53 memcpy(data, nd, w*h);
54 delete[] nd;
55 }
56
Lightmap(Heightmap * orghm,int level,int shadowLevelDif,LightingInfo * li)57 Lightmap::Lightmap(Heightmap* orghm, int level, int shadowLevelDif, LightingInfo* li)
58 {
59 const spring_time startTicks = spring_gettime();
60 tilesize.x = orghm->w-1;
61 tilesize.y = orghm->h-1;
62 name = "lightmap";
63
64 const Heightmap* hm = NULL;
65 int w;
66
67 for(;;) {
68 hm = orghm->GetLevel(-level);
69 w = hm->w - 1;
70
71 GLint maxw;
72 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxw);
73
74 if (w > maxw) level++;
75 else break;
76 }
77
78 shadowLevelDif = 0;
79 const Heightmap* shadowhm = orghm->GetLevel(-(level + shadowLevelDif));
80 int shadowScale= 1 << shadowLevelDif;
81 int shadowW = shadowhm->w - 1;
82 assert(w/shadowW == shadowScale);
83 //float org2c = w/float(orghm->w-1);
84 //float c2org = (float)(orghm->w-1)/w;
85
86 float* centerhm = new float[w*w];
87 Vector3* shading = new Vector3[w*w];
88 for (int y=0;y<w;y++)
89 for (int x=0;x<w;x++) {
90 centerhm[y*w+x] =/* hm->scale * */ 0.25f * ( (int)hm->atSynced(x, y)+ (int)hm->atSynced(x + 1, y) + (int)hm->atSynced(x, y + 1) + (int)hm->atSynced(x + 1, y + 1) ); //+ hm->offset;
91 shading[y*w + x] = li->ambient;
92 }
93
94 uchar* lightMap = new uchar[shadowW * shadowW];
95 for (std::vector<StaticLight>::const_iterator l = li->staticLights.begin(); l != li->staticLights.end(); ++l)
96 {
97 float lightx;
98 float lighty;
99
100 if (l->directional) {
101 lightx = l->position.x;
102 lighty = l->position.y;
103 } else {
104 lightx = (int)(l->position.x / shadowhm->squareSize);
105 lighty = (int)(l->position.z / shadowhm->squareSize);
106 }
107 CalculateShadows(lightMap, shadowW, lightx, lighty,
108 l->position.y, centerhm, w, shadowScale, l->directional);
109
110 for (int y = 0; y < w; y++)
111 {
112 for (int x = 0; x < w; x++)
113 {
114 if (!lightMap[(y*shadowW + x) / shadowScale])
115 continue;
116
117 Vector3 wp;
118 if (l->directional)
119 wp = l->position;
120 else
121 wp = l->position - Vector3((x + 0.5f) * hm->squareSize,centerhm[y*w + x], (y + 0.5f) * hm->squareSize);
122
123 const uchar* normal = hm->GetNormal(x, y);
124 Vector3 normv((2 * (int)normal[0] - 256)/255.0f, (2 * (int)normal[1] - 256)/255.0f, (2 * (int)normal[2] - 256)/255.0f);
125
126 wp.ANormalize();
127 float dot = wp.dot(normv);
128 if(dot < 0.0f) dot = 0.0f;
129 if(dot > 1.0f) dot = 1.0f;
130 dot *= lightMap[(y*shadowW + x) / shadowScale] * (1.0f / 255.0f);
131 shading[y*w + x] += l->color * dot;
132 }
133 }
134
135 }
136 delete[] lightMap;
137
138 glGenTextures(1, &shadingTex);
139 glBindTexture (GL_TEXTURE_2D, shadingTex);
140 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
141 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
142
143 uchar* shadingTexData = new uchar[w*w*4];
144 for (int y = 0; y < w; y++) {
145 for (int x = 0; x < w; x++) {
146 shadingTexData[(y*w + x) * 4 + 0] = (uchar)(min(1.0f, shading[y*w + x].x) * 255);
147 shadingTexData[(y*w + x) * 4 + 1] = (uchar)(min(1.0f, shading[y*w + x].y) * 255);
148 shadingTexData[(y*w + x) * 4 + 2] = (uchar)(min(1.0f, shading[y*w + x].z) * 255);
149 shadingTexData[(y*w + x) * 4 + 3] = CReadMap::EncodeHeight(centerhm[w*y + x]);
150 }
151 }
152
153 SaveImage ("lightmap.png", 4, IL_UNSIGNED_BYTE, w, w, shadingTexData);
154
155 glBuildMipmaps(GL_TEXTURE_2D, 4, w, w, GL_RGBA, GL_UNSIGNED_BYTE, shadingTexData);
156 delete[] shadingTexData;
157
158 id = shadingTex;
159
160 delete[] shading;
161 delete[] centerhm;
162
163 const spring_time numTicks = spring_gettime() - startTicks;
164 LOG("Lightmap generation: %2.3f seconds", spring_tomsecs(numTicks) * 0.001f);
165 }
166
~Lightmap()167 Lightmap::~Lightmap()
168 {
169 if (shadingTex)
170 glDeleteTextures(1, &shadingTex);
171 }
172
CalculateShadows(uchar * dst,int dstw,float lightX,float lightY,float lightH,float * centerhm,int hmw,int hmscale,bool directional)173 void Lightmap::CalculateShadows (uchar* dst, int dstw, float lightX, float lightY, float lightH, float* centerhm, int hmw, int hmscale, bool directional)
174 {
175 memset(dst, 255, dstw * dstw); // 255 is lit, 0 is unlit
176
177 for (int y = 0; y < dstw; y++)
178 {
179 for (int x = 0; x < dstw; x++)
180 {
181 if (!dst[y*dstw + x]) // shadowed pixels can't shadow other pixels
182 continue;
183
184 float dx, dy, dh;
185 float h = centerhm[(y*hmw + x) * hmscale];
186
187 if (directional) {
188 dx = lightX;
189 dy = lightY;
190 dh = lightH;
191 } else {
192 dx = lightX - x;
193 dy = lightY - y;
194 dh = lightH - h;
195
196 if (x == lightX && y == lightY)
197 continue;
198 }
199
200 float len = math::sqrt(dx*dx + dy*dy);
201 const float step = 5.0f;
202 float invLength2d = step / len;
203 dx *= invLength2d;
204 dy *= invLength2d;
205 dh *= invLength2d;
206
207 float px = (x + dx) * hmscale, py = (y + dy) * hmscale;
208 h += dh;
209 while ((px >= 0.0f) && (px < hmw) && (py >= 0.0f) && (py < hmw) && (len >= 0.0f))
210 {
211 int index = (int)py * hmw + (int)px;
212
213 if (centerhm[index] > h + 2.0f)
214 {
215 dst[y*dstw + x] = 0;
216 break;
217 }
218
219 px += dx;
220 py += dy;
221 h += dh;
222 len -= step;
223 }
224 }
225 }
226
227 BlurGrayscaleImage(dstw, dstw, dst);
228
229 char sm_fn[64];
230 static int lightIndex = 0;
231 SNPRINTF(sm_fn, sizeof(sm_fn), "shadowmap%d.png", lightIndex++);
232 SaveImage(sm_fn, 1, IL_UNSIGNED_BYTE, dstw, dstw, dst);
233 }
234 }
235