home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 6
/
AACD06.ISO
/
AACD
/
System
/
Mesa-3.1
/
src
/
vbcull.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-07
|
23KB
|
981 lines
/* $Id: vbcull.c,v 1.7 1999/11/08 15:28:58 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 3.1
*
* Copyright (C) 1999 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* New (3.1) transformation code written by Keith Whitwell.
*/
#ifdef PC_HEADER
#include "all.h"
#else
#ifndef XFree86Server
#include <stdio.h>
#else
#include "GL/xf86glx.h"
#endif
#include "context.h"
#include "macros.h"
#include "types.h"
#include "vb.h"
#include "vbcull.h"
#include "vbrender.h"
#include "xform.h"
#endif
/* Culling for vertices and primitives.
* (C) Keith Whitwell, December 1998.
*
* These functions build bitmasks which can be used to shortcircuit
* lighting, fogging and texture calculations, and to convert
* two-sided lighting into one-sided on a per-vertex basis.
*
* Each of these functions returns a value 'cullcount'. The meaning
* of this value just has to satisfy the requirements:
*
* cullcount == VB->Count implies the entire vb has been culled and
* can be discarded.
*
* cullcount == 0 implies that every vertex in the buffer is required
* and that the cullmask can be ignored for transformation
* and lighting.
*
*/
const char *gl_prim_name[GL_POLYGON+2] = {
"GL_POINTS",
"GL_LINES",
"GL_LINE_LOOP",
"GL_LINE_STRIP",
"GL_TRIANGLES",
"GL_TRIANGLE_STRIP",
"GL_TRIANGLE_FAN",
"GL_QUADS",
"GL_QUAD_STRIP",
"GL_POLYGON",
"culled primitive"
};
static GLuint gl_cull_points( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint parity,
CONST GLfloat (*proj)[4])
{
const GLubyte *clipmask = VB->ClipMask;
GLubyte *cullmask = VB->CullMask;
GLuint i, cullcount = 0;
(void) parity;
(void) proj;
/* This is pretty pointless. (arf arf)
*/
for (i=start+1;i<count;i++) {
if (clipmask[i] == 0)
cullmask[i] = VERT_FACE_FRONT | PRIM_FACE_FRONT;
else {
cullcount++;
}
}
return cullcount;
}
/* Covers all the non-polygonal primitives when only area culling is
* activated.
*/
static GLuint gl_cull_points_neither( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint parity,
CONST GLfloat (*proj)[4])
{
GLubyte unculled_prim = VERT_FACE_FRONT|PRIM_FACE_FRONT;
(void) parity;
(void) proj;
MEMSET(VB->CullMask+start, unculled_prim, (count-start)*sizeof(GLubyte));
return 0;
}
#define CULL_LINE( i1, i, nr ) \
do { \
GLubyte ClipOr = VB->ClipMask[i1] | VB->ClipMask[i]; \
\
if (ClipOr) { \
if (VB->ClipMask[i1] & VB->ClipMask[i] & CLIP_ALL_BITS) { \
cullcount+=nr; \
} \
else { \
cullmask[i1] |= VERT_FACE_FRONT; \
cullmask[i] |= VERT_FACE_FRONT | PRIM_FACE_FRONT | PRIM_CLIPPED; \
} \
} else { \
cullmask[i1] |= VERT_FACE_FRONT; \
cullmask[i] |= VERT_FACE_FRONT | PRIM_FACE_FRONT; \
} \
} while (0)
static GLuint gl_cull_lines( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint parity,
CONST GLfloat (*proj)[4])
{
GLubyte *cullmask = VB->CullMask;
GLuint cullcount = 0;
GLuint i;
GLuint last = count - 1;
(void) parity;
(void) proj;
for (i = start; i < last ; i += 2) {
CULL_LINE(i, i+1, 2);
}
if (i != last)
cullcount++;
return cullcount;
}
static GLuint gl_cull_line_strip( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint parity,
CONST GLfloat (*proj)[4])
{
GLubyte *cullmask = VB->CullMask;
GLuint cullcount = 0;
GLuint i;
GLuint last = count - 1;
GLuint nr = 2;
(void) parity;
(void) proj;
for (i = start; i < last ; i++, nr = 1) {
CULL_LINE(i, i+1, nr);
}
if (i != last)
cullcount++;
return cullcount;
}
static GLuint gl_cull_line_loop( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint parity,
CONST GLfloat (*proj)[4])
{
GLuint cullcount = 0;
GLubyte *cullmask = VB->CullMask;
GLuint i, last = count - 1;
(void) parity;
(void) proj;
if (count - start < 2)
return count - start;
for (i = start; i < last ; i++) {
CULL_LINE(i, i+1, 1);
}
CULL_LINE(last, start, 1);
return cullcount;
}
#define CULL_TRI( do_clip, do_area, i2, i1, i0, parity, nr ) \
do { \
GLubyte ClipOr = 0; \
if (do_clip) { \
ClipOr = (VB->ClipMask[i2] | \
VB->ClipMask[i1] | \
VB->ClipMask[i0]); \
} \
\
if (do_clip && (ClipOr&CLIP_ALL_BITS)) \
{ \
if (VB->ClipMask[i2] & VB->ClipMask[i1] & VB->ClipMask[i0] & \
CLIP_ALL_BITS) \
{ \
cullcount+=nr; \
} \
else \
{ \
cullmask[i0] = cull_faces | PRIM_CLIPPED; \
cullmask[i1] |= cull_faces; \
cullmask[i2] |= cull_faces; \
} \
} \
else \
{ \
GLfloat area; \
GLubyte face_flags; \
\
if (do_area) { \
area = ((proj[i2][0] - proj[i0][0]) * \
(proj[i1][1] - proj[i0][1]) - \
(proj[i2][1] - proj[i0][1]) * \
(proj[i1][0] - proj[i0][0])); \
\
face_flags = (((area<0.0F) ^ parity) + 1) & cull_faces; \
} else { \
face_flags = cull_faces; \
} \
\
if (!do_area || face_flags) \
{ \
cullmask[i0] = face_flags | (face_flags << PRIM_FLAG_SHIFT); \
cullmask[i1] |= face_flags; \
cullmask[i2] |= face_flags; \
if (do_clip && ClipOr) cullmask[i0] |= PRIM_CLIPPED; \
} \
else \
{ \
cullcount+=nr; \
} \
} \
} while (0)
#define CULL_QUAD( do_clip, do_area, i3, i2, i1, i, nr ) \
do { \
GLubyte ClipOr = 0; \
\
if (do_clip) { \
ClipOr = (VB->ClipMask[i3] | \
VB->ClipMask[i2] | \
VB->ClipMask[i1] | \
VB->ClipMask[i]); \
} \
\
if (do_clip && (ClipOr&CLIP_ALL_BITS)) \
{ \
if (VB->ClipMask[i3] & VB->ClipMask[i2] & \
VB->ClipMask[i1] & VB->ClipMask[i] & \
CLIP_ALL_BITS) \
{ \
cullcount+=nr; \
} \
else \
{ \
cullmask[i] = cull_faces | PRIM_CLIPPED; \
cullmask[i1] = cull_faces | PRIM_CLIPPED; \
cullmask[i2] |= cull_faces; \
cullmask[i3] |= cull_faces; \
} \
} \
else \
{ \
GLfloat area; \
GLubyte face_flags; \
\
if (do_area) { \
area = ((proj[i1][0] - proj[i3][0]) * /* ex */ \
(proj[i ][1] - proj[i2][1]) - /* fy */ \
(proj[i1][1] - proj[i3][1]) * /* ey */ \
(proj[i ][0] - proj[i2][0])); /* fx */ \
\
face_flags = (((area<0.0F) ^ face_bit) + 1) & cull_faces; \
} else { \
face_flags = cull_faces; \
} \
\
if (do_area && !face_flags) \
{ \
cullcount+=nr; \
} \
else \
{ \
cullmask[i] = face_flags | (face_flags<<PRIM_FLAG_SHIFT); \
cullmask[i1] = face_flags | (face_flags<<PRIM_FLAG_SHIFT); \
cullmask[i2] |= face_flags; \
cullmask[i3] |= face_flags; \
if (ClipOr) \
cullmask[i] |= PRIM_CLIPPED; \
} \
} \
} while(0)
#define DO_AREA 1
#define DO_CLIP 1
#define TAG(x) x
#include "cull_tmp.h"
#define DO_AREA 1
#define DO_CLIP 0
#define TAG(x) x##_area
#include "cull_tmp.h"
#define DO_AREA 0
#define DO_CLIP 1
#define TAG(x) x##_clip
#include "cull_tmp.h"
static GLuint gl_cull_dummy_prim( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint parity,
CONST GLfloat (*proj)[4])
{
(void) VB;
(void) parity;
(void) proj;
return count - start;
}
/* KW: Force the vertices which are used in both this and the
* next vertex buffer to be fully transformed on their first
* appearance. Need to do this because otherwise I would have
* to try to copy the un-transformed (Obj, Normal) data. This
* is difficult in the case of shared normals, and seems
* to be quite complex in the immediate mode case. For now,
* just force the copied vertices to be transformed.
*
* KW: Copy now organized to grow towards zero.
*/
static GLuint gl_copy_last_cull( struct vertex_buffer *VB,
GLuint start, GLuint count,
GLuint ovf, CONST GLfloat (*proj)[4])
{
const GLcontext *ctx = VB->ctx;
GLubyte *cullmask = VB->CullMask;
GLuint rv = 0;
(void) start;
(void) ovf;
if (cullmask[count-1] == 0) {
rv++;
cullmask[count-1] = ctx->Polygon.CullBits;
}
VB->CopyCount = 1;
VB->Copy[2] = count-1;
COPY_4FV(VB->CopyProj[2], proj[count-1]);
return rv;
}
static GLuint gl_copy_first_and_last_cull( struct vertex_buffer *VB,
GLuint start,
GLuint count, GLuint ovf,
CONST GLfloat (*proj)[4] )
{
const GLcontext *ctx = VB->ctx;
GLuint rv = 0;
GLubyte *cullmask = VB->CullMask;
(void) ovf;
if (cullmask[count-1] == 0) {
rv++;
cullmask[count-1] = ctx->Polygon.CullBits;
}
if (cullmask[start] == 0) {
rv++;
cullmask[start] = ctx->Polygon.CullBits;
}
VB->CopyCount = 2;
VB->Copy[1] = start;
VB->Copy[2] = count-1;
COPY_4FV(VB->CopyProj[1], proj[start]);
COPY_4FV(VB->CopyProj[2], proj[count-1]);
return rv;
}
/* Must be able to cope with zero or one overflow
*
*/
static GLuint gl_copy_last_two_cull( struct vertex_buffer *VB,
GLuint start,
GLuint count, GLuint ovf,
CONST GLfloat (*proj)[4] )
{
const GLcontext *ctx = VB->ctx;
GLubyte *cullmask = VB->CullMask;
GLuint rv = 0;
(void) start;
if (cullmask[count-1] == 0) {
rv++;
cullmask[count-1] = ctx->Polygon.CullBits;
}
if (cullmask[count-2] == 0) {
rv++;
cullmask[count-2] = ctx->Polygon.CullBits;
}
VB->CopyCount = 2;
VB->Copy[1] = count-2;
VB->Copy[2] = count-1;
COPY_4FV(VB->CopyProj[1], proj[count-2]);
COPY_4FV(VB->CopyProj[2], proj[count-1]);
if (ovf == 1) {
if (cullmask[count-3] == 0) {
rv++;
cullmask[count-3] = ctx->Polygon.CullBits;
}
VB->CopyCount = 3;
VB->Copy[0] = count-3;
COPY_4FV(VB->CopyProj[0], proj[count-3]);
}
return rv;
}
/* Eg, quads - just copy the overflow, guarenteed to all be culled.
*/
static GLuint gl_copy_overflow_cull( struct vertex_buffer *VB,
GLuint start, GLuint count,
GLuint ovf, CONST GLfloat (*proj)[4] )
{
const GLcontext *ctx = VB->ctx;
GLubyte *cullmask = VB->CullMask;
GLuint src_offset = count - ovf;
GLuint dst_offset = 3 - ovf;
GLuint i;
(void) start;
VB->CopyCount = ovf;
for (i = 0 ; i < ovf ; i++) {
cullmask[i+src_offset] = ctx->Polygon.CullBits;
VB->Copy[i+dst_offset] = i+src_offset;
COPY_4FV(VB->CopyProj[i+dst_offset], proj[i+src_offset]);
}
return ovf;
}
static GLuint gl_copy_last( struct vertex_buffer *VB,
GLuint start, GLuint count,
GLuint ovf, CONST GLfloat (*proj)[4])
{
(void) start;
(void) ovf;
VB->CopyCount = 1;
VB->Copy[2] = count-1;
COPY_4FV(VB->CopyProj[2], proj[count-1]);
return 0;
}
static GLuint gl_copy_first_and_last( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint ovf, CONST GLfloat (*proj)[4])
{
(void) ovf;
VB->CopyCount = 2;
VB->Copy[1] = start;
VB->Copy[2] = count-1;
COPY_4FV(VB->CopyProj[1], proj[start]);
COPY_4FV(VB->CopyProj[2], proj[count-1]);
return 0;
}
static GLuint gl_copy_last_two( struct vertex_buffer *VB,
GLuint start, GLuint count,
GLuint ovf, CONST GLfloat (*proj)[4])
{
(void) start;
VB->CopyCount = 2;
VB->Copy[1] = count-2;
VB->Copy[2] = count-1;
COPY_4FV(VB->CopyProj[1], proj[count-2]);
COPY_4FV(VB->CopyProj[2], proj[count-1]);
if (ovf == 1) {
VB->CopyCount = 3;
VB->Copy[0] = count-3;
COPY_4FV(VB->CopyProj[0], proj[count-3]);
}
return 0;
}
static GLuint gl_copy_overflow( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint ovf,
CONST GLfloat (*proj)[4] )
{
GLuint src_offset = count - ovf;
GLuint dst_offset = 3 - ovf;
GLuint i;
(void) start;
VB->CopyCount = ovf;
for (i = 0 ; i < ovf ; i++) {
VB->Copy[i+dst_offset] = i+src_offset;
COPY_4FV(VB->CopyProj[i+dst_offset], proj[i+src_offset]);
}
return 0;
}
static void gl_fast_copy_noop( struct vertex_buffer *VB,
GLuint start, GLuint count,
GLuint ovf)
{
(void) start;
(void) ovf;
(void) VB;
(void) count;
}
static void gl_fast_copy_last( struct vertex_buffer *VB,
GLuint start, GLuint count,
GLuint ovf)
{
(void) start;
(void) ovf;
VB->CopyCount = 1;
VB->Copy[2] = count-1;
}
static void gl_fast_copy_first_and_last( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint ovf)
{
(void) ovf;
VB->CopyCount = 2;
VB->Copy[1] = start;
VB->Copy[2] = count-1;
}
static void gl_fast_copy_last_two( struct vertex_buffer *VB,
GLuint start, GLuint count,
GLuint ovf )
{
(void) start;
VB->CopyCount = 2;
VB->Copy[1] = count-2;
VB->Copy[2] = count-1;
if (ovf == 1) {
VB->CopyCount = 3;
VB->Copy[0] = count-3;
}
}
static void gl_fast_copy_overflow( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint ovf )
{
GLuint src_offset = count - ovf;
GLuint dst_offset = 3 - ovf;
GLuint i;
(void) start;
VB->CopyCount = ovf;
for (i = 0 ; i < ovf ; i++)
VB->Copy[i+dst_offset] = i+src_offset;
}
typedef void (*fast_copy_func)( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint ovf );
typedef GLuint (*cull_func)( struct vertex_buffer *VB,
GLuint start,
GLuint count,
GLuint parity,
CONST GLfloat (*proj)[4]);
typedef GLuint (*copy_func)( struct vertex_buffer *VB,
GLuint start,
GLuint end,
GLuint ovf,
CONST GLfloat (*proj)[4] );
static cull_func cull_tab_both[GL_POLYGON+2] =
{
gl_cull_points,
gl_cull_lines,
gl_cull_line_loop,
gl_cull_line_strip,
gl_cull_triangles,
gl_cull_triangle_strip,
gl_cull_triangle_fan,
gl_cull_quads,
gl_cull_quad_strip,
gl_cull_triangle_fan,
gl_cull_dummy_prim
};
static cull_func cull_tab_area[GL_POLYGON+2] =
{
gl_cull_points_neither,
gl_cull_points_neither,
gl_cull_points_neither,
gl_cull_points_neither,
gl_cull_triangles_area,
gl_cull_triangle_strip_area,
gl_cull_triangle_fan_area,
gl_cull_quads_area,
gl_cull_quad_strip_area,
gl_cull_triangle_fan_area,
gl_cull_dummy_prim
};
static cull_func cull_tab_clip[GL_POLYGON+2] =
{
gl_cull_points,
gl_cull_lines,
gl_cull_line_loop,
gl_cull_line_strip,
gl_cull_triangles_clip,
gl_cull_triangle_strip_clip,
gl_cull_triangle_fan_clip,
gl_cull_quads_clip,
gl_cull_quad_strip_clip,
gl_cull_triangle_fan_clip,
gl_cull_dummy_prim
};
static cull_func *cull_tab[4] =
{
0,
cull_tab_area,
cull_tab_clip,
cull_tab_both
};
static copy_func copy_tab_cull[GL_POLYGON+2] =
{
0,
gl_copy_overflow_cull,
gl_copy_first_and_last_cull,
gl_copy_last_cull,
gl_copy_overflow_cull,
gl_copy_last_two_cull,
gl_copy_first_and_last_cull,
gl_copy_overflow_cull,
gl_copy_last_two_cull,
gl_copy_first_and_last_cull,
0,
};
static copy_func copy_tab_no_cull[GL_POLYGON+2] =
{
0,
gl_copy_overflow,
gl_copy_first_and_last,
gl_copy_last,
gl_copy_overflow,
gl_copy_last_two,
gl_copy_first_and_last,
gl_copy_overflow,
gl_copy_last_two,
gl_copy_first_and_last,
0,
};
static fast_copy_func fast_copy_tab[GL_POLYGON+2] =
{
gl_fast_copy_noop,
gl_fast_copy_overflow,
gl_fast_copy_first_and_last,
gl_fast_copy_last,
gl_fast_copy_overflow,
gl_fast_copy_last_two,
gl_fast_copy_first_and_last,
gl_fast_copy_overflow,
gl_fast_copy_last_two,
gl_fast_copy_first_and_last,
gl_fast_copy_noop,
};
/* Do this after (?) primitive fixup on buffers containing unwanted
* eval coords. No early culling will be done on these vertices (it's
* a degenerate case & not worth the code), and the vertices will be
* rendered by a special 'indirect' case in gl_render_vb. Otherwise,
* the cullmask will force (some) transforms to skip these vertices.
*/
void gl_purge_vertices( struct vertex_buffer *VB )
{
GLuint *flags = VB->Flag;
GLubyte *cullmask = VB->CullMask;
GLuint *indirect = VB->Indirect = VB->EltPtr->start;
GLuint *in_prim = VB->Primitive;
GLuint *out_prim = VB->IM->Primitive;
GLuint *in_nextprim = VB->NextPrimitive;
GLuint *out_nextprim = VB->IM->NextPrimitive;
GLuint count = VB->Count;
GLuint purge = VB->PurgeFlags;
GLuint next, start;
GLuint j;
/*
*/
for ( j = start = VB->CopyStart ; start < count ; start = next ) {
GLuint startj = j;
GLuint i;
next = in_nextprim[start];
out_prim[j] = in_prim[start];
for ( i = start ; i < next ; i++) {
if (~(flags[i] & purge)) {
indirect[j] = i;
cullmask[i] = PRIM_CLIPPED; /* nonzero */
j++;
}
}
out_nextprim[startj] = j;
}
VB->Primitive = out_prim;
VB->NextPrimitive = out_nextprim;
VB->IndirectCount = j;
}
#define VERT_NOT_CLIPPED 0x80
static void build_clip_vert_bits( GLubyte *clipmask, const GLubyte *cullmask,
GLuint count )
{
GLuint i = 0;
for (;;)
if (cullmask[++i]==0) {
clipmask[i] |= CLIP_CULLED_BIT;
if (&cullmask[i] == &cullmask[count]) return;
}
}
GLuint gl_cull_vb( struct vertex_buffer *VB )
{
const GLcontext *ctx = VB->ctx;
GLuint i, next, prim, n;
GLfloat (*proj)[4] = VB->Projected->data;
GLuint *in_prim = VB->Primitive;
GLuint *out_prim = VB->IM->Primitive;
GLuint cullcount = 0;
GLuint lastprim = in_prim[VB->LastPrimitive];
GLuint first = VB->CopyStart;
GLuint parity = VB->Parity;
cull_func *cull_funcs;
GLuint idx = 0;
if (VB->CullDone)
return 0;
if (VB->ClipOrMask)
idx |= 0x2;
if (ctx->IndirectTriangles & DD_ANY_CULL)
idx |= 0x1;
cull_funcs = cull_tab[idx];
for (i = VB->CopyStart ; i < VB->Start ; i++) {
COPY_4FV(proj[i], VB->CopyProj[i]);
}
VB->CopyCount = 0;
MEMSET(VB->CullMask, 0, (VB->Count+1) * sizeof(GLubyte));
for ( i = VB->CopyStart ; i < VB->Count ; i = next, parity = 0 )
{
first = i;
next = VB->NextPrimitive[i];
prim = in_prim[i];
n = cull_funcs[prim]( VB, i, next, parity, (const GLfloat (*)[4])proj );
if (n == next - i)
out_prim[i] = GL_POLYGON+1;
else
out_prim[i] = prim;
cullcount += n;
}
if (VB->LastPrimitive < VB->Count) {
if (copy_tab_cull[lastprim])
cullcount -= copy_tab_cull[prim]( VB,
first,
VB->Count,
VB->Ovf,
(const GLfloat (*)[4])proj );
}
VB->Primitive = out_prim;
VB->CullFlag[0] = VB->CullFlag[1] = (GLubyte) 0;
if (cullcount > 0 || (ctx->IndirectTriangles & DD_LIGHTING_CULL)) {
VB->CullMode |= CULL_MASK_ACTIVE;
VB->CullFlag[0] = VB->CullFlag[1] = CLIP_CULLED_BIT&ctx->AllowVertexCull;
if (cullcount < VB->Count)
build_clip_vert_bits( VB->ClipMask, VB->CullMask, VB->Count );
}
if (VB->ClipOrMask) {
VB->CullMode |= CLIP_MASK_ACTIVE;
VB->CullFlag[1] |= (CLIP_ALL_BITS|CLIP_USER_BIT) & ctx->AllowVertexCull;
}
VB->CullDone = 1;
return cullcount;
}
/* Need to set up to copy some vertices at the end of the buffer, even
* if culling is disabled or the entire vb has been culled by clipping.
*/
void gl_dont_cull_vb( struct vertex_buffer *VB )
{
GLfloat (*proj)[4] = VB->Projected->data;
GLuint i;
if (VB->CullDone)
return;
for (i = VB->CopyStart ; i < VB->Start ; i++)
COPY_4FV(proj[i], VB->CopyProj[i]);
VB->CopyCount = 0;
if (VB->LastPrimitive < VB->Count)
{
GLuint first = VB->LastPrimitive;
GLuint prim = VB->Primitive[first];
if (first == VB_START)
first = VB->Start;
if (copy_tab_no_cull[prim])
copy_tab_no_cull[prim]( VB,
first,
VB->Count,
VB->Ovf,
(const GLfloat (*)[4])proj );
}
VB->CullDone = 1;
}
void gl_fast_copy_vb( struct vertex_buffer *VB )
{
VB->CopyCount = 0;
if (VB->LastPrimitive < VB->Count)
{
GLuint first = VB->LastPrimitive;
GLuint prim = VB->Primitive[first];
if (first == VB_START)
first = VB->Start;
fast_copy_tab[prim]( VB, first, VB->Count, VB->Ovf );
}
VB->CullDone = 1;
}
void gl_make_normal_cullmask( struct vertex_buffer *VB )
{
GLuint i;
if (VB->CullMode & COMPACTED_NORMALS) {
/* The shared normals case - never for cva.
*/
MEMSET(VB->NormCullMask, 0, VB->Count * sizeof(GLubyte));
VB->NormCullStart = VB->NormCullMask + VB->Start;
if (VB->CullMode & CULL_MASK_ACTIVE) {
GLubyte *lastnorm = VB->NormCullStart;
for (i = VB->Start ;;) {
*lastnorm |= VB->CullMask[i];
if (VB->Flag[++i] & (VERT_NORM|VERT_END_VB)) {
lastnorm = &VB->NormCullMask[i];
if (VB->Flag[i] & VERT_END_VB) return;
}
}
} else {
VB->NormCullMask[VB->Start] = ~0;
for (i = VB->Start ;; )
if (VB->Flag[++i] & (VERT_NORM|VERT_END_VB)) {
VB->NormCullMask[i] = ~0;
if (VB->Flag[i] & VERT_END_VB) return;
}
}
} else {
/* Non-shared normals.
*/
VB->NormCullStart = VB->CullMask + VB->Start;
}
}