1 /* $Id: s_aatritemp.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 * Antialiased Triangle Rasterizer Template
31 * This file is #include'd to generate custom AA triangle rasterizers.
32 * NOTE: this code hasn't been optimized yet. That'll come after it
35 * The following macros may be defined to indicate what auxillary information
36 * must be copmuted across the triangle:
37 * DO_Z - if defined, compute Z values
38 * DO_RGBA - if defined, compute RGBA values
39 * DO_INDEX - if defined, compute color index values
40 * DO_SPEC - if defined, compute specular RGB values
41 * DO_TEX - if defined, compute unit 0 STRQ texcoords
42 * DO_MULTITEX - if defined, compute all unit's STRQ texcoords
45 /*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
47 const struct vertex_buffer
*VB
= ctx
->VB
;
48 const GLfloat
*p0
= VB
->Win
.data
[v0
];
49 const GLfloat
*p1
= VB
->Win
.data
[v1
];
50 const GLfloat
*p2
= VB
->Win
.data
[v2
];
51 GLint vMin
, vMid
, vMax
;
57 GLfloat zPlane
[4]; /* Z (depth) */
60 GLfixed fog
[MAX_WIDTH
];
63 GLfloat rPlane
[4], gPlane
[4], bPlane
[4], aPlane
[4]; /* color */
64 GLchan rgba
[MAX_WIDTH
][4];
67 GLfloat iPlane
[4]; /* color index */
68 GLuint index
[MAX_WIDTH
];
71 GLfloat srPlane
[4], sgPlane
[4], sbPlane
[4]; /* spec color */
72 GLchan spec
[MAX_WIDTH
][4];
75 GLfloat sPlane
[4], tPlane
[4], uPlane
[4], vPlane
[4];
76 GLfloat texWidth
, texHeight
;
77 GLfloat s
[MAX_WIDTH
], t
[MAX_WIDTH
], u
[MAX_WIDTH
];
78 GLfloat lambda
[MAX_WIDTH
];
79 #elif defined(DO_MULTITEX)
80 GLfloat sPlane
[MAX_TEXTURE_UNITS
][4];
81 GLfloat tPlane
[MAX_TEXTURE_UNITS
][4];
82 GLfloat uPlane
[MAX_TEXTURE_UNITS
][4];
83 GLfloat vPlane
[MAX_TEXTURE_UNITS
][4];
84 GLfloat texWidth
[MAX_TEXTURE_UNITS
], texHeight
[MAX_TEXTURE_UNITS
];
85 GLfloat s
[MAX_TEXTURE_UNITS
][MAX_WIDTH
];
86 GLfloat t
[MAX_TEXTURE_UNITS
][MAX_WIDTH
];
87 GLfloat u
[MAX_TEXTURE_UNITS
][MAX_WIDTH
];
88 GLfloat lambda
[MAX_TEXTURE_UNITS
][MAX_WIDTH
];
90 GLfloat bf
= ctx
->backface_sign
;
92 /* determine bottom to top order of vertices */
94 GLfloat y0
= VB
->Win
.data
[v0
][1];
95 GLfloat y1
= VB
->Win
.data
[v1
][1];
96 GLfloat y2
= VB
->Win
.data
[v2
][1];
99 vMin
= v0
; vMid
= v1
; vMax
= v2
; /* y0<=y1<=y2 */
102 vMin
= v2
; vMid
= v0
; vMax
= v1
; /* y2<=y0<=y1 */
105 vMin
= v0
; vMid
= v2
; vMax
= v1
; bf
= -bf
; /* y0<=y2<=y1 */
110 vMin
= v1
; vMid
= v0
; vMax
= v2
; bf
= -bf
; /* y1<=y0<=y2 */
113 vMin
= v2
; vMid
= v1
; vMax
= v0
; bf
= -bf
; /* y2<=y1<=y0 */
116 vMin
= v1
; vMid
= v2
; vMax
= v0
; /* y1<=y2<=y0 */
121 majDx
= VB
->Win
.data
[vMax
][0] - VB
->Win
.data
[vMin
][0];
122 majDy
= VB
->Win
.data
[vMax
][1] - VB
->Win
.data
[vMin
][1];
125 const GLfloat botDx
= VB
->Win
.data
[vMid
][0] - VB
->Win
.data
[vMin
][0];
126 const GLfloat botDy
= VB
->Win
.data
[vMid
][1] - VB
->Win
.data
[vMin
][1];
127 const GLfloat area
= majDx
* botDy
- botDx
* majDy
;
128 ltor
= (GLboolean
) (area
< 0.0F
);
129 /* Do backface culling */
130 if (area
* bf
< 0 || area
* area
< .0025)
134 #ifndef DO_OCCLUSION_TEST
135 ctx
->OcclusionResult
= GL_TRUE
;
140 compute_plane(p0
, p1
, p2
, p0
[2], p1
[2], p2
[2], zPlane
);
141 compute_plane(p0
, p1
, p2
,
142 VB
->FogCoordPtr
->data
[v0
],
143 VB
->FogCoordPtr
->data
[v1
],
144 VB
->FogCoordPtr
->data
[v2
],
148 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
149 GLchan (*rgba
)[4] = VB
->ColorPtr
->data
;
150 compute_plane(p0
, p1
, p2
, rgba
[v0
][0], rgba
[v1
][0], rgba
[v2
][0], rPlane
);
151 compute_plane(p0
, p1
, p2
, rgba
[v0
][1], rgba
[v1
][1], rgba
[v2
][1], gPlane
);
152 compute_plane(p0
, p1
, p2
, rgba
[v0
][2], rgba
[v1
][2], rgba
[v2
][2], bPlane
);
153 compute_plane(p0
, p1
, p2
, rgba
[v0
][3], rgba
[v1
][3], rgba
[v2
][3], aPlane
);
156 constant_plane(VB
->ColorPtr
->data
[pv
][RCOMP
], rPlane
);
157 constant_plane(VB
->ColorPtr
->data
[pv
][GCOMP
], gPlane
);
158 constant_plane(VB
->ColorPtr
->data
[pv
][BCOMP
], bPlane
);
159 constant_plane(VB
->ColorPtr
->data
[pv
][ACOMP
], aPlane
);
163 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
164 compute_plane(p0
, p1
, p2
, VB
->IndexPtr
->data
[v0
],
165 VB
->IndexPtr
->data
[v1
], VB
->IndexPtr
->data
[v2
], iPlane
);
168 constant_plane(VB
->IndexPtr
->data
[pv
], iPlane
);
173 GLchan (*spec
)[4] = VB
->SecondaryColorPtr
->data
;
174 compute_plane(p0
, p1
, p2
, spec
[v0
][0], spec
[v1
][0], spec
[v2
][0],srPlane
);
175 compute_plane(p0
, p1
, p2
, spec
[v0
][1], spec
[v1
][1], spec
[v2
][1],sgPlane
);
176 compute_plane(p0
, p1
, p2
, spec
[v0
][2], spec
[v1
][2], spec
[v2
][2],sbPlane
);
181 const struct gl_texture_object
*obj
= ctx
->Texture
.Unit
[0].Current
;
182 const struct gl_texture_image
*texImage
= obj
->Image
[obj
->BaseLevel
];
183 const GLint tSize
= 3;
184 const GLfloat invW0
= VB
->Win
.data
[v0
][3];
185 const GLfloat invW1
= VB
->Win
.data
[v1
][3];
186 const GLfloat invW2
= VB
->Win
.data
[v2
][3];
187 GLfloat (*texCoord
)[4] = VB
->TexCoordPtr
[0]->data
;
188 const GLfloat s0
= texCoord
[v0
][0] * invW0
;
189 const GLfloat s1
= texCoord
[v1
][0] * invW1
;
190 const GLfloat s2
= texCoord
[v2
][0] * invW2
;
191 const GLfloat t0
= (tSize
> 1) ? texCoord
[v0
][1] * invW0
: 0.0F
;
192 const GLfloat t1
= (tSize
> 1) ? texCoord
[v1
][1] * invW1
: 0.0F
;
193 const GLfloat t2
= (tSize
> 1) ? texCoord
[v2
][1] * invW2
: 0.0F
;
194 const GLfloat r0
= (tSize
> 2) ? texCoord
[v0
][2] * invW0
: 0.0F
;
195 const GLfloat r1
= (tSize
> 2) ? texCoord
[v1
][2] * invW1
: 0.0F
;
196 const GLfloat r2
= (tSize
> 2) ? texCoord
[v2
][2] * invW2
: 0.0F
;
197 const GLfloat q0
= (tSize
> 3) ? texCoord
[v0
][3] * invW0
: invW0
;
198 const GLfloat q1
= (tSize
> 3) ? texCoord
[v1
][3] * invW1
: invW1
;
199 const GLfloat q2
= (tSize
> 3) ? texCoord
[v2
][3] * invW2
: invW2
;
200 compute_plane(p0
, p1
, p2
, s0
, s1
, s2
, sPlane
);
201 compute_plane(p0
, p1
, p2
, t0
, t1
, t2
, tPlane
);
202 compute_plane(p0
, p1
, p2
, r0
, r1
, r2
, uPlane
);
203 compute_plane(p0
, p1
, p2
, q0
, q1
, q2
, vPlane
);
204 texWidth
= (GLfloat
) texImage
->Width
;
205 texHeight
= (GLfloat
) texImage
->Height
;
207 #elif defined(DO_MULTITEX)
210 for (u
= 0; u
< ctx
->Const
.MaxTextureUnits
; u
++) {
211 if (ctx
->Texture
.Unit
[u
].ReallyEnabled
) {
212 const struct gl_texture_object
*obj
= ctx
->Texture
.Unit
[u
].Current
;
213 const struct gl_texture_image
*texImage
= obj
->Image
[obj
->BaseLevel
];
214 const GLint tSize
= VB
->TexCoordPtr
[u
]->size
;
215 const GLfloat invW0
= VB
->Win
.data
[v0
][3];
216 const GLfloat invW1
= VB
->Win
.data
[v1
][3];
217 const GLfloat invW2
= VB
->Win
.data
[v2
][3];
218 GLfloat (*texCoord
)[4] = VB
->TexCoordPtr
[u
]->data
;
219 const GLfloat s0
= texCoord
[v0
][0] * invW0
;
220 const GLfloat s1
= texCoord
[v1
][0] * invW1
;
221 const GLfloat s2
= texCoord
[v2
][0] * invW2
;
222 const GLfloat t0
= (tSize
> 1) ? texCoord
[v0
][1] * invW0
: 0.0F
;
223 const GLfloat t1
= (tSize
> 1) ? texCoord
[v1
][1] * invW1
: 0.0F
;
224 const GLfloat t2
= (tSize
> 1) ? texCoord
[v2
][1] * invW2
: 0.0F
;
225 const GLfloat r0
= (tSize
> 2) ? texCoord
[v0
][2] * invW0
: 0.0F
;
226 const GLfloat r1
= (tSize
> 2) ? texCoord
[v1
][2] * invW1
: 0.0F
;
227 const GLfloat r2
= (tSize
> 2) ? texCoord
[v2
][2] * invW2
: 0.0F
;
228 const GLfloat q0
= (tSize
> 3) ? texCoord
[v0
][3] * invW0
: invW0
;
229 const GLfloat q1
= (tSize
> 3) ? texCoord
[v1
][3] * invW1
: invW1
;
230 const GLfloat q2
= (tSize
> 3) ? texCoord
[v2
][3] * invW2
: invW2
;
231 compute_plane(p0
, p1
, p2
, s0
, s1
, s2
, sPlane
[u
]);
232 compute_plane(p0
, p1
, p2
, t0
, t1
, t2
, tPlane
[u
]);
233 compute_plane(p0
, p1
, p2
, r0
, r1
, r2
, uPlane
[u
]);
234 compute_plane(p0
, p1
, p2
, q0
, q1
, q2
, vPlane
[u
]);
235 texWidth
[u
] = (GLfloat
) texImage
->Width
;
236 texHeight
[u
] = (GLfloat
) texImage
->Height
;
242 yMin
= VB
->Win
.data
[vMin
][1];
243 yMax
= VB
->Win
.data
[vMax
][1];
245 iyMax
= (int) yMax
+ 1;
248 /* scan left to right */
249 const float *pMin
= VB
->Win
.data
[vMin
];
250 const float *pMid
= VB
->Win
.data
[vMid
];
251 const float *pMax
= VB
->Win
.data
[vMax
];
252 const float dxdy
= majDx
/ majDy
;
253 const float xAdj
= dxdy
< 0.0F
? -dxdy
: 0.0F
;
254 float x
= VB
->Win
.data
[vMin
][0] - (yMin
- iyMin
) * dxdy
;
256 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
257 GLint ix
, startX
= (GLint
) (x
- xAdj
);
259 GLfloat coverage
= 0.0F
;
260 /* skip over fragments with zero coverage */
261 while (startX
< MAX_WIDTH
) {
262 coverage
= compute_coveragef(pMin
, pMid
, pMax
, startX
, iy
);
268 /* enter interior of triangle */
271 while (coverage
> 0.0F
) {
273 z
[count
] = (GLdepth
) solve_plane(ix
, iy
, zPlane
);
274 fog
[count
] = FloatToFixed(solve_plane(ix
, iy
, fogPlane
));
277 rgba
[count
][RCOMP
] = solve_plane_chan(ix
, iy
, rPlane
);
278 rgba
[count
][GCOMP
] = solve_plane_chan(ix
, iy
, gPlane
);
279 rgba
[count
][BCOMP
] = solve_plane_chan(ix
, iy
, bPlane
);
280 rgba
[count
][ACOMP
] = (GLchan
) (solve_plane_chan(ix
, iy
, aPlane
) * coverage
);
284 GLint frac
= compute_coveragei(pMin
, pMid
, pMax
, ix
, iy
);
285 GLint indx
= (GLint
) solve_plane(ix
, iy
, iPlane
);
286 index
[count
] = (indx
& ~0xf) | frac
;
290 spec
[count
][RCOMP
] = solve_plane_chan(ix
, iy
, srPlane
);
291 spec
[count
][GCOMP
] = solve_plane_chan(ix
, iy
, sgPlane
);
292 spec
[count
][BCOMP
] = solve_plane_chan(ix
, iy
, sbPlane
);
296 GLfloat invQ
= solve_plane_recip(ix
, iy
, vPlane
);
297 s
[count
] = solve_plane(ix
, iy
, sPlane
) * invQ
;
298 t
[count
] = solve_plane(ix
, iy
, tPlane
) * invQ
;
299 u
[count
] = solve_plane(ix
, iy
, uPlane
) * invQ
;
300 lambda
[count
] = compute_lambda(sPlane
, tPlane
, invQ
,
301 texWidth
, texHeight
);
303 #elif defined(DO_MULTITEX)
306 for (unit
= 0; unit
< ctx
->Const
.MaxTextureUnits
; unit
++) {
307 if (ctx
->Texture
.Unit
[unit
].ReallyEnabled
) {
308 GLfloat invQ
= solve_plane_recip(ix
, iy
, vPlane
[unit
]);
309 s
[unit
][count
] = solve_plane(ix
, iy
, sPlane
[unit
]) * invQ
;
310 t
[unit
][count
] = solve_plane(ix
, iy
, tPlane
[unit
]) * invQ
;
311 u
[unit
][count
] = solve_plane(ix
, iy
, uPlane
[unit
]) * invQ
;
312 lambda
[unit
][count
] = compute_lambda(sPlane
[unit
],
313 tPlane
[unit
], invQ
, texWidth
[unit
], texHeight
[unit
]);
320 coverage
= compute_coveragef(pMin
, pMid
, pMax
, ix
, iy
);
323 n
= (GLuint
) ix
- (GLuint
) startX
;
326 gl_write_multitexture_span(ctx
, n
, startX
, iy
, z
, fog
,
327 (const GLfloat (*)[MAX_WIDTH
]) s
,
328 (const GLfloat (*)[MAX_WIDTH
]) t
,
329 (const GLfloat (*)[MAX_WIDTH
]) u
,
330 (GLfloat (*)[MAX_WIDTH
]) lambda
,
331 rgba
, (const GLchan (*)[4]) spec
,
334 gl_write_multitexture_span(ctx
, n
, startX
, iy
, z
, fog
,
335 (const GLfloat (*)[MAX_WIDTH
]) s
,
336 (const GLfloat (*)[MAX_WIDTH
]) t
,
337 (const GLfloat (*)[MAX_WIDTH
]) u
,
338 lambda
, rgba
, NULL
, GL_POLYGON
);
340 #elif defined(DO_TEX)
342 gl_write_texture_span(ctx
, n
, startX
, iy
, z
, fog
,
343 s
, t
, u
, lambda
, rgba
,
344 (const GLchan (*)[4]) spec
, GL_POLYGON
);
346 gl_write_texture_span(ctx
, n
, startX
, iy
, z
, fog
,
348 rgba
, NULL
, GL_POLYGON
);
350 #elif defined(DO_RGBA)
351 gl_write_rgba_span(ctx
, n
, startX
, iy
, z
, fog
, rgba
, GL_POLYGON
);
352 #elif defined(DO_INDEX)
353 gl_write_index_span(ctx
, n
, startX
, iy
, z
, fog
, index
, GL_POLYGON
);
358 /* scan right to left */
359 const GLfloat
*pMin
= VB
->Win
.data
[vMin
];
360 const GLfloat
*pMid
= VB
->Win
.data
[vMid
];
361 const GLfloat
*pMax
= VB
->Win
.data
[vMax
];
362 const GLfloat dxdy
= majDx
/ majDy
;
363 const GLfloat xAdj
= dxdy
> 0 ? dxdy
: 0.0F
;
364 GLfloat x
= VB
->Win
.data
[vMin
][0] - (yMin
- iyMin
) * dxdy
;
366 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
367 GLint ix
, left
, startX
= (GLint
) (x
+ xAdj
);
369 GLfloat coverage
= 0.0F
;
370 /* skip fragments with zero coverage */
371 while (startX
>= 0) {
372 coverage
= compute_coveragef(pMin
, pMax
, pMid
, startX
, iy
);
378 /* enter interior of triangle */
381 while (coverage
> 0.0F
) {
383 z
[ix
] = (GLdepth
) solve_plane(ix
, iy
, zPlane
);
384 fog
[ix
] = FloatToFixed(solve_plane(ix
, iy
, fogPlane
));
387 rgba
[ix
][RCOMP
] = solve_plane_chan(ix
, iy
, rPlane
);
388 rgba
[ix
][GCOMP
] = solve_plane_chan(ix
, iy
, gPlane
);
389 rgba
[ix
][BCOMP
] = solve_plane_chan(ix
, iy
, bPlane
);
390 rgba
[ix
][ACOMP
] = (GLchan
) (solve_plane_chan(ix
, iy
, aPlane
) * coverage
);
394 GLint frac
= compute_coveragei(pMin
, pMax
, pMid
, ix
, iy
);
395 GLint indx
= (GLint
) solve_plane(ix
, iy
, iPlane
);
396 index
[ix
] = (indx
& ~0xf) | frac
;
400 spec
[ix
][RCOMP
] = solve_plane_chan(ix
, iy
, srPlane
);
401 spec
[ix
][GCOMP
] = solve_plane_chan(ix
, iy
, sgPlane
);
402 spec
[ix
][BCOMP
] = solve_plane_chan(ix
, iy
, sbPlane
);
406 GLfloat invQ
= solve_plane_recip(ix
, iy
, vPlane
);
407 s
[ix
] = solve_plane(ix
, iy
, sPlane
) * invQ
;
408 t
[ix
] = solve_plane(ix
, iy
, tPlane
) * invQ
;
409 u
[ix
] = solve_plane(ix
, iy
, uPlane
) * invQ
;
410 lambda
[ix
] = compute_lambda(sPlane
, tPlane
, invQ
,
411 texWidth
, texHeight
);
413 #elif defined(DO_MULTITEX)
416 for (unit
= 0; unit
< ctx
->Const
.MaxTextureUnits
; unit
++) {
417 if (ctx
->Texture
.Unit
[unit
].ReallyEnabled
) {
418 GLfloat invQ
= solve_plane_recip(ix
, iy
, vPlane
[unit
]);
419 s
[unit
][ix
] = solve_plane(ix
, iy
, sPlane
[unit
]) * invQ
;
420 t
[unit
][ix
] = solve_plane(ix
, iy
, tPlane
[unit
]) * invQ
;
421 u
[unit
][ix
] = solve_plane(ix
, iy
, uPlane
[unit
]) * invQ
;
422 lambda
[unit
][ix
] = compute_lambda(sPlane
[unit
],
423 tPlane
[unit
], invQ
, texWidth
[unit
], texHeight
[unit
]);
430 coverage
= compute_coveragef(pMin
, pMax
, pMid
, ix
, iy
);
433 n
= (GLuint
) startX
- (GLuint
) ix
;
438 for (unit
= 0; unit
< ctx
->Const
.MaxTextureUnits
; unit
++) {
439 if (ctx
->Texture
.Unit
[unit
].ReallyEnabled
) {
441 for (j
= 0; j
< n
; j
++) {
442 s
[unit
][j
] = s
[unit
][j
+ left
];
443 t
[unit
][j
] = t
[unit
][j
+ left
];
444 u
[unit
][j
] = u
[unit
][j
+ left
];
445 lambda
[unit
][j
] = lambda
[unit
][j
+ left
];
451 gl_write_multitexture_span(ctx
, n
, left
, iy
, z
+ left
, fog
+ left
,
452 (const GLfloat (*)[MAX_WIDTH
]) s
,
453 (const GLfloat (*)[MAX_WIDTH
]) t
,
454 (const GLfloat (*)[MAX_WIDTH
]) u
,
456 (const GLchan (*)[4]) (spec
+ left
),
459 gl_write_multitexture_span(ctx
, n
, left
, iy
, z
+ left
, fog
+ left
,
460 (const GLfloat (*)[MAX_WIDTH
]) s
,
461 (const GLfloat (*)[MAX_WIDTH
]) t
,
462 (const GLfloat (*)[MAX_WIDTH
]) u
,
464 rgba
+ left
, NULL
, GL_POLYGON
);
466 #elif defined(DO_TEX)
468 gl_write_texture_span(ctx
, n
, left
, iy
, z
+ left
, fog
+ left
,
469 s
+ left
, t
+ left
, u
+ left
,
470 lambda
+ left
, rgba
+ left
,
471 (const GLchan (*)[4]) (spec
+ left
),
474 gl_write_texture_span(ctx
, n
, left
, iy
, z
+ left
, fog
+ left
,
476 u
+ left
, lambda
+ left
,
477 rgba
+ left
, NULL
, GL_POLYGON
);
479 #elif defined(DO_RGBA)
480 gl_write_rgba_span(ctx
, n
, left
, iy
, z
+ left
, fog
+ left
,
481 rgba
+ left
, GL_POLYGON
);
482 #elif defined(DO_INDEX)
483 gl_write_index_span(ctx
, n
, left
, iy
, z
+ left
, fog
+ left
,
484 index
+ left
, GL_POLYGON
);
515 #ifdef DO_OCCLUSION_TEST
516 #undef DO_OCCLUSION_TEST