1 // renderva.cpp: handles the occlusion and rendering of vertex arrays
6 static inline void drawtris(GLsizei numindices
, const GLvoid
*indices
, ushort minvert
, ushort maxvert
)
8 if(hasDRE
) glDrawRangeElements_(GL_TRIANGLES
, minvert
, maxvert
, numindices
, GL_UNSIGNED_SHORT
, indices
);
9 else glDrawElements(GL_TRIANGLES
, numindices
, GL_UNSIGNED_SHORT
, indices
);
13 static inline void drawvatris(vtxarray
*va
, GLsizei numindices
, const GLvoid
*indices
)
15 drawtris(numindices
, indices
, va
->minvert
, va
->maxvert
);
18 ///////// view frustrum culling ///////////////////////
20 plane vfcP
[5]; // perpindictular vectors to view frustrum bounding planes
21 float vfcDfog
; // far plane culling distance (fog limit).
22 float vfcDnear
[5], vfcDfar
[5];
23 float vfcfov
, vfcfovy
;
27 int isvisiblesphere(float rad
, const vec
&cv
)
29 int v
= VFC_FULL_VISIBLE
;
34 dist
= vfcP
[i
].dist(cv
);
35 if(dist
< -rad
) return VFC_NOT_VISIBLE
;
36 if(dist
< rad
) v
= VFC_PART_VISIBLE
;
40 if(dist
> rad
) return VFC_FOGGED
; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM
41 if(dist
> -rad
) v
= VFC_PART_VISIBLE
;
46 int isvisiblecube(const ivec
&o
, int size
)
48 int v
= VFC_FULL_VISIBLE
;
53 dist
= o
.dist(vfcP
[i
]);
54 if(dist
< -vfcDfar
[i
]*size
) return VFC_NOT_VISIBLE
;
55 if(dist
< -vfcDnear
[i
]*size
) v
= VFC_PART_VISIBLE
;
59 if(dist
> -vfcDnear
[4]*size
) return VFC_FOGGED
;
60 if(dist
> -vfcDfar
[4]*size
) v
= VFC_PART_VISIBLE
;
65 float vadist(vtxarray
*va
, const vec
&p
)
67 return p
.dist_to_bb(va
->bbmin
, va
->bbmax
);
72 static vtxarray
*vasort
[VASORTSIZE
];
74 void addvisibleva(vtxarray
*va
)
76 float dist
= vadist(va
, camera1
->o
);
77 va
->distance
= int(dist
); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
79 int hash
= min(int(dist
*VASORTSIZE
/hdr
.worldsize
), VASORTSIZE
-1);
80 vtxarray
**prev
= &vasort
[hash
], *cur
= vasort
[hash
];
82 while(cur
&& va
->distance
>= cur
->distance
)
95 vtxarray
**last
= &visibleva
;
96 loopi(VASORTSIZE
) if(vasort
[i
])
98 vtxarray
*va
= vasort
[i
];
100 while(va
->next
) va
= va
->next
;
105 void findvisiblevas(vector
<vtxarray
*> &vas
, bool resetocclude
= false)
109 vtxarray
&v
= *vas
[i
];
110 int prevvfc
= resetocclude
? VFC_NOT_VISIBLE
: v
.curvfc
;
111 v
.curvfc
= isvisiblecube(v
.o
, v
.size
);
112 if(v
.curvfc
!=VFC_NOT_VISIBLE
)
114 if(pvsoccluded(v
.o
, v
.size
))
116 v
.curvfc
+= PVS_FULL_VISIBLE
- VFC_FULL_VISIBLE
;
120 if(v
.children
.length()) findvisiblevas(v
.children
, prevvfc
>=VFC_NOT_VISIBLE
);
121 if(prevvfc
>=VFC_NOT_VISIBLE
)
123 v
.occluded
= !v
.texs
|| pvsoccluded(v
.geommin
, v
.geommax
) ? OCCLUDE_GEOM
: OCCLUDE_NOTHING
;
135 vfcDnear
[i
] = vfcDfar
[i
] = 0;
136 loopk(3) if(p
[k
] > 0) vfcDfar
[i
] += p
[k
];
137 else vfcDnear
[i
] += p
[k
];
141 void setvfcP(float yaw
, float pitch
, const vec
&camera
, float minyaw
= -M_PI
, float maxyaw
= M_PI
, float minpitch
= -M_PI
, float maxpitch
= M_PI
)
145 vfcP
[0].toplane(vec(yaw
+ M_PI
/2 - min(vfcfov
, -minyaw
), pitch
), camera
); // left plane
146 vfcP
[1].toplane(vec(yaw
- M_PI
/2 + min(vfcfov
, maxyaw
), pitch
), camera
); // right plane
147 vfcP
[2].toplane(vec(yaw
, pitch
+ M_PI
/2 - min(vfcfovy
, -minpitch
)), camera
); // top plane
148 vfcP
[3].toplane(vec(yaw
, pitch
- M_PI
/2 + min(vfcfovy
, maxpitch
)), camera
); // bottom plane
149 vfcP
[4].toplane(vec(yaw
, pitch
), camera
); // near/far planes
157 void reflectvfcP(float z
, float minyaw
, float maxyaw
, float minpitch
, float maxpitch
)
159 memcpy(oldvfcP
, vfcP
, sizeof(vfcP
));
161 if(z
< 0) setvfcP(camera1
->yaw
, camera1
->pitch
, camera1
->o
, minyaw
, maxyaw
, minpitch
, maxpitch
);
165 o
.z
= z
-(camera1
->o
.z
-z
);
166 setvfcP(camera1
->yaw
, -camera1
->pitch
, o
, minyaw
, maxyaw
, -maxpitch
, -minpitch
);
172 memcpy(vfcP
, oldvfcP
, sizeof(vfcP
));
176 extern vector
<vtxarray
*> varoot
;
178 void visiblecubes(float fov
, float fovy
)
180 memset(vasort
, 0, sizeof(vasort
));
182 vfcfov
= fov
*0.5f
*RAD
;
183 vfcfovy
= fovy
*0.5f
*RAD
;
185 // Calculate view frustrum: Only changes if resize, but...
186 setvfcP(camera1
->yaw
, camera1
->pitch
, camera1
->o
);
188 findvisiblevas(varoot
);
192 static inline bool insideva(const vtxarray
*va
, const vec
&v
, int margin
= 1)
194 int size
= va
->size
+ margin
;
195 return v
.x
>=va
->o
.x
-margin
&& v
.y
>=va
->o
.y
-margin
&& v
.z
>=va
->o
.z
-margin
&&
196 v
.x
<=va
->o
.x
+size
&& v
.y
<=va
->o
.y
+size
&& v
.z
<=va
->o
.z
+size
;
199 static ivec vaorigin
;
201 static void resetorigin()
203 vaorigin
= ivec(-1, -1, -1);
206 static bool setorigin(vtxarray
*va
, bool shadowmatrix
= false)
208 ivec o
= floatvtx
? ivec(0, 0, 0) : ivec(va
->o
).mask(~VVEC_INT_MASK
).add(0x8000>>VVEC_FRAC
);
214 glTranslatef(o
.x
, o
.y
, o
.z
);
215 static const float scale
= 1.0f
/ (1<<VVEC_FRAC
);
216 glScalef(scale
, scale
, scale
);
218 if(shadowmatrix
) adjustshadowmatrix(o
, scale
);
224 ///////// occlusion queries /////////////
226 #define MAXQUERY 2048
231 occludequery queries
[MAXQUERY
];
234 static queryframe queryframes
[2] = {{0, 0}, {0, 0}};
235 static uint flipquery
= 0;
239 return queryframes
[flipquery
].cur
;
244 flipquery
= (flipquery
+ 1) % 2;
245 queryframe
&qf
= queryframes
[flipquery
];
246 loopi(qf
.cur
) qf
.queries
[i
].owner
= NULL
;
250 occludequery
*newquery(void *owner
)
252 queryframe
&qf
= queryframes
[flipquery
];
255 if(qf
.max
>= MAXQUERY
) return NULL
;
256 glGenQueries_(1, &qf
.queries
[qf
.max
++].id
);
258 occludequery
*query
= &qf
.queries
[qf
.cur
++];
259 query
->owner
= owner
;
260 query
->fragments
= -1;
266 loopi(2) loopj(queryframes
[i
].max
) queryframes
[i
].queries
[j
].owner
= NULL
;
273 queryframe
&qf
= queryframes
[i
];
276 glDeleteQueries_(1, &qf
.queries
[j
].id
);
277 qf
.queries
[j
].owner
= NULL
;
283 VAR(oqfrags
, 0, 8, 64);
284 VAR(oqreflect
, 0, 4, 64);
286 bool checkquery(occludequery
*query
, bool nowait
)
289 if(query
->fragments
>= 0) fragments
= query
->fragments
;
295 glGetQueryObjectiv_(query
->id
, GL_QUERY_RESULT_AVAILABLE
, &avail
);
296 if(!avail
) return false;
298 glGetQueryObjectuiv_(query
->id
, GL_QUERY_RESULT_ARB
, &fragments
);
299 query
->fragments
= fragments
;
301 return fragments
< (uint
)(reflecting
|| refracting
? oqreflect
: oqfrags
);
304 void drawbb(const ivec
&bo
, const ivec
&br
, const vec
&camera
, int scale
, const ivec
&origin
)
310 int dim
= dimension(i
), coord
= dimcoord(i
);
314 if(camera
[dim
] < bo
[dim
] + br
[dim
]) continue;
316 else if(camera
[dim
] > bo
[dim
]) continue;
320 const ivec
&cc
= cubecoords
[fv
[i
][j
]];
321 glVertex3f(((cc
.x
? bo
.x
+br
.x
: bo
.x
) - origin
.x
) << scale
,
322 ((cc
.y
? bo
.y
+br
.y
: bo
.y
) - origin
.y
) << scale
,
323 ((cc
.z
? bo
.z
+br
.z
: bo
.z
) - origin
.z
) << scale
);
332 extern int octaentsize
;
334 static octaentities
*visiblemms
, **lastvisiblemms
;
336 void findvisiblemms(const vector
<extentity
*> &ents
)
338 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
340 if(!va
->mapmodels
|| va
->curvfc
>= VFC_FOGGED
|| va
->occluded
>= OCCLUDE_BB
) continue;
341 loopv(*va
->mapmodels
)
343 octaentities
*oe
= (*va
->mapmodels
)[i
];
344 if(isvisiblecube(oe
->o
, oe
->size
) >= VFC_FOGGED
|| pvsoccluded(oe
->bbmin
, ivec(oe
->bbmax
).sub(oe
->bbmin
))) continue;
346 bool occluded
= oe
->query
&& oe
->query
->owner
== oe
&& checkquery(oe
->query
);
352 *lastvisiblemms
= oe
;
353 lastvisiblemms
= &oe
->next
;
360 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
361 if(e
.visible
|| (e
.attr3
&& e
.triggerstate
== TRIGGER_DISAPPEARED
)) continue;
365 if(!visible
) continue;
367 oe
->distance
= int(camera1
->o
.dist_to_bb(oe
->o
, oe
->size
));
369 octaentities
**prev
= &visiblemms
, *cur
= visiblemms
;
370 while(cur
&& cur
->distance
>= 0 && oe
->distance
> cur
->distance
)
376 if(*prev
== NULL
) lastvisiblemms
= &oe
->next
;
386 extern bool getentboundingbox(extentity
&e
, ivec
&o
, ivec
&r
);
388 void rendermapmodel(extentity
&e
)
390 int anim
= ANIM_MAPMODEL
|ANIM_LOOP
, basetime
= 0;
391 if(e
.attr3
) switch(e
.triggerstate
)
393 case TRIGGER_RESET
: anim
= ANIM_TRIGGER
|ANIM_START
; break;
394 case TRIGGERING
: anim
= ANIM_TRIGGER
; basetime
= e
.lasttrigger
; break;
395 case TRIGGERED
: anim
= ANIM_TRIGGER
|ANIM_END
; break;
396 case TRIGGER_RESETTING
: anim
= ANIM_TRIGGER
|ANIM_REVERSE
; basetime
= e
.lasttrigger
; break;
398 mapmodelinfo
&mmi
= getmminfo(e
.attr2
);
399 if(&mmi
) rendermodel(&e
.light
, mmi
.name
, anim
, e
.o
, (float)((e
.attr1
+7)-(e
.attr1
+7)%15), 0, MDL_CULL_VFC
| MDL_CULL_DIST
| MDL_DYNLIGHT
, NULL
, NULL
, basetime
);
402 extern int reflectdist
;
404 static vector
<octaentities
*> renderedmms
;
406 vtxarray
*reflectedva
;
408 void renderreflectedmapmodels()
410 vector
<octaentities
*> reflectedmms
;
411 vector
<octaentities
*> &mms
= reflecting
? reflectedmms
: renderedmms
;
412 const vector
<extentity
*> &ents
= et
->getents();
416 for(vtxarray
*va
= reflectedva
; va
; va
= va
->rnext
)
418 if(!va
->mapmodels
|| va
->distance
> reflectdist
) continue;
419 loopv(*va
->mapmodels
) reflectedmms
.add((*va
->mapmodels
)[i
]);
424 octaentities
*oe
= mms
[i
];
425 if(reflecting
|| refracting
>0 ? oe
->bbmax
.z
<= reflectz
: oe
->bbmin
.z
>= reflectz
) continue;
426 if(isvisiblecube(oe
->o
, oe
->size
) >= VFC_FOGGED
) continue;
429 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
430 if(e
.visible
|| (e
.attr3
&& e
.triggerstate
== TRIGGER_DISAPPEARED
)) continue;
439 octaentities
*oe
= mms
[i
];
442 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
443 if(!e
.visible
) continue;
452 void rendermapmodels()
454 const vector
<extentity
*> &ents
= et
->getents();
457 lastvisiblemms
= &visiblemms
;
458 findvisiblemms(ents
);
460 static int skipoq
= 0;
461 bool doquery
= hasOQ
&& oqfrags
&& oqmm
;
463 renderedmms
.setsizenodelete(0);
465 for(octaentities
*oe
= visiblemms
; oe
; oe
= oe
->next
) if(oe
->distance
>=0)
469 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
470 if(!e
.visible
|| (e
.attr3
&& e
.triggerstate
== TRIGGER_DISAPPEARED
)) continue;
471 if(renderedmms
.empty() || renderedmms
.last()!=oe
)
474 oe
->query
= doquery
&& oe
->distance
>0 && !(++skipoq
%oqmm
) ? newquery(oe
) : NULL
;
475 if(oe
->query
) startmodelquery(oe
->query
);
480 if(renderedmms
.length() && renderedmms
.last()==oe
&& oe
->query
) endmodelquery();
484 bool colormask
= true;
485 for(octaentities
*oe
= visiblemms
; oe
; oe
= oe
->next
) if(oe
->distance
<0)
487 oe
->query
= doquery
? newquery(oe
) : NULL
;
488 if(!oe
->query
) continue;
491 glDepthMask(GL_FALSE
);
492 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
493 nocolorshader
->set();
496 startquery(oe
->query
);
497 drawbb(oe
->bbmin
, ivec(oe
->bbmax
).sub(oe
->bbmin
));
502 glDepthMask(GL_TRUE
);
503 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, fading
? GL_FALSE
: GL_TRUE
);
507 static inline bool bbinsideva(const ivec
&bo
, const ivec
&br
, vtxarray
*va
)
509 return bo
.x
>= va
->bbmin
.x
&& bo
.y
>= va
->bbmin
.y
&& va
->o
.z
>= va
->bbmin
.z
&&
510 bo
.x
+ br
.x
<= va
->bbmax
.x
&& bo
.y
+ br
.y
<= va
->bbmax
.y
&& bo
.z
+ br
.z
<= va
->bbmax
.z
;
513 static inline bool bboccluded(const ivec
&bo
, const ivec
&br
, cube
*c
, const ivec
&o
, int size
)
515 loopoctabox(o
, size
, bo
, br
)
517 ivec
co(i
, o
.x
, o
.y
, o
.z
, size
);
518 if(c
[i
].ext
&& c
[i
].ext
->va
)
520 vtxarray
*va
= c
[i
].ext
->va
;
521 if(va
->curvfc
>= VFC_FOGGED
|| (va
->occluded
>= OCCLUDE_BB
&& bbinsideva(bo
, br
, va
))) continue;
523 if(c
[i
].children
&& bboccluded(bo
, br
, c
[i
].children
, co
, size
>>1)) continue;
529 bool bboccluded(const ivec
&bo
, const ivec
&br
)
531 int diff
= (bo
.x
^(bo
.x
+br
.x
)) | (bo
.y
^(bo
.y
+br
.y
)) | (bo
.z
^(bo
.z
+br
.z
));
532 if(diff
&~((1<<worldscale
)-1)) return false;
533 int scale
= worldscale
-1;
534 if(diff
&(1<<scale
)) return bboccluded(bo
, br
, worldroot
, ivec(0, 0, 0), 1<<scale
);
535 cube
*c
= &worldroot
[octastep(bo
.x
, bo
.y
, bo
.z
, scale
)];
536 if(c
->ext
&& c
->ext
->va
)
538 vtxarray
*va
= c
->ext
->va
;
539 if(va
->curvfc
>= VFC_FOGGED
|| va
->occluded
>= OCCLUDE_BB
) return true;
542 while(c
->children
&& !(diff
&(1<<scale
)))
544 c
= &c
->children
[octastep(bo
.x
, bo
.y
, bo
.z
, scale
)];
545 if(c
->ext
&& c
->ext
->va
)
547 vtxarray
*va
= c
->ext
->va
;
548 if(va
->curvfc
>= VFC_FOGGED
|| va
->occluded
>= OCCLUDE_BB
) return true;
552 if(c
->children
) return bboccluded(bo
, br
, c
->children
, ivec(bo
).mask(~((2<<scale
)-1)), 1<<scale
);
556 VAR(outline
, 0, 0, 0xFFFFFF);
557 VAR(dtoutline
, 0, 1, 1);
561 notextureshader
->set();
563 glDisable(GL_TEXTURE_2D
);
564 glEnableClientState(GL_VERTEX_ARRAY
);
568 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
569 glColor3ub((outline
>>16)&0xFF, (outline
>>8)&0xFF, outline
&0xFF);
571 enablepolygonoffset(GL_POLYGON_OFFSET_LINE
);
573 if(!dtoutline
) glDisable(GL_DEPTH_TEST
);
576 vtxarray
*prev
= NULL
;
577 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
579 if(!va
->texs
|| va
->occluded
>= OCCLUDE_GEOM
) continue;
581 if(!prev
|| va
->vbuf
!= prev
->vbuf
)
586 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbuf
);
587 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, va
->ebuf
);
589 glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &va
->vdata
[0].x
);
592 drawvatris(va
, 3*va
->tris
, va
->edata
);
593 xtravertsva
+= va
->verts
;
598 if(!dtoutline
) glEnable(GL_DEPTH_TEST
);
600 disablepolygonoffset(GL_POLYGON_OFFSET_LINE
);
602 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
608 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
609 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
611 glDisableClientState(GL_VERTEX_ARRAY
);
612 glEnable(GL_TEXTURE_2D
);
614 defaultshader
->set();
617 void rendershadowmapreceivers()
621 static Shader
*shadowmapshader
= NULL
;
622 if(!shadowmapshader
) shadowmapshader
= lookupshaderbyname("shadowmapreceiver");
623 shadowmapshader
->set();
625 glDisable(GL_TEXTURE_2D
);
626 glEnableClientState(GL_VERTEX_ARRAY
);
629 glDepthMask(GL_FALSE
);
630 glDepthFunc(GL_GREATER
);
632 extern int ati_minmax_bug
;
633 if(!ati_minmax_bug
) glColorMask(GL_FALSE
, GL_FALSE
, GL_TRUE
, GL_FALSE
);
636 glBlendEquation_(GL_MAX_EXT
);
637 glBlendFunc(GL_ONE
, GL_ONE
);
642 vtxarray
*prev
= NULL
;
643 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
645 if(!va
->texs
|| va
->curvfc
>= VFC_FOGGED
|| !isshadowmapreceiver(va
)) continue;
647 if(!prev
|| va
->vbuf
!= prev
->vbuf
)
652 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbuf
);
653 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, va
->ebuf
);
655 glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &va
->vdata
[0].x
);
658 drawvatris(va
, 3*va
->tris
, va
->edata
);
659 xtravertsva
+= va
->verts
;
667 glBlendEquation_(GL_FUNC_ADD_EXT
);
669 glCullFace(GL_FRONT
);
670 glDepthMask(GL_TRUE
);
671 glDepthFunc(GL_LESS
);
673 if(!ati_minmax_bug
) glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
677 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
678 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
680 glDisableClientState(GL_VERTEX_ARRAY
);
681 glEnable(GL_TEXTURE_2D
);
684 void renderdepthobstacles(const vec
&bbmin
, const vec
&bbmax
, float scale
, float *ranges
, int numranges
)
686 float scales
[4] = { 0, 0, 0, 0 }, offsets
[4] = { 0, 0, 0, 0 };
689 SETSHADER(depthfxsplitworld
);
693 if(!i
) scales
[i
] = 1.0f
/scale
;
694 else scales
[i
] = scales
[i
-1]*256;
699 SETSHADER(depthfxworld
);
701 if(!numranges
) loopi(4) scales
[i
] = 1.0f
/scale
;
702 else loopi(numranges
)
704 scales
[i
] = 1.0f
/scale
;
705 offsets
[i
] = -ranges
[i
]/scale
;
708 setlocalparamfv("depthscale", SHPARAM_VERTEX
, 0, scales
);
709 setlocalparamfv("depthoffsets", SHPARAM_VERTEX
, 1, offsets
);
711 glDisable(GL_TEXTURE_2D
);
712 glEnableClientState(GL_VERTEX_ARRAY
);
717 vtxarray
*prev
= NULL
;
718 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
720 if(!va
->texs
|| va
->occluded
>= OCCLUDE_GEOM
||
721 va
->o
.x
> bbmax
.x
|| va
->o
.y
> bbmax
.y
|| va
->o
.z
> bbmax
.z
||
722 va
->o
.x
+ va
->size
< bbmin
.x
|| va
->o
.y
+ va
->size
< bbmin
.y
|| va
->o
.z
+ va
->size
< bbmin
.z
)
725 if(!prev
|| va
->vbuf
!= prev
->vbuf
)
730 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbuf
);
731 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, va
->ebuf
);
733 glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &va
->vdata
[0].x
);
736 drawvatris(va
, 3*va
->tris
, va
->edata
);
737 xtravertsva
+= va
->verts
;
746 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
747 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
749 glDisableClientState(GL_VERTEX_ARRAY
);
750 glEnable(GL_TEXTURE_2D
);
752 defaultshader
->set();
755 // [rotation][dimension] = vec4
756 float orientation_tangent
[6][3][4] =
758 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
759 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
760 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
761 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
762 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
763 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
765 float orientation_binormal
[6][3][4] =
767 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
768 { { 0, -1, 0, 0 }, { -1, 0, 0, 0 }, { -1, 0, 0, 0 } },
769 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
770 { { 0, 1, 0, 0 }, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
771 { { 0, 0, -1, 0 }, { 0, 0, -1, 0 }, { 0, 1, 0, 0 } },
772 { { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, -1, 0, 0 } },
777 bool colormask
, depthmask
, mtglow
, skippedglow
;
780 int diffusetmu
, lightmaptmu
, glowtmu
, fogtmu
, causticstmu
;
785 float texgenSk
, texgenSoff
, texgenTk
, texgenToff
;
788 int visibledynlights
;
791 renderstate() : colormask(true), depthmask(true), mtglow(false), skippedglow(false), vbuf(0), fogplane(-1), diffusetmu(0), lightmaptmu(1), glowtmu(-1), fogtmu(-1), causticstmu(-1), glowcolor(1, 1, 1), slot(NULL
), texgendim(-1), mttexgen(false), visibledynlights(0), dynlightmask(0)
793 loopk(4) color
[k
] = 1;
794 loopk(8) textures
[k
] = 0;
798 void renderquery(renderstate
&cur
, occludequery
*query
, vtxarray
*va
)
800 nocolorshader
->set();
801 if(cur
.colormask
) { cur
.colormask
= false; glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
); }
802 if(cur
.depthmask
) { cur
.depthmask
= false; glDepthMask(GL_FALSE
); }
804 vec
camera(camera1
->o
);
805 if(reflecting
) camera
.z
= reflectz
;
809 drawbb(va
->bbmin
, ivec(va
->bbmax
).sub(va
->bbmin
), camera
, vaorigin
.x
>= 0 ? VVEC_FRAC
: 0, vaorigin
.x
>= 0 ? vaorigin
: ivec(0, 0, 0));
816 RENDERPASS_LIGHTMAP
= 0,
826 const elementset
&es
;
832 geombatch(const elementset
&es
, ushort
*edata
, vtxarray
*va
)
833 : es(es
), slot(lookuptexture(es
.texture
)), edata(edata
), va(va
),
837 int compare(const geombatch
&b
) const
839 if(va
->vbuf
< b
.va
->vbuf
) return -1;
840 if(va
->vbuf
> b
.va
->vbuf
) return 1;
841 if(va
->dynlightmask
< b
.va
->dynlightmask
) return -1;
842 if(va
->dynlightmask
> b
.va
->dynlightmask
) return 1;
843 if(renderpath
!=R_FIXEDFUNCTION
)
845 if(slot
.shader
< b
.slot
.shader
) return -1;
846 if(slot
.shader
> b
.slot
.shader
) return 1;
847 if(slot
.params
.length() < b
.slot
.params
.length()) return -1;
848 if(slot
.params
.length() > b
.slot
.params
.length()) return 1;
850 if(es
.texture
< b
.es
.texture
) return -1;
851 if(es
.texture
> b
.es
.texture
) return 1;
852 if(es
.lmid
< b
.es
.lmid
) return -1;
853 if(es
.lmid
> b
.es
.lmid
) return 1;
854 if(es
.envmap
< b
.es
.envmap
) return -1;
855 if(es
.envmap
> b
.es
.envmap
) return 1;
860 static vector
<geombatch
> geombatches
;
861 static int firstbatch
= -1, numbatches
= 0;
863 static void mergetexs(vtxarray
*va
, elementset
*texs
= NULL
, int numtexs
= 0, ushort
*edata
= NULL
)
874 firstbatch
= geombatches
.length();
875 numbatches
= numtexs
;
878 geombatches
.add(geombatch(texs
[i
], edata
, va
)).next
= i
+1;
879 edata
+= texs
[i
].length
[5];
881 geombatches
.add(geombatch(texs
[numtexs
-1], edata
, va
));
885 int prevbatch
= -1, curbatch
= firstbatch
, curtex
= 0;
888 geombatch
&b
= geombatches
.add(geombatch(texs
[curtex
], edata
, va
));
889 edata
+= texs
[curtex
].length
[5];
893 dir
= b
.compare(geombatches
[curbatch
]);
895 prevbatch
= curbatch
;
896 curbatch
= geombatches
[curbatch
].next
;
900 int last
= curbatch
, next
;
903 next
= geombatches
[last
].batch
;
910 b
.next
= geombatches
[curbatch
].next
;
911 if(prevbatch
< 0) firstbatch
= geombatches
.length()-1;
912 else geombatches
[prevbatch
].next
= geombatches
.length()-1;
913 curbatch
= geombatches
.length()-1;
918 geombatches
[last
].batch
= geombatches
.length()-1;
925 if(prevbatch
< 0) firstbatch
= geombatches
.length()-1;
926 else geombatches
[prevbatch
].next
= geombatches
.length()-1;
927 prevbatch
= geombatches
.length()-1;
930 while(++curtex
< numtexs
);
933 static void mergeglowtexs(vtxarray
*va
)
936 ushort
*edata
= va
->edata
, *startdata
= NULL
;
939 elementset
&es
= va
->eslist
[i
];
940 Slot
&slot
= lookuptexture(es
.texture
, false);
941 if(slot
.texmask
&(1<<TEX_GLOW
) && !slot
.mtglowed
)
943 if(start
<0) { start
= i
; startdata
= edata
; }
947 mergetexs(va
, &va
->eslist
[start
], i
-start
, startdata
);
950 edata
+= es
.length
[5];
952 if(start
>=0) mergetexs(va
, &va
->eslist
[start
], va
->texs
-start
, startdata
);
955 static void changefogplane(renderstate
&cur
, int pass
, vtxarray
*va
)
957 if(renderpath
!=R_FIXEDFUNCTION
)
959 if(fading
|| fogging
)
961 float fogplane
= reflectz
- vaorigin
.z
;
962 if(cur
.fogplane
!=fogplane
)
964 cur
.fogplane
= fogplane
;
965 if(fogging
) setfogplane(1.0f
/(1<<VVEC_FRAC
), fogplane
, false, -0.25f
/(1<<VVEC_FRAC
), 0.5f
+ 0.25f
*fogplane
);
966 else setfogplane(0, 0, false, 0.25f
/(1<<VVEC_FRAC
), 0.5f
- 0.25f
*fogplane
);
970 else if(pass
==RENDERPASS_FOG
|| (cur
.fogtmu
>=0 && (pass
==RENDERPASS_LIGHTMAP
|| pass
==RENDERPASS_GLOW
)))
972 if(pass
==RENDERPASS_LIGHTMAP
) glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
973 else if(pass
==RENDERPASS_GLOW
) glActiveTexture_(GL_TEXTURE1_ARB
);
974 GLfloat s
[4] = { 0, 0, -1.0f
/(waterfog
<<VVEC_FRAC
), (reflectz
- vaorigin
.z
)/waterfog
};
975 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, s
);
976 if(pass
==RENDERPASS_LIGHTMAP
) glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
977 else if(pass
==RENDERPASS_GLOW
) glActiveTexture_(GL_TEXTURE0_ARB
);
981 static void changevbuf(renderstate
&cur
, int pass
, vtxarray
*va
)
983 if(setorigin(va
, pass
==RENDERPASS_LIGHTMAP
&& !envmapping
))
985 cur
.visibledynlights
= 0;
986 cur
.dynlightmask
= 0;
990 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbuf
);
991 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, va
->ebuf
);
995 glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &va
->vdata
[0].x
);
997 if(pass
==RENDERPASS_LIGHTMAP
)
999 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1000 glTexCoordPointer(2, GL_SHORT
, VTXSIZE
, floatvtx
? &((fvertex
*)va
->vdata
)[0].u
: &va
->vdata
[0].u
);
1001 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1003 if(renderpath
!=R_FIXEDFUNCTION
)
1005 glColorPointer(3, GL_UNSIGNED_BYTE
, VTXSIZE
, floatvtx
? &((fvertex
*)va
->vdata
)[0].n
: &va
->vdata
[0].n
);
1006 setenvparamf("camera", SHPARAM_VERTEX
, 4,
1007 (camera1
->o
.x
- vaorigin
.x
)*(1<<VVEC_FRAC
),
1008 (camera1
->o
.y
- vaorigin
.y
)*(1<<VVEC_FRAC
),
1009 (camera1
->o
.z
- vaorigin
.z
)*(1<<VVEC_FRAC
),
1015 static void changebatchtmus(renderstate
&cur
, int pass
, geombatch
&b
)
1017 bool changed
= false;
1018 extern bool brightengeom
;
1019 int lmid
= brightengeom
? LMID_BRIGHT
: b
.es
.lmid
;
1020 if(cur
.textures
[cur
.lightmaptmu
]!=lightmaptexs
[lmid
].id
)
1022 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1023 glBindTexture(GL_TEXTURE_2D
, cur
.textures
[cur
.lightmaptmu
] = lightmaptexs
[lmid
].id
);
1026 if(renderpath
!=R_FIXEDFUNCTION
)
1028 int tmu
= cur
.lightmaptmu
+1;
1029 if(b
.slot
.shader
->type
&SHADER_NORMALSLMS
)
1031 if(cur
.textures
[tmu
]!=lightmaptexs
[lmid
+1].id
)
1033 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
);
1034 glBindTexture(GL_TEXTURE_2D
, cur
.textures
[tmu
] = lightmaptexs
[lmid
+1].id
);
1039 if(b
.slot
.shader
->type
&SHADER_ENVMAP
&& b
.es
.envmap
!=EMID_CUSTOM
)
1041 GLuint emtex
= lookupenvmap(b
.es
.envmap
);
1042 if(cur
.textures
[tmu
]!=emtex
)
1044 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
);
1045 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB
, cur
.textures
[tmu
] = emtex
);
1050 if(changed
) glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1053 static void changeglow(renderstate
&cur
, int pass
, Slot
&slot
)
1055 vec color
= slot
.glowcolor
;
1056 if(slot
.pulseglowspeed
)
1058 float k
= lastmillis
*slot
.pulseglowspeed
;
1061 color
.lerp(color
, slot
.pulseglowcolor
, k
);
1063 if(pass
==RENDERPASS_GLOW
)
1065 if(cur
.glowcolor
!=color
) glColor3fv(color
.v
);
1069 if(cur
.glowcolor
!=color
)
1071 if(color
==vec(1, 1, 1))
1073 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1074 setuptmu(cur
.glowtmu
, "P + T");
1076 else if(hasTE3
|| hasTE4
)
1078 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1079 if(cur
.glowcolor
==vec(1, 1, 1))
1081 if(hasTE3
) setuptmu(cur
.glowtmu
, "TPK3");
1082 else if(hasTE4
) setuptmu(cur
.glowtmu
, "TKP14");
1084 colortmu(cur
.glowtmu
, color
.x
, color
.y
, color
.z
);
1088 slot
.mtglowed
= false;
1089 cur
.skippedglow
= true;
1093 else glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1094 if(!cur
.mtglow
) { glEnable(GL_TEXTURE_2D
); cur
.mtglow
= true; }
1095 slot
.mtglowed
= true;
1099 Slot::Tex
&t
= slot
.sts
[j
];
1100 if(t
.type
==TEX_GLOW
&& t
.combined
<0)
1102 if(cur
.textures
[cur
.glowtmu
]!=t
.t
->id
)
1103 glBindTexture(GL_TEXTURE_2D
, cur
.textures
[cur
.glowtmu
] = t
.t
->id
);
1107 cur
.glowcolor
= color
;
1110 static void changeslottmus(renderstate
&cur
, int pass
, Slot
&slot
)
1112 if(pass
==RENDERPASS_LIGHTMAP
|| pass
==RENDERPASS_COLOR
)
1114 GLuint diffusetex
= slot
.sts
.empty() ? notexture
->id
: slot
.sts
[0].t
->id
;
1115 if(cur
.textures
[cur
.diffusetmu
]!=diffusetex
)
1116 glBindTexture(GL_TEXTURE_2D
, cur
.textures
[cur
.diffusetmu
] = diffusetex
);
1119 if(renderpath
==R_FIXEDFUNCTION
)
1121 if(slot
.texmask
&(1<<TEX_GLOW
))
1123 if(pass
==RENDERPASS_LIGHTMAP
|| pass
==RENDERPASS_COLOR
)
1125 if(cur
.glowtmu
<0) { slot
.mtglowed
= false; cur
.skippedglow
= true; }
1126 else changeglow(cur
, pass
, slot
);
1128 else if(pass
==RENDERPASS_GLOW
&& !slot
.mtglowed
) changeglow(cur
, pass
, slot
);
1132 if(!(slot
.texmask
&(1<<TEX_GLOW
)) || !slot
.mtglowed
)
1134 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1135 glDisable(GL_TEXTURE_2D
);
1138 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1143 int tmu
= cur
.lightmaptmu
+1, envmaptmu
= -1;
1144 if(slot
.shader
->type
&SHADER_NORMALSLMS
) tmu
++;
1145 if(slot
.shader
->type
&SHADER_ENVMAP
) envmaptmu
= tmu
++;
1148 Slot::Tex
&t
= slot
.sts
[j
];
1149 if(t
.type
==TEX_DIFFUSE
|| t
.combined
>=0) continue;
1150 if(t
.type
==TEX_ENVMAP
)
1152 if(envmaptmu
>=0 && cur
.textures
[envmaptmu
]!=t
.t
->id
)
1154 glActiveTexture_(GL_TEXTURE0_ARB
+envmaptmu
);
1155 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB
, cur
.textures
[envmaptmu
] = t
.t
->id
);
1159 else if(cur
.textures
[tmu
]!=t
.t
->id
)
1161 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
);
1162 glBindTexture(GL_TEXTURE_2D
, cur
.textures
[tmu
] = t
.t
->id
);
1166 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1169 Texture
*curtex
= !cur
.slot
|| cur
.slot
->sts
.empty() ? notexture
: cur
.slot
->sts
[0].t
,
1170 *tex
= slot
.sts
.empty() ? notexture
: slot
.sts
[0].t
;
1171 if(!cur
.slot
|| slot
.sts
.empty() ||
1172 (curtex
->xs
!= tex
->xs
|| curtex
->ys
!= tex
->ys
||
1173 cur
.slot
->rotation
!= slot
.rotation
|| cur
.slot
->scale
!= slot
.scale
||
1174 cur
.slot
->xoffset
!= slot
.xoffset
|| cur
.slot
->yoffset
!= slot
.yoffset
||
1175 cur
.slot
->scrollS
!= slot
.scrollS
|| cur
.slot
->scrollT
!= slot
.scrollT
))
1177 float k
= 8.0f
/slot
.scale
/(1<<VVEC_FRAC
),
1178 xs
= slot
.rotation
>=2 && slot
.rotation
<=4 ? -tex
->xs
: tex
->xs
,
1179 ys
= (slot
.rotation
>=1 && slot
.rotation
<=2) || slot
.rotation
==5 ? -tex
->ys
: tex
->ys
;
1180 if((slot
.rotation
&5)==1)
1182 cur
.texgenSk
= k
/xs
; cur
.texgenSoff
= (slot
.scrollT
*lastmillis
*tex
->xs
- slot
.yoffset
)/xs
;
1183 cur
.texgenTk
= k
/ys
; cur
.texgenToff
= (slot
.scrollS
*lastmillis
*tex
->ys
- slot
.xoffset
)/ys
;
1187 cur
.texgenSk
= k
/xs
; cur
.texgenSoff
= (slot
.scrollS
*lastmillis
*tex
->xs
- slot
.xoffset
)/xs
;
1188 cur
.texgenTk
= k
/ys
; cur
.texgenToff
= (slot
.scrollT
*lastmillis
*tex
->ys
- slot
.yoffset
)/ys
;
1196 static void changeshader(renderstate
&cur
, Shader
*s
, Slot
&slot
, bool shadowed
)
1200 Shader
*g
= s
->hasvariant(min(s
->variants
[4].length()-1, cur
.visibledynlights
), 4);
1201 if(g
) g
->set(&slot
);
1204 static Shader
*noglareshader
= NULL
;
1205 if(!noglareshader
) noglareshader
= lookupshaderbyname("noglareworld");
1206 noglareshader
->set(&slot
);
1211 if(shadowed
) s
->variant(min(s
->variants
[3].length()-1, cur
.visibledynlights
), 3)->set(&slot
);
1212 else s
->variant(min(s
->variants
[2].length()-1, cur
.visibledynlights
), 2)->set(&slot
);
1214 else if(shadowed
) s
->variant(min(s
->variants
[1].length()-1, cur
.visibledynlights
), 1)->set(&slot
);
1215 else if(!cur
.visibledynlights
) s
->set(&slot
);
1216 else s
->variant(min(s
->variants
[0].length()-1, cur
.visibledynlights
-1))->set(&slot
);
1217 if(s
->type
&SHADER_GLSLANG
) cur
.texgendim
= -1;
1220 static void changetexgen(renderstate
&cur
, Slot
&slot
, int dim
)
1222 static const int si
[] = { 1, 0, 0 };
1223 static const int ti
[] = { 2, 2, 1 };
1225 GLfloat sgen
[4] = { 0.0f
, 0.0f
, 0.0f
, cur
.texgenSoff
},
1226 tgen
[4] = { 0.0f
, 0.0f
, 0.0f
, cur
.texgenToff
};
1227 int sdim
= si
[dim
], tdim
= ti
[dim
];
1228 if((slot
.rotation
&5)==1)
1230 sgen
[tdim
] = (dim
<= 1 ? -cur
.texgenSk
: cur
.texgenSk
);
1231 sgen
[3] += (vaorigin
[tdim
]<<VVEC_FRAC
)*sgen
[tdim
];
1232 tgen
[sdim
] = cur
.texgenTk
;
1233 tgen
[3] += (vaorigin
[sdim
]<<VVEC_FRAC
)*tgen
[sdim
];
1237 sgen
[sdim
] = cur
.texgenSk
;
1238 sgen
[3] += (vaorigin
[sdim
]<<VVEC_FRAC
)*sgen
[sdim
];
1239 tgen
[tdim
] = (dim
<= 1 ? -cur
.texgenTk
: cur
.texgenTk
);
1240 tgen
[3] += (vaorigin
[tdim
]<<VVEC_FRAC
)*tgen
[tdim
];
1243 if(renderpath
==R_FIXEDFUNCTION
)
1245 if(cur
.texgendim
!=dim
)
1247 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, sgen
);
1248 glTexGenfv(GL_T
, GL_OBJECT_PLANE
, tgen
);
1249 // KLUGE: workaround for buggy nvidia drivers
1250 // object planes are somehow invalid unless texgen is toggled
1251 extern int nvidia_texgen_bug
;
1252 if(nvidia_texgen_bug
)
1254 glDisable(GL_TEXTURE_GEN_S
);
1255 glDisable(GL_TEXTURE_GEN_T
);
1256 glEnable(GL_TEXTURE_GEN_S
);
1257 glEnable(GL_TEXTURE_GEN_T
);
1263 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1264 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, sgen
);
1265 glTexGenfv(GL_T
, GL_OBJECT_PLANE
, tgen
);
1266 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1267 cur
.mttexgen
= cur
.mtglow
;
1272 // have to pass in env, otherwise same problem as fixed function
1273 setlocalparamfv("texgenS", SHPARAM_VERTEX
, 0, sgen
);
1274 setlocalparamfv("texgenT", SHPARAM_VERTEX
, 1, tgen
);
1275 setlocalparamfv("orienttangent", SHPARAM_VERTEX
, 2, orientation_tangent
[slot
.rotation
][dim
]);
1276 setlocalparamfv("orientbinormal", SHPARAM_VERTEX
, 3, orientation_binormal
[slot
.rotation
][dim
]);
1279 cur
.texgendim
= dim
;
1282 struct batchdrawinfo
1285 ushort len
, minvert
, maxvert
;
1287 batchdrawinfo(geombatch
&b
, int dim
, ushort offset
, ushort len
)
1288 : edata(b
.edata
+ offset
), len(len
),
1289 minvert(b
.va
->shadowed
? b
.es
.minvert
[dim
] : min(b
.es
.minvert
[dim
], b
.es
.minvert
[dim
+1])),
1290 maxvert(b
.va
->shadowed
? b
.es
.maxvert
[dim
] : max(b
.es
.maxvert
[dim
], b
.es
.maxvert
[dim
+1]))
1294 static void renderbatch(renderstate
&cur
, int pass
, geombatch
&b
)
1296 static vector
<batchdrawinfo
> draws
[6];
1297 for(geombatch
*curbatch
= &b
;; curbatch
= &geombatches
[curbatch
->batch
])
1300 ushort offset
= 0, len
= 0;
1304 len
= curbatch
->es
.length
[dim
+ (curbatch
->va
->shadowed
? 0 : 1)] - offset
;
1305 if(len
) draws
[dim
].add(batchdrawinfo(*curbatch
, dim
, offset
, len
));
1308 if(curbatch
->va
->shadowed
)
1311 len
= curbatch
->es
.length
[dim
] - offset
;
1312 if(len
) draws
[dim
].add(batchdrawinfo(*curbatch
, dim
, offset
, len
));
1316 if(curbatch
->batch
< 0) break;
1320 bool rendered
= false;
1323 vector
<batchdrawinfo
> &draw
= draws
[2*dim
+ shadowed
];
1324 if(draw
.empty()) continue;
1328 if(renderpath
!=R_FIXEDFUNCTION
) changeshader(cur
, b
.slot
.shader
, b
.slot
, shadowed
!=0);
1331 if(cur
.texgendim
!=dim
|| cur
.mtglow
>cur
.mttexgen
)
1332 changetexgen(cur
, b
.slot
, dim
);
1337 batchdrawinfo
&info
= draw
[i
];
1338 drawtris(info
.len
, info
.edata
, info
.minvert
, info
.maxvert
);
1339 vtris
+= info
.len
/3;
1341 draw
.setsizenodelete(0);
1346 static void resetbatches()
1348 geombatches
.setsizenodelete(0);
1353 static void renderbatches(renderstate
&cur
, int pass
)
1356 int curbatch
= firstbatch
;
1359 if(!cur
.depthmask
) { cur
.depthmask
= true; glDepthMask(GL_TRUE
); }
1360 if(!cur
.colormask
) { cur
.colormask
= true; glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
); }
1362 while(curbatch
>= 0)
1364 geombatch
&b
= geombatches
[curbatch
];
1367 if(cur
.vbuf
!= b
.va
->vbuf
)
1369 changevbuf(cur
, pass
, b
.va
);
1370 changefogplane(cur
, pass
, b
.va
);
1372 if(pass
== RENDERPASS_LIGHTMAP
)
1374 changebatchtmus(cur
, pass
, b
);
1375 if(cur
.dynlightmask
!= b
.va
->dynlightmask
)
1377 cur
.visibledynlights
= setdynlights(b
.va
, vaorigin
);
1378 cur
.dynlightmask
= b
.va
->dynlightmask
;
1381 if(cur
.slot
!= &b
.slot
) changeslottmus(cur
, pass
, b
.slot
);
1383 renderbatch(cur
, pass
, b
);
1386 if(pass
== RENDERPASS_LIGHTMAP
&& cur
.mtglow
)
1388 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1389 glDisable(GL_TEXTURE_2D
);
1390 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1397 void renderzpass(renderstate
&cur
, vtxarray
*va
)
1399 if(cur
.vbuf
!=va
->vbuf
) changevbuf(cur
, RENDERPASS_Z
, va
);
1400 if(!cur
.depthmask
) { cur
.depthmask
= true; glDepthMask(GL_TRUE
); }
1401 if(cur
.colormask
) { cur
.colormask
= false; glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
); }
1403 extern int apple_glsldepth_bug
;
1404 if(renderpath
!=R_GLSLANG
|| !apple_glsldepth_bug
)
1406 nocolorshader
->set();
1407 drawvatris(va
, 3*va
->tris
, va
->edata
);
1411 static Shader
*nocolorglslshader
= NULL
;
1412 if(!nocolorglslshader
) nocolorglslshader
= lookupshaderbyname("nocolorglsl");
1413 Slot
*lastslot
= NULL
;
1414 int lastdraw
= 0, offset
= 0;
1417 Slot
&slot
= lookuptexture(va
->eslist
[i
].texture
);
1418 if(lastslot
&& (slot
.shader
->type
&SHADER_GLSLANG
) != (lastslot
->shader
->type
&SHADER_GLSLANG
) && offset
> lastdraw
)
1420 (lastslot
->shader
->type
&SHADER_GLSLANG
? nocolorglslshader
: nocolorshader
)->set();
1421 drawvatris(va
, offset
-lastdraw
, va
->edata
+lastdraw
);
1425 offset
+= va
->eslist
[i
].length
[5];
1427 if(offset
> lastdraw
)
1429 (lastslot
->shader
->type
&SHADER_GLSLANG
? nocolorglslshader
: nocolorshader
)->set();
1430 drawvatris(va
, offset
-lastdraw
, va
->edata
+lastdraw
);
1433 xtravertsva
+= va
->verts
;
1436 vector
<vtxarray
*> foggedvas
;
1438 #define startvaquery(va, flush) \
1442 occludequery *query = reflecting ? va->rquery : va->query; \
1446 startquery(query); \
1452 #define endvaquery(va, flush) \
1456 occludequery *query = reflecting ? va->rquery : va->query; \
1465 void renderfoggedvas(renderstate
&cur
, bool doquery
= false)
1467 static Shader
*fogshader
= NULL
;
1468 if(!fogshader
) fogshader
= lookupshaderbyname("fogworld");
1471 glDisable(GL_TEXTURE_2D
);
1474 getwatercolour(wcol
);
1479 vtxarray
*va
= foggedvas
[i
];
1480 if(cur
.vbuf
!=va
->vbuf
) changevbuf(cur
, RENDERPASS_FOG
, va
);
1482 if(doquery
) startvaquery(va
, );
1483 drawvatris(va
, 3*va
->tris
, va
->edata
);
1485 if(doquery
) endvaquery(va
, );
1488 glEnable(GL_TEXTURE_2D
);
1490 foggedvas
.setsizenodelete(0);
1493 VAR(batchgeom
, 0, 1, 1);
1495 void renderva(renderstate
&cur
, vtxarray
*va
, int pass
= RENDERPASS_LIGHTMAP
, bool fogpass
= false, bool doquery
= false)
1499 case RENDERPASS_GLOW
:
1500 if(!(va
->texmask
&(1<<TEX_GLOW
))) return;
1502 if(!batchgeom
&& geombatches
.length()) renderbatches(cur
, pass
);
1505 case RENDERPASS_COLOR
:
1506 case RENDERPASS_LIGHTMAP
:
1507 vverts
+= va
->verts
;
1508 va
->shadowed
= false;
1509 va
->dynlightmask
= 0;
1510 if(fogpass
? va
->geommax
.z
<=reflectz
-waterfog
: va
->curvfc
==VFC_FOGGED
)
1515 if(renderpath
!=R_FIXEDFUNCTION
&& !envmapping
)
1517 va
->shadowed
= isshadowmapreceiver(va
);
1518 calcdynlightmask(va
);
1520 if(doquery
) startvaquery(va
, { if(geombatches
.length()) renderbatches(cur
, pass
); });
1522 if(doquery
) endvaquery(va
, { if(geombatches
.length()) renderbatches(cur
, pass
); });
1523 else if(!batchgeom
&& geombatches
.length()) renderbatches(cur
, pass
);
1526 case RENDERPASS_FOG
:
1527 if(cur
.vbuf
!=va
->vbuf
)
1529 changevbuf(cur
, pass
, va
);
1530 changefogplane(cur
, pass
, va
);
1532 drawvatris(va
, 3*va
->tris
, va
->edata
);
1533 xtravertsva
+= va
->verts
;
1536 case RENDERPASS_CAUSTICS
:
1537 if(cur
.vbuf
!=va
->vbuf
) changevbuf(cur
, pass
, va
);
1538 drawvatris(va
, 3*va
->tris
, va
->edata
);
1539 xtravertsva
+= va
->verts
;
1543 if(doquery
) startvaquery(va
, );
1544 renderzpass(cur
, va
);
1545 if(doquery
) endvaquery(va
, );
1550 VAR(oqdist
, 0, 256, 1024);
1551 VAR(zpass
, 0, 1, 1);
1552 VAR(glowpass
, 0, 1, 1);
1554 extern int ati_texgen_bug
;
1556 static void setuptexgen(int dims
= 2)
1558 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_OBJECT_LINEAR
);
1559 glEnable(GL_TEXTURE_GEN_S
);
1562 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_OBJECT_LINEAR
);
1563 glEnable(GL_TEXTURE_GEN_T
);
1564 if(ati_texgen_bug
) glEnable(GL_TEXTURE_GEN_R
); // should not be needed, but apparently makes some ATI drivers happy
1568 static void disabletexgen(int dims
= 2)
1570 glDisable(GL_TEXTURE_GEN_S
);
1573 glDisable(GL_TEXTURE_GEN_T
);
1574 if(ati_texgen_bug
) glDisable(GL_TEXTURE_GEN_R
);
1582 extern int bilinear
;
1583 uchar buf
[2*256] = { 255, 0, 255, 255 };
1584 if(!bilinear
) loopi(256) { buf
[2*i
] = 255; buf
[2*i
+1] = i
; }
1585 glGenTextures(1, &fogtex
);
1586 createtexture(fogtex
, bilinear
? 2 : 256, 1, buf
, 3, false, GL_LUMINANCE_ALPHA
, GL_TEXTURE_1D
);
1589 #define NUMCAUSTICS 32
1591 VARR(causticscale
, 0, 100, 10000);
1592 VARR(causticmillis
, 0, 75, 1000);
1593 VARP(caustics
, 0, 1, 1);
1595 static Texture
*caustictex
[NUMCAUSTICS
] = { NULL
};
1599 if(caustictex
[0]) return;
1603 renderpath
==R_FIXEDFUNCTION
?
1604 "<mad:0.6,0.4>packages/caustics/caust%.2d.png" :
1605 "<mad:-0.6,0.6>packages/caustics/caust%.2d.png",
1607 caustictex
[i
] = textureload(name
);
1613 vaclearc(worldroot
);
1615 if(fogtex
) { glDeleteTextures(1, &fogtex
); fogtex
= 0; }
1616 loopi(NUMCAUSTICS
) caustictex
[i
] = NULL
;
1619 void setupcaustics(int tmu
, float blend
, GLfloat
*color
= NULL
)
1621 if(!caustictex
[0]) loadcaustics();
1623 GLfloat s
[4] = { 0.011f
, 0, 0.0066f
, 0 };
1624 GLfloat t
[4] = { 0, 0.011f
, 0.0066f
, 0 };
1627 s
[k
] *= 100.0f
/(causticscale
<<VVEC_FRAC
);
1628 t
[k
] *= 100.0f
/(causticscale
<<VVEC_FRAC
);
1630 int tex
= (lastmillis
/causticmillis
)%NUMCAUSTICS
;
1631 float frac
= float(lastmillis
%causticmillis
)/causticmillis
;
1632 if(color
) color
[3] = frac
;
1633 else glColor4f(1, 1, 1, frac
);
1636 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
+i
);
1637 glEnable(GL_TEXTURE_2D
);
1638 glBindTexture(GL_TEXTURE_2D
, caustictex
[(tex
+i
)%NUMCAUSTICS
]->id
);
1639 if(renderpath
==R_FIXEDFUNCTION
)
1642 setuptmu(tmu
+i
, !i
? "= T" : "T , P @ Ca");
1643 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, s
);
1644 glTexGenfv(GL_T
, GL_OBJECT_PLANE
, t
);
1647 if(renderpath
!=R_FIXEDFUNCTION
)
1649 static Shader
*causticshader
= NULL
;
1650 if(!causticshader
) causticshader
= lookupshaderbyname("caustic");
1651 causticshader
->set();
1652 setlocalparamfv("texgenS", SHPARAM_VERTEX
, 0, s
);
1653 setlocalparamfv("texgenT", SHPARAM_VERTEX
, 1, t
);
1654 setlocalparamf("frameoffset", SHPARAM_PIXEL
, 0, blend
*(1-frac
), blend
*frac
, blend
);
1658 void setupTMUs(renderstate
&cur
, float causticspass
, bool fogpass
)
1660 if(!reflecting
&& !refracting
&& !envmapping
&& shadowmap
&& hasFBO
)
1662 glDisableClientState(GL_VERTEX_ARRAY
);
1666 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
1667 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
1672 glEnableClientState(GL_VERTEX_ARRAY
);
1675 if(renderpath
==R_FIXEDFUNCTION
)
1677 if(nolights
) cur
.lightmaptmu
= -1;
1680 if(maxtmus
>=4 && causticspass
>=1)
1682 cur
.causticstmu
= 0;
1684 cur
.lightmaptmu
= 3;
1687 if(fogpass
) cur
.fogtmu
= 4;
1688 else if(glowpass
) cur
.glowtmu
= 4;
1691 else if(fogpass
&& causticspass
<1) cur
.fogtmu
= 2;
1692 else if(glowpass
) cur
.glowtmu
= 2;
1696 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1698 setuptmu(cur
.glowtmu
, "P + T");
1702 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
1703 glEnable(GL_TEXTURE_1D
);
1705 setuptmu(cur
.fogtmu
, "C , P @ Ta");
1706 if(!fogtex
) createfogtex();
1707 glBindTexture(GL_TEXTURE_1D
, fogtex
);
1709 getwatercolour(wcol
);
1710 loopk(3) cur
.color
[k
] = wcol
[k
]/255.0f
;
1712 if(cur
.causticstmu
>=0) setupcaustics(cur
.causticstmu
, causticspass
, cur
.color
);
1716 // need to invalidate vertex params in case they were used somewhere else for streaming params
1717 invalidateenvparams(SHPARAM_VERTEX
, 10, RESERVEDSHADERPARAMS
+ MAXSHADERPARAMS
- 10);
1718 glEnableClientState(GL_COLOR_ARRAY
);
1719 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB
+i
); glEnable(GL_TEXTURE_2D
); }
1720 glActiveTexture_(GL_TEXTURE0_ARB
);
1721 setenvparamf("ambient", SHPARAM_PIXEL
, 5, hdr
.ambient
/255.0f
, hdr
.ambient
/255.0f
, hdr
.ambient
/255.0f
);
1722 setenvparamf("millis", SHPARAM_VERTEX
, 6, lastmillis
/1000.0f
, lastmillis
/1000.0f
, lastmillis
/1000.0f
);
1725 glColor4fv(cur
.color
);
1727 if(cur
.lightmaptmu
>=0)
1729 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1730 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1732 setuptmu(cur
.lightmaptmu
, "P * T x 2");
1733 glEnable(GL_TEXTURE_2D
);
1734 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
1735 glMatrixMode(GL_TEXTURE
);
1737 glScalef(1.0f
/SHRT_MAX
, 1.0f
/SHRT_MAX
, 1.0f
);
1738 glMatrixMode(GL_MODELVIEW
);
1740 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1741 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1742 glEnable(GL_TEXTURE_2D
);
1743 setuptmu(cur
.diffusetmu
, cur
.diffusetmu
>0 ? "P * T" : "= T");
1746 if(renderpath
==R_FIXEDFUNCTION
) setuptexgen();
1749 void cleanupTMUs(renderstate
&cur
)
1751 if(cur
.lightmaptmu
>=0)
1753 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1754 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1756 resettmu(cur
.lightmaptmu
);
1757 glDisable(GL_TEXTURE_2D
);
1758 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
1759 glMatrixMode(GL_TEXTURE
);
1761 glMatrixMode(GL_MODELVIEW
);
1765 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1766 resettmu(cur
.glowtmu
);
1768 glDisable(GL_TEXTURE_2D
);
1772 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
1773 resettmu(cur
.fogtmu
);
1775 glDisable(GL_TEXTURE_1D
);
1777 if(cur
.causticstmu
>=0) loopi(2)
1779 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.causticstmu
+i
);
1780 resettmu(cur
.causticstmu
+i
);
1782 glDisable(GL_TEXTURE_2D
);
1785 if(cur
.lightmaptmu
>=0)
1787 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1788 resettmu(cur
.diffusetmu
);
1789 glDisable(GL_TEXTURE_2D
);
1792 if(renderpath
==R_FIXEDFUNCTION
) disabletexgen();
1795 glDisableClientState(GL_COLOR_ARRAY
);
1796 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB
+i
); glDisable(GL_TEXTURE_2D
); }
1799 if(cur
.lightmaptmu
>=0)
1801 glActiveTexture_(GL_TEXTURE0_ARB
);
1802 glClientActiveTexture_(GL_TEXTURE0_ARB
);
1803 glEnable(GL_TEXTURE_2D
);
1807 #define FIRSTVA (reflecting ? reflectedva : visibleva)
1808 #define NEXTVA (reflecting ? va->rnext : va->next)
1810 void rendergeommultipass(renderstate
&cur
, int pass
, bool fogpass
)
1813 for(vtxarray
*va
= FIRSTVA
; va
; va
= NEXTVA
)
1815 if(!va
->texs
|| va
->occluded
>= OCCLUDE_GEOM
) continue;
1818 if(refracting
< 0 ? va
->geommin
.z
> reflectz
: va
->geommax
.z
<= reflectz
) continue;
1819 if(isvisiblecube(va
->o
, va
->size
) >= VFC_NOT_VISIBLE
) continue;
1820 if((!hasOQ
|| !oqfrags
) && va
->distance
> reflectdist
) break;
1824 if(va
->geommax
.z
<= reflectz
|| (va
->rquery
&& checkquery(va
->rquery
))) continue;
1826 if(fogpass
? va
->geommax
.z
<= reflectz
-waterfog
: va
->curvfc
==VFC_FOGGED
) continue;
1827 renderva(cur
, va
, pass
, fogpass
);
1829 if(geombatches
.length()) renderbatches(cur
, pass
);
1832 VAR(oqgeom
, 0, 1, 1);
1833 VAR(oqbatch
, 0, 1, 1);
1835 void rendergeom(float causticspass
, bool fogpass
)
1839 if(causticspass
&& ((renderpath
==R_FIXEDFUNCTION
&& maxtmus
<2) || !causticscale
|| !causticmillis
)) causticspass
= 0;
1841 glEnableClientState(GL_VERTEX_ARRAY
);
1843 if(!reflecting
&& !refracting
)
1849 bool doOQ
= reflecting
? hasOQ
&& oqfrags
&& oqreflect
: !refracting
&& zpass
!=0;
1852 setupTMUs(cur
, causticspass
, fogpass
);
1853 if(shadowmap
) pushshadowmap();
1864 for(vtxarray
*va
= FIRSTVA
; va
; va
= NEXTVA
)
1866 if(!va
->texs
) continue;
1869 if((refracting
< 0 ? va
->geommin
.z
> reflectz
: va
->geommax
.z
<= reflectz
) || va
->occluded
>= OCCLUDE_GEOM
) continue;
1870 if(isvisiblecube(va
->o
, va
->size
) >= VFC_NOT_VISIBLE
) continue;
1871 if((!hasOQ
|| !oqfrags
) && va
->distance
> reflectdist
) break;
1875 if(va
->geommax
.z
<= reflectz
) continue;
1878 va
->rquery
= newquery(&va
->rquery
);
1879 if(!va
->rquery
) continue;
1880 if(va
->occluded
>= OCCLUDE_BB
|| va
->curvfc
>= VFC_NOT_VISIBLE
)
1882 renderquery(cur
, va
->rquery
, va
);
1887 else if(hasOQ
&& oqfrags
&& (zpass
|| va
->distance
> oqdist
) && !insideva(va
, camera1
->o
) && oqgeom
)
1889 if(!zpass
&& va
->query
&& va
->query
->owner
== va
)
1891 if(checkquery(va
->query
)) va
->occluded
= min(va
->occluded
+1, int(OCCLUDE_BB
));
1892 else va
->occluded
= pvsoccluded(va
->geommin
, va
->geommax
) ? OCCLUDE_GEOM
: OCCLUDE_NOTHING
;
1894 if(zpass
&& oqbatch
)
1896 if(va
->parent
&& va
->parent
->occluded
>= OCCLUDE_BB
)
1899 va
->occluded
= OCCLUDE_PARENT
;
1902 bool succeeded
= false;
1903 if(va
->query
&& va
->query
->owner
== va
&& checkquery(va
->query
))
1905 va
->occluded
= min(va
->occluded
+1, int(OCCLUDE_BB
));
1908 va
->query
= newquery(va
);
1909 if(!va
->query
|| !succeeded
)
1910 va
->occluded
= pvsoccluded(va
->geommin
, va
->geommax
) ? OCCLUDE_GEOM
: OCCLUDE_NOTHING
;
1911 if(va
->occluded
>= OCCLUDE_GEOM
)
1913 if(va
->query
) renderquery(cur
, va
->query
, va
);
1917 else if(zpass
&& va
->parent
&&
1918 (va
->parent
->occluded
== OCCLUDE_PARENT
||
1919 (va
->parent
->occluded
>= OCCLUDE_BB
&&
1920 va
->parent
->query
&& va
->parent
->query
->owner
== va
->parent
&& va
->parent
->query
->fragments
< 0)))
1923 if(va
->occluded
>= OCCLUDE_GEOM
|| pvsoccluded(va
->geommin
, va
->geommax
))
1925 va
->occluded
= OCCLUDE_PARENT
;
1929 else if(va
->occluded
>= OCCLUDE_GEOM
)
1931 va
->query
= newquery(va
);
1932 if(va
->query
) renderquery(cur
, va
->query
, va
);
1935 else va
->query
= newquery(va
);
1940 va
->occluded
= pvsoccluded(va
->geommin
, va
->geommax
) ? OCCLUDE_GEOM
: OCCLUDE_NOTHING
;
1941 if(va
->occluded
>= OCCLUDE_GEOM
) continue;
1944 renderva(cur
, va
, doOQ
? RENDERPASS_Z
: (nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
), fogpass
, true);
1947 if(geombatches
.length()) renderbatches(cur
, nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
);
1949 if(!cur
.colormask
) { cur
.colormask
= true; glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
); }
1950 if(!cur
.depthmask
) { cur
.depthmask
= true; glDepthMask(GL_TRUE
); }
1954 setupTMUs(cur
, causticspass
, fogpass
);
1962 glDepthFunc(GL_LEQUAL
);
1965 for(vtxarray
**prevva
= &FIRSTVA
, *va
= FIRSTVA
; va
; prevva
= &NEXTVA
, va
= NEXTVA
)
1967 if(!va
->texs
) continue;
1970 if(va
->geommax
.z
<= reflectz
) continue;
1971 if(va
->rquery
&& checkquery(va
->rquery
))
1973 if(va
->occluded
>= OCCLUDE_BB
|| va
->curvfc
>= VFC_NOT_VISIBLE
) *prevva
= va
->rnext
;
1979 if(va
->occluded
>= OCCLUDE_GEOM
) continue;
1981 else if(va
->parent
&& va
->parent
->occluded
>= OCCLUDE_BB
&& (!va
->parent
->query
|| va
->parent
->query
->fragments
>= 0))
1984 va
->occluded
= OCCLUDE_BB
;
1989 if(va
->query
&& checkquery(va
->query
)) va
->occluded
= min(va
->occluded
+1, int(OCCLUDE_BB
));
1990 else va
->occluded
= pvsoccluded(va
->geommin
, va
->geommax
) ? OCCLUDE_GEOM
: OCCLUDE_NOTHING
;
1991 if(va
->occluded
>= OCCLUDE_GEOM
) continue;
1994 renderva(cur
, va
, nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
, fogpass
);
1996 if(geombatches
.length()) renderbatches(cur
, nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
);
1997 if(oqbatch
&& !reflecting
) for(vtxarray
**prevva
= &FIRSTVA
, *va
= FIRSTVA
; va
; prevva
= &NEXTVA
, va
= NEXTVA
)
1999 if(!va
->texs
|| va
->occluded
< OCCLUDE_GEOM
) continue;
2000 else if(va
->query
&& checkquery(va
->query
)) continue;
2001 else if(va
->parent
&& (va
->parent
->occluded
>= OCCLUDE_BB
||
2002 (va
->parent
->occluded
>= OCCLUDE_GEOM
&& va
->parent
->query
&& checkquery(va
->parent
->query
))))
2004 va
->occluded
= OCCLUDE_BB
;
2009 va
->occluded
= pvsoccluded(va
->geommin
, va
->geommax
) ? OCCLUDE_GEOM
: OCCLUDE_NOTHING
;
2010 if(va
->occluded
>= OCCLUDE_GEOM
) continue;
2012 renderva(cur
, va
, nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
, fogpass
);
2014 if(geombatches
.length()) renderbatches(cur
, nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
);
2016 if(foggedvas
.empty()) glDepthFunc(GL_LESS
);
2019 if(shadowmap
) popshadowmap();
2023 if(foggedvas
.length())
2025 renderfoggedvas(cur
, !doOQ
);
2026 if(doOQ
) glDepthFunc(GL_LESS
);
2029 if(renderpath
==R_FIXEDFUNCTION
? (glowpass
&& cur
.skippedglow
) || (causticspass
>=1 && cur
.causticstmu
<0) || (fogpass
&& cur
.fogtmu
<0) : causticspass
)
2031 glDepthFunc(GL_LEQUAL
);
2032 glDepthMask(GL_FALSE
);
2034 static GLfloat zerofog
[4] = { 0, 0, 0, 1 }, onefog
[4] = { 1, 1, 1, 1 };
2036 glGetFloatv(GL_FOG_COLOR
, oldfogc
);
2038 if(renderpath
==R_FIXEDFUNCTION
&& glowpass
&& cur
.skippedglow
)
2040 glBlendFunc(GL_ONE
, GL_ONE
);
2041 glFogfv(GL_FOG_COLOR
, zerofog
);
2045 setuptmu(0, "C * T");
2046 glActiveTexture_(GL_TEXTURE1_ARB
);
2047 glEnable(GL_TEXTURE_1D
);
2049 setuptmu(1, "P * T~a");
2050 if(!fogtex
) createfogtex();
2051 glBindTexture(GL_TEXTURE_1D
, fogtex
);
2052 glActiveTexture_(GL_TEXTURE0_ARB
);
2054 cur
.glowcolor
= vec(-1, -1, -1);
2056 rendergeommultipass(cur
, RENDERPASS_GLOW
, fogpass
);
2061 glActiveTexture_(GL_TEXTURE1_ARB
);
2064 glDisable(GL_TEXTURE_1D
);
2065 glActiveTexture_(GL_TEXTURE0_ARB
);
2069 if(renderpath
==R_FIXEDFUNCTION
? causticspass
>=1 && cur
.causticstmu
<0 : causticspass
)
2071 setupcaustics(0, causticspass
);
2072 glBlendFunc(GL_ZERO
, renderpath
==R_FIXEDFUNCTION
? GL_SRC_COLOR
: GL_ONE_MINUS_SRC_COLOR
);
2073 glFogfv(GL_FOG_COLOR
, renderpath
==R_FIXEDFUNCTION
? onefog
: zerofog
);
2074 if(fading
) glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_FALSE
);
2075 rendergeommultipass(cur
, RENDERPASS_CAUSTICS
, fogpass
);
2076 if(fading
) glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
2079 glActiveTexture_(GL_TEXTURE0_ARB
+i
);
2081 if(renderpath
==R_FIXEDFUNCTION
|| !i
)
2086 if(i
) glDisable(GL_TEXTURE_2D
);
2088 glActiveTexture_(GL_TEXTURE0_ARB
);
2091 if(renderpath
==R_FIXEDFUNCTION
&& fogpass
&& cur
.fogtmu
<0)
2093 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
2094 glDisable(GL_TEXTURE_2D
);
2095 glEnable(GL_TEXTURE_1D
);
2097 if(!fogtex
) createfogtex();
2098 glBindTexture(GL_TEXTURE_1D
, fogtex
);
2101 getwatercolour(wcol
);
2103 rendergeommultipass(cur
, RENDERPASS_FOG
, fogpass
);
2105 glDisable(GL_TEXTURE_1D
);
2106 glEnable(GL_TEXTURE_2D
);
2109 glFogfv(GL_FOG_COLOR
, oldfogc
);
2110 glDisable(GL_BLEND
);
2111 glDepthFunc(GL_LESS
);
2112 glDepthMask(GL_TRUE
);
2119 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
2120 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
2122 glDisableClientState(GL_VERTEX_ARRAY
);
2125 void findreflectedvas(vector
<vtxarray
*> &vas
, int prevvfc
= VFC_PART_VISIBLE
)
2127 bool doOQ
= hasOQ
&& oqfrags
&& oqreflect
;
2130 vtxarray
*va
= vas
[i
];
2131 if(prevvfc
>= VFC_NOT_VISIBLE
) va
->curvfc
= prevvfc
;
2132 if(va
->curvfc
== VFC_FOGGED
|| va
->curvfc
== PVS_FOGGED
|| va
->o
.z
+va
->size
<= reflectz
|| isvisiblecube(va
->o
, va
->size
) >= VFC_FOGGED
) continue;
2134 if(va
->curvfc
== VFC_FULL_VISIBLE
)
2136 if(va
->occluded
>= OCCLUDE_BB
) continue;
2137 if(va
->occluded
>= OCCLUDE_GEOM
) render
= false;
2139 else if(va
->curvfc
== PVS_FULL_VISIBLE
) continue;
2142 if(va
->curvfc
>= VFC_NOT_VISIBLE
) va
->distance
= (int)vadist(va
, camera1
->o
);
2143 if(!doOQ
&& va
->distance
> reflectdist
) continue;
2145 vtxarray
**vprev
= &reflectedva
, *vcur
= reflectedva
;
2146 while(vcur
&& va
->distance
> vcur
->distance
)
2148 vprev
= &vcur
->rnext
;
2154 if(va
->children
.length()) findreflectedvas(va
->children
, va
->curvfc
);
2158 void renderreflectedgeom(bool causticspass
, bool fogpass
)
2163 findreflectedvas(varoot
);
2164 rendergeom(causticspass
? 1 : 0, fogpass
);
2166 else rendergeom(causticspass
? 1 : 0, fogpass
);
2169 static vtxarray
*prevskyva
= NULL
;
2171 void renderskyva(vtxarray
*va
, bool explicitonly
= false)
2173 if(!prevskyva
|| va
->vbuf
!= prevskyva
->vbuf
)
2177 glEnableClientState(GL_VERTEX_ARRAY
);
2185 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbuf
);
2186 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, va
->skybuf
);
2188 glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &va
->vdata
[0].x
);
2191 drawvatris(va
, explicitonly
? va
->explicitsky
: va
->sky
+va
->explicitsky
, explicitonly
? va
->skydata
+va
->sky
: va
->skydata
);
2193 if(!explicitonly
) xtraverts
+= va
->sky
/3;
2194 xtraverts
+= va
->explicitsky
/3;
2199 int renderedsky
= 0, renderedexplicitsky
= 0, renderedskyfaces
= 0, renderedskyclip
= INT_MAX
;
2201 static inline void updateskystats(vtxarray
*va
)
2203 renderedsky
+= va
->sky
;
2204 renderedexplicitsky
+= va
->explicitsky
;
2205 renderedskyfaces
|= va
->skyfaces
&0x3F;
2206 if(!(va
->skyfaces
&0x1F) || camera1
->o
.z
< va
->skyclip
) renderedskyclip
= min(renderedskyclip
, va
->skyclip
);
2207 else renderedskyclip
= 0;
2210 void renderreflectedskyvas(vector
<vtxarray
*> &vas
, int prevvfc
= VFC_PART_VISIBLE
)
2214 vtxarray
*va
= vas
[i
];
2215 if(prevvfc
>= VFC_NOT_VISIBLE
) va
->curvfc
= prevvfc
;
2216 if((va
->curvfc
== VFC_FULL_VISIBLE
&& va
->occluded
>= OCCLUDE_BB
) || va
->curvfc
==PVS_FULL_VISIBLE
) continue;
2217 if(va
->o
.z
+va
->size
<= reflectz
|| isvisiblecube(va
->o
, va
->size
) == VFC_NOT_VISIBLE
) continue;
2218 if(va
->sky
+va
->explicitsky
)
2223 if(va
->children
.length()) renderreflectedskyvas(va
->children
, va
->curvfc
);
2227 bool rendersky(bool explicitonly
)
2230 renderedsky
= renderedexplicitsky
= renderedskyfaces
= 0;
2231 renderedskyclip
= INT_MAX
;
2235 renderreflectedskyvas(varoot
);
2237 else for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
2239 if((va
->occluded
>= OCCLUDE_BB
&& va
->skyfaces
&0x80) || !(va
->sky
+va
->explicitsky
)) continue;
2241 // count possibly visible sky even if not actually rendered
2243 if(explicitonly
&& !va
->explicitsky
) continue;
2244 renderskyva(va
, explicitonly
);
2250 glDisableClientState(GL_VERTEX_ARRAY
);
2253 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
2254 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
2258 return renderedsky
+renderedexplicitsky
> 0;