| 1 | /* $Id: mapdesc.cpp,v 1.1 2000-02-09 08:50:24 jeroen Exp $ */
|
|---|
| 2 | /*
|
|---|
| 3 | ** License Applicability. Except to the extent portions of this file are
|
|---|
| 4 | ** made subject to an alternative license as permitted in the SGI Free
|
|---|
| 5 | ** Software License B, Version 1.0 (the "License"), the contents of this
|
|---|
| 6 | ** file are subject only to the provisions of the License. You may not use
|
|---|
| 7 | ** this file except in compliance with the License. You may obtain a copy
|
|---|
| 8 | ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
|
|---|
| 9 | ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
|
|---|
| 10 | **
|
|---|
| 11 | ** http://oss.sgi.com/projects/FreeB
|
|---|
| 12 | **
|
|---|
| 13 | ** Note that, as provided in the License, the Software is distributed on an
|
|---|
| 14 | ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
|
|---|
| 15 | ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
|
|---|
| 16 | ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
|
|---|
| 17 | ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
|---|
| 18 | **
|
|---|
| 19 | ** Original Code. The Original Code is: OpenGL Sample Implementation,
|
|---|
| 20 | ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
|
|---|
| 21 | ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
|
|---|
| 22 | ** Copyright in any portions created by third parties is as indicated
|
|---|
| 23 | ** elsewhere herein. All Rights Reserved.
|
|---|
| 24 | **
|
|---|
| 25 | ** Additional Notice Provisions: The application programming interfaces
|
|---|
| 26 | ** established by SGI in conjunction with the Original Code are The
|
|---|
| 27 | ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
|
|---|
| 28 | ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
|
|---|
| 29 | ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
|
|---|
| 30 | ** Window System(R) (Version 1.3), released October 19, 1998. This software
|
|---|
| 31 | ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
|
|---|
| 32 | ** published by SGI, but has not been independently verified as being
|
|---|
| 33 | ** compliant with the OpenGL(R) version 1.2.1 Specification.
|
|---|
| 34 | */
|
|---|
| 35 |
|
|---|
| 36 | /*
|
|---|
| 37 | * mapdesc.c++
|
|---|
| 38 | *
|
|---|
| 39 | * $Date: 2000-02-09 08:50:24 $ $Revision: 1.1 $
|
|---|
| 40 | * $Header: /home/ktk/tmp/odin/2007/netlabs.cvs/odin32/src/opengl/glu/nurbs/internals/mapdesc.cpp,v 1.1 2000-02-09 08:50:24 jeroen Exp $
|
|---|
| 41 | */
|
|---|
| 42 |
|
|---|
| 43 | #include <stdio.h>
|
|---|
| 44 | #include "glimports.h"
|
|---|
| 45 | #include "mystdio.h"
|
|---|
| 46 | #include "myassert.h"
|
|---|
| 47 | #include "mystring.h"
|
|---|
| 48 | #include "mymath.h"
|
|---|
| 49 | #include "backend.h"
|
|---|
| 50 | #include "nurbsconsts.h"
|
|---|
| 51 | #include "mapdesc.h"
|
|---|
| 52 |
|
|---|
| 53 | Mapdesc::Mapdesc( long _type, int _israt, int _ncoords, Backend& b )
|
|---|
| 54 | : backend( b )
|
|---|
| 55 | {
|
|---|
| 56 | type = _type;
|
|---|
| 57 | isrational = _israt;
|
|---|
| 58 | ncoords = _ncoords;
|
|---|
| 59 | hcoords = _ncoords + (_israt ? 0 : 1 );
|
|---|
| 60 | inhcoords = _ncoords - (_israt ? 1 : 0 );
|
|---|
| 61 | mask = ((1<<(inhcoords*2))-1);
|
|---|
| 62 | next = 0;
|
|---|
| 63 |
|
|---|
| 64 | assert( hcoords <= MAXCOORDS );
|
|---|
| 65 | assert( inhcoords >= 1 );
|
|---|
| 66 |
|
|---|
| 67 | pixel_tolerance = 1.0;
|
|---|
| 68 | error_tolerance = 1.0;
|
|---|
| 69 | bbox_subdividing = N_NOBBOXSUBDIVISION;
|
|---|
| 70 | culling_method = N_NOCULLING;
|
|---|
| 71 | sampling_method = N_NOSAMPLING;
|
|---|
| 72 | clampfactor = N_NOCLAMPING;
|
|---|
| 73 | minsavings = N_NOSAVINGSSUBDIVISION;
|
|---|
| 74 | s_steps = 0.0;
|
|---|
| 75 | t_steps = 0.0;
|
|---|
| 76 | maxrate = ( s_steps < 0.0 ) ? 0.0 : s_steps;
|
|---|
| 77 | maxsrate = ( s_steps < 0.0 ) ? 0.0 : s_steps;
|
|---|
| 78 | maxtrate = ( t_steps < 0.0 ) ? 0.0 : t_steps;
|
|---|
| 79 | identify( bmat );
|
|---|
| 80 | identify( cmat );
|
|---|
| 81 | identify( smat );
|
|---|
| 82 | for( int i = 0; i != inhcoords; i++ )
|
|---|
| 83 | bboxsize[i] = 1.0;
|
|---|
| 84 | }
|
|---|
| 85 |
|
|---|
| 86 | void
|
|---|
| 87 | Mapdesc::setBboxsize( INREAL *mat )
|
|---|
| 88 | {
|
|---|
| 89 | for( int i = 0; i != inhcoords; i++ )
|
|---|
| 90 | bboxsize[i] = (REAL) mat[i];
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | void
|
|---|
| 94 | Mapdesc::identify( REAL dest[MAXCOORDS][MAXCOORDS] )
|
|---|
| 95 | {
|
|---|
| 96 | memset( dest, 0, sizeof( dest ) );
|
|---|
| 97 | for( int i=0; i != hcoords; i++ )
|
|---|
| 98 | dest[i][i] = 1.0;
|
|---|
| 99 | }
|
|---|
| 100 |
|
|---|
| 101 | void
|
|---|
| 102 | Mapdesc::surfbbox( REAL bb[2][MAXCOORDS] )
|
|---|
| 103 | {
|
|---|
| 104 | backend.surfbbox( type, bb[0], bb[1] );
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | void
|
|---|
| 108 | Mapdesc::copy( REAL dest[MAXCOORDS][MAXCOORDS], long n, INREAL *src,
|
|---|
| 109 | long rstride, long cstride )
|
|---|
| 110 | {
|
|---|
| 111 | assert( n >= 0 );
|
|---|
| 112 | for( int i=0; i != n; i++ )
|
|---|
| 113 | for( int j=0; j != n; j++ )
|
|---|
| 114 | dest[i][j] = src[i*rstride + j*cstride];
|
|---|
| 115 | }
|
|---|
| 116 |
|
|---|
| 117 | /*--------------------------------------------------------------------------
|
|---|
| 118 | * copyPt - copy a homogeneous point
|
|---|
| 119 | *--------------------------------------------------------------------------
|
|---|
| 120 | */
|
|---|
| 121 | void
|
|---|
| 122 | Mapdesc::copyPt( REAL *d, REAL *s )
|
|---|
| 123 | {
|
|---|
| 124 | assert( hcoords > 0 );
|
|---|
| 125 | switch( hcoords ) {
|
|---|
| 126 | case 4:
|
|---|
| 127 | d[3] = s[3];
|
|---|
| 128 | d[2] = s[2];
|
|---|
| 129 | d[1] = s[1];
|
|---|
| 130 | d[0] = s[0];
|
|---|
| 131 | break;
|
|---|
| 132 | case 3:
|
|---|
| 133 | d[2] = s[2];
|
|---|
| 134 | d[1] = s[1];
|
|---|
| 135 | d[0] = s[0];
|
|---|
| 136 | break;
|
|---|
| 137 | case 2:
|
|---|
| 138 | d[1] = s[1];
|
|---|
| 139 | d[0] = s[0];
|
|---|
| 140 | break;
|
|---|
| 141 | case 1:
|
|---|
| 142 | d[0] = s[0];
|
|---|
| 143 | break;
|
|---|
| 144 | case 5:
|
|---|
| 145 | d[4] = s[4];
|
|---|
| 146 | d[3] = s[3];
|
|---|
| 147 | d[2] = s[2];
|
|---|
| 148 | d[1] = s[1];
|
|---|
| 149 | d[0] = s[0];
|
|---|
| 150 | break;
|
|---|
| 151 | default:
|
|---|
| 152 | memcpy( d, s, hcoords * sizeof( REAL ) );
|
|---|
| 153 | break;
|
|---|
| 154 | }
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 | /*--------------------------------------------------------------------------
|
|---|
| 158 | * sumPt - compute affine combination of two homogeneous points
|
|---|
| 159 | *--------------------------------------------------------------------------
|
|---|
| 160 | */
|
|---|
| 161 | void
|
|---|
| 162 | Mapdesc::sumPt( REAL *dst, REAL *src1, REAL *src2, register REAL alpha, register REAL beta )
|
|---|
| 163 | {
|
|---|
| 164 | assert( hcoords > 0 );
|
|---|
| 165 | switch( hcoords ) {
|
|---|
| 166 | case 4:
|
|---|
| 167 | dst[3] = src1[3] * alpha + src2[3] * beta;
|
|---|
| 168 | dst[2] = src1[2] * alpha + src2[2] * beta;
|
|---|
| 169 | dst[1] = src1[1] * alpha + src2[1] * beta;
|
|---|
| 170 | dst[0] = src1[0] * alpha + src2[0] * beta;
|
|---|
| 171 | break;
|
|---|
| 172 | case 3:
|
|---|
| 173 | dst[2] = src1[2] * alpha + src2[2] * beta;
|
|---|
| 174 | dst[1] = src1[1] * alpha + src2[1] * beta;
|
|---|
| 175 | dst[0] = src1[0] * alpha + src2[0] * beta;
|
|---|
| 176 | break;
|
|---|
| 177 | case 2:
|
|---|
| 178 | dst[1] = src1[1] * alpha + src2[1] * beta;
|
|---|
| 179 | dst[0] = src1[0] * alpha + src2[0] * beta;
|
|---|
| 180 | break;
|
|---|
| 181 | case 1:
|
|---|
| 182 | dst[0] = src1[0] * alpha + src2[0] * beta;
|
|---|
| 183 | break;
|
|---|
| 184 | case 5:
|
|---|
| 185 | dst[4] = src1[4] * alpha + src2[4] * beta;
|
|---|
| 186 | dst[3] = src1[3] * alpha + src2[3] * beta;
|
|---|
| 187 | dst[2] = src1[2] * alpha + src2[2] * beta;
|
|---|
| 188 | dst[1] = src1[1] * alpha + src2[1] * beta;
|
|---|
| 189 | dst[0] = src1[0] * alpha + src2[0] * beta;
|
|---|
| 190 | break;
|
|---|
| 191 | default: {
|
|---|
| 192 | for( int i = 0; i != hcoords; i++ )
|
|---|
| 193 | dst[i] = src1[i] * alpha + src2[i] * beta;
|
|---|
| 194 | }
|
|---|
| 195 | break;
|
|---|
| 196 | }
|
|---|
| 197 | }
|
|---|
| 198 |
|
|---|
| 199 | /*--------------------------------------------------------------------------
|
|---|
| 200 | * clipbits - compute bit-vector indicating point/window position
|
|---|
| 201 | * of a (transformed) homogeneous point
|
|---|
| 202 | *--------------------------------------------------------------------------
|
|---|
| 203 | */
|
|---|
| 204 | unsigned int
|
|---|
| 205 | Mapdesc::clipbits( REAL *p )
|
|---|
| 206 | {
|
|---|
| 207 | assert( inhcoords >= 0 );
|
|---|
| 208 | assert( inhcoords <= 3 );
|
|---|
| 209 |
|
|---|
| 210 | register int nc = inhcoords;
|
|---|
| 211 | register REAL pw = p[nc];
|
|---|
| 212 | register REAL nw = -pw;
|
|---|
| 213 | register unsigned int bits = 0;
|
|---|
| 214 |
|
|---|
| 215 | if( pw == 0.0 ) return mask;
|
|---|
| 216 |
|
|---|
| 217 | if( pw > 0.0 ) {
|
|---|
| 218 | switch( nc ) {
|
|---|
| 219 | case 3:
|
|---|
| 220 | if( p[2] <= pw ) bits |= (1<<5);
|
|---|
| 221 | if( p[2] >= nw ) bits |= (1<<4);
|
|---|
| 222 | if( p[1] <= pw ) bits |= (1<<3);
|
|---|
| 223 | if( p[1] >= nw ) bits |= (1<<2);
|
|---|
| 224 | if( p[0] <= pw ) bits |= (1<<1);
|
|---|
| 225 | if( p[0] >= nw ) bits |= (1<<0);
|
|---|
| 226 | return bits;
|
|---|
| 227 | case 2:
|
|---|
| 228 | if( p[1] <= pw ) bits |= (1<<3);
|
|---|
| 229 | if( p[1] >= nw ) bits |= (1<<2);
|
|---|
| 230 | if( p[0] <= pw ) bits |= (1<<1);
|
|---|
| 231 | if( p[0] >= nw ) bits |= (1<<0);
|
|---|
| 232 | return bits;
|
|---|
| 233 | case 1:
|
|---|
| 234 | if( p[0] <= pw ) bits |= (1<<1);
|
|---|
| 235 | if( p[0] >= nw ) bits |= (1<<0);
|
|---|
| 236 | return bits;
|
|---|
| 237 | default: {
|
|---|
| 238 | int bit = 1;
|
|---|
| 239 | for( int i=0; i<nc; i++ ) {
|
|---|
| 240 | if( p[i] >= nw ) bits |= bit;
|
|---|
| 241 | bit <<= 1;
|
|---|
| 242 | if( p[i] <= pw ) bits |= bit;
|
|---|
| 243 | bit <<= 1;
|
|---|
| 244 | }
|
|---|
| 245 | abort();
|
|---|
| 246 | break;
|
|---|
| 247 | }
|
|---|
| 248 | }
|
|---|
| 249 | } else {
|
|---|
| 250 | switch( nc ) {
|
|---|
| 251 | case 3:
|
|---|
| 252 | if( p[2] <= nw ) bits |= (1<<5);
|
|---|
| 253 | if( p[2] >= pw ) bits |= (1<<4);
|
|---|
| 254 | if( p[1] <= nw ) bits |= (1<<3);
|
|---|
| 255 | if( p[1] >= pw ) bits |= (1<<2);
|
|---|
| 256 | if( p[0] <= nw ) bits |= (1<<1);
|
|---|
| 257 | if( p[0] >= pw ) bits |= (1<<0);
|
|---|
| 258 | return bits;
|
|---|
| 259 | case 2:
|
|---|
| 260 | if( p[1] <= nw ) bits |= (1<<3);
|
|---|
| 261 | if( p[1] >= pw ) bits |= (1<<2);
|
|---|
| 262 | if( p[0] <= nw ) bits |= (1<<1);
|
|---|
| 263 | if( p[0] >= pw ) bits |= (1<<0);
|
|---|
| 264 | return bits;
|
|---|
| 265 | case 1:
|
|---|
| 266 | if( p[0] <= nw ) bits |= (1<<1);
|
|---|
| 267 | if( p[0] >= pw ) bits |= (1<<0);
|
|---|
| 268 | return bits;
|
|---|
| 269 | default: {
|
|---|
| 270 | int bit = 1;
|
|---|
| 271 | for( int i=0; i<nc; i++ ) {
|
|---|
| 272 | if( p[i] >= pw ) bits |= bit;
|
|---|
| 273 | bit <<= 1;
|
|---|
| 274 | if( p[i] <= nw ) bits |= bit;
|
|---|
| 275 | bit <<= 1;
|
|---|
| 276 | }
|
|---|
| 277 | abort();
|
|---|
| 278 | break;
|
|---|
| 279 | }
|
|---|
| 280 | }
|
|---|
| 281 | }
|
|---|
| 282 | return bits;
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | /*--------------------------------------------------------------------------
|
|---|
| 286 | * xformRational - transform a homogeneous point
|
|---|
| 287 | *--------------------------------------------------------------------------
|
|---|
| 288 | */
|
|---|
| 289 | void
|
|---|
| 290 | Mapdesc::xformRational( Maxmatrix mat, REAL *d, REAL *s )
|
|---|
| 291 | {
|
|---|
| 292 | assert( hcoords >= 0 );
|
|---|
| 293 |
|
|---|
| 294 | if( hcoords == 3 ) {
|
|---|
| 295 | REAL x = s[0];
|
|---|
| 296 | REAL y = s[1];
|
|---|
| 297 | REAL z = s[2];
|
|---|
| 298 | d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0];
|
|---|
| 299 | d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1];
|
|---|
| 300 | d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2];
|
|---|
| 301 | } else if( hcoords == 4 ) {
|
|---|
| 302 | REAL x = s[0];
|
|---|
| 303 | REAL y = s[1];
|
|---|
| 304 | REAL z = s[2];
|
|---|
| 305 | REAL w = s[3];
|
|---|
| 306 | d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0]+w*mat[3][0];
|
|---|
| 307 | d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1]+w*mat[3][1];
|
|---|
| 308 | d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2]+w*mat[3][2];
|
|---|
| 309 | d[3] = x*mat[0][3]+y*mat[1][3]+z*mat[2][3]+w*mat[3][3];
|
|---|
| 310 | } else {
|
|---|
| 311 | for( int i=0; i != hcoords; i++ ) {
|
|---|
| 312 | d[i] = 0;
|
|---|
| 313 | for( int j = 0; j != hcoords; j++ )
|
|---|
| 314 | d[i] += s[j] * mat[j][i];
|
|---|
| 315 | }
|
|---|
| 316 | }
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | /*--------------------------------------------------------------------------
|
|---|
| 320 | * xformNonrational - transform a inhomogeneous point to a homogeneous point
|
|---|
| 321 | *--------------------------------------------------------------------------
|
|---|
| 322 | */
|
|---|
| 323 | void
|
|---|
| 324 | Mapdesc::xformNonrational( Maxmatrix mat, REAL *d, REAL *s )
|
|---|
| 325 | {
|
|---|
| 326 | if( inhcoords == 2 ) {
|
|---|
| 327 | REAL x = s[0];
|
|---|
| 328 | REAL y = s[1];
|
|---|
| 329 | d[0] = x*mat[0][0]+y*mat[1][0]+mat[2][0];
|
|---|
| 330 | d[1] = x*mat[0][1]+y*mat[1][1]+mat[2][1];
|
|---|
| 331 | d[2] = x*mat[0][2]+y*mat[1][2]+mat[2][2];
|
|---|
| 332 | } else if( inhcoords == 3 ) {
|
|---|
| 333 | REAL x = s[0];
|
|---|
| 334 | REAL y = s[1];
|
|---|
| 335 | REAL z = s[2];
|
|---|
| 336 | d[0] = x*mat[0][0]+y*mat[1][0]+z*mat[2][0]+mat[3][0];
|
|---|
| 337 | d[1] = x*mat[0][1]+y*mat[1][1]+z*mat[2][1]+mat[3][1];
|
|---|
| 338 | d[2] = x*mat[0][2]+y*mat[1][2]+z*mat[2][2]+mat[3][2];
|
|---|
| 339 | d[3] = x*mat[0][3]+y*mat[1][3]+z*mat[2][3]+mat[3][3];
|
|---|
| 340 | } else {
|
|---|
| 341 | assert( inhcoords >= 0 );
|
|---|
| 342 | for( int i=0; i != hcoords; i++ ) {
|
|---|
| 343 | d[i] = mat[inhcoords][i];
|
|---|
| 344 | for( int j = 0; j < inhcoords; j++ )
|
|---|
| 345 | d[i] += s[j] * mat[j][i];
|
|---|
| 346 | }
|
|---|
| 347 | }
|
|---|
| 348 | }
|
|---|
| 349 |
|
|---|
| 350 | /*--------------------------------------------------------------------------
|
|---|
| 351 | * xformAndCullCheck - transform a set of points that may be EITHER
|
|---|
| 352 | * homogeneous or inhomogeneous depending on the map description and
|
|---|
| 353 | * check if they are either completely inside, completely outside,
|
|---|
| 354 | * or intersecting the viewing frustrum.
|
|---|
| 355 | *--------------------------------------------------------------------------
|
|---|
| 356 | */
|
|---|
| 357 | int
|
|---|
| 358 | Mapdesc::xformAndCullCheck(
|
|---|
| 359 | REAL *pts, int uorder, int ustride, int vorder, int vstride )
|
|---|
| 360 | {
|
|---|
| 361 | assert( uorder > 0 );
|
|---|
| 362 | assert( vorder > 0 );
|
|---|
| 363 |
|
|---|
| 364 | unsigned int inbits = mask;
|
|---|
| 365 | unsigned int outbits = 0;
|
|---|
| 366 |
|
|---|
| 367 | REAL *p = pts;
|
|---|
| 368 | for( REAL *pend = p + uorder * ustride; p != pend; p += ustride ) {
|
|---|
| 369 | REAL *q = p;
|
|---|
| 370 | for( REAL *qend = q + vorder * vstride; q != qend; q += vstride ) {
|
|---|
| 371 | REAL cpts[MAXCOORDS];
|
|---|
| 372 | xformCulling( cpts, q );
|
|---|
| 373 | unsigned int bits = clipbits( cpts );
|
|---|
| 374 | outbits |= bits;
|
|---|
| 375 | inbits &= bits;
|
|---|
| 376 | if( ( outbits == mask ) && ( inbits != mask ) ) return CULL_ACCEPT;
|
|---|
| 377 | }
|
|---|
| 378 | }
|
|---|
| 379 |
|
|---|
| 380 | if( outbits != mask ) {
|
|---|
| 381 | return CULL_TRIVIAL_REJECT;
|
|---|
| 382 | } else if( inbits == mask ) {
|
|---|
| 383 | return CULL_TRIVIAL_ACCEPT;
|
|---|
| 384 | } else {
|
|---|
| 385 | return CULL_ACCEPT;
|
|---|
| 386 | }
|
|---|
| 387 | }
|
|---|
| 388 |
|
|---|
| 389 | /*--------------------------------------------------------------------------
|
|---|
| 390 | * cullCheck - check if a set of homogeneous transformed points are
|
|---|
| 391 | * either completely inside, completely outside,
|
|---|
| 392 | * or intersecting the viewing frustrum.
|
|---|
| 393 | *--------------------------------------------------------------------------
|
|---|
| 394 | */
|
|---|
| 395 | int
|
|---|
| 396 | Mapdesc::cullCheck( REAL *pts, int uorder, int ustride, int vorder, int vstride )
|
|---|
| 397 | {
|
|---|
| 398 | unsigned int inbits = mask;
|
|---|
| 399 | unsigned int outbits = 0;
|
|---|
| 400 |
|
|---|
| 401 | REAL *p = pts;
|
|---|
| 402 | for( REAL *pend = p + uorder * ustride; p != pend; p += ustride ) {
|
|---|
| 403 | REAL *q = p;
|
|---|
| 404 | for( REAL *qend = q + vorder * vstride; q != qend; q += vstride ) {
|
|---|
| 405 | unsigned int bits = clipbits( q );
|
|---|
| 406 | outbits |= bits;
|
|---|
| 407 | inbits &= bits;
|
|---|
| 408 | if( ( outbits == mask ) && ( inbits != mask ) ) return CULL_ACCEPT;
|
|---|
| 409 | }
|
|---|
| 410 | }
|
|---|
| 411 |
|
|---|
| 412 | if( outbits != mask ) {
|
|---|
| 413 | return CULL_TRIVIAL_REJECT;
|
|---|
| 414 | } else if( inbits == mask ) {
|
|---|
| 415 | return CULL_TRIVIAL_ACCEPT;
|
|---|
| 416 | } else {
|
|---|
| 417 | return CULL_ACCEPT;
|
|---|
| 418 | }
|
|---|
| 419 | }
|
|---|
| 420 |
|
|---|
| 421 | /*--------------------------------------------------------------------------
|
|---|
| 422 | * cullCheck - check if a set of homogeneous transformed points are
|
|---|
| 423 | * either completely inside, completely outside,
|
|---|
| 424 | * or intersecting the viewing frustrum.
|
|---|
| 425 | *--------------------------------------------------------------------------
|
|---|
| 426 | */
|
|---|
| 427 | int
|
|---|
| 428 | Mapdesc::cullCheck( REAL *pts, int order, int stride )
|
|---|
| 429 | {
|
|---|
| 430 | unsigned int inbits = mask;
|
|---|
| 431 | unsigned int outbits = 0;
|
|---|
| 432 |
|
|---|
| 433 | REAL *p = pts;
|
|---|
| 434 | for( REAL *pend = p + order * stride; p != pend; p += stride ) {
|
|---|
| 435 | unsigned int bits = clipbits( p );
|
|---|
| 436 | outbits |= bits;
|
|---|
| 437 | inbits &= bits;
|
|---|
| 438 | if( ( outbits == mask ) && ( inbits != mask ) ) return CULL_ACCEPT;
|
|---|
| 439 | }
|
|---|
| 440 |
|
|---|
| 441 | if( outbits != mask ) {
|
|---|
| 442 | return CULL_TRIVIAL_REJECT;
|
|---|
| 443 | } else if( inbits == mask ) {
|
|---|
| 444 | return CULL_TRIVIAL_ACCEPT;
|
|---|
| 445 | } else {
|
|---|
| 446 | return CULL_ACCEPT;
|
|---|
| 447 | }
|
|---|
| 448 | }
|
|---|
| 449 |
|
|---|
| 450 | /*--------------------------------------------------------------------------
|
|---|
| 451 | * xformSampling - transform a set of points that may be EITHER
|
|---|
| 452 | * homogeneous or inhomogeneous depending on the map description
|
|---|
| 453 | * into sampling space
|
|---|
| 454 | *--------------------------------------------------------------------------
|
|---|
| 455 | */
|
|---|
| 456 | void
|
|---|
| 457 | Mapdesc::xformSampling( REAL *pts, int order, int stride, REAL *sp, int outstride )
|
|---|
| 458 | {
|
|---|
| 459 | xformMat( smat, pts, order, stride, sp, outstride );
|
|---|
| 460 | }
|
|---|
| 461 |
|
|---|
| 462 | void
|
|---|
| 463 | Mapdesc::xformBounding( REAL *pts, int order, int stride, REAL *sp, int outstride )
|
|---|
| 464 | {
|
|---|
| 465 | xformMat( bmat, pts, order, stride, sp, outstride );
|
|---|
| 466 | }
|
|---|
| 467 |
|
|---|
| 468 | /*--------------------------------------------------------------------------
|
|---|
| 469 | * xformCulling - transform a set of points that may be EITHER
|
|---|
| 470 | * homogeneous or inhomogeneous depending on the map description
|
|---|
| 471 | * into culling space
|
|---|
| 472 | *--------------------------------------------------------------------------
|
|---|
| 473 | */
|
|---|
| 474 | void
|
|---|
| 475 | Mapdesc::xformCulling( REAL *pts, int order, int stride, REAL *cp, int outstride )
|
|---|
| 476 | {
|
|---|
| 477 | xformMat( cmat, pts, order, stride, cp, outstride );
|
|---|
| 478 | }
|
|---|
| 479 |
|
|---|
| 480 | /*--------------------------------------------------------------------------
|
|---|
| 481 | * xformCulling - transform a set of points that may be EITHER
|
|---|
| 482 | * homogeneous or inhomogeneous depending on the map description
|
|---|
| 483 | * into culling space
|
|---|
| 484 | *--------------------------------------------------------------------------
|
|---|
| 485 | */
|
|---|
| 486 | void
|
|---|
| 487 | Mapdesc::xformCulling( REAL *pts,
|
|---|
| 488 | int uorder, int ustride,
|
|---|
| 489 | int vorder, int vstride,
|
|---|
| 490 | REAL *cp, int outustride, int outvstride )
|
|---|
| 491 | {
|
|---|
| 492 | xformMat( cmat, pts, uorder, ustride, vorder, vstride, cp, outustride, outvstride );
|
|---|
| 493 | }
|
|---|
| 494 |
|
|---|
| 495 | /*--------------------------------------------------------------------------
|
|---|
| 496 | * xformSampling - transform a set of points that may be EITHER
|
|---|
| 497 | * homogeneous or inhomogeneous depending on the map description
|
|---|
| 498 | * into sampling space
|
|---|
| 499 | *--------------------------------------------------------------------------
|
|---|
| 500 | */
|
|---|
| 501 | void
|
|---|
| 502 | Mapdesc::xformSampling( REAL *pts,
|
|---|
| 503 | int uorder, int ustride,
|
|---|
| 504 | int vorder, int vstride,
|
|---|
| 505 | REAL *sp, int outustride, int outvstride )
|
|---|
| 506 | {
|
|---|
| 507 | xformMat( smat, pts, uorder, ustride, vorder, vstride, sp, outustride, outvstride );
|
|---|
| 508 | }
|
|---|
| 509 |
|
|---|
| 510 | void
|
|---|
| 511 | Mapdesc::xformBounding( REAL *pts,
|
|---|
| 512 | int uorder, int ustride,
|
|---|
| 513 | int vorder, int vstride,
|
|---|
| 514 | REAL *sp, int outustride, int outvstride )
|
|---|
| 515 | {
|
|---|
| 516 | xformMat( bmat, pts, uorder, ustride, vorder, vstride, sp, outustride, outvstride );
|
|---|
| 517 | }
|
|---|
| 518 |
|
|---|
| 519 | void
|
|---|
| 520 | Mapdesc::xformMat(
|
|---|
| 521 | Maxmatrix mat,
|
|---|
| 522 | REAL * pts,
|
|---|
| 523 | int order,
|
|---|
| 524 | int stride,
|
|---|
| 525 | REAL * cp,
|
|---|
| 526 | int outstride )
|
|---|
| 527 | {
|
|---|
| 528 | if( isrational ) {
|
|---|
| 529 | REAL *pend = pts + order * stride;
|
|---|
| 530 | for( REAL *p = pts ; p != pend; p += stride ) {
|
|---|
| 531 | xformRational( mat, cp, p );
|
|---|
| 532 | cp += outstride;
|
|---|
| 533 | }
|
|---|
| 534 | } else {
|
|---|
| 535 | REAL *pend = pts + order * stride;
|
|---|
| 536 | for( REAL *p = pts ; p != pend; p += stride ) {
|
|---|
| 537 | xformNonrational( mat, cp, p );
|
|---|
| 538 | cp += outstride;
|
|---|
| 539 | }
|
|---|
| 540 | }
|
|---|
| 541 | }
|
|---|
| 542 |
|
|---|
| 543 | void
|
|---|
| 544 | Mapdesc::xformMat( Maxmatrix mat, REAL *pts,
|
|---|
| 545 | int uorder, int ustride,
|
|---|
| 546 | int vorder, int vstride,
|
|---|
| 547 | REAL *cp, int outustride, int outvstride )
|
|---|
| 548 | {
|
|---|
| 549 | if( isrational ) {
|
|---|
| 550 | REAL *pend = pts + uorder * ustride;
|
|---|
| 551 | for( REAL *p = pts ; p != pend; p += ustride ) {
|
|---|
| 552 | REAL *cpts2 = cp;
|
|---|
| 553 | REAL *qend = p + vorder * vstride;
|
|---|
| 554 | for( REAL *q = p; q != qend; q += vstride ) {
|
|---|
| 555 | xformRational( mat, cpts2, q );
|
|---|
| 556 | cpts2 += outvstride;
|
|---|
| 557 | }
|
|---|
| 558 | cp += outustride;
|
|---|
| 559 | }
|
|---|
| 560 | } else {
|
|---|
| 561 | REAL *pend = pts + uorder * ustride;
|
|---|
| 562 | for( REAL *p = pts ; p != pend; p += ustride ) {
|
|---|
| 563 | REAL *cpts2 = cp;
|
|---|
| 564 | REAL *qend = p + vorder * vstride;
|
|---|
| 565 | for( REAL *q = p; q != qend; q += vstride ) {
|
|---|
| 566 | xformNonrational( mat, cpts2, q );
|
|---|
| 567 | cpts2 += outvstride;
|
|---|
| 568 | }
|
|---|
| 569 | cp += outustride;
|
|---|
| 570 | }
|
|---|
| 571 | }
|
|---|
| 572 | }
|
|---|
| 573 |
|
|---|
| 574 | /*--------------------------------------------------------------------------
|
|---|
| 575 | * subdivide - subdivide a curve along an isoparametric line
|
|---|
| 576 | *--------------------------------------------------------------------------
|
|---|
| 577 | */
|
|---|
| 578 |
|
|---|
| 579 | void
|
|---|
| 580 | Mapdesc::subdivide( REAL *src, REAL *dst, REAL v, int stride, int order )
|
|---|
| 581 | {
|
|---|
| 582 | REAL mv = 1.0 - v;
|
|---|
| 583 |
|
|---|
| 584 | for( REAL *send=src+stride*order; src!=send; send-=stride, dst+=stride ) {
|
|---|
| 585 | copyPt( dst, src );
|
|---|
| 586 | REAL *qpnt = src + stride;
|
|---|
| 587 | for( REAL *qp=src; qpnt!=send; qp=qpnt, qpnt+=stride )
|
|---|
| 588 | sumPt( qp, qp, qpnt, mv, v );
|
|---|
| 589 | }
|
|---|
| 590 | }
|
|---|
| 591 |
|
|---|
| 592 | /*--------------------------------------------------------------------------
|
|---|
| 593 | * subdivide - subdivide a patch along an isoparametric line
|
|---|
| 594 | *--------------------------------------------------------------------------
|
|---|
| 595 | */
|
|---|
| 596 |
|
|---|
| 597 | void
|
|---|
| 598 | Mapdesc::subdivide( REAL *src, REAL *dst, REAL v,
|
|---|
| 599 | int so, int ss, int to, int ts )
|
|---|
| 600 | {
|
|---|
| 601 | REAL mv = 1.0 - v;
|
|---|
| 602 |
|
|---|
| 603 | for( REAL *slast = src+ss*so; src != slast; src += ss, dst += ss ) {
|
|---|
| 604 | REAL *sp = src;
|
|---|
| 605 | REAL *dp = dst;
|
|---|
| 606 | for( REAL *send = src+ts*to; sp != send; send -= ts, dp += ts ) {
|
|---|
| 607 | copyPt( dp, sp );
|
|---|
| 608 | REAL *qp = sp;
|
|---|
| 609 | for( REAL *qpnt = sp+ts; qpnt != send; qp = qpnt, qpnt += ts )
|
|---|
| 610 | sumPt( qp, qp, qpnt, mv, v );
|
|---|
| 611 | }
|
|---|
| 612 | }
|
|---|
| 613 | }
|
|---|
| 614 |
|
|---|
| 615 |
|
|---|
| 616 | #define sign(x) ((x > 0) ? 1 : ((x < 0.0) ? -1 : 0))
|
|---|
| 617 |
|
|---|
| 618 | /*--------------------------------------------------------------------------
|
|---|
| 619 | * project - project a set of homogeneous coordinates into inhomogeneous ones
|
|---|
| 620 | *--------------------------------------------------------------------------
|
|---|
| 621 | */
|
|---|
| 622 | int
|
|---|
| 623 | Mapdesc::project( REAL *src, int rstride, int cstride,
|
|---|
| 624 | REAL *dest, int trstride, int tcstride,
|
|---|
| 625 | int nrows, int ncols )
|
|---|
| 626 | {
|
|---|
| 627 | int s = sign( src[inhcoords] );
|
|---|
| 628 | REAL *rlast = src + nrows * rstride;
|
|---|
| 629 | REAL *trptr = dest;
|
|---|
| 630 | for( REAL *rptr=src; rptr != rlast; rptr+=rstride, trptr+=trstride ) {
|
|---|
| 631 | REAL *clast = rptr + ncols * cstride;
|
|---|
| 632 | REAL *tcptr = trptr;
|
|---|
| 633 | for( REAL *cptr = rptr; cptr != clast; cptr+=cstride, tcptr+=tcstride ) {
|
|---|
| 634 | REAL *coordlast = cptr + inhcoords;
|
|---|
| 635 | if( sign( *coordlast ) != s ) return 0;
|
|---|
| 636 | REAL *tcoord = tcptr;
|
|---|
| 637 | for( REAL *coord = cptr; coord != coordlast; coord++, tcoord++ ) {
|
|---|
| 638 | *tcoord = *coord / *coordlast;
|
|---|
| 639 | }
|
|---|
| 640 | }
|
|---|
| 641 | }
|
|---|
| 642 | return 1;
|
|---|
| 643 | }
|
|---|
| 644 |
|
|---|
| 645 | /*--------------------------------------------------------------------------
|
|---|
| 646 | * project - project a set of homogeneous coordinates into inhomogeneous ones
|
|---|
| 647 | *--------------------------------------------------------------------------
|
|---|
| 648 | */
|
|---|
| 649 | int
|
|---|
| 650 | Mapdesc::project( REAL *src, int stride, REAL *dest, int tstride, int ncols )
|
|---|
| 651 | {
|
|---|
| 652 | int s = sign( src[inhcoords] );
|
|---|
| 653 |
|
|---|
| 654 | REAL *clast = src + ncols * stride;
|
|---|
| 655 | for( REAL *cptr = src, *tcptr = dest; cptr != clast; cptr+=stride, tcptr+=tstride ) {
|
|---|
| 656 | REAL *coordlast = cptr + inhcoords;
|
|---|
| 657 | if( sign( *coordlast ) != s ) return 0;
|
|---|
| 658 | for( REAL *coord = cptr, *tcoord = tcptr; coord != coordlast; coord++, tcoord++ )
|
|---|
| 659 | *tcoord = *coord / *coordlast;
|
|---|
| 660 | }
|
|---|
| 661 |
|
|---|
| 662 | return 1;
|
|---|
| 663 | }
|
|---|
| 664 |
|
|---|
| 665 | int
|
|---|
| 666 | Mapdesc::bboxTooBig(
|
|---|
| 667 | REAL *p,
|
|---|
| 668 | int rstride,
|
|---|
| 669 | int cstride,
|
|---|
| 670 | int nrows,
|
|---|
| 671 | int ncols,
|
|---|
| 672 | REAL bb[2][MAXCOORDS] )
|
|---|
| 673 | {
|
|---|
| 674 | REAL bbpts[MAXORDER][MAXORDER][MAXCOORDS];
|
|---|
| 675 | const int trstride = sizeof(bbpts[0]) / sizeof(REAL);
|
|---|
| 676 | const int tcstride = sizeof(bbpts[0][0]) / sizeof(REAL);
|
|---|
| 677 |
|
|---|
| 678 | // points have been transformed, therefore they are homogeneous
|
|---|
| 679 | // project points
|
|---|
| 680 | int val = project( p, rstride, cstride,
|
|---|
| 681 | &bbpts[0][0][0], trstride, tcstride, nrows, ncols );
|
|---|
| 682 | if( val == 0 ) return -1;
|
|---|
| 683 |
|
|---|
| 684 | // compute bounding box
|
|---|
| 685 | bbox( bb, &bbpts[0][0][0], trstride, tcstride, nrows, ncols );
|
|---|
| 686 |
|
|---|
| 687 | // find out if bounding box can't fit in unit cube
|
|---|
| 688 | if( bbox_subdividing == N_BBOXROUND ) {
|
|---|
| 689 | for( int k=0; k != inhcoords; k++ )
|
|---|
| 690 | if( ceilf(bb[1][k]) - floorf(bb[0][k]) > bboxsize[k] ) return 1;
|
|---|
| 691 | } else {
|
|---|
| 692 | for( int k=0; k != inhcoords; k++ )
|
|---|
| 693 | if( bb[1][k] - bb[0][k] > bboxsize[k] ) return 1;
|
|---|
| 694 | }
|
|---|
| 695 | return 0;
|
|---|
| 696 | }
|
|---|
| 697 |
|
|---|
| 698 | void
|
|---|
| 699 | Mapdesc::bbox(
|
|---|
| 700 | REAL bb[2][MAXCOORDS],
|
|---|
| 701 | REAL *p,
|
|---|
| 702 | int rstride,
|
|---|
| 703 | int cstride,
|
|---|
| 704 | int nrows,
|
|---|
| 705 | int ncols )
|
|---|
| 706 | {
|
|---|
| 707 | int k;
|
|---|
| 708 | for( k=0; k != inhcoords; k++ )
|
|---|
| 709 | bb[0][k] = bb[1][k] = p[k];
|
|---|
| 710 |
|
|---|
| 711 | for( int i=0; i != nrows; i++ )
|
|---|
| 712 | for( int j=0; j != ncols; j++ )
|
|---|
| 713 | for( k=0; k != inhcoords; k++ ) {
|
|---|
| 714 | REAL x = p[i*rstride + j*cstride + k];
|
|---|
| 715 | if( x < bb[0][k] ) bb[0][k] = x;
|
|---|
| 716 | else if( x > bb[1][k] ) bb[1][k] = x;
|
|---|
| 717 | }
|
|---|
| 718 | }
|
|---|
| 719 |
|
|---|
| 720 | /*--------------------------------------------------------------------------
|
|---|
| 721 | * calcVelocityRational - calculate upper bound on first partial derivative
|
|---|
| 722 | * of a homogeneous set of points and bounds on each row of points.
|
|---|
| 723 | *--------------------------------------------------------------------------
|
|---|
| 724 | */
|
|---|
| 725 | REAL
|
|---|
| 726 | Mapdesc::calcVelocityRational( REAL *p, int stride, int ncols )
|
|---|
| 727 | {
|
|---|
| 728 | REAL tmp[MAXORDER][MAXCOORDS];
|
|---|
| 729 |
|
|---|
| 730 | assert( ncols <= MAXORDER );
|
|---|
| 731 |
|
|---|
| 732 | const int tstride = sizeof(tmp[0]) / sizeof(REAL);
|
|---|
| 733 |
|
|---|
| 734 | if( project( p, stride, &tmp[0][0], tstride, ncols ) ) {
|
|---|
| 735 | return calcPartialVelocity( &tmp[0][0], tstride, ncols, 1, 1.0 );
|
|---|
| 736 | } else { /* XXX */
|
|---|
| 737 | return calcPartialVelocity( &tmp[0][0], tstride, ncols, 1, 1.0 );
|
|---|
| 738 | }
|
|---|
| 739 | }
|
|---|
| 740 |
|
|---|
| 741 | /*--------------------------------------------------------------------------
|
|---|
| 742 | * calcVelocityNonrational - calculate upper bound on first partial
|
|---|
| 743 | * derivative of a inhomogeneous set of points.
|
|---|
| 744 | *--------------------------------------------------------------------------
|
|---|
| 745 | */
|
|---|
| 746 | REAL
|
|---|
| 747 | Mapdesc::calcVelocityNonrational( REAL *pts, int stride, int ncols )
|
|---|
| 748 | {
|
|---|
| 749 | return calcPartialVelocity( pts, stride, ncols, 1, 1.0 );
|
|---|
| 750 | }
|
|---|
| 751 |
|
|---|
| 752 | int
|
|---|
| 753 | Mapdesc::isProperty( long property )
|
|---|
| 754 | {
|
|---|
| 755 | switch ( property ) {
|
|---|
| 756 | case N_PIXEL_TOLERANCE:
|
|---|
| 757 | case N_ERROR_TOLERANCE:
|
|---|
| 758 | case N_CULLING:
|
|---|
| 759 | case N_BBOX_SUBDIVIDING:
|
|---|
| 760 | case N_S_STEPS:
|
|---|
| 761 | case N_T_STEPS:
|
|---|
| 762 | case N_SAMPLINGMETHOD:
|
|---|
| 763 | case N_CLAMPFACTOR:
|
|---|
| 764 | case N_MINSAVINGS:
|
|---|
| 765 | return 1;
|
|---|
| 766 | default:
|
|---|
| 767 | return 0;
|
|---|
| 768 | }
|
|---|
| 769 | }
|
|---|
| 770 |
|
|---|
| 771 | REAL
|
|---|
| 772 | Mapdesc::getProperty( long property )
|
|---|
| 773 | {
|
|---|
| 774 | switch ( property ) {
|
|---|
| 775 | case N_PIXEL_TOLERANCE:
|
|---|
| 776 | return pixel_tolerance;
|
|---|
| 777 | case N_ERROR_TOLERANCE:
|
|---|
| 778 | return error_tolerance;
|
|---|
| 779 | case N_CULLING:
|
|---|
| 780 | return culling_method;
|
|---|
| 781 | case N_BBOX_SUBDIVIDING:
|
|---|
| 782 | return bbox_subdividing;
|
|---|
| 783 | case N_S_STEPS:
|
|---|
| 784 | return s_steps;
|
|---|
| 785 | case N_T_STEPS:
|
|---|
| 786 | return t_steps;
|
|---|
| 787 | case N_SAMPLINGMETHOD:
|
|---|
| 788 | return sampling_method;
|
|---|
| 789 | case N_CLAMPFACTOR:
|
|---|
| 790 | return clampfactor;
|
|---|
| 791 | case N_MINSAVINGS:
|
|---|
| 792 | return minsavings;
|
|---|
| 793 | default:
|
|---|
| 794 | abort();
|
|---|
| 795 | return -1; //not necessary, needed to shut up compiler
|
|---|
| 796 | }
|
|---|
| 797 | }
|
|---|
| 798 |
|
|---|
| 799 | void
|
|---|
| 800 | Mapdesc::setProperty( long property, REAL value )
|
|---|
| 801 | {
|
|---|
| 802 |
|
|---|
| 803 | switch ( property ) {
|
|---|
| 804 | case N_PIXEL_TOLERANCE:
|
|---|
| 805 | pixel_tolerance = value;
|
|---|
| 806 | break;
|
|---|
| 807 | case N_ERROR_TOLERANCE:
|
|---|
| 808 | error_tolerance = value;
|
|---|
| 809 | break;
|
|---|
| 810 | case N_CULLING:
|
|---|
| 811 | culling_method = value;
|
|---|
| 812 | break;
|
|---|
| 813 | case N_BBOX_SUBDIVIDING:
|
|---|
| 814 | if( value <= 0.0 ) value = N_NOBBOXSUBDIVISION;
|
|---|
| 815 | bbox_subdividing = value;
|
|---|
| 816 | break;
|
|---|
| 817 | case N_S_STEPS:
|
|---|
| 818 | if( value < 0.0 ) value = 0.0;
|
|---|
| 819 | s_steps = value;
|
|---|
| 820 | maxrate = ( value < 0.0 ) ? 0.0 : value;
|
|---|
| 821 | maxsrate = ( value < 0.0 ) ? 0.0 : value;
|
|---|
| 822 | break;
|
|---|
| 823 | case N_T_STEPS:
|
|---|
| 824 | if( value < 0.0 ) value = 0.0;
|
|---|
| 825 | t_steps = value;
|
|---|
| 826 | maxtrate = ( value < 0.0 ) ? 0.0 : value;
|
|---|
| 827 | break;
|
|---|
| 828 | case N_SAMPLINGMETHOD:
|
|---|
| 829 | sampling_method = value;
|
|---|
| 830 | break;
|
|---|
| 831 | case N_CLAMPFACTOR:
|
|---|
| 832 | if( value <= 0.0 ) value = N_NOCLAMPING;
|
|---|
| 833 | clampfactor = value;
|
|---|
| 834 | break;
|
|---|
| 835 | case N_MINSAVINGS:
|
|---|
| 836 | if( value <= 0.0 ) value = N_NOSAVINGSSUBDIVISION;
|
|---|
| 837 | minsavings = value;
|
|---|
| 838 | break;
|
|---|
| 839 | default:
|
|---|
| 840 | abort();
|
|---|
| 841 | break;
|
|---|
| 842 | }
|
|---|
| 843 | }
|
|---|
| 844 |
|
|---|