You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kpovmodeler/pmrendermanager.cpp

1648 lines
47 KiB

/*
**************************************************************************
description
--------------------
copyright : (C) 2000-2002 by Andreas Zehender
email : zehender@kde.org
**************************************************************************
**************************************************************************
* *
* 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. *
* *
**************************************************************************/
// conflicting types for INT32 in qt and glx
#ifndef QT_CLEAN_NAMESPACE
#define QT_CLEAN_NAMESPACE
#endif
#include "pmrendermanager.h"
#include "pmviewstructure.h"
#include "pmobject.h"
#include "pmdeclare.h"
#include "pmcamera.h"
#include "pmquickcolor.h"
#include "pmdefaults.h"
#include "pmgraphicalobject.h"
#include "pmmath.h"
#include <tqptrstack.h>
#include <tqapplication.h>
#include <tqbitmap.h>
#include <tqimage.h>
#include <tqpainter.h>
#include <kconfig.h>
#include <klocale.h>
#include <time.h>
#include <stdio.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h> // Only needed for gluPerspective
#include "pmglview.h"
const GLdouble dA = 0.75;
const GLdouble dB = 0.15;
const GLdouble viewVolumeZ = 1e5;
// Size has to be controlPointSize (see pmglview.h)
const GLubyte PointBitmap[7] = { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE };
const GLubyte CrossBitmap[7] = { 0x10, 0x10, 0x10, 0xFE, 0x10, 0x10, 0x10 };
const int activeTimeAfterRendering = 2;
const int maxEventTime = 0;
const int maxSubdivisions = 32;
const double subdivisionDistance = 0.05;
PMRenderManager* PMRenderManager::s_pManager = 0;
KStaticDeleter<PMRenderManager> PMRenderManager::s_staticDeleter;
bool PMRenderManager::s_hasOpenGL = true;
bool PMRenderManager::s_hasOpenGLChecked = false;
PMRenderManager* PMRenderManager::theManager( )
{
if( !s_pManager )
s_staticDeleter.setObject( s_pManager, new PMRenderManager( ) );
return s_pManager;
}
PMRenderManager::PMRenderManager( )
: TQObject( qApp )
{
int i;
m_bStartTask = false;
m_bStopTask = false;
m_bTaskIsRunning = false;
m_graphicalObjectColor[0] = c_defaultGraphicalObjectColor0;
m_graphicalObjectColor[1] = c_defaultGraphicalObjectColor1;
m_textureColor[0] = c_defaultTextureColor0;
m_textureColor[1] = c_defaultTextureColor1;
m_axesColor[0] = c_defaultAxesColorX;
m_axesColor[1] = c_defaultAxesColorY;
m_axesColor[2] = c_defaultAxesColorZ;
m_controlPointColor[0] = c_defaultControlPointColor0;
m_controlPointColor[1] = c_defaultControlPointColor1;
m_backgroundColor = c_defaultBackgroundColor;
m_fieldOfViewColor = c_defaultFieldOfViewColor;
m_highDetailCameraView = c_defaultHighDetailCameraView;
m_nMaxRenderedLines = 1000;
m_gridDistance = c_defaultGridDistance;
m_gridColor = c_defaultGridColor;
m_axesViewStructureCreated = false;
m_currentVisibility = 0;
m_renderTasks.setAutoDelete( true );
m_matrixStack.setAutoDelete( true );
m_quickColors.setAutoDelete( true );
m_nViews = 0;
m_subdivisionViewStructure = PMViewStructure( maxSubdivisions + 1,
maxSubdivisions );
PMLineArray& lines = m_subdivisionViewStructure.lines( );
for( i = 0; i < maxSubdivisions; i++ )
lines[i] = PMLine( i, i+1 );
}
PMRenderManager::~PMRenderManager( )
{
s_pManager = 0;
}
void PMRenderManager::addView( PMGLView* view, PMObject* active, PMObject* top,
PMControlPointList* controlPoints,
double aspectRatio, int visibilityLevel,
bool graphicalChange )
{
PMRenderTaskListIterator it( m_renderTasks );
PMRenderTask* task = 0;
bool restart = false;
bool first = true;
for( ; it.current( ) && !task; ++it )
{
if( it.current( )->view( ) == view )
task = it.current( );
else
first = false;
}
if( task )
{
if( first )
restart = true;
else if( graphicalChange )
{
m_renderTasks.findRef( task );
m_renderTasks.take( );
m_renderTasks.prepend( task );
restart = true;
}
task->setActiveObject( active );
task->setTopLevelObject( top );
task->setControlPoints( controlPoints );
task->setAspectRatio( aspectRatio );
task->setVisibilityLevel( visibilityLevel );
}
else
{
task = new PMRenderTask( view, active, top, controlPoints, aspectRatio,
visibilityLevel );
if( graphicalChange )
{
m_renderTasks.prepend( task );
restart = true;
}
else
{
m_renderTasks.append( task );
if( m_renderTasks.count( ) == 1 )
restart = true;
}
}
if( restart )
restartRendering( );
}
void PMRenderManager::removeView( PMGLView* view )
{
PMRenderTaskListIterator it( m_renderTasks );
PMRenderTask* task = 0;
bool restart = false;
for( ; it.current( ) && !task; ++it )
if( it.current( )->view( ) == view )
task = it.current( );
if( task )
{
if( task == m_renderTasks.first( ) )
{
restart = true;
if( m_bTaskIsRunning )
emit renderingFinished( task->view( ) );
}
m_renderTasks.removeRef( task );
}
if( restart )
restartRendering( );
}
bool PMRenderManager::containsTask( PMGLView* view ) const
{
PMRenderTaskListIterator it( m_renderTasks );
bool contains = false;
for( ; it.current( ) && !contains; ++it )
if( it.current( )->view( ) == view )
contains = true;
return contains;
}
TQColor PMRenderManager::controlPointColor( int i ) const
{
if( ( i >= 0 ) && ( i <= 1 ) )
return m_controlPointColor[i];
return TQColor( 0, 0, 0 );
}
void PMRenderManager::setControlPointColor( int i, const TQColor& c )
{
if( ( i >= 0 ) && ( i <= 1 ) )
m_controlPointColor[i] = c;
}
TQColor PMRenderManager::graphicalObjectColor( int i ) const
{
if( ( i >= 0 ) && ( i <= 1 ) )
return m_graphicalObjectColor[i];
return TQColor( 0, 0, 0 );
}
void PMRenderManager::setGraphicalObjectColor( int i, const TQColor& c )
{
if( ( i >= 0 ) && ( i <= 1 ) )
m_graphicalObjectColor[i] = c;
}
TQColor PMRenderManager::axesColor( int i ) const
{
if( ( i >= 0 ) && ( i <= 2 ) )
return m_axesColor[i];
return TQColor( 0, 0, 0 );
}
void PMRenderManager::setAxesColor( int i, const TQColor& c )
{
if( ( i >= 0 ) && ( i <= 2 ) )
m_axesColor[i] = c;
}
void PMRenderManager::setGridDistance( int d )
{
if( d >= 20 )
m_gridDistance = d;
}
void PMRenderManager::restartRendering( )
{
if( !m_bTaskIsRunning && !m_bStartTask )
startTimer( 0 );
m_bStartTask = true;
m_bStopTask = false;
}
void PMRenderManager::slotStopRendering( )
{
m_bStopTask = true;
m_bStartTask = false;
if( m_bTaskIsRunning )
if( m_pCurrentTask )
emit renderingFinished( m_pCurrentTask->view( ) );
m_renderTasks.clear( );
}
void PMRenderManager::timerEvent( TQTimerEvent* )
{
killTimers( );
renderTask( );
}
void PMRenderManager::renderTask( )
{
m_bTaskIsRunning = true;
emit renderingStarted( );
int r, g, b;
bool disableView = false;
while( m_bStartTask && !m_bStopTask )
{
m_bStartTask = false;
// render the views sequential
while( m_renderTasks.first( ) && !m_bStopTask && !m_bStartTask )
{
// reset the member variables for rendering
m_pCurrentTask = m_renderTasks.first( );
m_pCurrentGlView = m_pCurrentTask->view( );
emit renderingStarted( m_pCurrentGlView );
m_renderedLines = 0;
m_selected = false;
m_pDeselectObject = 0;
m_matrixStack.clear( );
m_quickColorObjects.clear( );
m_quickColors.clear( );
m_currentColor = m_graphicalObjectColor[0];
m_specialCameraMode = false;
m_currentVisibility = 0;
m_visibilityStack.clear( );
if( m_bStopTask || m_bStartTask )
break;
m_pCurrentGlView->makeCurrent( );
m_backgroundColor.rgb( &r, &g, &b );
glClearColor( r/255.0, g/255.0, b/255.0, 1.0 );
glPointSize( controlPointSize );
glEnable( GL_DEPTH_TEST );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glViewport( 0, 0, ( GLint ) m_pCurrentGlView->width( ),
( GLint ) m_pCurrentGlView->height( ) );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
disableView = false;
if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
{
if( m_pCurrentGlView->camera( ) )
{
if( m_pCurrentGlView->camera( )->cameraType( )
== PMCamera::Omnimax )
disableView = true;
}
else
disableView = true;
}
if( !disableView )
setProjection( );
glLoadIdentity( );
glDisable( GL_DEPTH_TEST );
if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
renderFieldOfView( );
else
renderGrid( );
renderDescription( );
glEnable( GL_DEPTH_TEST );
if( !disableView )
{
renderAxes( );
renderObject( m_pCurrentTask->topLevelObject( ) );
if( !m_bStopTask && ! m_bStartTask )
renderControlPoints( );
}
if( !m_bStopTask && ! m_bStartTask )
{
glXWaitX( );
emit aboutToUpdate( m_pCurrentGlView );
if( m_bStopTask || m_bStartTask )
break;
glXWaitX( );
m_pCurrentGlView->swapBuffers( );
glFinish( );
glXWaitGL( );
emit renderingFinished( m_pCurrentGlView );
if( m_bStopTask || m_bStartTask )
break;
qApp->processEvents( maxEventTime );
if( m_bStopTask || m_bStartTask )
break;
m_renderTasks.removeFirst( );
}
}
}
emit renderingFinished( );
m_bStopTask = false;
m_bStartTask = false;
m_bTaskIsRunning = false;
}
void PMRenderManager::renderObject( PMObject* objectToRender )
{
bool children = false;
PMGraphicalObject* go = 0;
m_objectToRenderStack.append( objectToRender );
if( objectToRender->isA( "GraphicalObject" ) )
{
go = ( PMGraphicalObject* ) objectToRender;
m_visibilityStack.push( m_currentVisibility );
if( go->isVisibilityLevelRelative( ) )
m_currentVisibility += go->visibilityLevel( );
else
m_currentVisibility = go->visibilityLevel( );
}
if( !m_selected )
{
if( objectToRender->isSelected( ) )
{
m_selected = true;
m_pDeselectObject = objectToRender;
if( objectToRender->hasTransformationMatrix( ) )
if( objectToRender->parent( ) )
m_pDeselectObject = objectToRender->parent( );
}
}
if( ( m_pCurrentGlView->type( ) != PMGLView::PMViewCamera )
|| ( objectToRender != ( PMObject* ) ( m_pCurrentGlView->camera( ) ) ) )
{
PMObject* obj = 0;
children = objectToRender->lastChild( ) || objectToRender->linkedObject( );
if( children )
{
bool stop;
PMMatrix* matrix;
if( m_specialCameraMode )
matrix = new PMMatrix( m_viewTransformation );
else
matrix = new PMMatrix( PMMatrix::modelviewMatrix( ) );
m_matrixStack.push( matrix );
// render the children and the linked object
obj = objectToRender->lastChild( );
while( obj && !m_bStopTask && !m_bStartTask )
{
if( !obj->isA( "Declare" ) )
renderObject( obj );
if( !m_bStopTask && !m_bStartTask )
{
do
{
// Do not render declares
obj = obj->prevSibling( );
if( !obj )
stop = true;
else
stop = !obj->isA( "Declare" );
}
while( !stop );
}
}
if( !m_bStopTask && !m_bStartTask )
{
obj = objectToRender->linkedObject( );
if( obj )
renderObject( obj );
}
}
if( !m_bStopTask && !m_bStartTask )
{
// children of the object are rendered
// render the object
if( objectToRender == m_pCurrentTask->activeObject( ) )
{
if( m_specialCameraMode )
m_controlPointTransformation = m_viewTransformation;
else
m_controlPointTransformation = PMMatrix::modelviewMatrix( );
}
if( objectToRender->type( ) == "QuickColor" )
{
PMQuickColor* qc = ( PMQuickColor* ) objectToRender;
PMObjectListIterator it( m_objectToRenderStack );
bool pofound = false;
it.toLast( );
while( it.current( ) && !pofound )
{
if( it.current( )->isA( "GraphicalObject" ) )
pofound = true;
else
--it;
}
if( pofound )
{
if( m_quickColorObjects.top( ) != it.current( ) )
{
m_quickColorObjects.push( it.current( ) );
m_quickColors.push( new TQColor( m_currentColor ) );
m_currentColor = qc->color( ).toQColor( );
}
}
}
PMViewStructure* vs = objectToRender->viewStructure( );
if( objectToRender->hasTransformationMatrix( ) || vs )
{
// object has transformation or view structure
if( vs )
{
if( ( m_currentVisibility <= m_pCurrentTask->visibilityLevel( ) )
|| ( objectToRender == m_pCurrentTask->activeObject( ) ) )
{
// render the view structure.
// call qApp->processEvents( ) each m_nMaxRenderedLines rendered
// lines
if( m_selected )
setGLColor( m_graphicalObjectColor[ 1 ] );
else
setGLColor( m_currentColor );
renderViewStructure( *vs );
}
}
else if( objectToRender->hasTransformationMatrix( ) )
{
if( m_specialCameraMode )
m_viewTransformation = m_viewTransformation * objectToRender->transformationMatrix( );
else
glMultMatrixd( objectToRender->transformationMatrix( ).data( ) );
}
}
// end rendering
}
}
if( !m_bStopTask && !m_bStartTask )
{
if( children )
{
PMMatrix* matrix = m_matrixStack.pop( );
if( matrix )
{
if( m_specialCameraMode )
m_viewTransformation = (*matrix);
else
glLoadMatrixd( matrix->data( ) );
delete matrix;
matrix = 0;
}
}
if( m_selected )
{
if( m_pDeselectObject == objectToRender )
{
m_selected = false;
m_pDeselectObject = 0;
}
}
if( m_quickColorObjects.top( ) == objectToRender )
{
m_quickColorObjects.pop( );
TQColor* col = m_quickColors.pop( );
if( col )
{
m_currentColor = *col;
delete col;
col = 0;
}
}
}
if( go )
m_currentVisibility = m_visibilityStack.pop( );
m_objectToRenderStack.removeLast( );
}
void PMRenderManager::renderViewStructure( PMViewStructure& vs )
{
if( m_specialCameraMode )
{
PMPointArray points = vs.points( );
points.detach( );
transformProjection( points.data( ), points.size( ),
m_pCurrentGlView->camera( ) );
if( m_highDetailCameraView )
{
// subdivide line
PMLineArray& lines = vs.lines( );
PMPointArray& utPoints = vs.points( );
int numLines = lines.size( );
PMPointArray& sdPoints = m_subdivisionViewStructure.points( );
PMLineArray& sdLines = m_subdivisionViewStructure.lines( );
int i, li, sd;
double distance;
PMPoint start, end, dir;
for( i = 0; ( i < numLines ) && !m_bStopTask && !m_bStartTask; i++ )
{
// calculate screen distance
start = points[lines[i].startPoint( )];
end = points[lines[i].endPoint( )];
dir[0] = ( end[0] - start[0] ) / m_anglex;
dir[1] = ( end[1] - start[1] ) / m_angley;
distance = sqrt( dir[0] * dir[0] + dir[1] * dir[1] );
// calculate number of subdivisions
sd = ( int ) ( distance / subdivisionDistance );
if( sd > 1 )
{
// calculate subdivision
if( sd > maxSubdivisions )
sd = maxSubdivisions;
sdPoints[0] = start;
sdPoints[sd] = end;
start = utPoints[lines[i].startPoint( )];
end = utPoints[lines[i].endPoint( )];
dir[0] = ( end[0] - start[0] ) / sd;
dir[1] = ( end[1] - start[1] ) / sd;
dir[2] = ( end[2] - start[2] ) / sd;
for( li = 1; li < sd; li++ )
{
sdPoints[li][0] = start[0] + li * dir[0];
sdPoints[li][1] = start[1] + li * dir[1];
sdPoints[li][2] = start[2] + li * dir[2];
}
// transform points (first and last are already transformed)
transformProjection( sdPoints.data( ) + 1, sd - 1,
m_pCurrentGlView->camera( ) );
renderViewStructureSimple( sdPoints, sdLines, sd );
}
else
{
sdPoints[0] = start;
sdPoints[1] = end;
renderViewStructureSimple( sdPoints, sdLines, 1 );
}
}
}
else
renderViewStructureSimple( points, vs.lines( ) );
}
else
renderViewStructureSimple( vs.points( ), vs.lines( ) );
}
void PMRenderManager::renderViewStructureSimple( PMPointArray& points,
PMLineArray& lines,
int numberOfLines )
{
GLuint* linesData = ( GLuint* ) ( lines.data( ) );
unsigned int vsLines = 0;
unsigned int rl;
if( numberOfLines < 0 )
vsLines = lines.size( );
else
vsLines = ( unsigned ) numberOfLines;
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_DOUBLE, 0, points.data( ) );
while( ( vsLines > 0 ) && !m_bStopTask && !m_bStartTask )
{
rl = m_nMaxRenderedLines - m_renderedLines;
if( rl > vsLines )
rl = vsLines;
glDrawElements( GL_LINES, rl * 2,
GL_UNSIGNED_INT, linesData );
m_renderedLines += rl;
if( m_renderedLines >= m_nMaxRenderedLines )
{
m_renderedLines = 0;
qApp->processEvents( maxEventTime );
if( !m_bStopTask && !m_bStartTask )
m_pCurrentGlView->makeCurrent( );
}
vsLines -= rl;
linesData = linesData + ( rl * 2 );
}
glDisableClientState( GL_VERTEX_ARRAY );
}
void PMRenderManager::transformProjection( PMPoint* points, int size,
PMCamera* camera )
{
int i;
PMPoint* data = points;
PMPoint p;
double cameraAngle = camera->angle( ) * M_PI / 180.0;
double rad, phi, h;
if( approxZero( cameraAngle ) )
cameraAngle = M_PI;
switch( camera->cameraType( ) )
{
case PMCamera::Perspective:
case PMCamera::Orthographic:
break;
case PMCamera::UltraWideAngle:
for( i = 0; i < size; i++ )
{
p = m_viewTransformation * (*data);
// reverse povray's calculations
p[0] /= m_rightLength;
p[1] /= m_upLength;
p[2] /= m_directionLength;
h = sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] );
if( !approxZero( h ) )
{
p[0] /= h;
p[1] /= h;
}
(*data)[0] = asin( p[0] );
(*data)[1] = asin( p[1] );
if( p[2] > 0 )
{
(*data)[0] = M_PI - (*data)[0];
(*data)[1] = M_PI - (*data)[1];
}
(*data)[2] = -h;
data++;
}
break;
case PMCamera::FishEye:
for( i = 0; i < size; i++ )
{
p = m_viewTransformation * (*data);
// reverse povray's calculations
phi = atan2( p[1], p[0] );
rad = atan2( sqrt( p[0] * p[0] + p[1] * p[1] ), -p[2] );
(*data)[0] = rad * cos( phi );
(*data)[1] = rad * sin( phi );
(*data)[2] = -sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] );
data++;
}
break;
case PMCamera::Panoramic:
for( i = 0; i < size; i++ )
{
p = m_viewTransformation * (*data);
// reverse povray's calculations
p[0] /= m_rightLength;
p[1] /= m_upLength;
p[2] /= m_directionLength;
(*data)[0] = atan2( p[0], -p[2] );
(*data)[1] = atan2( p[1], sqrt( p[0] * p[0] + p[2] * p[2] ) );
(*data)[2] = -sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] );
data++;
}
break;
case PMCamera::Cylinder:
switch( camera->cylinderType( ) )
{
case 1:
for( i = 0; i < size; i++ )
{
p = m_viewTransformation * (*data);
// reverse povray's calculations
p[0] /= m_rightLength;
p[1] /= m_upLength;
p[2] /= m_directionLength;
h = sqrt( p[0] * p[0] + p[2] * p[2] );
if( approxZero( h ) )
h = 1e-5;
(*data)[0] = atan2( p[0], -p[2] ) / cameraAngle;
(*data)[1] = p[1] / h;
(*data)[2] = -h;
data++;
}
break;
case 2:
for( i = 0; i < size; i++ )
{
p = m_viewTransformation * (*data);
// reverse povray's calculations
p[0] /= m_rightLength;
p[1] /= m_upLength;
p[2] /= m_directionLength;
h = sqrt( p[1] * p[1] + p[2] * p[2] );
if( approxZero( h ) )
h = 1e-5;
(*data)[0] = p[0] / h;
(*data)[1] = atan2( p[1], -p[2] ) / cameraAngle;
(*data)[2] = -h;
data++;
}
break;
case 3:
for( i = 0; i < size; i++ )
{
p = m_viewTransformation * (*data);
// reverse povray's calculations
p[0] /= m_rightLength;
p[1] /= m_upLength;
p[2] /= m_directionLength;
h = sqrt( p[0] * p[0] + p[2] * p[2] );
if( approxZero( h ) )
h = 1e-5;
(*data)[0] = atan2( p[0], -p[2] ) / cameraAngle;
(*data)[1] = p[1];
(*data)[2] = -h;
data++;
}
break;
case 4:
for( i = 0; i < size; i++ )
{
p = m_viewTransformation * (*data);
// reverse povray's calculations
p[0] /= m_rightLength;
p[1] /= m_upLength;
p[2] /= m_directionLength;
h = sqrt( p[1] * p[1] + p[2] * p[2] );
if( approxZero( h ) )
h = 1e-5;
(*data)[0] = p[0];
(*data)[1] = atan2( p[1], -p[2] ) / cameraAngle;
(*data)[2] = -h;
data++;
}
break;
}
break;
case PMCamera::Omnimax:
break;
}
}
void PMRenderManager::renderControlPoints( )
{
if( ( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
&& ( m_pCurrentGlView->camera( ) == m_pCurrentTask->activeObject( ) ) )
return;
if( m_specialCameraMode )
m_viewTransformation = m_controlPointTransformation;
else
glLoadMatrixd( m_controlPointTransformation.data( ) );
PMControlPointList* cplist = m_pCurrentTask->controlPoints( );
if( cplist->count( ) > 0 )
{
PMControlPointListIterator it( *cplist );
PMControlPoint* cp;
PMPoint v;
const GLubyte* bitmap = 0;
// draw extra control point lines
setGLColor( m_graphicalObjectColor[1] );
for( it.toFirst( ); it.current( ); ++it )
{
cp = it.current( );
if( cp->hasExtraLine( ) )
{
PMPoint s = PMPoint( cp->extraLineStart( ) );
PMPoint e = PMPoint( cp->extraLineEnd( ) );
if( m_specialCameraMode )
{
transformProjection( &s, 1, m_pCurrentGlView->camera( ) );
transformProjection( &e, 1, m_pCurrentGlView->camera( ) );
}
glBegin( GL_LINES );
glVertex3d( s[0], s[1], s[2] );
glVertex3d( e[0], e[1], e[2] );
glEnd( );
}
}
glDisable( GL_DEPTH_TEST );
// draw not selected control points
setGLColor( m_controlPointColor[0] );
for( it.toFirst( ); it.current( ); ++it )
{
cp = it.current( );
if( cp->display( ) )
{
v = PMPoint( cp->position( ) );
if( m_specialCameraMode )
transformProjection( &v, 1, m_pCurrentGlView->camera( ) );
switch( cp->displayType( ) )
{
case PMControlPoint::CPPoint:
if( !cp->selected( ) )
bitmap = PointBitmap;
break;
case PMControlPoint::CPCross:
bitmap = CrossBitmap;
break;
}
glRasterPos3d( v[0], v[1], v[2] );
if( bitmap )
glBitmap( controlPointSize, controlPointSize,
controlPointSize/2, controlPointSize/2,
0, 0, bitmap );
}
}
// draw selected control points
setGLColor( m_controlPointColor[1] );
for( it.toFirst( ); it.current( ); ++it )
{
cp = it.current( );
if( cp->selected( ) && cp->display( ) )
{
v = PMPoint( cp->position( ) );
if( m_specialCameraMode )
transformProjection( &v, 1, m_pCurrentGlView->camera( ) );
if( cp->displayType( ) == PMControlPoint::CPPoint )
bitmap = PointBitmap;
glRasterPos3d( v[0], v[1], v[2] );
if( bitmap )
glBitmap( controlPointSize, controlPointSize,
controlPointSize/2, controlPointSize/2,
0, 0, bitmap );
}
}
}
}
void PMRenderManager::renderAxes( )
{
int i;
if( !m_axesViewStructureCreated )
{
m_axesViewStructure[0] = PMViewStructure( 6, 9 );
PMPointArray& points = m_axesViewStructure[0].points( );
PMLineArray& lines = m_axesViewStructure[0].lines( );
lines[0] = PMLine( 0, 1 );
lines[1] = PMLine( 1, 2 );
lines[2] = PMLine( 1, 3 );
lines[3] = PMLine( 1, 4 );
lines[4] = PMLine( 1, 5 );
lines[5] = PMLine( 2, 3 );
lines[6] = PMLine( 3, 4 );
lines[7] = PMLine( 4, 5 );
lines[8] = PMLine( 5, 2 );
points[0] = PMPoint( 0.0, 0.0, 0.0 );
points[1] = PMPoint( 1.0, 0.0, 0.0 );
points[2] = PMPoint( dA, dB, dB );
points[3] = PMPoint( dA, -dB, dB );
points[4] = PMPoint( dA, -dB, -dB );
points[5] = PMPoint( dA, dB, -dB );
m_axesViewStructure[1] = m_axesViewStructure[0];
PMPointArray& points1 = m_axesViewStructure[1].points( );
points1.detach( );
points1[0] = PMPoint( 0.0, 0.0, 0.0 );
points1[1] = PMPoint( 0.0, 1.0, 0.0 );
points1[2] = PMPoint( dB, dA, dB );
points1[3] = PMPoint( -dB, dA, dB );
points1[4] = PMPoint( -dB, dA, -dB );
points1[5] = PMPoint( dB, dA, -dB );
m_axesViewStructure[2] = m_axesViewStructure[0];
PMPointArray& points2 = m_axesViewStructure[2].points( );
points2.detach( );
points2[0] = PMPoint( 0.0, 0.0, 0.0 );
points2[1] = PMPoint( 0.0, 0.0, 1.0 );
points2[2] = PMPoint( dB, dB, dA );
points2[3] = PMPoint( -dB, dB, dA );
points2[4] = PMPoint( -dB, -dB, dA );
points2[5] = PMPoint( dB, -dB, dA );
m_axesViewStructureCreated = true;
}
glEnable( GL_DEPTH_TEST );
for( i = 0; i < 3; i++ )
{
setGLColor( m_axesColor[i] );
renderViewStructure( m_axesViewStructure[i] );
}
}
PMMatrix PMRenderManager::viewTransformation( PMCamera* c ) const
{
PMVector location, lookAt, sky;
PMMatrix m;
sky = c->sky( );
location = c->location( );
lookAt = c->lookAt( );
if( approxZero( sky.abs( ) ) )
sky = PMVector( 0.0, 1.0, 0.0 );
if( approxZero( ( location - lookAt ).abs( ) ) )
lookAt = location + PMVector( 0.0, 0.0, 1.0 );
m = c->transformedWith( );
if( m.canBuildInverse( ) )
return PMMatrix::viewTransformation( location, lookAt, sky ) * m.inverse( );
return PMMatrix::viewTransformation( location, lookAt, sky );
}
void PMRenderManager::setProjection( )
{
PMGLView::PMViewType type = m_pCurrentGlView->type( );
PMCamera* camera = m_pCurrentGlView->camera( );
int width = m_pCurrentGlView->width( );
int height = m_pCurrentGlView->height( );
if( type == PMGLView::PMViewCamera )
{
if( camera )
setCameraProjection( );
}
else
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity( );
double d = m_pCurrentGlView->scale( );
// TODO calculating the z clipping plane
glOrtho( -width/2, width/2, -height/2, height/2,
-viewVolumeZ, viewVolumeZ );
glScaled( d, d, d );
glTranslated( m_pCurrentGlView->translationX( ),
m_pCurrentGlView->translationY( ), 0 );
switch( type )
{
case PMGLView::PMViewPosZ:
break;
case PMGLView::PMViewNegZ:
glRotated( 180.0, 0.0, 1.0, 0.0 );
break;
case PMGLView::PMViewNegY:
glRotated( 90.0, 1.0, 0.0, 0.0 );
break;
case PMGLView::PMViewPosY:
glRotated( -90.0, 1.0, 0.0, 0.0 );
break;
case PMGLView::PMViewPosX:
glRotated( 90.0, 0.0, 1.0, 0.0 );
break;
case PMGLView::PMViewNegX:
glRotated( -90.0, 0.0, 1.0, 0.0 );
break;
default:
break;
}
glScaled( 1.0, 1.0, -1.0 );
glMatrixMode( GL_MODELVIEW );
m_pCurrentGlView->setProjectionUpToDate( true );
}
}
void PMRenderManager::setCameraProjection( )
{
PMCamera* camera = m_pCurrentGlView->camera( );
int width = m_pCurrentGlView->width( );
int height = m_pCurrentGlView->height( );
double angle = M_PI / 2.0;
double modeAspect, viewAspect, cameraAspect;
m_viewTransformation = viewTransformation( camera );
m_upLength = camera->up( ).abs( );
if( approxZero( m_upLength ) )
m_upLength = 1.0;
m_rightLength = camera->right( ).abs( );
if( approxZero( m_rightLength ) )
m_rightLength = 1.0;
m_directionLength = camera->direction( ).abs( );
if( approxZero( m_directionLength ) )
m_directionLength = 1.0;
if( camera->isAngleEnabled( ) )
angle = camera->angle( ) * M_PI / 180.0;
m_anglex = 0.5;
m_angley = 0.5;
if( ( angle <= 0.0 ) || ( angle > 2 * M_PI ) )
angle = M_PI;
switch( camera->cameraType( ) )
{
case PMCamera::Perspective:
// If angle wasn't specified determine one from right and direction
if( !camera->isAngleEnabled( ) )
angle = 2 * atan2( 0.5 * m_rightLength, m_directionLength );
break;
case PMCamera::UltraWideAngle:
m_anglex = angle / ( 2.0 * M_PI );
m_angley = angle / ( 2.0 * M_PI );
m_specialCameraMode = true;
break;
case PMCamera::FishEye:
m_anglex = angle / 2.0;
m_angley = angle / 2.0;
m_specialCameraMode = true;
break;
case PMCamera::Panoramic:
m_anglex = M_PI / 2.0;
m_angley = M_PI / 2.0;
m_specialCameraMode = true;
break;
case PMCamera::Cylinder:
m_anglex = 0.5;
m_angley = 0.5;
m_specialCameraMode = true;
break;
case PMCamera::Omnimax:
m_specialCameraMode = true;
break;
default:
break;
}
modeAspect = m_pCurrentTask->aspectRatio( );
if( approxZero( modeAspect ) )
modeAspect = 1.0;
cameraAspect = camera->aspect( );
if( approxZero( cameraAspect ) )
cameraAspect = 1.0;
viewAspect = ( double ) width / ( double ) height;
if( approxZero( viewAspect ) )
viewAspect = 1.0;
if( viewAspect > modeAspect )
m_anglex *= viewAspect / modeAspect;
else
m_angley *= modeAspect / viewAspect;
glMatrixMode( GL_PROJECTION );
glLoadIdentity( );
PMVector up, right, direction;
double handedness;
PMMatrix m;
up = camera->up( );
right = camera->right( );
direction = camera->direction( );
if( approxZero( m_upLength ) )
up = PMVector( 0.0, 1.0, 0.0 );
if( approxZero( m_rightLength ) )
right = PMVector( 1.0, 0.0, 0.0 );
if( approxZero( m_directionLength ) )
direction = PMVector( 0.0, 0.0, 1.0 );
handedness = PMVector::dot( PMVector::cross( up, direction ), right );
switch( camera->cameraType( ) )
{
case PMCamera::Perspective:
if( ( angle <= 0.0 ) || ( angle >= M_PI ) )
angle = M_PI / 2.0;
// opengl needs the vertical angle
if( viewAspect < modeAspect )
angle = atan( tan( angle / 2.0 ) / cameraAspect * modeAspect
/ viewAspect ) * 360.0 / M_PI;
else
angle = atan( tan( angle / 2.0 ) / cameraAspect )
* 360.0 / M_PI;
gluPerspective( angle, cameraAspect * viewAspect / modeAspect,
0.001, viewVolumeZ );
if( handedness > 0 )
glScaled( -1.0, 1.0, 1.0 );
glMultMatrixd( m_viewTransformation.data( ) );
break;
case PMCamera::Orthographic:
m_anglex = m_rightLength / 2.0;
m_angley = m_upLength / 2.0;
if( viewAspect > modeAspect )
m_anglex *= viewAspect / modeAspect;
else
m_angley *= modeAspect / viewAspect;
glOrtho( -m_anglex, m_anglex, -m_angley, m_angley,
0, viewVolumeZ );
if( handedness > 0 )
glScaled( -1.0, 1.0, 1.0 );
glMultMatrixd( m_viewTransformation.data( ) );
break;
case PMCamera::UltraWideAngle:
case PMCamera::FishEye:
case PMCamera::Panoramic:
case PMCamera::Cylinder:
case PMCamera::Omnimax:
glOrtho( -m_anglex, m_anglex, -m_angley, m_angley,
-viewVolumeZ, viewVolumeZ );
if( handedness > 0 )
glScaled( -1.0, 1.0, 1.0 );
break;
}
glMatrixMode( GL_MODELVIEW );
m_pCurrentGlView->setProjectionUpToDate( true );
}
void PMRenderManager::renderFieldOfView( )
{
if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
{
PMCamera* camera = m_pCurrentGlView->camera( );
if( camera )
{
int width = m_pCurrentGlView->width( );
int height = m_pCurrentGlView->height( );
double modeAspect, viewAspect;
int d, vx1, vx2, vy1, vy2;
modeAspect = m_pCurrentTask->aspectRatio( ); //camera->aspect( );
if( approxZero( modeAspect ) )
modeAspect = 1.0;
viewAspect = ( double ) width / ( double ) height;
if( viewAspect < modeAspect )
{
vx1 = 0;
vx2 = width - 1;
d = ( int ) ( height - width / modeAspect + 0.5 ) / 2;
vy1 = d;
vy2 = height - d - 1;
}
else
{
vy1 = 0;
vy2 = height - 1;
d = ( int ) ( height * modeAspect );
d = ( width - d ) / 2;
vx1 = d;
vx2 = width - d - 1;
}
glMatrixMode( GL_PROJECTION );
glPushMatrix( );
glLoadIdentity( );
glOrtho( 0, width, 0, height, -2, 2 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix( );
glLoadIdentity( );
setGLColor( m_fieldOfViewColor );
glDisable( GL_DEPTH_TEST );
if( camera->cameraType( ) == PMCamera::Omnimax )
renderString( i18n( "not supported" ), 5.0,
height - qApp->fontMetrics( ).height( ) * 2 - 2 );
else if( m_specialCameraMode && !m_highDetailCameraView )
renderString( i18n( "approximated" ), 5.0,
height - qApp->fontMetrics( ).height( ) * 2 - 2 );
glBegin( GL_LINE_LOOP );
glVertex2d( vx1, vy1 );
glVertex2d( vx2, vy1 );
glVertex2d( vx2, vy2 );
glVertex2d( vx1, vy2 );
glEnd( );
glEnable( GL_DEPTH_TEST );
glMatrixMode( GL_PROJECTION );
glPopMatrix( );
glMatrixMode( GL_MODELVIEW );
glPopMatrix( );
}
}
}
void PMRenderManager::renderGrid( )
{
double scale = m_pCurrentGlView->scale( );
if( scale >= 0 )
{
// calculate the views grid distance
double viewGridDistance = pow( 10.0, ceil( log10( ( double ) m_gridDistance / scale ) ) );
int sd = ( int ) ( viewGridDistance * scale + 0.5 );
if( ( sd * 0.2 ) > m_gridDistance )
viewGridDistance *= 0.2;
else if( ( sd * 0.5 ) > m_gridDistance )
viewGridDistance *= 0.5;
// draw the grid
double x1, x2, y1, y2, sx, sy;
double x, y;
int gi;
double screenx, screeny;
double signx = 1.0, signy = 1.0;
int height = m_pCurrentGlView->height( );
int width = m_pCurrentGlView->width( );
double transX = m_pCurrentGlView->translationX( );
double transY = m_pCurrentGlView->translationY( );
int fontHeight = qApp->fontMetrics( ).height( );
glMatrixMode( GL_PROJECTION );
glPushMatrix( );
glLoadIdentity( );
glOrtho( -width/2, width/2, -height/2, height/2, -2, 2 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix( );
glLoadIdentity( );
setGLColor( m_gridColor );
glDisable( GL_DEPTH_TEST );
switch( m_pCurrentGlView->type( ) )
{
case PMGLView::PMViewPosX:
signx = -1.0;
break;
case PMGLView::PMViewPosY:
signy = -1.0;
break;
case PMGLView::PMViewNegZ:
signx = -1.0;
break;
default:
break;
}
sx = width / scale;
sy = height / scale;
x1 = -transX - sx / 2;
x2 = -transX + sx / 2;
y1 = -transY - sy / 2;
y2 = -transY + sy / 2;
sx = ceil( x1 / viewGridDistance ) * viewGridDistance;
gi = 0;
x = sx;
while( x < x2 )
{
screenx = ( x + transX ) * scale;
glBegin( GL_LINES );
glVertex2d( screenx, -height/2 );
glVertex2d( screenx, height/2 );
glEnd( );
TQString label = TQString( "%1" ).arg( x * signx, 0, 'g', 4 );
if( approxZero( x ) && label.find( "e-" ) )
label = "0";
renderString( label, screenx + 3, height / 2 - fontHeight - 2 );
gi++;
x = sx + viewGridDistance * gi;
}
sy = ceil( y1 / viewGridDistance ) * viewGridDistance;
gi = 0;
y = sy;
while( y < y2 )
{
screeny = ( y + transY ) * scale;
glBegin( GL_LINES );
glVertex2d( -width/2, screeny );
glVertex2d( width/2, screeny );
glEnd( );
TQString label = TQString( "%1" ).arg( y * signy, 0, 'g', 4 );
if( approxZero( y ) && label.find( "e-" ) )
label = "0";
renderString( label, -width / 2 + 3, screeny + 2 );
gi++;
y = sy + viewGridDistance * gi;
}
setGLColor( axesColor( 0 ) );
switch( m_pCurrentGlView->type( ) )
{
case PMGLView::PMViewPosY:
case PMGLView::PMViewPosZ:
case PMGLView::PMViewNegY:
renderString( "x", width / 2 - qApp->fontMetrics( ).boundingRect( "x" ).width( ) - 4, -3 );
break;
case PMGLView::PMViewNegZ:
renderString( "x", -width / 2 + 3, -3 );
break;
default:
break;
}
setGLColor( axesColor( 1 ) );
switch( m_pCurrentGlView->type( ) )
{
case PMGLView::PMViewPosX:
case PMGLView::PMViewNegX:
case PMGLView::PMViewPosZ:
case PMGLView::PMViewNegZ:
renderString( "y", -3, height / 2 - fontHeight );
break;
default:
break;
}
setGLColor( axesColor( 2 ) );
switch( m_pCurrentGlView->type( ) )
{
case PMGLView::PMViewPosX:
renderString( "z", -width / 2 + 3, -3 );
break;
case PMGLView::PMViewNegX:
renderString( "z", width / 2 - qApp->fontMetrics( ).boundingRect( "z" ).width( ) - 4, -3 );
break;
case PMGLView::PMViewNegY:
renderString( "z", -3, height / 2 - fontHeight );
break;
case PMGLView::PMViewPosY:
renderString( "z", -3, -height / 2 );
break;
default:
break;
}
glEnable( GL_DEPTH_TEST );
glMatrixMode( GL_PROJECTION );
glPopMatrix( );
glMatrixMode( GL_MODELVIEW );
glPopMatrix( );
}
}
void PMRenderManager::renderDescription( )
{
int height = m_pCurrentGlView->height( );
int width = m_pCurrentGlView->width( );
int fontHeight = qApp->fontMetrics( ).height( );
glMatrixMode( GL_PROJECTION );
glPushMatrix( );
glLoadIdentity( );
glOrtho( 0, width, 0, height, -2, 2 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix( );
glLoadIdentity( );
setGLColor( m_fieldOfViewColor );
switch( m_pCurrentGlView->type( ) )
{
case PMGLView::PMViewPosX:
renderString( i18n( "left" ), 5.0, height - fontHeight - 2 );
break;
case PMGLView::PMViewNegX:
renderString( i18n( "right" ), 5.0, height - fontHeight - 2 );
break;
case PMGLView::PMViewPosY:
renderString( i18n( "bottom" ), 5.0, height - fontHeight - 2 );
break;
case PMGLView::PMViewNegY:
renderString( i18n( "top" ), 5.0, height - fontHeight - 2 );
break;
case PMGLView::PMViewPosZ:
renderString( i18n( "front" ), 5.0, height - fontHeight - 2 );
break;
case PMGLView::PMViewNegZ:
renderString( i18n( "back" ), 5.0, height - fontHeight - 2 );
break;
case PMGLView::PMViewCamera:
{
PMCamera* c = m_pCurrentGlView->camera( );
if( c )
{
TQString name( "-" );
if( !c->name( ).isEmpty( ) )
name = c->name( );
else
name = i18n( "(unnamed)" );
renderString( i18n( "camera" ) + ": " + name,
5.0, height - fontHeight - 2 );
}
else
renderString( i18n( "camera" ), 5.0, height - fontHeight - 2 );
break;
}
}
glEnable( GL_DEPTH_TEST );
glMatrixMode( GL_PROJECTION );
glPopMatrix( );
glMatrixMode( GL_MODELVIEW );
glPopMatrix( );
}
void PMRenderManager::renderString( const TQString& str, double x, double y )
{
int width = qApp->fontMetrics( ).boundingRect( str ).width( );
int height = qApp->fontMetrics( ).height( );
// GL wants word aligned bitmap
TQBitmap bm( ( ( width + 32 ) % 32 ) * 32, height, true );
TQPainter p( &bm );
p.setFont( qApp->font( ) );
p.drawText( bm.rect( ), Qt::AlignLeft | Qt::AlignBottom, str );
p.end();
// Transform to GL bitmap
TQImage img = bm.convertToImage( ).mirror( ).convertBitOrder( TQImage::BigEndian );
glRasterPos2d( x, y );
glBitmap( img.width( ), img.height( ), 0, 0, 0, 0, img.bits( ) );
}
void PMRenderManager::setGLColor( const TQColor& c )
{
int r, g, b;
c.rgb( &r, &g, &b );
glColor3ub( ( GLubyte ) r, ( GLubyte ) g, ( GLubyte ) b );
}
void PMRenderManager::slotRenderingSettingsChanged( )
{
emit renderingSettingsChanged( );
}
void PMRenderManager::saveConfig( KConfig* cfg )
{
cfg->setGroup( "Rendering" );
cfg->writeEntry( "BackgroundColor", m_backgroundColor );
cfg->writeEntry( "GraphicalObjectColor0", m_graphicalObjectColor[0] );
cfg->writeEntry( "GraphicalObjectColor1", m_graphicalObjectColor[1] );
cfg->writeEntry( "ControlPointColor0", m_controlPointColor[0] );
cfg->writeEntry( "ControlPointColor1", m_controlPointColor[1] );
cfg->writeEntry( "AxesColorX", m_axesColor[0] );
cfg->writeEntry( "AxesColorY", m_axesColor[1] );
cfg->writeEntry( "AxesColorZ", m_axesColor[2] );
cfg->writeEntry( "GridColor", m_gridColor );
cfg->writeEntry( "GridDistance", m_gridDistance );
cfg->writeEntry( "FieldOfViewColor", m_fieldOfViewColor );
cfg->writeEntry( "HighDetailCameraViews", m_highDetailCameraView );
}
void PMRenderManager::restoreConfig( KConfig* cfg )
{
cfg->setGroup( "Rendering" );
m_backgroundColor = cfg->readColorEntry( "BackgroundColor", &m_backgroundColor );
m_graphicalObjectColor[0] = cfg->readColorEntry( "GraphicalObjectColor0", &( m_graphicalObjectColor[0] ) );
m_graphicalObjectColor[1] = cfg->readColorEntry( "GraphicalObjectColor1", &( m_graphicalObjectColor[1] ) );
m_controlPointColor[0] = cfg->readColorEntry( "ControlPointColor0", &( m_controlPointColor[0] ) );
m_controlPointColor[1] = cfg->readColorEntry( "ControlPointColor1", &( m_controlPointColor[1] ) );
m_axesColor[0] = cfg->readColorEntry( "AxesColorX", &( m_axesColor[0] ) );
m_axesColor[1] = cfg->readColorEntry( "AxesColorY", &( m_axesColor[1] ) );
m_axesColor[2] = cfg->readColorEntry( "AxesColorZ", &( m_axesColor[2] ) );
m_gridColor = cfg->readColorEntry( "GridColor", &m_gridColor );
m_gridDistance = cfg->readNumEntry( "GridDistance", m_gridDistance );
m_fieldOfViewColor = cfg->readColorEntry( "FieldOfViewColor", &m_fieldOfViewColor );
m_highDetailCameraView = cfg->readBoolEntry( "HighDetailCameraViews", m_highDetailCameraView );
}
bool PMRenderManager::hasOpenGL( )
{
if( !s_hasOpenGLChecked )
{
s_hasOpenGL = ( glXQueryExtension( qt_xdisplay( ), 0, 0 ) != 0 );
s_hasOpenGLChecked = true;
}
return s_hasOpenGL;
}
void PMRenderManager::disableOpenGL( )
{
s_hasOpenGLChecked = true;
s_hasOpenGL = false;
}
#include "pmrendermanager.moc"