clip.c revision afb833d4e89c312460a4ab9ed6a7a8ca4ebbfe1c
1/* $Id: clip.c,v 1.1 1999/08/19 00:55:41 jtg Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.1 6 * 7 * Copyright (C) 1999 Brian Paul All Rights Reserved. 8 * 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: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 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. 25 */ 26 27 28 29 30 31#ifdef PC_HEADER 32#include "all.h" 33#else 34#include <string.h> 35#include <stdlib.h> 36#include "clip.h" 37#include "context.h" 38#include "macros.h" 39#include "matrix.h" 40#include "mmath.h" 41#include "types.h" 42#include "vb.h" 43#include "xform.h" 44#ifdef XFree86Server 45#include "GL/xf86glx.h" 46#endif 47#endif 48 49 50 51 52/* Linear interpolation between A and B: */ 53#define LINTERP( T, A, B ) ( (A) + (T) * ( (B) - (A) ) ) 54 55 56 57#define INTERP_SZ( t, vec, to, a, b, sz ) \ 58do { \ 59 switch (sz) { \ 60 case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \ 61 case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \ 62 case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \ 63 case 1: vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \ 64 } \ 65} while(0) 66 67 68 69 70#define CLIP_RGBA0 0x1 71#define CLIP_RGBA1 0x2 72#define CLIP_TEX0 0x4 73#define CLIP_TEX1 0x8 74#define CLIP_INDEX0 0x10 75#define CLIP_INDEX1 0x20 76#define CLIP_EDGE 0x40 77 78/* This is sparsely populated: */ 79static clip_interp_func clip_interp_tab[0x80]; 80 81#define IND 0 82#define NAME clip_nil 83#include "interp_tmp.h" 84 85#define IND (CLIP_RGBA0) 86#define NAME clipRGBA0 87#include "interp_tmp.h" 88 89#define IND (CLIP_RGBA0|CLIP_RGBA1) 90#define NAME clipRGBA0_RGBA1 91#include "interp_tmp.h" 92 93#define IND (CLIP_TEX0|CLIP_RGBA0) 94#define NAME clipTEX0_RGBA0 95#include "interp_tmp.h" 96 97#define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1) 98#define NAME clipTEX0_RGBA0_RGBA1 99#include "interp_tmp.h" 100 101#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0) 102#define NAME clipTEX1_TEX0_RGBA0 103#include "interp_tmp.h" 104 105#define IND (CLIP_TEX0) 106#define NAME clipTEX0 107#include "interp_tmp.h" 108 109#define IND (CLIP_TEX1|CLIP_TEX0) 110#define NAME clipTEX1_TEX0 111#include "interp_tmp.h" 112 113#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1) 114#define NAME clipTEX1_TEX0_RGBA0_RGBA1 115#include "interp_tmp.h" 116 117#define IND (CLIP_INDEX0) 118#define NAME clipINDEX0 119#include "interp_tmp.h" 120 121#define IND (CLIP_INDEX0|CLIP_INDEX1) 122#define NAME clipINDEX0_INDEX1 123#include "interp_tmp.h" 124 125#define IND (CLIP_RGBA0|CLIP_EDGE) 126#define NAME clipRGBA0_EDGE 127#include "interp_tmp.h" 128 129#define IND (CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE) 130#define NAME clipRGBA0_RGBA1_EDGE 131#include "interp_tmp.h" 132 133#define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE) 134#define NAME clipTEX0_RGBA0_EDGE 135#include "interp_tmp.h" 136 137#define IND (CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE) 138#define NAME clipTEX0_RGBA0_RGBA1_EDGE 139#include "interp_tmp.h" 140 141#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE) 142#define NAME clipTEX1_TEX0_RGBA0_EDGE 143#include "interp_tmp.h" 144 145#define IND (CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE) 146#define NAME clipTEX1_TEX0_RGBA0_RGBA1_EDGE 147#include "interp_tmp.h" 148 149#define IND (CLIP_INDEX0|CLIP_EDGE) 150#define NAME clipINDEX0_EDGE 151#include "interp_tmp.h" 152 153#define IND (CLIP_INDEX0|CLIP_INDEX1|CLIP_EDGE) 154#define NAME clipINDEX0_INDEX1_EDGE 155#include "interp_tmp.h" 156 157 158 159 160/**********************************************************************/ 161/* Get/Set User clip-planes. */ 162/**********************************************************************/ 163 164 165 166void gl_ClipPlane( GLcontext* ctx, GLenum plane, const GLfloat *equation ) 167{ 168 GLint p; 169 170 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClipPlane"); 171 172 p = (GLint) plane - (GLint) GL_CLIP_PLANE0; 173 if (p<0 || p>=MAX_CLIP_PLANES) { 174 gl_error( ctx, GL_INVALID_ENUM, "glClipPlane" ); 175 return; 176 } 177 178 /* 179 * The equation is transformed by the transpose of the inverse of the 180 * current modelview matrix and stored in the resulting eye coordinates. 181 * 182 * KW: Eqn is then transformed to the current clip space, where user 183 * clipping now takes place. The clip-space equations are recalculated 184 * whenever the projection matrix changes. 185 */ 186 if (ctx->ModelView.flags & MAT_DIRTY_ALL_OVER) { 187 gl_matrix_analyze( &ctx->ModelView ); 188 } 189 gl_transform_vector( ctx->Transform.EyeUserPlane[p], equation, 190 ctx->ModelView.inv ); 191 192 193 if (ctx->Transform.ClipEnabled[p]) { 194 ctx->NewState |= NEW_USER_CLIP; 195 196 if (ctx->ProjectionMatrix.flags & MAT_DIRTY_ALL_OVER) { 197 gl_matrix_analyze( &ctx->ProjectionMatrix ); 198 } 199 gl_transform_vector( ctx->Transform.ClipUserPlane[p], 200 ctx->Transform.EyeUserPlane[p], 201 ctx->ProjectionMatrix.inv ); 202 } 203} 204 205 206void gl_update_userclip( GLcontext *ctx ) 207{ 208 GLuint p; 209 210 for (p = 0 ; p < MAX_CLIP_PLANES ; p++) { 211 if (ctx->Transform.ClipEnabled[p]) { 212 gl_transform_vector( ctx->Transform.ClipUserPlane[p], 213 ctx->Transform.EyeUserPlane[p], 214 ctx->ProjectionMatrix.inv ); 215 } 216 } 217} 218 219void gl_GetClipPlane( GLcontext* ctx, GLenum plane, GLdouble *equation ) 220{ 221 GLint p; 222 223 ASSERT_OUTSIDE_BEGIN_END(ctx, "glGetClipPlane"); 224 225 226 p = (GLint) (plane - GL_CLIP_PLANE0); 227 if (p<0 || p>=MAX_CLIP_PLANES) { 228 gl_error( ctx, GL_INVALID_ENUM, "glGetClipPlane" ); 229 return; 230 } 231 232 equation[0] = (GLdouble) ctx->Transform.EyeUserPlane[p][0]; 233 equation[1] = (GLdouble) ctx->Transform.EyeUserPlane[p][1]; 234 equation[2] = (GLdouble) ctx->Transform.EyeUserPlane[p][2]; 235 equation[3] = (GLdouble) ctx->Transform.EyeUserPlane[p][3]; 236} 237 238 239 240 241/**********************************************************************/ 242/* View volume clipping. */ 243/**********************************************************************/ 244 245 246/* 247 * Clip a point against the view volume. 248 * Input: v - vertex-vector describing the point to clip 249 * Return: 0 = outside view volume 250 * 1 = inside view volume 251 */ 252GLuint gl_viewclip_point( const GLfloat v[] ) 253{ 254 if ( v[0] > v[3] || v[0] < -v[3] 255 || v[1] > v[3] || v[1] < -v[3] 256 || v[2] > v[3] || v[2] < -v[3] ) { 257 return 0; 258 } 259 else { 260 return 1; 261 } 262} 263 264/* 265 * Clip a point against the user clipping planes. 266 * Input: v - vertex-vector describing the point to clip. 267 * Return: 0 = point was clipped 268 * 1 = point not clipped 269 */ 270GLuint gl_userclip_point( GLcontext* ctx, const GLfloat v[] ) 271{ 272 GLuint p; 273 274 for (p=0;p<MAX_CLIP_PLANES;p++) { 275 if (ctx->Transform.ClipEnabled[p]) { 276 GLfloat dot = v[0] * ctx->Transform.ClipUserPlane[p][0] 277 + v[1] * ctx->Transform.ClipUserPlane[p][1] 278 + v[2] * ctx->Transform.ClipUserPlane[p][2] 279 + v[3] * ctx->Transform.ClipUserPlane[p][3]; 280 if (dot < 0.0F) { 281 return 0; 282 } 283 } 284 } 285 286 return 1; 287} 288 289 290 291 292clip_poly_func gl_poly_clip_tab[5]; 293clip_line_func gl_line_clip_tab[5]; 294 295 296#if defined(__i386__) 297#define NEGATIVE(x) ((*(int *)&x)<0) 298#else 299#define NEGATIVE(x) (x < 0) 300#endif 301 302#define W(i) coord[i][3] 303#define Z(i) coord[i][2] 304#define Y(i) coord[i][1] 305#define X(i) coord[i][0] 306#define SIZE 4 307#define TAG(x) x##_4 308#include "clip_funcs.h" 309 310 311#define W(i) 1.0 312#define Z(i) coord[i][2] 313#define Y(i) coord[i][1] 314#define X(i) coord[i][0] 315#define SIZE 3 316#define TAG(x) x##_3 317#include "clip_funcs.h" 318 319#define W(i) 1.0 320#define Z(i) 0.0 321#define Y(i) coord[i][1] 322#define X(i) coord[i][0] 323#define SIZE 2 324#define TAG(x) x##_2 325#include "clip_funcs.h" 326 327#define USER_CLIPTEST(NAME, SZ) \ 328static void NAME( struct vertex_buffer *VB ) \ 329{ \ 330 GLcontext *ctx = VB->ctx; \ 331 GLubyte *clipMask = VB->ClipMask; \ 332 GLubyte *userClipMask = VB->UserClipMask; \ 333 GLuint start = VB->Start; \ 334 GLuint count = VB->Count; \ 335 GLuint p, i; \ 336 GLubyte bit; \ 337 \ 338 \ 339 for (bit = 1, p = 0; p < MAX_CLIP_PLANES ; p++, bit *=2) \ 340 if (ctx->Transform.ClipEnabled[p]) { \ 341 GLuint nr = 0; \ 342 const GLfloat a = ctx->Transform.ClipUserPlane[p][0]; \ 343 const GLfloat b = ctx->Transform.ClipUserPlane[p][1]; \ 344 const GLfloat c = ctx->Transform.ClipUserPlane[p][2]; \ 345 const GLfloat d = ctx->Transform.ClipUserPlane[p][3]; \ 346 GLfloat *coord = VB->ClipPtr->start; \ 347 GLuint stride = VB->ClipPtr->stride; \ 348 \ 349 for (i = start ; i < count ; i++, STRIDE_F(coord, stride)) { \ 350 GLfloat dp = coord[0] * a + coord[1] * b; \ 351 if (SZ > 2) dp += coord[2] * c; \ 352 if (SZ > 3) dp += coord[3] * d; else dp += d; \ 353 \ 354 if (dp < 0) { \ 355 clipMask[i] |= CLIP_USER_BIT; \ 356 userClipMask[i] |= bit; \ 357 nr++; \ 358 } \ 359 } \ 360 \ 361 if (nr > 0) { \ 362 VB->ClipOrMask |= CLIP_USER_BIT; \ 363 VB->CullMode |= CLIP_MASK_ACTIVE; \ 364 if (nr == count - start) { \ 365 VB->ClipAndMask |= CLIP_USER_BIT; \ 366 VB->Culled = 1; \ 367 return; \ 368 } \ 369 } \ 370 } \ 371} 372 373 374USER_CLIPTEST(userclip2, 2) 375USER_CLIPTEST(userclip3, 3) 376USER_CLIPTEST(userclip4, 4) 377 378static void (*(usercliptab[5]))( struct vertex_buffer * ) = { 379 0, 380 0, 381 userclip2, 382 userclip3, 383 userclip4 384}; 385 386void gl_user_cliptest( struct vertex_buffer *VB ) 387{ 388 usercliptab[VB->ClipPtr->size]( VB ); 389} 390 391 392 393static clip_interp_func get_interp_func( GLcontext *ctx ) 394{ 395 GLuint mask = 0; 396 397 if (ctx->Visual->RGBAflag) 398 { 399 if (ctx->Light.ShadeModel==GL_SMOOTH) 400 { 401 mask |= CLIP_RGBA0; 402 403 if (ctx->TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_SEPERATE_SPECULAR)) 404 mask |= CLIP_RGBA1; 405 } 406 407 if (ctx->Texture.ReallyEnabled & 0xf0) 408 mask |= CLIP_TEX1|CLIP_TEX0; 409 410 if (ctx->Texture.ReallyEnabled & 0xf) 411 mask |= CLIP_TEX0; 412 } 413 else if (ctx->Light.ShadeModel==GL_SMOOTH) 414 { 415 mask |= CLIP_INDEX0; 416 417 if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) 418 mask |= CLIP_INDEX1; 419 } 420 421 422 return clip_interp_tab[mask]; 423} 424 425 426void gl_update_clipmask( GLcontext *ctx ) 427{ 428 ctx->ClipInterpFunc = get_interp_func( ctx ); 429} 430 431void gl_init_clip(void) 432{ 433 init_clip_funcs_4(); 434 init_clip_funcs_3(); 435 init_clip_funcs_2(); 436 437 clip_interp_tab[0] = clip_nil; 438 clip_interp_tab[CLIP_RGBA0] = clipRGBA0; 439 clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1] = clipRGBA0_RGBA1; 440 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0] = clipTEX0_RGBA0; 441 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] = clipTEX0_RGBA0_RGBA1; 442 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0] = clipTEX1_TEX0_RGBA0; 443 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1] = clipTEX1_TEX0_RGBA0_RGBA1; 444 445 clip_interp_tab[CLIP_TEX0] = clipTEX0; 446 clip_interp_tab[CLIP_TEX1|CLIP_TEX0] = clipTEX1_TEX0; 447 448 clip_interp_tab[CLIP_INDEX0] = clipINDEX0; 449 clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1] = clipINDEX0_INDEX1; 450 451 clip_interp_tab[CLIP_RGBA0|CLIP_EDGE] = clipRGBA0_EDGE; 452 clip_interp_tab[CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE] = clipRGBA0_RGBA1_EDGE; 453 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE] = clipTEX0_RGBA0_EDGE; 454 clip_interp_tab[CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE] = clipTEX0_RGBA0_RGBA1_EDGE; 455 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_EDGE] = clipTEX1_TEX0_RGBA0_EDGE; 456 clip_interp_tab[CLIP_TEX1|CLIP_TEX0|CLIP_RGBA0|CLIP_RGBA1|CLIP_EDGE] = clipTEX1_TEX0_RGBA0_RGBA1_EDGE; 457 clip_interp_tab[CLIP_INDEX0|CLIP_EDGE] = clipINDEX0_EDGE; 458 clip_interp_tab[CLIP_INDEX0|CLIP_INDEX1|CLIP_EDGE] = clipINDEX0_INDEX1_EDGE; 459} 460 461