4 VARP(grassanimdist
, 0, 500, 10000);
5 VARP(grassdist
, 0, 500, 10000);
6 VARP(grassfalloff
, 0, 100, 1000);
8 VAR(grasswidth
, 1, 6, 64);
9 VAR(grassheight
, 1, 8, 64);
11 void resetgrasssamples()
13 extern vector
<vtxarray
*> valist
;
16 vtxarray
*va
= valist
[i
];
17 DELETEP(va
->grasssamples
);
21 VARF(grassgrid
, 1, 6, 32, resetgrasssamples());
23 void gengrasssample(vtxarray
*va
, const vec
&o
, float tu
, float tv
, LightMap
*lm
)
25 grasssample
&g
= va
->grasssamples
->add();
27 g
.x
= ushort(o
.x
-va
->x
) | GRASS_SAMPLE
;
28 g
.y
= ushort(o
.y
-va
->y
);
29 g
.z
= ushort(4*(o
.z
-va
->z
));
33 tu
= min(tu
, LM_PACKW
-0.01f
);
34 tv
= min(tv
, LM_PACKH
-0.01f
);
35 memcpy(g
.color
, &lm
->data
[3*(int(tv
)*LM_PACKW
+ int(tu
))], 3);
37 else loopk(3) g
.color
[k
] = hdr
.ambient
;
40 bool gengrassheader(vtxarray
*va
, const vec
*v
)
47 float r1
= center
.dist(v
[0]),
48 r2
= center
.dist(v
[1]),
49 r3
= center
.dist(v
[2]),
50 radius
= min(r1
, min(r2
, r3
));
51 if(radius
< grassgrid
*2) return false;
53 grassbounds
&g
= *(grassbounds
*)&va
->grasssamples
->add();
54 g
.x
= ushort(center
.x
-va
->x
) | GRASS_BOUNDS
;
55 g
.y
= ushort(center
.y
-va
->y
);
56 g
.z
= ushort(4*(center
.z
-va
->z
));
57 g
.radius
= ushort(radius
+ grasswidth
);
62 void gengrasssamples(vtxarray
*va
, const vec
*v
, float *tc
, LightMap
*lm
)
65 if(v
[1].y
< v
[0].y
) u
= v
[1].y
< v
[2].y
? 1 : 2;
66 else u
= v
[0].y
< v
[2].y
? 0 : 2;
69 if(v
[l
].x
> v
[r
].x
) swap(int, l
, r
);
72 if(v
[l
].x
<= v
[u
].x
) swap(int, u
, l
);
75 vec o1
= v
[u
], dl
= v
[l
];
77 if(dl
.x
==0 && dl
.y
==0) return;
79 ls
= tc
[2*u
], lt
= tc
[2*u
+1],
80 lds
= tc
[2*l
] - ls
, ldt
= tc
[2*l
+1] - lt
;
83 float endr
, rs
, rt
, rds
, rdt
;
86 if(v
[u
].x
==v
[r
].x
) return;
106 rdt
= tc
[2*r
+1] - rt
;
108 if(dr
.y
==0 && (dr
.x
==0 || dl
.y
==0)) return;
109 if(dr
.x
==0 && dl
.x
==0) return;
113 float dy
= grassgrid
- fmodf(o1
.y
, grassgrid
);
116 if(endl
> o1
.y
) dy
= min(dy
, endl
- o1
.y
);
117 if(endr
> o2
.y
) dy
= min(dy
, endr
- o2
.y
);
120 o1
.x
+= dl
.x
* dy
/dl
.y
;
121 o1
.z
+= dl
.z
* dy
/dl
.y
;
126 o2
.x
+= dr
.x
* dy
/dr
.y
;
127 o2
.z
+= dr
.z
* dy
/dr
.y
;
131 if(o1
.y
<= endl
&& o2
.y
<= endr
&& fmod(o1
.y
, grassgrid
) < 0.01f
)
135 float s
= ls
, t
= lt
,
136 ds
= rs
- ls
, dt
= rt
- lt
;
137 float dx
= grassgrid
- fmodf(o1
.x
, grassgrid
);
138 if(o1
.x
==o2
.x
&& dx
==grassgrid
)
140 if(!numsamples
++) header
= gengrassheader(va
, v
);
141 gengrasssample(va
, p
, s
, t
, lm
);
143 else while(!header
|| numsamples
<USHRT_MAX
)
146 p
.y
+= dp
.y
* dx
/dp
.x
;
147 p
.z
+= dp
.z
* dx
/dp
.x
;
151 if(p
.x
> o2
.x
) break;
153 if(!numsamples
++) header
= gengrassheader(va
, v
);
154 gengrasssample(va
, p
, s
, t
, lm
);
158 if(header
&& numsamples
>=USHRT_MAX
) break;
163 if(v
[r
].y
<= endl
) break;
167 lds
= tc
[2*r
] - tc
[2*l
];
168 ldt
= tc
[2*r
+1] - tc
[2*l
+1];
170 dy
= grassgrid
- fmod(o1
.y
, grassgrid
);
176 if(v
[l
].y
<= endr
) break;
180 rds
= tc
[2*l
] - tc
[2*r
];
181 rdt
= tc
[2*l
+1] - tc
[2*r
+1];
183 dy
= grassgrid
- fmod(o1
.y
, grassgrid
);
191 grassbounds
&g
= *(grassbounds
*)&(*va
->grasssamples
)[va
->grasssamples
->length() - numsamples
- 1];
192 g
.numsamples
= numsamples
;
196 void gengrasssamples(vtxarray
*va
)
198 if(va
->grasssamples
) return;
199 va
->grasssamples
= new vector
<grasssample
>;
201 loopv(*va
->grasstris
)
203 grasstri
&g
= (*va
->grasstris
)[i
];
204 if(g
.texture
!= lasttex
)
206 grasstexture
&t
= *(grasstexture
*)&va
->grasssamples
->add();
208 t
.texture
= g
.texture
;
213 static int remap
[4] = { 1, 2, 0, 3 };
217 v
[k
] = g
.v
[j
].tovec(va
->x
, va
->y
, va
->z
);
220 tc
[2*k
] = float(g
.surface
->x
+ (g
.surface
->texcoords
[j
*2] / 255.0f
) * (g
.surface
->w
- 1) + 0.5f
);
221 tc
[2*k
+1] = float(g
.surface
->y
+ (g
.surface
->texcoords
[j
*2 + 1] / 255.0f
) * (g
.surface
->h
- 1) + 0.5f
);
224 LightMap
*lm
= g
.surface
&& g
.surface
->lmid
>= LMID_RESERVED
? &lightmaps
[g
.surface
->lmid
-LMID_RESERVED
] : NULL
;
225 gengrasssamples(va
, v
, tc
, lm
);
226 gengrasssamples(va
, &v
[1], &tc
[2], lm
);
230 VAR(grasstest
, 0, 0, 3);
232 static Texture
*grasstex
= NULL
;
234 VARP(grasslod
, 0, 25, 1000);
236 VARP(grasslodz
, 0, 150, 10000);
238 float loddist(const vec
&o
)
240 float dx
= o
.x
- camera1
->o
.x
, dy
= o
.y
- camera1
->o
.y
, dz
= camera1
->o
.z
- o
.z
;
241 float dist
= sqrt(dx
*dx
+ dy
*dy
);
242 dist
-= grasslodz
/100.0f
* max(dz
, 0);
246 VAR(grassrand
, 0, 30, 90);
248 VARP(grasssamples
, 0, 50, 10000);
250 VARP(grassbillboard
, 0, 1, 100);
251 VARP(grassbbcorrect
, 0, 1, 1);
252 VARP(grasstaper
, 0, 200, 10000);
254 void rendergrasssample(const grasssample
&g
, const vec
&o
, float dist
, int seed
, float height
, int numsamples
)
256 if(grasstest
>2) return;
258 if(seed
>= 2*numsamples
) return;
260 vec
up(0, 0, 1), right(seed
%2, (seed
+1)%2, 0);
261 float width
= grasswidth
;
262 if(numsamples
<=grassbillboard
)
266 if(grassrand
) right
.rotate_around_z((detrnd((size_t)&g
* (seed
+ 1), 2*grassrand
)-grassrand
)*RAD
);
269 if(fabs(right
.x
) > fabs(right
.y
)) width
*= sqrt(right
.y
*right
.y
/(right
.x
*right
.x
) + 1);
270 else width
*= sqrt(right
.x
*right
.x
/(right
.y
*right
.y
) + 1);
273 else if(grassrand
) right
.rotate_around_z((detrnd((size_t)&g
* (seed
+ 1), 2*grassrand
)-grassrand
)*RAD
);
278 b1
[seed
%2] += (seed
/2 * grassgrid
) / float(numsamples
) - grassgrid
/2.0f
;
284 vec t1
= b1
, t2
= b2
;
285 t1
.z
+= grassheight
* height
;
286 t2
.z
+= grassheight
* height
;
288 float w1
= 0, w2
= 0;
289 if(grasstest
>0) t1
= t2
= b1
;
290 else if(dist
< grassanimdist
)
292 w1
= detrnd((size_t)&g
* (seed
+ 1)*7, 360)*RAD
+ t1
.x
*0.4f
+ t1
.y
*0.5f
;
293 w1
+= lastmillis
*0.0015f
;
295 vec
d1(1.0f
, 1.0f
, 0.5f
);
296 d1
.mul(grassheight
/4.0f
* w1
);
299 w2
= detrnd((size_t)&g
* (seed
+ 1)*11, 360)*RAD
+ t2
.x
*0.55f
+ t2
.y
*0.45f
;
300 w2
+= lastmillis
*0.0015f
;
302 vec
d2(0.4f
, 0.4f
, 0.2f
);
303 d2
.mul(grassheight
/4.0f
* w2
);
307 if(grasstest
>1) return;
309 extern int fullbright
;
310 if(nolights
|| (fullbright
&& editmode
)) glColor3ub(128, 128, 128);
311 else glColor3ubv(g
.color
);
312 float offset
= detrnd((size_t)&g
* (seed
+ 1)*13, grasstex
->xs
)/float(grasstex
->xs
);
313 glTexCoord2f(offset
, 1); glVertex3fv(b1
.v
);
314 glTexCoord2f(offset
, 0); glVertex3fv(t1
.v
);
315 glTexCoord2f(offset
+ float(grasswidth
)*64.0f
/grasstex
->xs
, 0); glVertex3fv(t2
.v
);
316 glTexCoord2f(offset
+ float(grasswidth
)*64.0f
/grasstex
->xs
, 1); glVertex3fv(b2
.v
);
320 void rendergrasssamples(vtxarray
*va
, const vec
&dir
)
322 if(!va
->grasssamples
) return;
323 loopv(*va
->grasssamples
)
325 grasssample
&g
= (*va
->grasssamples
)[i
];
327 vec
o((g
.x
&~GRASS_TYPE
)+va
->x
, g
.y
+va
->y
, g
.z
/4.0f
+va
->z
), tograss
;
328 switch(g
.x
&GRASS_TYPE
)
332 grassbounds
&b
= *(grassbounds
*)&g
;
333 if(reflecting
&& (refracting
? o
.z
-b
.radius
>=refracting
: o
.z
+b
.radius
<reflecting
))
338 float dist
= o
.dist(camera1
->o
, tograss
);
339 if(dist
> grassdist
+ b
.radius
|| (dir
.dot(tograss
)<0 && dist
> b
.radius
+ 2*(grassgrid
+ player
->eyeheight
)))
346 grasstexture
&t
= *(grasstexture
*)&g
;
347 Slot
&s
= lookuptexture(t
.texture
, false);
348 if(!s
.grasstex
|| s
.grasstex
!=grasstex
)
351 if(!s
.grasstex
) s
.grasstex
= textureload(s
.autograss
, 2);
352 glBindTexture(GL_TEXTURE_2D
, s
.grasstex
->gl
);
354 grasstex
= s
.grasstex
;
361 if(reflecting
&& (refracting
? o
.z
>=reflecting
: o
.z
+grassheight
<=reflecting
)) continue;
362 float dist
= o
.dist(camera1
->o
, tograss
);
363 if(dist
> grassdist
|| (dir
.dot(tograss
)<0 && dist
> grasswidth
/2 + 2*(grassgrid
+ player
->eyeheight
))) continue;
365 float ld
= loddist(o
);
366 int numsamples
= int(grasssamples
/100.0f
*max(grassgrid
- ld
/grasslod
, 100.0f
/grasssamples
));
367 float height
= 1 - (dist
+ grasstaper
- grassdist
) / (grasstaper
? grasstaper
: 1);
368 height
= min(height
, 1);
371 rendergrasssample(g
, o
, dist
, j
, height
, numsamples
);
379 VAR(grassblend
, 0, 0, 100);
383 glDisable(GL_CULL_FACE
);
384 glEnable(GL_ALPHA_TEST
);
385 glAlphaFunc(GL_GREATER
, grassblend
? grassblend
/100.0f
: 0.6f
);
389 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
392 static Shader
*grassshader
= NULL
;
393 if(!grassshader
) grassshader
= lookupshaderbyname("grass");
398 setuptmu(0, "C * T x 2");
409 defaultshader
->set();
411 if(grassblend
) glDisable(GL_BLEND
);
412 glDisable(GL_ALPHA_TEST
);
413 glEnable(GL_CULL_FACE
);
416 VARP(grass
, 0, 1, 1);
420 if(!grass
|| !grasssamples
|| !grassdist
) return;
423 vecfromyawpitch(camera1
->yaw
, 0, 1, 0, dir
);
426 extern vtxarray
*visibleva
;
427 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
429 if(!va
->grasstris
|| va
->occluded
>= OCCLUDE_GEOM
|| va
->curlod
) continue;
430 if(va
->distance
> grassdist
) continue;
431 if(reflecting
&& (refracting
? va
->z
>=refracting
: va
->z
+va
->size
<reflecting
)) continue;
432 if(!va
->grasssamples
) gengrasssamples(va
);
433 if(!rendered
++) setupgrass();
434 rendergrasssamples(va
, dir
);
437 if(rendered
) cleanupgrass();