📄 gxsphere.cpp
字号:
/*----------------------------------------------------------------------------
_ _ _
/\ | | | (_)
/ \ _ __ __| |_ __ ___ _ __ ___ ___ __| |_ __ _
/ /\ \ | '_ \ / _` | '__/ _ \| '_ ` _ \ / _ \/ _` | |/ _` |
/ ____ \| | | | (_| | | | (_) | | | | | | __/ (_| | | (_| |
/_/ \_\_| |_|\__,_|_| \___/|_| |_| |_|\___|\__,_|_|\__,_|
The contents of this file are subject to the Andromedia Public
License Version 1.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.andromedia.com/APL/
Software distributed under the License is distributed on an
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Pueblo client code, released November 4, 1998.
The Initial Developer of the Original Code is Andromedia Incorporated.
Portions created by Andromedia are Copyright (C) 1998 Andromedia
Incorporated. All Rights Reserved.
Andromedia Incorporated 415.365.6700
818 Mission Street - 2nd Floor 415.365.6701 fax
San Francisco, CA 94103
Contributor(s):
--------------------------------------------------------------------------
Chaco team: Dan Greening, Glenn Crocker, Jim Doubek,
Coyote Lussier, Pritham Shetty.
Wrote and designed original codebase.
------------------------------------------------------------------------------
This file contains the implementation for VRML Sphere classes.
----------------------------------------------------------------------------*/
// $Header: /home/cvs/chaco/modules/client/portable/ChGraphx/GxSphere.cpp,v 1.8 1996/06/27 03:44:30 jimd Exp $
#ifndef _GX_SPHERE_C_
#define _GX_SPHERE_C_
#include "GxSphere.h"
#define TESS_LAT_LONG 1
/*----------------------------------------------------------------------------
GxSphere class static members
----------------------------------------------------------------------------*/
int GxSphere::iOctantOrdering[8][3] = { { 1, 1, 1 },
{-1, 1, 1 },
{-1,-1, 1 },
{ 1,-1, 1 },
{ 1,-1,-1 },
{ 1, 1,-1 },
{-1, 1,-1 },
{-1,-1,-1 } };
int GxSphere::iOctantDirection[8] = { 1, -1, 1, -1, 1, -1, 1, -1 };
/*----------------------------------------------------------------------------
GxSphere class
----------------------------------------------------------------------------*/
GxSphere::GxSphere( int level )
{
if ( level < 1 ) level = 1;
m_pLevel = level;
m_pNumVerts = VertsInLevel( level );
m_pVertices = new GxVec3f[m_pNumVerts];
m_pTexCoords = new GxVec2f[m_pNumVerts];
if ( !m_pVertices || !m_pTexCoords )
{
Kill();
return;
}
Tessellate();
}
GxSphere::GxSphere( const GxSphere& sphere )
{
Copy( sphere );
}
GxSphere::~GxSphere()
{
Kill();
}
int GxSphere::VertsInLevel( int lvl )
{
#if defined(TESS_LAT_LONG)
return ((lvl+1)*lvl) + 1;
#else
return ((lvl+1)*(lvl+2))/2;
#endif
}
int GxSphere::TrisInLevel( int lvl )
{
#if defined(TESS_LAT_LONG)
return lvl*lvl;
#else
return (lvl * (lvl - 1) * 2 + lvl);
#endif
}
GxSphere& GxSphere::operator=( const GxSphere& sphere )
{
if (this != &sphere)
{
Kill();
Copy( sphere );
}
return *this;
}
void GxSphere::Tessellate()
{
#if defined(TESS_LAT_LONG)
// Tesselate one octant
// as (level - 1) rows of lat/log rectangles
// plus one row of triangles at North Pole
double x, y, z, s, t;
for (int i = 0, v = 0; i < m_pLevel; i++)
{
// For this latitude band, with north being up..
// starting at the equator
double lat = M_PI / 2. * float(i) / m_pLevel;
y = sin(lat);
double cosLat = cos(lat); // compiler bug - making this float breaks things
t = .5 - float(i) / m_pLevel / 2;
for ( int j = 0; j <= m_pLevel; j++ )
{
// Do a point of longitude
double longitude = M_PI / 2. * float(j) / m_pLevel;
x = sin(longitude) * cosLat;
// Cheapest way I know to get z,
z = sqrt(1 - (x * x + y * y));
m_pVertices[v].set( x, y, z );
// Compute s and set s,t (or u,v)
// s goes from 0 to .25
// t goes from .5 at equator to 0 at NP
s = float(j) / m_pLevel / 4;
m_pTexCoords[v].set( s, t );
v++;
}
}
m_pVertices[v].set( 0, 1, 0 ); // North pole xyz
m_pTexCoords[v].set( 0, 0 ); // North pole uv
#else // old triangle tesselator
double x, y, z, s, t;
for (int i = 0, v = 0; i <= m_pLevel; i++)
{
y = i;
y /= m_pLevel;
y = 1 - y;
t = atan2( 1-y, y )/M_PI;
for ( int j = 0; j <= i; j++ )
{
x = j; x /= m_pLevel;
z = 1 - x - y;
m_pVertices[v].set( x, y, z );
m_pVertices[v].normalize();
// t = asin(1. - m_pVertices[v].y()) / M_PI; // jwd squashed at equator
t = .5 - asin(m_pVertices[v].y()) / M_PI; // jwd
if ( i )
{
s = j; s /= i;
s = 0.5*atan2( s, 1-s )/M_PI;
//s = 0.5 * atan2( m_pVertices[v].x(), m_pVertices[v].z() ) / M_PI; // jwd
}
else
{
s = 0;
}
m_pTexCoords[v].set( s, t );
v++;
}
}
#endif
}
void GxSphere::Kill()
{
delete[] m_pVertices; m_pVertices = 0;
delete[] m_pTexCoords; m_pTexCoords = 0;
m_pLevel = 0;
m_pNumVerts = 0;
}
void GxSphere::Copy( const GxSphere& sphere )
{
m_pLevel = 0;
m_pNumVerts = 0;
if (sphere.m_pVertices)
{
m_pVertices = new GxVec3f[sphere.m_pNumVerts];
m_pTexCoords = new GxVec2f[sphere.m_pNumVerts];
if ( !m_pVertices || !m_pTexCoords )
{
Kill();
return;
}
m_pLevel = sphere.m_pLevel;
m_pNumVerts = sphere.m_pNumVerts;
for ( int i = 0; i < m_pNumVerts; i++ )
{
m_pVertices[i] = sphere.m_pVertices[i];
m_pTexCoords[i] = sphere.m_pTexCoords[i];
}
}
}
/*----------------------------------------------------------------------------
GxSphereVertexIterator class
----------------------------------------------------------------------------*/
GxSphereVertexIterator::GxSphereVertexIterator()
{
m_pSphere = 0;
}
GxSphereVertexIterator::GxSphereVertexIterator( const GxSphere& sph )
{
Attach( sph );
}
GxSphereVertexIterator::~GxSphereVertexIterator()
{
}
void GxSphereVertexIterator::Attach( const GxSphere& sph )
{
m_pSphere = &sph;
}
int GxSphereVertexIterator::NumVertices() const
{
if (m_pSphere)
{
return 8 * m_pSphere->NumVerts();
}
else
{
return 0;
}
}
int GxSphereVertexIterator::Iterate()
{
if ( !m_pSphere )
return 0;
GxVec3f* vs = m_pSphere->Vertices();
int nvs = m_pSphere->NumVerts();
GxVec3f v;
for (int i = 0, nv = 0; i < 8; i++)
{
int sx = (GxSphere::iOctantOrdering[i][0] > 0 ? 1 : -1 );
int sy = (GxSphere::iOctantOrdering[i][1] > 0 ? 1 : -1 );
int sz = (GxSphere::iOctantOrdering[i][2] > 0 ? 1 : -1 );
for (int j = 0; j < nvs; j++)
{
v[0] = vs[j][0]*sx;
v[1] = vs[j][1]*sy;
v[2] = vs[j][2]*sz;
DoVertex( nv++, v );
}
}
return 1;
}
int GxSphereVertexIterator::DoVertex( int, const GxVec3f& )
{
return 1;
}
/*----------------------------------------------------------------------------
GxSphereTriangleIterator class
----------------------------------------------------------------------------*/
GxSphereTriangleIterator::GxSphereTriangleIterator()
{
m_pSphere = 0;
}
GxSphereTriangleIterator::GxSphereTriangleIterator( const GxSphere& sph )
{
Attach( sph );
}
GxSphereTriangleIterator::~GxSphereTriangleIterator()
{
}
void GxSphereTriangleIterator::Attach( const GxSphere& sph )
{
m_pSphere = &sph;
}
int GxSphereTriangleIterator::NumTriangles() const
{
if (m_pSphere)
{
return 8 * GxSphere::TrisInLevel( m_pSphere->Level() );
}
else
{
return 0;
}
}
int GxSphereTriangleIterator::Iterate( GxSphere::IType itp )
{
if (!m_pSphere)
{
return 0;
}
// This needs to be fixed for lat/long tesselation!!
#if defined(TESS_LAT_LONG)
if ( !m_pSphere ) return 0;
int level = m_pSphere->Level();
GxVec3f* vs = m_pSphere->Vertices();
int nvs = m_pSphere->NumVerts();
int nts = GxSphere::TrisInLevel( level );
int tri = 0;
for ( int i = 0; i < 8; i++ )
{
int vbase = i*nvs;
int isclk = ( GxSphere::iOctantDirection[i] == -1 );
int sx = (GxSphere::iOctantOrdering[i][0] > 0 ? 1 : -1 );
int sy = (GxSphere::iOctantOrdering[i][1] > 0 ? 1 : -1 );
int sz = (GxSphere::iOctantOrdering[i][2] > 0 ? 1 : -1 );
if ( itp == GxSphere::Indexed )
{
// Do the latitudinal belts of rectangles
// level - 1 belts
// level rects in each belt
// This means 2 * level tris in a belt
// in each belt.
for ( int j = 0, top = 0, bot = level + 1; j < level - 1; j++ )
{
for ( int k = 0; k < level; k++ )
{
int a = vbase + top++, b = vbase + bot++;
int c = vbase + top, d = vbase + bot;
if ( isclk )
{
GxSwap( a, b );
GxSwap( c, d );
}
if ( !DoTriangle( tri++, a, b, c ) ) return 0;
if ( !DoTriangle( tri++, c, b, d ) ) return 0;
}
top ++;
bot ++;
}
// Do the polar triangles
for ( j = 0; j < level; j++ )
{
int pole = vbase + nvs - 1;
int a = vbase + (level + 1) * (level - 1) + j;
int b = a + 1;
if ( isclk ) GxSwap( a, b );
if ( !DoTriangle( tri++, a, pole, b ) ) return 0;
}
}
else
{
#if 0
for ( int j = 0, top = 0, bot = 1; j < level; j++ )
{
if ( !StartStrip( strip ) ) return 0;
for ( int k = 0; k <= j; k++ )
{
int a = top++, b = bot++;
if ( isclk ) GxSwap( a, b );
GxVec3f va, vb;
va[0] = vs[a][0]*sx, va[1] = vs[a][1]*sy, va[2] = vs[a][2]*sz;
vb[0] = vs[b][0]*sx, vb[1] = vs[b][1]*sy, vb[2] = vs[b][2]*sz;
if ( !DoVertex( va ) ) return 0;
if ( !DoVertex( vb ) ) return 0;
}
int c = bot++;
GxVec3f vc;
vc[0] = vs[c][0]*sx, vc[1] = vs[c][1]*sy, vc[2] = vs[c][2]*sz;
if ( !DoVertex( vc ) ) return 0;
if ( !StopStrip( strip++ ) ) return 0;
}
#else
//ASSERT(0);
#endif
}
}
return 1;
#else
int level = m_pSphere->Level();
GxVec3f* vs = m_pSphere->Vertices();
int nvs = m_pSphere->NumVerts();
int nts = GxSphere::TrisInLevel( level );
for (int i = 0, tri = 0; i < 8; i++)
{
int vbase = i * nvs;
int isclk = ( GxSphere::iOctantDirection[i] == -1 );
int sx = (GxSphere::iOctantOrdering[i][0] > 0 ? 1 : -1 );
int sy = (GxSphere::iOctantOrdering[i][1] > 0 ? 1 : -1 );
int sz = (GxSphere::iOctantOrdering[i][2] > 0 ? 1 : -1 );
for (int j = 0, top = 0, bot = 1; j < level; j++)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -