1 // renderva.cpp: handles the occlusion and rendering of vertex arrays
6 void drawvatris(vtxarray
*va
, GLsizei numindices
, const GLvoid
*indices
, ushort minvert
= 0, ushort maxvert
= 0)
8 if(!minvert
&& !maxvert
) { minvert
= va
->minvert
; maxvert
= va
->maxvert
; }
9 if(hasDRE
) glDrawRangeElements_(GL_TRIANGLES
, minvert
, maxvert
, numindices
, GL_UNSIGNED_SHORT
, indices
);
10 else glDrawElements(GL_TRIANGLES
, numindices
, GL_UNSIGNED_SHORT
, indices
);
14 ///////// view frustrum culling ///////////////////////
16 plane vfcP
[5]; // perpindictular vectors to view frustrum bounding planes
17 float vfcDfog
; // far plane culling distance (fog limit).
18 int vfcw
, vfch
, vfcfov
;
22 int isvisiblesphere(float rad
, const vec
&cv
)
24 int v
= VFC_FULL_VISIBLE
;
29 dist
= vfcP
[i
].dist(cv
);
30 if(dist
< -rad
) return VFC_NOT_VISIBLE
;
31 if(dist
< rad
) v
= VFC_PART_VISIBLE
;
35 if(dist
> rad
) return VFC_FOGGED
; //VFC_NOT_VISIBLE; // culling when fog is closer than size of world results in HOM
36 if(dist
> -rad
) v
= VFC_PART_VISIBLE
;
41 int isvisiblecube(const vec
&o
, int size
)
44 center
.add(size
/2.0f
);
45 return isvisiblesphere(size
*SQRT3
/2.0f
, center
);
48 float vadist(vtxarray
*va
, const vec
&p
)
50 if(va
->min
.x
>va
->max
.x
)
52 ivec
o(va
->x
, va
->y
, va
->z
);
53 return p
.dist_to_bb(o
, ivec(o
).add(va
->size
)); // box contains only sky/water
55 return p
.dist_to_bb(va
->min
, va
->max
);
60 static vtxarray
*vasort
[VASORTSIZE
];
62 void addvisibleva(vtxarray
*va
)
64 extern int lodsize
, loddistance
;
66 float dist
= vadist(va
, camera1
->o
);
67 va
->distance
= int(dist
); /*cv.dist(camera1->o) - va->size*SQRT3/2*/
68 va
->curlod
= lodsize
==0 || va
->distance
<loddistance
? 0 : 1;
70 int hash
= min(int(dist
*VASORTSIZE
/hdr
.worldsize
), VASORTSIZE
-1);
71 vtxarray
**prev
= &vasort
[hash
], *cur
= vasort
[hash
];
73 while(cur
&& va
->distance
> cur
->distance
)
86 vtxarray
**last
= &visibleva
;
87 loopi(VASORTSIZE
) if(vasort
[i
])
89 vtxarray
*va
= vasort
[i
];
91 while(va
->next
) va
= va
->next
;
96 void findvisiblevas(vector
<vtxarray
*> &vas
, bool resetocclude
= false)
100 vtxarray
&v
= *vas
[i
];
101 int prevvfc
= resetocclude
? VFC_NOT_VISIBLE
: v
.curvfc
;
102 v
.curvfc
= isvisiblecube(vec(v
.x
, v
.y
, v
.z
), v
.size
);
103 if(v
.curvfc
!=VFC_NOT_VISIBLE
)
106 if(v
.children
->length()) findvisiblevas(*v
.children
, prevvfc
==VFC_NOT_VISIBLE
);
107 if(prevvfc
==VFC_NOT_VISIBLE
)
109 v
.occluded
= OCCLUDE_NOTHING
;
116 void setvfcP(float yaw
, float pitch
, const vec
&camera
)
118 float yawd
= (90.0f
- vfcfov
/2.0f
) * RAD
;
119 float pitchd
= (90.0f
- (vfcfov
*float(vfch
)/float(vfcw
))/2.0f
) * RAD
;
122 vfcP
[0].toplane(vec(yaw
+ yawd
, pitch
), camera
); // left plane
123 vfcP
[1].toplane(vec(yaw
- yawd
, pitch
), camera
); // right plane
124 vfcP
[2].toplane(vec(yaw
, pitch
+ pitchd
), camera
); // top plane
125 vfcP
[3].toplane(vec(yaw
, pitch
- pitchd
), camera
); // bottom plane
126 vfcP
[4].toplane(vec(yaw
, pitch
), camera
); // near/far planes
133 void reflectvfcP(float z
)
135 memcpy(oldvfcP
, vfcP
, sizeof(vfcP
));
138 o
.z
= z
-(camera1
->o
.z
-z
);
139 setvfcP(camera1
->yaw
, -camera1
->pitch
, o
);
144 memcpy(vfcP
, oldvfcP
, sizeof(vfcP
));
147 extern vector
<vtxarray
*> varoot
;
149 void visiblecubes(cube
*c
, int size
, int cx
, int cy
, int cz
, int w
, int h
, int fov
)
151 memset(vasort
, 0, sizeof(vasort
));
157 // Calculate view frustrum: Only changes if resize, but...
158 setvfcP(camera1
->yaw
, camera1
->pitch
, camera1
->o
);
160 findvisiblevas(varoot
);
164 bool insideva(const vtxarray
*va
, const vec
&v
)
166 return v
.x
>=va
->x
&& v
.y
>=va
->y
&& v
.z
>=va
->z
&& v
.x
<=va
->x
+va
->size
&& v
.y
<=va
->y
+va
->size
&& v
.z
<=va
->z
+va
->size
;
169 static ivec vaorigin
;
173 vaorigin
= ivec(-1, -1, -1);
176 void setorigin(vtxarray
*va
, bool shadowmatrix
= false)
178 ivec
o(va
->x
, va
->y
, va
->z
);
179 o
.mask(~VVEC_INT_MASK
);
185 glTranslatef(o
.x
, o
.y
, o
.z
);
186 static const float scale
= 1.0f
/(1<<VVEC_FRAC
);
187 glScalef(scale
, scale
, scale
);
189 if(shadowmatrix
) adjustshadowmatrix(o
, scale
);
193 ///////// occlusion queries /////////////
195 #define MAXQUERY 2048
200 occludequery queries
[MAXQUERY
];
203 static queryframe queryframes
[2] = {{0, 0}, {0, 0}};
204 static uint flipquery
= 0;
208 return queryframes
[flipquery
].cur
;
213 flipquery
= (flipquery
+ 1) % 2;
214 queryframe
&qf
= queryframes
[flipquery
];
215 loopi(qf
.cur
) qf
.queries
[i
].owner
= NULL
;
219 occludequery
*newquery(void *owner
)
221 queryframe
&qf
= queryframes
[flipquery
];
224 if(qf
.max
>= MAXQUERY
) return NULL
;
225 glGenQueries_(1, &qf
.queries
[qf
.max
++].id
);
227 occludequery
*query
= &qf
.queries
[qf
.cur
++];
228 query
->owner
= owner
;
229 query
->fragments
= -1;
235 loopi(2) loopj(queryframes
[i
].max
) queryframes
[i
].queries
[j
].owner
= NULL
;
242 queryframe
&qf
= queryframes
[i
];
243 loopj(qf
.max
) glDeleteQueries_(1, &qf
.queries
[j
].id
);
248 VAR(oqfrags
, 0, 8, 64);
249 VAR(oqreflect
, 0, 4, 64);
251 bool checkquery(occludequery
*query
, bool nowait
)
254 if(query
->fragments
>= 0) fragments
= query
->fragments
;
260 glGetQueryObjectiv_(query
->id
, GL_QUERY_RESULT_AVAILABLE
, &avail
);
261 if(!avail
) return false;
263 glGetQueryObjectuiv_(query
->id
, GL_QUERY_RESULT_ARB
, &fragments
);
264 query
->fragments
= fragments
;
266 return fragments
< (uint
)(reflecting
? oqreflect
: oqfrags
);
269 void drawbb(const ivec
&bo
, const ivec
&br
, const vec
&camera
)
275 int dim
= dimension(i
), coord
= dimcoord(i
);
279 if(camera
[dim
] < bo
[dim
] + br
[dim
]) continue;
281 else if(camera
[dim
] > bo
[dim
]) continue;
285 const ivec
&cc
= cubecoords
[fv
[i
][j
]];
286 glVertex3i(cc
.x
? bo
.x
+br
.x
: bo
.x
,
287 cc
.y
? bo
.y
+br
.y
: bo
.y
,
288 cc
.z
? bo
.z
+br
.z
: bo
.z
);
297 extern int octaentsize
;
299 static octaentities
*visiblemms
, **lastvisiblemms
;
301 void findvisiblemms(const vector
<extentity
*> &ents
)
303 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
305 if(!va
->mapmodels
|| va
->curvfc
>= VFC_FOGGED
|| va
->occluded
>= OCCLUDE_BB
) continue;
306 loopv(*va
->mapmodels
)
308 octaentities
*oe
= (*va
->mapmodels
)[i
];
309 if(isvisiblecube(oe
->o
.tovec(), oe
->size
) >= VFC_FOGGED
) continue;
311 bool occluded
= oe
->query
&& oe
->query
->owner
== oe
&& checkquery(oe
->query
);
317 *lastvisiblemms
= oe
;
318 lastvisiblemms
= &oe
->next
;
325 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
326 if(e
.visible
|| (e
.attr3
&& e
.triggerstate
== TRIGGER_DISAPPEARED
)) continue;
330 if(!visible
) continue;
332 oe
->distance
= int(camera1
->o
.dist_to_bb(oe
->o
, oe
->size
));
334 octaentities
**prev
= &visiblemms
, *cur
= visiblemms
;
335 while(cur
&& cur
->distance
>= 0 && oe
->distance
> cur
->distance
)
341 if(*prev
== NULL
) lastvisiblemms
= &oe
->next
;
351 extern bool getentboundingbox(extentity
&e
, ivec
&o
, ivec
&r
);
353 void rendermapmodel(extentity
&e
)
355 int anim
= ANIM_MAPMODEL
|ANIM_LOOP
, basetime
= 0;
356 if(e
.attr3
) switch(e
.triggerstate
)
358 case TRIGGER_RESET
: anim
= ANIM_TRIGGER
|ANIM_START
; break;
359 case TRIGGERING
: anim
= ANIM_TRIGGER
; basetime
= e
.lasttrigger
; break;
360 case TRIGGERED
: anim
= ANIM_TRIGGER
|ANIM_END
; break;
361 case TRIGGER_RESETTING
: anim
= ANIM_TRIGGER
|ANIM_REVERSE
; basetime
= e
.lasttrigger
; break;
363 mapmodelinfo
&mmi
= getmminfo(e
.attr2
);
364 if(&mmi
) rendermodel(e
.color
, e
.dir
, mmi
.name
, anim
, 0, mmi
.tex
, e
.o
, (float)((e
.attr1
+7)-(e
.attr1
+7)%15), 0, 0, basetime
, NULL
, MDL_CULL_VFC
| MDL_CULL_DIST
);
367 extern int reflectdist
;
369 static vector
<octaentities
*> renderedmms
;
371 vtxarray
*reflectedva
;
373 void renderreflectedmapmodels(float z
, bool refract
)
375 bool reflected
= !refract
&& camera1
->o
.z
>= z
;
376 vector
<octaentities
*> reflectedmms
;
377 vector
<octaentities
*> &mms
= reflected
? reflectedmms
: renderedmms
;
378 const vector
<extentity
*> &ents
= et
->getents();
383 for(vtxarray
*va
= reflectedva
; va
; va
= va
->rnext
)
385 if(!va
->mapmodels
|| va
->distance
> reflectdist
) continue;
386 loopv(*va
->mapmodels
) reflectedmms
.add((*va
->mapmodels
)[i
]);
391 octaentities
*oe
= mms
[i
];
392 if(refract
? oe
->o
.z
>= z
: oe
->o
.z
+oe
->size
<= z
) continue;
393 if(reflected
&& isvisiblecube(oe
->o
.tovec(), oe
->size
) >= VFC_FOGGED
) continue;
396 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
397 if(e
.visible
|| (e
.attr3
&& e
.triggerstate
== TRIGGER_DISAPPEARED
)) continue;
406 octaentities
*oe
= mms
[i
];
409 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
410 if(!e
.visible
) continue;
417 if(reflected
) restorevfcP();
420 void rendermapmodels()
422 const vector
<extentity
*> &ents
= et
->getents();
425 lastvisiblemms
= &visiblemms
;
426 findvisiblemms(ents
);
428 static int skipoq
= 0;
429 bool doquery
= hasOQ
&& oqfrags
&& oqmm
;
431 renderedmms
.setsizenodelete(0);
433 for(octaentities
*oe
= visiblemms
; oe
; oe
= oe
->next
) if(oe
->distance
>=0)
437 extentity
&e
= *ents
[oe
->mapmodels
[i
]];
438 if(!e
.visible
|| (e
.attr3
&& e
.triggerstate
== TRIGGER_DISAPPEARED
)) continue;
439 if(renderedmms
.empty() || renderedmms
.last()!=oe
)
442 oe
->query
= doquery
&& oe
->distance
>0 && !(++skipoq
%oqmm
) ? newquery(oe
) : NULL
;
443 if(oe
->query
) startmodelquery(oe
->query
);
448 if(renderedmms
.length() && renderedmms
.last()==oe
&& oe
->query
) endmodelquery();
452 bool colormask
= true;
453 for(octaentities
*oe
= visiblemms
; oe
; oe
= oe
->next
) if(oe
->distance
<0)
455 oe
->query
= doquery
? newquery(oe
) : NULL
;
456 if(!oe
->query
) continue;
459 glDepthMask(GL_FALSE
);
460 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
461 nocolorshader
->set();
464 startquery(oe
->query
);
465 drawbb(oe
->bbmin
, ivec(oe
->bbmax
).sub(oe
->bbmin
));
470 glDepthMask(GL_TRUE
);
471 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, refracting
&& renderpath
!=R_FIXEDFUNCTION
? GL_FALSE
: GL_TRUE
);
475 bool bboccluded(const ivec
&bo
, const ivec
&br
, cube
*c
, const ivec
&o
, int size
)
477 loopoctabox(o
, size
, bo
, br
)
479 ivec
co(i
, o
.x
, o
.y
, o
.z
, size
);
480 if(c
[i
].ext
&& c
[i
].ext
->va
)
482 vtxarray
*va
= c
[i
].ext
->va
;
483 if(va
->curvfc
>= VFC_FOGGED
|| va
->occluded
>= OCCLUDE_BB
) continue;
485 if(c
[i
].children
&& bboccluded(bo
, br
, c
[i
].children
, co
, size
>>1)) continue;
491 VAR(outline
, 0, 0, 0xFFFFFF);
492 VAR(dtoutline
, 0, 0, 1);
496 if(!editmode
|| !outline
) return;
498 notextureshader
->set();
500 glDisable(GL_TEXTURE_2D
);
501 glEnableClientState(GL_VERTEX_ARRAY
);
505 glEnable(GL_POLYGON_OFFSET_LINE
);
506 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
507 glColor3ub((outline
>>16)&0xFF, (outline
>>8)&0xFF, outline
&0xFF);
509 if(dtoutline
) glDisable(GL_DEPTH_TEST
);
512 GLuint vbufGL
= 0, ebufGL
= 0;
513 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
515 lodlevel
&lod
= va
->curlod
? va
->l1
: va
->l0
;
516 if(!lod
.texs
|| va
->occluded
>= OCCLUDE_GEOM
) continue;
520 bool vbufchanged
= true;
523 if(vbufGL
== va
->vbufGL
) vbufchanged
= false;
526 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbufGL
);
529 if(ebufGL
!= lod
.ebufGL
)
531 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, lod
.ebufGL
);
535 if(vbufchanged
) glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &(va
->vbuf
[0].x
));
537 drawvatris(va
, 3*lod
.tris
, lod
.ebuf
);
538 xtravertsva
+= va
->verts
;
541 if(dtoutline
) glEnable(GL_DEPTH_TEST
);
543 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
544 glDisable(GL_POLYGON_OFFSET_LINE
);
550 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
551 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
553 glDisableClientState(GL_VERTEX_ARRAY
);
554 glEnable(GL_TEXTURE_2D
);
556 defaultshader
->set();
559 void rendershadowmapreceivers()
563 static Shader
*shadowmapshader
= NULL
;
564 if(!shadowmapshader
) shadowmapshader
= lookupshaderbyname("shadowmapreceiver");
565 shadowmapshader
->set();
567 glDisable(GL_TEXTURE_2D
);
568 glEnableClientState(GL_VERTEX_ARRAY
);
571 glDepthMask(GL_FALSE
);
572 glDepthFunc(GL_GREATER
);
574 extern int apple_minmax_bug
;
575 if(!apple_minmax_bug
) glColorMask(GL_FALSE
, GL_FALSE
, GL_TRUE
, GL_FALSE
);
578 glBlendEquation_(GL_MAX_EXT
);
579 glBlendFunc(GL_ONE
, GL_ONE
);
584 GLuint vbufGL
= 0, ebufGL
= 0;
585 for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
587 lodlevel
&lod
= va
->curlod
? va
->l1
: va
->l0
;
588 if(va
->curvfc
>= VFC_FOGGED
|| !isshadowmapreceiver(va
)) continue;
592 bool vbufchanged
= true;
595 if(vbufGL
== va
->vbufGL
) vbufchanged
= false;
598 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbufGL
);
601 if(ebufGL
!= lod
.ebufGL
)
603 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, lod
.ebufGL
);
607 if(vbufchanged
) glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &(va
->vbuf
[0].x
));
609 drawvatris(va
, 3*lod
.tris
, lod
.ebuf
);
610 xtravertsva
+= va
->verts
;
616 glBlendEquation_(GL_FUNC_ADD_EXT
);
618 glCullFace(GL_FRONT
);
619 glDepthMask(GL_TRUE
);
620 glDepthFunc(GL_LESS
);
622 if(!apple_minmax_bug
) glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
626 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
627 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
629 glDisableClientState(GL_VERTEX_ARRAY
);
630 glEnable(GL_TEXTURE_2D
);
633 VARP(maxdynlights
, 0, MAXDYNLIGHTS
, MAXDYNLIGHTS
);
634 VARP(dynlightdist
, 0, 1024, 10000);
641 int fade
, peak
, expire
;
643 float calcradius() const
645 return peak
>0 && expire
-lastmillis
>fade
? (radius
/peak
)*(peak
-(expire
-lastmillis
-fade
)) : radius
;
648 float intensity() const
652 int remaining
= expire
- lastmillis
;
653 return remaining
> fade
? 1.0f
- float(remaining
- fade
)/peak
: float(remaining
)/fade
;
659 vector
<dynlight
> dynlights
;
660 vector
<dynlight
*> closedynlights
, visibledynlights
;
662 void adddynlight(const vec
&o
, float radius
, const vec
&color
, int fade
, int peak
)
664 if(o
.dist(camera1
->o
) > dynlightdist
) return;
666 int insert
= 0, expire
= fade
+ peak
+ lastmillis
;
667 loopvrev(dynlights
) if(expire
>=dynlights
[i
].expire
) { insert
= i
+1; break; }
675 dynlights
.insert(insert
, d
);
678 void cleardynlights()
681 loopv(dynlights
) if(lastmillis
<dynlights
[i
].expire
) { faded
= i
; break; }
682 if(faded
<0) dynlights
.setsizenodelete(0);
683 else if(faded
>0) dynlights
.remove(0, faded
);
688 closedynlights
.setsizenodelete(0);
689 if(maxdynlights
) loopvj(dynlights
)
691 dynlight
&d
= dynlights
[j
];
692 d
.dist
= camera1
->o
.dist(d
.o
) - d
.calcradius();
693 if(d
.dist
>dynlightdist
|| isvisiblesphere(d
.radius
, d
.o
) >= VFC_FOGGED
) continue;
695 loopvrev(closedynlights
) if(d
.dist
>= closedynlights
[i
]->dist
) { insert
= i
+1; break; }
696 if(closedynlights
.length()>=maxdynlights
)
698 if(insert
+1>=maxdynlights
) continue;
699 closedynlights
.drop();
701 closedynlights
.insert(insert
, &d
);
703 return closedynlights
.length();
706 void dynlightreaching(const vec
&target
, vec
&color
, vec
&dir
)
708 vec
dyncolor(0, 0, 0);//, dyndir(0, 0, 0);
711 dynlight
&d
= dynlights
[i
];
714 float mag
= ray
.magnitude(), radius
= d
.calcradius();
715 if(radius
<=0 || mag
>= radius
) continue;
716 float intensity
= d
.intensity()*(1 - mag
/radius
);
717 dyncolor
.add(vec(d
.color
).mul(intensity
));
718 //dyndir.add(ray.mul(intensity/mag));
724 float x
= dyncolor
.magnitude(), y
= color
.magnitude();
729 dir
.add(dyndir
).div(x
+y
);
730 if(dir
.iszero()) dir
= vec(0, 0, 1);
731 else dir
.normalize();
738 void setdynlights(vtxarray
*va
)
740 visibledynlights
.setsizenodelete(0);
741 loopv(closedynlights
)
743 dynlight
&d
= *closedynlights
[i
];
744 if(d
.o
.dist_to_bb(va
->min
, va
->max
) < d
.calcradius()) visibledynlights
.add(&d
);
746 if(visibledynlights
.empty()) return;
748 static string vertexparams
[MAXDYNLIGHTS
] = { "" }, pixelparams
[MAXDYNLIGHTS
] = { "" };
749 if(!*vertexparams
[0]) loopi(MAXDYNLIGHTS
)
751 s_sprintf(vertexparams
[i
])("dynlight%dpos", i
);
752 s_sprintf(pixelparams
[i
])("dynlight%dcolor", i
);
755 loopv(visibledynlights
)
757 dynlight
&d
= *visibledynlights
[i
];
758 setenvparamfv(vertexparams
[i
], SHPARAM_VERTEX
, 10+i
, vec4(d
.o
, 1).sub(ivec(va
->x
, va
->y
, va
->z
).mask(~VVEC_INT_MASK
).tovec()).mul(1<<VVEC_FRAC
).v
);
760 color
.mul(2*d
.intensity());
761 float radius
= d
.calcradius();
762 setenvparamf(pixelparams
[i
], SHPARAM_PIXEL
, 10+i
, color
.x
, color
.y
, color
.z
, -1.0f
/(radius
*radius
*(1<<(2*VVEC_FRAC
))));
766 float orientation_tangent
[3][4] = { { 0,1, 0,0 }, { 1,0, 0,0 }, { 1,0,0,0 }};
767 float orientation_binormal
[3][4] = { { 0,0,-1,0 }, { 0,0,-1,0 }, { 0,1,0,0 }};
771 bool colormask
, depthmask
, texture
;
772 GLuint vbufGL
, ebufGL
;
774 int diffusetmu
, lightmaptmu
, glowtmu
, fogtmu
, causticstmu
;
777 renderstate() : colormask(true), depthmask(true), texture(true), vbufGL(0), ebufGL(0), fogplane(-1), diffusetmu(0), lightmaptmu(1), glowtmu(-1), fogtmu(-1), causticstmu(-1)
779 loopk(4) color
[k
] = 1;
783 void renderquery(renderstate
&cur
, occludequery
*query
, vtxarray
*va
)
786 nocolorshader
->set();
787 if(cur
.colormask
) { cur
.colormask
= false; glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
); }
788 if(cur
.depthmask
) { cur
.depthmask
= false; glDepthMask(GL_FALSE
); }
792 ivec
origin(va
->x
, va
->y
, va
->z
);
793 origin
.mask(~VVEC_INT_MASK
);
795 vec
camera(camera1
->o
);
796 if(reflecting
&& !refracting
) camera
.z
= reflecting
;
799 if(va
->children
|| va
->mapmodels
|| va
->l0
.matsurfs
|| va
->l0
.sky
|| va
->l0
.explicitsky
)
801 bbmin
= ivec(va
->x
, va
->y
, va
->z
);
802 bbmax
= ivec(va
->size
, va
->size
, va
->size
);
811 drawbb(bbmin
.sub(origin
).mul(1<<VVEC_FRAC
),
812 bbmax
.mul(1<<VVEC_FRAC
),
813 vec(camera
).sub(origin
.tovec()).mul(1<<VVEC_FRAC
));
820 RENDERPASS_LIGHTMAP
= 0,
828 void renderva(renderstate
&cur
, vtxarray
*va
, lodlevel
&lod
, int pass
= RENDERPASS_LIGHTMAP
, bool fogpass
= false)
830 if(pass
==RENDERPASS_GLOW
)
835 Slot
&slot
= lookuptexture(lod
.eslist
[i
].texture
);
838 Slot::Tex
&t
= slot
.sts
[j
];
839 if(t
.type
==TEX_GLOW
&& t
.combined
<0) noglow
= false;
845 setorigin(va
, pass
==RENDERPASS_LIGHTMAP
&& !envmapping
);
846 bool vbufchanged
= true;
849 if(cur
.vbufGL
== va
->vbufGL
) vbufchanged
= false;
852 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbufGL
);
853 cur
.vbufGL
= va
->vbufGL
;
855 if(cur
.ebufGL
!= lod
.ebufGL
)
857 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, lod
.ebufGL
);
858 cur
.ebufGL
= lod
.ebufGL
;
861 if(vbufchanged
) glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &(va
->vbuf
[0].x
));
862 if(!cur
.depthmask
) { cur
.depthmask
= true; glDepthMask(GL_TRUE
); }
864 if(pass
==RENDERPASS_Z
)
866 if(cur
.colormask
) { cur
.colormask
= false; glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
); }
867 extern int apple_glsldepth_bug
;
868 if(renderpath
!=R_GLSLANG
|| !apple_glsldepth_bug
)
870 nocolorshader
->set();
871 drawvatris(va
, 3*lod
.tris
, lod
.ebuf
);
875 static Shader
*nocolorglslshader
= NULL
;
876 if(!nocolorglslshader
) nocolorglslshader
= lookupshaderbyname("nocolorglsl");
877 Slot
*lastslot
= NULL
;
878 int lastdraw
= 0, offset
= 0;
881 Slot
&slot
= lookuptexture(lod
.eslist
[i
].texture
);
882 if(lastslot
&& (slot
.shader
->type
&SHADER_GLSLANG
) != (lastslot
->shader
->type
&SHADER_GLSLANG
) && offset
> lastdraw
)
884 (lastslot
->shader
->type
&SHADER_GLSLANG
? nocolorglslshader
: nocolorshader
)->set();
885 drawvatris(va
, offset
-lastdraw
, lod
.ebuf
+lastdraw
);
889 offset
+= lod
.eslist
[i
].length
[5];
891 if(offset
> lastdraw
)
893 (lastslot
->shader
->type
&SHADER_GLSLANG
? nocolorglslshader
: nocolorshader
)->set();
894 drawvatris(va
, offset
-lastdraw
, lod
.ebuf
+lastdraw
);
897 xtravertsva
+= va
->verts
;
901 if(refracting
&& renderpath
!=R_FIXEDFUNCTION
)
903 float fogplane
= refracting
- (va
->z
& ~VVEC_INT_MASK
);
904 if(cur
.fogplane
!=fogplane
)
906 cur
.fogplane
= fogplane
;
907 setfogplane(1.0f
/(1<<VVEC_FRAC
), fogplane
);
910 if(!cur
.colormask
) { cur
.colormask
= true; glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
); }
912 if((pass
==RENDERPASS_LIGHTMAP
|| pass
==RENDERPASS_COLOR
) && (fogpass
? va
->z
+va
->size
<=refracting
-waterfog
: va
->curvfc
==VFC_FOGGED
))
914 // this case is never reached if called from rendergeommultipass()
915 static Shader
*fogshader
= NULL
;
916 if(!fogshader
) fogshader
= lookupshaderbyname("fogworld");
922 glDisable(GL_TEXTURE_2D
);
923 if(fogpass
&& cur
.fogtmu
<0)
926 getwatercolour(wcol
);
929 if(pass
==RENDERPASS_LIGHTMAP
)
931 if(renderpath
!=R_FIXEDFUNCTION
) glDisableClientState(GL_COLOR_ARRAY
);
932 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
933 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
934 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
935 glDisable(GL_TEXTURE_2D
);
938 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
939 glDisable(GL_TEXTURE_1D
);
941 if(cur
.causticstmu
>=0) loopi(2)
943 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.causticstmu
+i
);
944 glDisable(GL_TEXTURE_2D
);
946 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
947 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
951 drawvatris(va
, 3*lod
.tris
, lod
.ebuf
);
960 if(pass
==RENDERPASS_LIGHTMAP
|| pass
==RENDERPASS_COLOR
)
962 glEnable(GL_TEXTURE_2D
);
963 if(fogpass
&& cur
.fogtmu
<0) glColor4fv(cur
.color
);
965 if(pass
==RENDERPASS_LIGHTMAP
)
967 if(renderpath
!=R_FIXEDFUNCTION
) glEnableClientState(GL_COLOR_ARRAY
);
968 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
969 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
970 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
971 glEnable(GL_TEXTURE_2D
);
974 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
975 glEnable(GL_TEXTURE_1D
);
977 if(cur
.causticstmu
>=0) loopi(2)
979 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.causticstmu
+i
);
980 glEnable(GL_TEXTURE_2D
);
982 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
983 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
988 if(pass
==RENDERPASS_FOG
|| (cur
.fogtmu
>=0 && (pass
==RENDERPASS_LIGHTMAP
|| pass
==RENDERPASS_GLOW
)))
990 if(pass
==RENDERPASS_LIGHTMAP
) glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
991 else if(pass
==RENDERPASS_GLOW
) glActiveTexture_(GL_TEXTURE1_ARB
);
992 GLfloat s
[4] = { 0, 0, -1.0f
/(waterfog
<<VVEC_FRAC
), (refracting
- (va
->z
& ~VVEC_INT_MASK
))/waterfog
};
993 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, s
);
994 if(pass
==RENDERPASS_LIGHTMAP
) glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
995 else if(pass
==RENDERPASS_GLOW
) glActiveTexture_(GL_TEXTURE0_ARB
);
998 bool shadowmapreceiver
= false;
999 if(pass
==RENDERPASS_CAUSTICS
|| pass
==RENDERPASS_FOG
)
1001 drawvatris(va
, 3*lod
.tris
, lod
.ebuf
);
1002 xtravertsva
+= va
->verts
;
1005 else if(pass
==RENDERPASS_LIGHTMAP
)
1007 if(renderpath
!=R_FIXEDFUNCTION
)
1009 if(!envmapping
&& !va
->curlod
) shadowmapreceiver
= isshadowmapreceiver(va
);
1010 if(vbufchanged
) glColorPointer(3, GL_UNSIGNED_BYTE
, VTXSIZE
, floatvtx
? &(((fvertex
*)va
->vbuf
)[0].n
) : &(va
->vbuf
[0].n
));
1011 setenvparamfv("camera", SHPARAM_VERTEX
, 4, vec4(camera1
->o
, 1).sub(ivec(va
->x
, va
->y
, va
->z
).mask(~VVEC_INT_MASK
).tovec()).mul(1<<VVEC_FRAC
).v
);
1017 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1018 glTexCoordPointer(2, GL_SHORT
, VTXSIZE
, floatvtx
? &(((fvertex
*)va
->vbuf
)[0].u
) : &(va
->vbuf
[0].u
));
1019 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1023 ushort
*ebuf
= lod
.ebuf
;
1024 int lastlm
= -1, lastxs
= -1, lastys
= -1, lastl
= -1, lasto
= -1, lastenvmap
= -1, envmapped
= 0;
1025 bool mtglow
= false, shadowmapped
= false;
1026 float lastscale
= -1;
1027 Slot
*lastslot
= NULL
;
1028 Shader
*lastshader
= NULL
;
1031 const elementset
&es
= lod
.eslist
[i
];
1032 Slot
&slot
= lookuptexture(es
.texture
);
1033 Texture
*tex
= slot
.sts
[0].t
;
1034 Shader
*s
= slot
.shader
;
1036 extern vector
<GLuint
> lmtexids
;
1037 int lmid
= es
.lmid
, curlm
= pass
==RENDERPASS_LIGHTMAP
? (int)lmtexids
[lmid
] : -1;
1038 if(s
&& renderpath
!=R_FIXEDFUNCTION
&& pass
==RENDERPASS_LIGHTMAP
)
1040 int tmu
= cur
.lightmaptmu
+1;
1041 if(s
->type
&SHADER_NORMALSLMS
)
1043 if((!lastslot
|| s
->type
!=lastslot
->shader
->type
|| curlm
!=lastlm
) && (lmid
<LMID_RESERVED
|| lightmaps
[lmid
-LMID_RESERVED
].type
==LM_BUMPMAP0
))
1045 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
);
1046 glBindTexture(GL_TEXTURE_2D
, lmtexids
[lmid
+1]);
1050 if(s
->type
&SHADER_ENVMAP
)
1052 int envmap
= es
.envmap
;
1053 if((!lastslot
|| s
->type
!=lastslot
->shader
->type
|| (envmap
==EMID_CUSTOM
? &slot
!=lastslot
: envmap
!=lastenvmap
)) && hasCM
)
1055 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
);
1056 if(!(envmapped
& (1<<tmu
)))
1058 glEnable(GL_TEXTURE_CUBE_MAP_ARB
);
1059 envmapped
|= 1<<tmu
;
1062 if(envmap
==EMID_CUSTOM
) loopvj(slot
.sts
)
1064 Slot::Tex
&t
= slot
.sts
[j
];
1065 if(t
.type
==TEX_ENVMAP
&& t
.t
) { emtex
= t
.t
->gl
; break; }
1067 if(!emtex
) emtex
= lookupenvmap(envmap
);
1068 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB
, emtex
);
1069 lastenvmap
= envmap
;
1073 glActiveTexture_(GL_TEXTURE0_ARB
);
1075 if(curlm
!=lastlm
&& pass
==RENDERPASS_LIGHTMAP
)
1077 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1078 glBindTexture(GL_TEXTURE_2D
, curlm
);
1080 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1084 if(pass
==RENDERPASS_LIGHTMAP
|| pass
==RENDERPASS_COLOR
) glBindTexture(GL_TEXTURE_2D
, tex
->gl
);
1085 if(renderpath
==R_FIXEDFUNCTION
)
1088 if(pass
==RENDERPASS_GLOW
|| cur
.glowtmu
>=0) loopvj(slot
.sts
)
1090 Slot::Tex
&t
= slot
.sts
[j
];
1091 if(t
.type
==TEX_GLOW
&& t
.combined
<0)
1095 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1096 if(!mtglow
) { glEnable(GL_TEXTURE_2D
); mtglow
= true; }
1098 glBindTexture(GL_TEXTURE_2D
, t
.t
->gl
);
1102 if(pass
==RENDERPASS_GLOW
&& noglow
)
1104 ebuf
+= es
.length
[5];
1109 if(noglow
) { glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
); glDisable(GL_TEXTURE_2D
); mtglow
= false; }
1110 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1113 else if(pass
==RENDERPASS_LIGHTMAP
&& s
)
1115 int tmu
= cur
.lightmaptmu
+1;
1116 if(s
->type
&SHADER_NORMALSLMS
) tmu
++;
1117 if(s
->type
&SHADER_ENVMAP
) tmu
++;
1120 Slot::Tex
&t
= slot
.sts
[j
];
1121 if(t
.type
==TEX_DIFFUSE
|| t
.type
==TEX_ENVMAP
|| t
.combined
>=0) continue;
1122 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
++);
1123 glBindTexture(GL_TEXTURE_2D
, t
.t
->gl
);
1125 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1132 float scale
= slot
.sts
[0].scale
;
1133 if(!scale
) scale
= 1;
1134 loopk(shadowmapreceiver
? 2 : 1) loopl(3)
1137 ushort offset
= dim
>0 ? es
.length
[dim
-1] : 0,
1138 len
= es
.length
[dim
+ (shadowmapreceiver
? 0 : 1)] - offset
;
1141 if(pass
==RENDERPASS_LIGHTMAP
&& s
&& (lastshader
!=s
|| shadowmapped
!=(k
!=0)))
1143 if(refracting
&& hasFBO
&& waterrefract
&& waterfade
)
1145 if(k
) s
->variant(min(s
->variants
[3].length()-1, visibledynlights
.length()), 3)->set(&slot
);
1146 else s
->variant(min(s
->variants
[2].length()-1, visibledynlights
.length()), 2)->set(&slot
);
1148 else if(k
) s
->variant(min(s
->variants
[1].length()-1, visibledynlights
.length()), 1)->set(&slot
);
1149 else if(visibledynlights
.empty()) s
->set(&slot
);
1150 else s
->variant(min(s
->variants
[0].length()-1, visibledynlights
.length()-1))->set(&slot
);
1151 shadowmapped
= k
!=0;
1155 if(lastl
!=l
|| lastxs
!=tex
->xs
|| lastys
!=tex
->ys
|| lastscale
!=scale
|| (s
&& s
->type
&SHADER_GLSLANG
))
1157 static const int si
[] = { 1, 0, 0 };
1158 static const int ti
[] = { 2, 2, 1 };
1160 GLfloat sgen
[] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
};
1161 sgen
[si
[l
]] = 8.0f
/scale
/(tex
->xs
<<VVEC_FRAC
);
1162 GLfloat tgen
[] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
};
1163 tgen
[ti
[l
]] = (l
<= 1 ? -8.0f
: 8.0f
)/scale
/(tex
->ys
<<VVEC_FRAC
);
1165 if(renderpath
==R_FIXEDFUNCTION
)
1167 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, sgen
);
1168 glTexGenfv(GL_T
, GL_OBJECT_PLANE
, tgen
);
1169 // KLUGE: workaround for buggy nvidia drivers
1170 // object planes are somehow invalid unless texgen is toggled
1171 extern int nvidia_texgen_bug
;
1172 if(nvidia_texgen_bug
)
1174 glDisable(GL_TEXTURE_GEN_S
);
1175 glDisable(GL_TEXTURE_GEN_T
);
1176 glEnable(GL_TEXTURE_GEN_S
);
1177 glEnable(GL_TEXTURE_GEN_T
);
1182 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1183 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, sgen
);
1184 glTexGenfv(GL_T
, GL_OBJECT_PLANE
, tgen
);
1185 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1190 // have to pass in env, otherwise same problem as fixed function
1191 setlocalparamfv("texgenS", SHPARAM_VERTEX
, 0, sgen
);
1192 setlocalparamfv("texgenT", SHPARAM_VERTEX
, 1, tgen
);
1201 if(renderpath
!=R_FIXEDFUNCTION
&& pass
==RENDERPASS_LIGHTMAP
&& s
&& s
->type
&SHADER_NORMALSLMS
&& (lasto
!=l
|| s
->type
&SHADER_GLSLANG
))
1203 setlocalparamfv("orienttangent", SHPARAM_VERTEX
, 2, orientation_tangent
[l
]);
1204 setlocalparamfv("orientbinormal", SHPARAM_VERTEX
, 3, orientation_binormal
[l
]);
1208 ushort minvert
= es
.minvert
[dim
], maxvert
= es
.maxvert
[dim
];
1209 if(!shadowmapreceiver
) { minvert
= min(minvert
, es
.minvert
[dim
+1]); maxvert
= max(maxvert
, es
.maxvert
[dim
+1]); }
1210 drawvatris(va
, len
, &ebuf
[offset
], minvert
, maxvert
);
1212 ebuf
+= es
.length
[5];
1217 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1218 glDisable(GL_TEXTURE_2D
);
1222 loopi(4) if(envmapped
&(1<<i
))
1224 glActiveTexture_(GL_TEXTURE0_ARB
+i
);
1225 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
1228 if(mtglow
|| envmapped
) glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1231 vverts
+= va
->verts
;
1234 VAR(oqdist
, 0, 256, 1024);
1235 VAR(zpass
, 0, 1, 1);
1236 VAR(glowpass
, 0, 1, 1);
1238 extern int ati_texgen_bug
;
1240 static void setuptexgen(int dims
= 2)
1242 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_OBJECT_LINEAR
);
1243 glEnable(GL_TEXTURE_GEN_S
);
1246 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_OBJECT_LINEAR
);
1247 glEnable(GL_TEXTURE_GEN_T
);
1248 if(ati_texgen_bug
) glEnable(GL_TEXTURE_GEN_R
); // should not be needed, but apparently makes some ATI drivers happy
1252 static void disabletexgen(int dims
= 2)
1254 glDisable(GL_TEXTURE_GEN_S
);
1257 glDisable(GL_TEXTURE_GEN_T
);
1258 if(ati_texgen_bug
) glDisable(GL_TEXTURE_GEN_R
);
1266 glGenTextures(1, &fogtex
);
1267 uchar buf
[4] = { 255, 0, 255, 255 };
1268 createtexture(fogtex
, 2, 1, buf
, 3, false, GL_LUMINANCE_ALPHA
, GL_TEXTURE_1D
);
1271 #define NUMCAUSTICS 32
1273 VAR(causticscale
, 0, 100, 10000);
1274 VAR(causticmillis
, 0, 75, 1000);
1275 VARP(caustics
, 0, 1, 1);
1277 static Texture
*caustictex
[NUMCAUSTICS
] = { NULL
};
1281 if(caustictex
[0]) return;
1284 s_sprintfd(name
)("<mad:0.6,0.4>packages/caustics/caust%.2d.png", i
);
1285 caustictex
[i
] = textureload(name
);
1289 void setupcaustics(int tmu
, GLfloat
*color
= NULL
)
1291 if(!caustictex
[0]) loadcaustics();
1293 GLfloat s
[4] = { 0.011f
, 0, 0.0066f
, 0 };
1294 GLfloat t
[4] = { 0, 0.011f
, 0.0066f
, 0 };
1297 s
[k
] *= 100.0f
/(causticscale
<<VVEC_FRAC
);
1298 t
[k
] *= 100.0f
/(causticscale
<<VVEC_FRAC
);
1300 int tex
= (lastmillis
/causticmillis
)%NUMCAUSTICS
;
1301 float frac
= float(lastmillis
%causticmillis
)/causticmillis
;
1302 if(color
) color
[3] = frac
;
1303 else glColor4f(1, 1, 1, frac
);
1306 glActiveTexture_(GL_TEXTURE0_ARB
+tmu
+i
);
1307 glEnable(GL_TEXTURE_2D
);
1308 glBindTexture(GL_TEXTURE_2D
, caustictex
[(tex
+i
)%NUMCAUSTICS
]->gl
);
1309 if(renderpath
==R_FIXEDFUNCTION
|| !i
)
1312 setuptmu(tmu
+i
, !i
? "= T" : "T , P @ Ca");
1313 glTexGenfv(GL_S
, GL_OBJECT_PLANE
, s
);
1314 glTexGenfv(GL_T
, GL_OBJECT_PLANE
, t
);
1317 if(renderpath
!=R_FIXEDFUNCTION
)
1319 static Shader
*causticshader
= NULL
;
1320 if(!causticshader
) causticshader
= lookupshaderbyname("caustic");
1321 causticshader
->set();
1322 setlocalparamf("frameoffset", SHPARAM_PIXEL
, 0, frac
, frac
, frac
);
1326 void setupTMUs(renderstate
&cur
, bool causticspass
, bool fogpass
)
1328 extern GLuint shadowmapfb
;
1329 if(!reflecting
&& !refracting
&& !envmapping
&& shadowmap
&& shadowmapfb
)
1331 glDisableClientState(GL_VERTEX_ARRAY
);
1335 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
1336 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
1341 glEnableClientState(GL_VERTEX_ARRAY
);
1344 if(renderpath
==R_FIXEDFUNCTION
)
1346 if(nolights
) cur
.lightmaptmu
= -1;
1349 if(maxtmus
>=4 && causticspass
)
1351 cur
.causticstmu
= 0;
1353 cur
.lightmaptmu
= 3;
1356 if(fogpass
) cur
.fogtmu
= 4;
1357 else if(glowpass
) cur
.glowtmu
= 4;
1360 else if(fogpass
&& !causticspass
) cur
.fogtmu
= 2;
1361 else if(glowpass
) cur
.glowtmu
= 2;
1365 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1367 setuptmu(cur
.glowtmu
, "P + T");
1371 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
1372 glEnable(GL_TEXTURE_1D
);
1374 setuptmu(cur
.fogtmu
, "C , P @ Ta");
1375 if(!fogtex
) createfogtex();
1376 glBindTexture(GL_TEXTURE_1D
, fogtex
);
1378 getwatercolour(wcol
);
1379 loopk(3) cur
.color
[k
] = wcol
[k
]/255.0f
;
1381 if(cur
.causticstmu
>=0) setupcaustics(cur
.causticstmu
, cur
.color
);
1385 glEnableClientState(GL_COLOR_ARRAY
);
1386 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB
+i
); glEnable(GL_TEXTURE_2D
); }
1387 glActiveTexture_(GL_TEXTURE0_ARB
);
1388 setenvparamf("ambient", SHPARAM_PIXEL
, 5, hdr
.ambient
/255.0f
, hdr
.ambient
/255.0f
, hdr
.ambient
/255.0f
);
1389 setenvparamf("millis", SHPARAM_VERTEX
, 6, lastmillis
/1000.0f
, lastmillis
/1000.0f
, lastmillis
/1000.0f
);
1392 glColor4fv(cur
.color
);
1394 if(cur
.lightmaptmu
>=0)
1396 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1397 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1399 setuptmu(cur
.lightmaptmu
, "P * T x 2");
1400 glEnable(GL_TEXTURE_2D
);
1401 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
1402 glMatrixMode(GL_TEXTURE
);
1404 glScalef(1.0f
/SHRT_MAX
, 1.0f
/SHRT_MAX
, 1.0f
);
1405 glMatrixMode(GL_MODELVIEW
);
1407 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1408 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1409 glEnable(GL_TEXTURE_2D
);
1410 setuptmu(cur
.diffusetmu
, cur
.diffusetmu
>0 ? "P * T" : "= T");
1416 void cleanupTMUs(renderstate
&cur
)
1418 if(cur
.lightmaptmu
>=0)
1420 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1421 glClientActiveTexture_(GL_TEXTURE0_ARB
+cur
.lightmaptmu
);
1423 resettmu(cur
.lightmaptmu
);
1424 glDisable(GL_TEXTURE_2D
);
1425 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
1426 glMatrixMode(GL_TEXTURE
);
1428 glMatrixMode(GL_MODELVIEW
);
1432 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.glowtmu
);
1433 resettmu(cur
.glowtmu
);
1435 glDisable(GL_TEXTURE_2D
);
1439 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.fogtmu
);
1440 resettmu(cur
.fogtmu
);
1442 glDisable(GL_TEXTURE_1D
);
1444 if(cur
.causticstmu
>=0) loopi(2)
1446 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.causticstmu
+i
);
1447 resettmu(cur
.causticstmu
+i
);
1449 glDisable(GL_TEXTURE_2D
);
1452 if(cur
.lightmaptmu
>=0)
1454 glActiveTexture_(GL_TEXTURE0_ARB
+cur
.diffusetmu
);
1455 resettmu(cur
.diffusetmu
);
1456 glDisable(GL_TEXTURE_2D
);
1461 if(renderpath
!=R_FIXEDFUNCTION
)
1463 glDisableClientState(GL_COLOR_ARRAY
);
1464 loopi(8-2) { glActiveTexture_(GL_TEXTURE2_ARB
+i
); glDisable(GL_TEXTURE_2D
); }
1467 if(cur
.lightmaptmu
>=0)
1469 glActiveTexture_(GL_TEXTURE0_ARB
);
1470 glClientActiveTexture_(GL_TEXTURE0_ARB
);
1471 glEnable(GL_TEXTURE_2D
);
1475 #define FIRSTVA (reflecting && !refracting && camera1->o.z >= reflecting ? reflectedva : visibleva)
1476 #define NEXTVA (reflecting && !refracting && camera1->o.z >= reflecting ? va->rnext : va->next)
1478 void rendergeommultipass(renderstate
&cur
, int pass
, bool fogpass
)
1480 cur
.vbufGL
= cur
.ebufGL
= 0;
1481 for(vtxarray
*va
= FIRSTVA
; va
; va
= NEXTVA
)
1483 lodlevel
&lod
= va
->curlod
? va
->l1
: va
->l0
;
1484 if(!lod
.texs
|| va
->occluded
>= OCCLUDE_GEOM
) continue;
1485 if(refracting
|| (reflecting
&& camera1
->o
.z
< reflecting
))
1487 if(va
->curvfc
== VFC_FOGGED
|| (refracting
&& camera1
->o
.z
>= refracting
? va
->min
.z
> refracting
: va
->max
.z
<= refracting
)) continue;
1488 if((!hasOQ
|| !oqfrags
) && va
->distance
> reflectdist
) break;
1492 if(va
->max
.z
<= reflecting
|| (va
->rquery
&& checkquery(va
->rquery
))) continue;
1493 if(va
->rquery
&& checkquery(va
->rquery
)) continue;
1495 if(fogpass
? va
->z
+va
->size
<=refracting
-waterfog
: va
->curvfc
==VFC_FOGGED
) continue;
1496 renderva(cur
, va
, lod
, pass
, fogpass
);
1500 void rendergeom(bool causticspass
, bool fogpass
)
1504 if(causticspass
&& ((renderpath
==R_FIXEDFUNCTION
&& maxtmus
<2) || !causticscale
|| !causticmillis
)) causticspass
= false;
1506 glEnableClientState(GL_VERTEX_ARRAY
);
1508 if(!reflecting
&& !refracting
)
1514 bool doOQ
= !refracting
&& (reflecting
? camera1
->o
.z
>= reflecting
&& hasOQ
&& oqfrags
&& oqreflect
: zpass
!=0);
1517 setupTMUs(cur
, causticspass
, fogpass
);
1518 if(shadowmap
) pushshadowmap();
1527 for(vtxarray
*va
= FIRSTVA
; va
; va
= NEXTVA
)
1529 lodlevel
&lod
= va
->curlod
? va
->l1
: va
->l0
;
1530 if(!lod
.texs
) continue;
1531 if(refracting
|| (reflecting
&& camera1
->o
.z
< reflecting
))
1533 if(va
->curvfc
== VFC_FOGGED
|| (refracting
&& camera1
->o
.z
>= refracting
? va
->min
.z
> refracting
: va
->max
.z
<= reflecting
) || va
->occluded
>= OCCLUDE_GEOM
) continue;
1534 if((!hasOQ
|| !oqfrags
) && va
->distance
> reflectdist
) break;
1538 if(va
->max
.z
<= reflecting
) continue;
1541 va
->rquery
= newquery(&va
->rquery
);
1542 if(!va
->rquery
) continue;
1543 if(va
->occluded
>= OCCLUDE_BB
|| va
->curvfc
== VFC_NOT_VISIBLE
)
1545 renderquery(cur
, va
->rquery
, va
);
1550 else if(hasOQ
&& oqfrags
&& (zpass
|| va
->distance
> oqdist
) && !insideva(va
, camera1
->o
))
1552 if(!zpass
&& va
->query
&& va
->query
->owner
== va
)
1553 va
->occluded
= checkquery(va
->query
) ? min(va
->occluded
+1, OCCLUDE_BB
) : OCCLUDE_NOTHING
;
1554 if(zpass
&& va
->parent
&&
1555 (va
->parent
->occluded
== OCCLUDE_PARENT
||
1556 (va
->parent
->occluded
>= OCCLUDE_BB
&&
1557 va
->parent
->query
&& va
->parent
->query
->owner
== va
->parent
&& va
->parent
->query
->fragments
< 0)))
1560 if(va
->occluded
>= OCCLUDE_GEOM
)
1562 va
->occluded
= OCCLUDE_PARENT
;
1566 else if(va
->occluded
>= OCCLUDE_GEOM
)
1568 va
->query
= newquery(va
);
1569 if(va
->query
) renderquery(cur
, va
->query
, va
);
1572 else va
->query
= newquery(va
);
1577 va
->occluded
= OCCLUDE_NOTHING
;
1582 if(!reflecting
) { if(va
->query
) startquery(va
->query
); }
1583 else if(camera1
->o
.z
>= reflecting
&& va
->rquery
) startquery(va
->rquery
);
1586 renderva(cur
, va
, lod
, doOQ
? RENDERPASS_Z
: (nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
), fogpass
);
1590 if(!reflecting
) { if(va
->query
) endquery(va
->query
); }
1591 else if(camera1
->o
.z
>= reflecting
&& va
->rquery
) endquery(va
->rquery
);
1595 if(!cur
.colormask
) { cur
.colormask
= true; glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
); }
1596 if(!cur
.depthmask
) { cur
.depthmask
= true; glDepthMask(GL_TRUE
); }
1600 setupTMUs(cur
, causticspass
, fogpass
);
1606 glDepthFunc(GL_LEQUAL
);
1607 cur
.vbufGL
= cur
.ebufGL
= 0;
1609 for(vtxarray
**prevva
= &FIRSTVA
, *va
= FIRSTVA
; va
; prevva
= &NEXTVA
, va
= NEXTVA
)
1611 lodlevel
&lod
= va
->curlod
? va
->l1
: va
->l0
;
1612 if(!lod
.texs
) continue;
1615 if(va
->max
.z
<= reflecting
) continue;
1616 if(va
->rquery
&& checkquery(va
->rquery
))
1618 if(va
->occluded
>= OCCLUDE_BB
|| va
->curvfc
== VFC_NOT_VISIBLE
) *prevva
= va
->rnext
;
1622 else if(va
->parent
&& va
->parent
->occluded
>= OCCLUDE_BB
&& (!va
->parent
->query
|| va
->parent
->query
->fragments
>= 0))
1625 va
->occluded
= OCCLUDE_BB
;
1630 va
->occluded
= checkquery(va
->query
) ? min(va
->occluded
+1, OCCLUDE_BB
) : OCCLUDE_NOTHING
;
1631 if(va
->occluded
>= OCCLUDE_GEOM
) continue;
1633 else if(va
->occluded
== OCCLUDE_PARENT
) va
->occluded
= OCCLUDE_NOTHING
;
1635 renderva(cur
, va
, lod
, nolights
? RENDERPASS_COLOR
: RENDERPASS_LIGHTMAP
, fogpass
);
1637 glDepthFunc(GL_LESS
);
1640 if(shadowmap
) popshadowmap();
1644 if((causticspass
&& cur
.causticstmu
<0) || (renderpath
==R_FIXEDFUNCTION
&& ((glowpass
&& cur
.glowtmu
<0) || (fogpass
&& cur
.fogtmu
<0))))
1646 glDepthFunc(GL_LEQUAL
);
1647 glDepthMask(GL_FALSE
);
1649 static GLfloat zerofog
[4] = { 0, 0, 0, 1 }, onefog
[4] = { 1, 1, 1, 1 };
1651 glGetFloatv(GL_FOG_COLOR
, oldfogc
);
1653 if(renderpath
==R_FIXEDFUNCTION
&& glowpass
&& cur
.glowtmu
<0)
1655 glBlendFunc(GL_ONE
, GL_ONE
);
1656 glFogfv(GL_FOG_COLOR
, zerofog
);
1661 glActiveTexture_(GL_TEXTURE1_ARB
);
1662 glEnable(GL_TEXTURE_1D
);
1664 setuptmu(1, "C , P @ Ta");
1665 if(!fogtex
) createfogtex();
1666 glBindTexture(GL_TEXTURE_1D
, fogtex
);
1668 glActiveTexture_(GL_TEXTURE0_ARB
);
1670 else glColor3f(1, 1, 1);
1671 rendergeommultipass(cur
, RENDERPASS_GLOW
, fogpass
);
1676 glActiveTexture_(GL_TEXTURE1_ARB
);
1679 glDisable(GL_TEXTURE_1D
);
1680 glActiveTexture_(GL_TEXTURE0_ARB
);
1684 if(causticspass
&& cur
.causticstmu
<0)
1687 glBlendFunc(GL_ZERO
, GL_SRC_COLOR
);
1688 glFogfv(GL_FOG_COLOR
, onefog
);
1689 if(renderpath
!=R_FIXEDFUNCTION
&& refracting
) glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_FALSE
);
1690 rendergeommultipass(cur
, RENDERPASS_CAUSTICS
, fogpass
);
1691 if(renderpath
!=R_FIXEDFUNCTION
&& refracting
) glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1694 glActiveTexture_(GL_TEXTURE0_ARB
+i
);
1696 if(renderpath
==R_FIXEDFUNCTION
|| !i
)
1701 if(i
) glDisable(GL_TEXTURE_2D
);
1703 glActiveTexture_(GL_TEXTURE0_ARB
);
1706 if(renderpath
==R_FIXEDFUNCTION
&& fogpass
&& cur
.fogtmu
<0)
1708 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1709 glDisable(GL_TEXTURE_2D
);
1710 glEnable(GL_TEXTURE_1D
);
1712 if(!fogtex
) createfogtex();
1713 glBindTexture(GL_TEXTURE_1D
, fogtex
);
1716 getwatercolour(wcol
);
1718 rendergeommultipass(cur
, RENDERPASS_FOG
, fogpass
);
1720 glDisable(GL_TEXTURE_1D
);
1721 glEnable(GL_TEXTURE_2D
);
1724 glFogfv(GL_FOG_COLOR
, oldfogc
);
1725 glDisable(GL_BLEND
);
1726 glDepthFunc(GL_LESS
);
1727 glDepthMask(GL_TRUE
);
1734 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
1735 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
1737 glDisableClientState(GL_VERTEX_ARRAY
);
1740 void findreflectedvas(vector
<vtxarray
*> &vas
, float z
, bool refract
, bool vfc
= true)
1742 bool doOQ
= hasOQ
&& oqfrags
&& oqreflect
;
1745 vtxarray
*va
= vas
[i
];
1746 if(!vfc
) va
->curvfc
= VFC_NOT_VISIBLE
;
1747 if(va
->curvfc
== VFC_FOGGED
|| va
->z
+va
->size
<= z
|| isvisiblecube(vec(va
->x
, va
->y
, va
->z
), va
->size
) >= VFC_FOGGED
) continue;
1749 if(va
->curvfc
== VFC_FULL_VISIBLE
)
1751 if(va
->occluded
>= OCCLUDE_BB
) continue;
1752 if(va
->occluded
>= OCCLUDE_GEOM
) render
= false;
1756 if(va
->curvfc
== VFC_NOT_VISIBLE
) va
->distance
= (int)vadist(va
, camera1
->o
);
1757 if(!doOQ
&& va
->distance
> reflectdist
) continue;
1759 vtxarray
**vprev
= &reflectedva
, *vcur
= reflectedva
;
1760 while(vcur
&& va
->distance
> vcur
->distance
)
1762 vprev
= &vcur
->rnext
;
1768 if(va
->children
->length()) findreflectedvas(*va
->children
, z
, refract
, va
->curvfc
!= VFC_NOT_VISIBLE
);
1772 void renderreflectedgeom(float z
, bool refract
, bool causticspass
, bool fogpass
)
1774 if(!refract
&& camera1
->o
.z
>= z
)
1778 findreflectedvas(varoot
, z
, refract
);
1779 rendergeom(causticspass
, fogpass
);
1782 else rendergeom(causticspass
, fogpass
);
1785 static GLuint skyvbufGL
, skyebufGL
;
1787 void renderskyva(vtxarray
*va
, lodlevel
&lod
, bool explicitonly
= false)
1791 bool vbufchanged
= true;
1794 if(skyvbufGL
== va
->vbufGL
) vbufchanged
= false;
1797 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, va
->vbufGL
);
1798 skyvbufGL
= va
->vbufGL
;
1800 if(skyebufGL
!= lod
.skybufGL
)
1802 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, lod
.skybufGL
);
1803 skyebufGL
= lod
.skybufGL
;
1806 if(vbufchanged
) glVertexPointer(3, floatvtx
? GL_FLOAT
: GL_SHORT
, VTXSIZE
, &(va
->vbuf
[0].x
));
1808 drawvatris(va
, explicitonly
? lod
.explicitsky
: lod
.sky
+lod
.explicitsky
, explicitonly
? lod
.skybuf
+lod
.sky
: lod
.skybuf
);
1810 if(!explicitonly
) xtraverts
+= lod
.sky
/3;
1811 xtraverts
+= lod
.explicitsky
/3;
1814 int renderreflectedskyvas(vector
<vtxarray
*> &vas
, float z
, bool vfc
= true)
1819 vtxarray
*va
= vas
[i
];
1820 lodlevel
&lod
= va
->curlod
? va
->l1
: va
->l0
;
1821 if((vfc
&& va
->curvfc
== VFC_FULL_VISIBLE
) && va
->occluded
>= OCCLUDE_BB
) continue;
1822 if(va
->z
+va
->size
<= z
|| isvisiblecube(vec(va
->x
, va
->y
, va
->z
), va
->size
) == VFC_NOT_VISIBLE
) continue;
1823 if(lod
.sky
+lod
.explicitsky
)
1825 renderskyva(va
, lod
);
1828 if(va
->children
->length()) rendered
+= renderreflectedskyvas(*va
->children
, z
, vfc
&& va
->curvfc
!= VFC_NOT_VISIBLE
);
1833 bool rendersky(bool explicitonly
, float zreflect
)
1835 glEnableClientState(GL_VERTEX_ARRAY
);
1841 skyvbufGL
= skyebufGL
= 0;
1846 reflectvfcP(zreflect
);
1847 rendered
= renderreflectedskyvas(varoot
, zreflect
);
1850 else for(vtxarray
*va
= visibleva
; va
; va
= va
->next
)
1852 lodlevel
&lod
= va
->curlod
? va
->l1
: va
->l0
;
1853 if(va
->occluded
>= OCCLUDE_BB
|| !(explicitonly
? lod
.explicitsky
: lod
.sky
+lod
.explicitsky
)) continue;
1855 renderskyva(va
, lod
, explicitonly
);
1861 if(skyvbufGL
) glBindBuffer_(GL_ARRAY_BUFFER_ARB
, 0);
1862 if(skyebufGL
) glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
1864 glDisableClientState(GL_VERTEX_ARRAY
);