kicad/3d-viewer/3d_rendering/opengl/layer_triangles.cpp

797 lines
24 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "layer_triangles.h"
#include "../raytracing/ray.h"
#include <wx/debug.h> // For the wxASSERT
#include <mutex>
TRIANGLE_LIST::TRIANGLE_LIST( unsigned int aNrReservedTriangles, bool aReserveNormals )
{
wxASSERT( aNrReservedTriangles > 0 );
m_vertexs.clear();
m_normals.clear();
m_vertexs.reserve( aNrReservedTriangles * 3 );
if( aReserveNormals )
m_normals.reserve( aNrReservedTriangles * 3 );
}
void TRIANGLE_LIST::Reserve_More( unsigned int aNrReservedTriangles, bool aReserveNormals )
{
m_vertexs.reserve( m_vertexs.size() + aNrReservedTriangles * 3 );
if( aReserveNormals )
m_normals.reserve( m_normals.size() + aNrReservedTriangles * 3 );
}
void TRIANGLE_LIST::AddQuad( const SFVEC3F& aV1, const SFVEC3F& aV2, const SFVEC3F& aV3,
const SFVEC3F& aV4 )
{
m_vertexs.push_back( aV1 );
m_vertexs.push_back( aV2 );
m_vertexs.push_back( aV3 );
m_vertexs.push_back( aV3 );
m_vertexs.push_back( aV4 );
m_vertexs.push_back( aV1 );
}
void TRIANGLE_LIST::AddTriangle( const SFVEC3F& aV1, const SFVEC3F& aV2, const SFVEC3F& aV3 )
{
m_vertexs.push_back( aV1 );
m_vertexs.push_back( aV2 );
m_vertexs.push_back( aV3 );
}
void TRIANGLE_LIST::AddNormal( const SFVEC3F& aN1, const SFVEC3F& aN2, const SFVEC3F& aN3 )
{
m_normals.push_back( aN1 );
m_normals.push_back( aN2 );
m_normals.push_back( aN3 );
}
void TRIANGLE_LIST::AddNormal( const SFVEC3F& aN1, const SFVEC3F& aN2, const SFVEC3F& aN3,
const SFVEC3F& aN4 )
{
m_normals.push_back( aN1 );
m_normals.push_back( aN2 );
m_normals.push_back( aN3 );
m_normals.push_back( aN3 );
m_normals.push_back( aN4 );
m_normals.push_back( aN1 );
}
TRIANGLE_DISPLAY_LIST::TRIANGLE_DISPLAY_LIST( unsigned int aNrReservedTriangles )
{
wxASSERT( aNrReservedTriangles > 0 );
m_layer_top_segment_ends = new TRIANGLE_LIST( aNrReservedTriangles, false );
m_layer_top_triangles = new TRIANGLE_LIST( aNrReservedTriangles, false );
m_layer_middle_contourns_quads = new TRIANGLE_LIST( aNrReservedTriangles, true );
m_layer_bot_triangles = new TRIANGLE_LIST( aNrReservedTriangles, false );
m_layer_bot_segment_ends = new TRIANGLE_LIST( aNrReservedTriangles, false );
}
TRIANGLE_DISPLAY_LIST::~TRIANGLE_DISPLAY_LIST()
{
delete m_layer_top_segment_ends;
m_layer_top_segment_ends = nullptr;
delete m_layer_top_triangles;
m_layer_top_triangles = nullptr;
delete m_layer_middle_contourns_quads;
m_layer_middle_contourns_quads = nullptr;
delete m_layer_bot_triangles;
m_layer_bot_triangles = nullptr;
delete m_layer_bot_segment_ends;
m_layer_bot_segment_ends = nullptr;
}
void TRIANGLE_DISPLAY_LIST::AddToMiddleContourns( const std::vector< SFVEC2F >& aContournPoints,
float zBot, float zTop, bool aInvertFaceDirection,
const BVH_CONTAINER_2D* aThroughHoles )
{
if( aContournPoints.size() >= 4 )
{
// Calculate normals of each segment of the contourn
std::vector< SFVEC2F > contournNormals;
contournNormals.clear();
contournNormals.resize( aContournPoints.size() - 1 );
if( aInvertFaceDirection )
{
for( unsigned int i = 0; i < ( aContournPoints.size() - 1 ); ++i )
{
const SFVEC2F& v0 = aContournPoints[i + 0];
const SFVEC2F& v1 = aContournPoints[i + 1];
const SFVEC2F n = glm::normalize( v1 - v0 );
contournNormals[i] = SFVEC2F( n.y,-n.x );
}
}
else
{
for( unsigned int i = 0; i < ( aContournPoints.size() - 1 ); ++i )
{
const SFVEC2F& v0 = aContournPoints[i + 0];
const SFVEC2F& v1 = aContournPoints[i + 1];
const SFVEC2F n = glm::normalize( v1 - v0 );
contournNormals[i] = SFVEC2F( -n.y, n.x );
}
}
if( aInvertFaceDirection )
std::swap( zBot, zTop );
const unsigned int nContournsToProcess = ( aContournPoints.size() - 1 );
for( unsigned int i = 0; i < nContournsToProcess; ++i )
{
SFVEC2F lastNormal;
if( i > 0 )
lastNormal = contournNormals[i - 1];
else
lastNormal = contournNormals[nContournsToProcess - 1];
SFVEC2F n0 = contournNormals[i];
// Only interpolate the normal if the angle is closer
if( glm::dot( n0, lastNormal ) > 0.5f )
n0 = glm::normalize( n0 + lastNormal );
SFVEC2F nextNormal;
if( i < (nContournsToProcess - 1) )
nextNormal = contournNormals[i + 1];
else
nextNormal = contournNormals[0];
SFVEC2F n1 = contournNormals[i];
if( glm::dot( n1, nextNormal ) > 0.5f )
n1 = glm::normalize( n1 + nextNormal );
const SFVEC3F n3d0 = SFVEC3F( n0.x, n0.y, 0.0f );
const SFVEC3F n3d1 = SFVEC3F( n1.x, n1.y, 0.0f );
const SFVEC2F& v0 = aContournPoints[i + 0];
const SFVEC2F& v1 = aContournPoints[i + 1];
if( aThroughHoles && aThroughHoles->IntersectAny( RAYSEG2D( v0, v1 ) ) )
{
continue;
}
else
{
std::lock_guard<std::mutex> lock( m_middle_layer_lock );
m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, zTop ),
SFVEC3F( v1.x, v1.y, zTop ),
SFVEC3F( v1.x, v1.y, zBot ),
SFVEC3F( v0.x, v0.y, zBot ) );
m_layer_middle_contourns_quads->AddNormal( n3d0, n3d1, n3d1, n3d0 );
}
}
}
}
void TRIANGLE_DISPLAY_LIST::AddToMiddleContourns( const SHAPE_LINE_CHAIN& outlinePath, float zBot,
float zTop, double aBiuTo3Du,
bool aInvertFaceDirection,
const BVH_CONTAINER_2D* aThroughHoles )
{
std::vector< SFVEC2F >contournPoints;
contournPoints.clear();
contournPoints.reserve( outlinePath.PointCount() + 2 );
const VECTOR2I& firstV = outlinePath.CPoint( 0 );
SFVEC2F lastV = SFVEC2F( firstV.x * aBiuTo3Du, -firstV.y * aBiuTo3Du );
contournPoints.push_back( lastV );
for( unsigned int i = 1; i < (unsigned int)outlinePath.PointCount(); ++i )
{
const VECTOR2I& v = outlinePath.CPoint( i );
const SFVEC2F vf = SFVEC2F( v.x * aBiuTo3Du, -v.y * aBiuTo3Du );
if( vf != lastV ) // Do not add repeated points
{
lastV = vf;
contournPoints.push_back( vf );
}
}
// Add first position fo the list to close the path
if( lastV != contournPoints[0] )
contournPoints.push_back( contournPoints[0] );
AddToMiddleContourns( contournPoints, zBot, zTop, aInvertFaceDirection, aThroughHoles );
}
void TRIANGLE_DISPLAY_LIST::AddToMiddleContourns( const SHAPE_POLY_SET& aPolySet, float zBot,
float zTop, double aBiuTo3Du,
bool aInvertFaceDirection,
const BVH_CONTAINER_2D* aThroughHoles )
{
if( aPolySet.OutlineCount() == 0 )
return;
// Calculate an estimation of points to reserve
unsigned int nrContournPointsToReserve = 0;
for( int i = 0; i < aPolySet.OutlineCount(); ++i )
{
const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );
nrContournPointsToReserve += pathOutline.PointCount();
for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
{
const SHAPE_LINE_CHAIN& hole = aPolySet.CHole( i, h );
nrContournPointsToReserve += hole.PointCount();
}
}
// Request to reserve more space
m_layer_middle_contourns_quads->Reserve_More( nrContournPointsToReserve * 2, true );
for( int i = 0; i < aPolySet.OutlineCount(); i++ )
{
// Add outline
const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i );
AddToMiddleContourns( pathOutline, zBot, zTop, aBiuTo3Du, aInvertFaceDirection,
aThroughHoles );
// Add holes for this outline
for( int h = 0; h < aPolySet.HoleCount( i ); ++h )
{
const SHAPE_LINE_CHAIN& hole = aPolySet.CHole( i, h );
AddToMiddleContourns( hole, zBot, zTop, aBiuTo3Du, aInvertFaceDirection,
aThroughHoles );
}
}
}
OPENGL_RENDER_LIST::OPENGL_RENDER_LIST( const TRIANGLE_DISPLAY_LIST& aLayerTriangles,
GLuint aTextureIndexForSegEnds,
float aZBot, float aZTop )
{
m_zBot = aZBot;
m_zTop = aZTop;
m_layer_top_segment_ends = 0;
m_layer_top_triangles = 0;
m_layer_middle_contourns_quads = 0;
m_layer_bot_triangles = 0;
m_layer_bot_segment_ends = 0;
if( aTextureIndexForSegEnds )
{
wxASSERT( glIsTexture( aTextureIndexForSegEnds ) );
if( glIsTexture( aTextureIndexForSegEnds ) )
{
m_layer_top_segment_ends =
generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_top_segment_ends,
true, aTextureIndexForSegEnds );
m_layer_bot_segment_ends =
generate_top_or_bot_seg_ends( aLayerTriangles.m_layer_bot_segment_ends,
false, aTextureIndexForSegEnds );
}
}
m_layer_top_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_top_triangles,
true );
m_layer_bot_triangles = generate_top_or_bot_triangles( aLayerTriangles.m_layer_bot_triangles,
false );
if( aLayerTriangles.m_layer_middle_contourns_quads->GetVertexSize() > 0 )
{
m_layer_middle_contourns_quads =
generate_middle_triangles( aLayerTriangles.m_layer_middle_contourns_quads );
}
m_draw_it_transparent = false;
m_haveTransformation = false;
m_zPositionTransformation = 0.0f;
m_zScaleTransformation = 0.0f;
}
OPENGL_RENDER_LIST::~OPENGL_RENDER_LIST()
{
if( glIsList( m_layer_top_segment_ends ) )
glDeleteLists( m_layer_top_segment_ends, 1 );
if( glIsList( m_layer_top_triangles ) )
glDeleteLists( m_layer_top_triangles, 1 );
if( glIsList( m_layer_middle_contourns_quads ) )
glDeleteLists( m_layer_middle_contourns_quads, 1 );
if( glIsList( m_layer_bot_triangles ) )
glDeleteLists( m_layer_bot_triangles, 1 );
if( glIsList( m_layer_bot_segment_ends ) )
glDeleteLists( m_layer_bot_segment_ends, 1 );
m_layer_top_segment_ends = 0;
m_layer_top_triangles = 0;
m_layer_middle_contourns_quads = 0;
m_layer_bot_triangles = 0;
m_layer_bot_segment_ends = 0;
}
void OPENGL_RENDER_LIST::DrawTopAndMiddle() const
{
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
endTransformation();
}
void OPENGL_RENDER_LIST::DrawBotAndMiddle() const
{
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void OPENGL_RENDER_LIST::DrawTop() const
{
beginTransformation();
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
endTransformation();
}
void OPENGL_RENDER_LIST::DrawBot() const
{
beginTransformation();
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void OPENGL_RENDER_LIST::DrawMiddle() const
{
beginTransformation();
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
endTransformation();
}
void OPENGL_RENDER_LIST::DrawAll( bool aDrawMiddle ) const
{
beginTransformation();
if( aDrawMiddle )
if( glIsList( m_layer_middle_contourns_quads ) )
glCallList( m_layer_middle_contourns_quads );
if( glIsList( m_layer_top_triangles ) )
glCallList( m_layer_top_triangles );
if( glIsList( m_layer_bot_triangles ) )
glCallList( m_layer_bot_triangles );
if( glIsList( m_layer_top_segment_ends ) )
glCallList( m_layer_top_segment_ends );
if( glIsList( m_layer_bot_segment_ends ) )
glCallList( m_layer_bot_segment_ends );
endTransformation();
}
void OPENGL_RENDER_LIST::DrawAllCameraCulled( float zCameraPos, bool aDrawMiddle ) const
{
zCameraPos = m_haveTransformation
? ( ( zCameraPos - m_zPositionTransformation ) / m_zScaleTransformation )
: zCameraPos;
if( aDrawMiddle )
DrawMiddle();
if( zCameraPos > m_zTop )
{
DrawTop();
}
else
{
if( zCameraPos < m_zBot )
{
DrawBot();
}
else
{
// If camera is in the middle dont draw it.
}
}
}
void OPENGL_RENDER_LIST::DrawAllCameraCulled( bool aDrawMiddle,
const OPENGL_RENDER_LIST* aSubtractList,
const OPENGL_RENDER_LIST* bSubtractList,
const OPENGL_RENDER_LIST* cSubtractList,
const OPENGL_RENDER_LIST* dSubtractList ) const
{
glClearStencil( 0x00 );
glClear( GL_STENCIL_BUFFER_BIT );
glEnable( GL_CULL_FACE );
glCullFace( GL_BACK );
glDisable( GL_DEPTH_TEST );
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glDepthMask( GL_FALSE );
glEnable( GL_STENCIL_TEST );
glStencilFunc( GL_ALWAYS, 1, 0 );
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
if( aSubtractList )
aSubtractList->DrawBot();
if( bSubtractList )
bSubtractList->DrawBot();
if( cSubtractList )
cSubtractList->DrawBot();
if( dSubtractList )
dSubtractList->DrawBot();
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glStencilFunc( GL_EQUAL, 0, 1 );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
DrawBot();
glDisable( GL_DEPTH_TEST );
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glDepthMask( GL_FALSE );
glEnable( GL_STENCIL_TEST );
glStencilFunc( GL_ALWAYS, 2, 0 );
glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
if( aSubtractList )
aSubtractList->DrawTop();
if( bSubtractList )
bSubtractList->DrawTop();
if( cSubtractList )
cSubtractList->DrawTop();
if( dSubtractList )
dSubtractList->DrawTop();
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glStencilFunc( GL_NOTEQUAL, 2, 0x03 );
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
DrawTop();
if( aDrawMiddle )
DrawMiddle();
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
glCullFace( GL_FRONT );
glStencilFunc( GL_GEQUAL, 3, 0x03 );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
if( aDrawMiddle )
{
if( aSubtractList )
aSubtractList->DrawMiddle();
}
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glCullFace( GL_BACK );
glDisable( GL_STENCIL_TEST );
}
void OPENGL_RENDER_LIST::ApplyScalePosition( float aZposition, float aZscale )
{
wxCHECK2( aZscale > FLT_EPSILON, aZscale = FLT_EPSILON + 1 );
m_zPositionTransformation = aZposition;
m_zScaleTransformation = aZscale;
m_haveTransformation = true;
}
void OPENGL_RENDER_LIST::ApplyScalePosition( OPENGL_RENDER_LIST* aOtherList )
{
ApplyScalePosition( aOtherList->GetZBot(), aOtherList->GetZTop() - aOtherList->GetZBot() );
}
void OPENGL_RENDER_LIST::SetItIsTransparent( bool aSetTransparent )
{
m_draw_it_transparent = aSetTransparent;
}
GLuint OPENGL_RENDER_LIST::generate_top_or_bot_seg_ends(
const TRIANGLE_LIST* aTriangleContainer, bool aIsNormalUp, GLuint aTextureId ) const
{
wxASSERT( aTriangleContainer != nullptr );
wxASSERT( ( aTriangleContainer->GetVertexSize() % 3 ) == 0 );
// Top and Bot dont have normals array stored in container
wxASSERT( aTriangleContainer->GetNormalsSize() == 0 );
if( ( aTriangleContainer->GetVertexSize() > 0 )
&& ( ( aTriangleContainer->GetVertexSize() % 3 ) == 0 ) )
{
GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
// Prepare an array of UV text coordinates
SFVEC2F* uvArray = new SFVEC2F[aTriangleContainer->GetVertexSize()];
for( unsigned int i = 0; i < aTriangleContainer->GetVertexSize(); i += 3 )
{
uvArray[i + 0] = SFVEC2F( 1.0f, 0.0f );
uvArray[i + 1] = SFVEC2F( 0.0f, 1.0f );
uvArray[i + 2] = SFVEC2F( 0.0f, 0.0f );
}
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, aTriangleContainer->GetVertexPointer() );
glTexCoordPointer( 2, GL_FLOAT, 0, uvArray );
glNewList( listIdx, GL_COMPILE );
glDisable( GL_COLOR_MATERIAL );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, aTextureId );
glAlphaFunc( GL_GREATER, 0.2f );
glEnable( GL_ALPHA_TEST );
glNormal3f( 0.0f, 0.0f, aIsNormalUp?1.0f:-1.0f );
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
glDisable( GL_ALPHA_TEST );
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
delete [] uvArray;
return listIdx;
}
}
return 0;
}
GLuint OPENGL_RENDER_LIST::generate_top_or_bot_triangles( const TRIANGLE_LIST* aTriangleContainer,
bool aIsNormalUp ) const
{
wxASSERT( aTriangleContainer != nullptr );
wxASSERT( ( aTriangleContainer->GetVertexSize() % 3 ) == 0 );
// Top and Bot dont have normals array stored in container
wxASSERT( aTriangleContainer->GetNormalsSize() == 0 );
if( ( aTriangleContainer->GetVertexSize() > 0 )
&& ( ( aTriangleContainer->GetVertexSize() % 3 ) == 0 ) )
{
const GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, aTriangleContainer->GetVertexPointer() );
glNewList( listIdx, GL_COMPILE );
setBlendfunction();
glNormal3f( 0.0f, 0.0f, aIsNormalUp?1.0f:-1.0f );
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
return listIdx;
}
}
return 0;
}
GLuint OPENGL_RENDER_LIST::generate_middle_triangles(
const TRIANGLE_LIST* aTriangleContainer ) const
{
wxASSERT( aTriangleContainer != nullptr );
// We expect that it is a multiple of 3 vertex
wxASSERT( ( aTriangleContainer->GetVertexSize() % 3 ) == 0 );
// We expect that it is a multiple of 6 vertex (because we expect to add quads)
wxASSERT( (aTriangleContainer->GetVertexSize() % 6 ) == 0 );
// We expect that there are normals with same size as vertex
wxASSERT( aTriangleContainer->GetNormalsSize() == aTriangleContainer->GetVertexSize() );
if( ( aTriangleContainer->GetVertexSize() > 0 )
&& ( ( aTriangleContainer->GetVertexSize() % 3 ) == 0 )
&& ( ( aTriangleContainer->GetVertexSize() % 6 ) == 0 )
&& ( aTriangleContainer->GetNormalsSize() == aTriangleContainer->GetVertexSize() ) )
{
const GLuint listIdx = glGenLists( 1 );
if( glIsList( listIdx ) )
{
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, aTriangleContainer->GetVertexPointer() );
glNormalPointer( GL_FLOAT, 0, aTriangleContainer->GetNormalsPointer() );
glNewList( listIdx, GL_COMPILE );
setBlendfunction();
glDrawArrays( GL_TRIANGLES, 0, aTriangleContainer->GetVertexSize() );
glDisable( GL_BLEND );
glEndList();
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
return listIdx;
}
}
return 0;
}
void OPENGL_RENDER_LIST::endTransformation() const
{
if( m_haveTransformation )
{
glPopMatrix();
}
}
void OPENGL_RENDER_LIST::setBlendfunction() const
{
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
void OPENGL_RENDER_LIST::beginTransformation() const
{
if( m_haveTransformation )
{
glPushMatrix();
glTranslatef( 0.0f, 0.0f, m_zPositionTransformation );
glScalef( 1.0f, 1.0f, m_zScaleTransformation );
}
}