2009-06-23 23:56:46 +04:00
/*
* OpenSCAD ( www . openscad . at )
* Copyright ( C ) 2009 Clifford Wolf < clifford @ clifford . at >
*
* 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 , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# define INCLUDE_ABSTRACT_NODE_DETAILS
# include "openscad.h"
# include <QMenu>
# include <QMenuBar>
# include <QSplitter>
2009-06-24 02:32:08 +04:00
# include <QFileDialog>
# include <QApplication>
2009-06-23 23:56:46 +04:00
MainWindow : : MainWindow ( const char * filename )
{
root_ctx . functions_p = & builtin_functions ;
root_ctx . modules_p = & builtin_modules ;
2009-06-26 08:32:52 +04:00
root_ctx . set_variable ( " $fs_render " , Value ( 1.0 ) ) ;
root_ctx . set_variable ( " $fa_render " , Value ( 12.0 ) ) ;
root_ctx . set_variable ( " $fs_preview " , Value ( 1.0 ) ) ;
root_ctx . set_variable ( " $fa_preview " , Value ( 12.0 ) ) ;
2009-06-23 23:56:46 +04:00
root_module = NULL ;
root_node = NULL ;
2009-06-24 19:39:08 +04:00
root_raw_term = NULL ;
root_norm_term = NULL ;
2009-06-25 12:12:41 +04:00
root_chain = NULL ;
2009-06-24 14:59:15 +04:00
# ifdef ENABLE_CGAL
2009-06-23 23:56:46 +04:00
root_N = NULL ;
2009-06-24 14:59:15 +04:00
# endif
2009-06-23 23:56:46 +04:00
if ( filename ) {
this - > filename = QString ( filename ) ;
setWindowTitle ( this - > filename ) ;
} else {
setWindowTitle ( " New Document " ) ;
}
{
QMenu * menu = menuBar ( ) - > addMenu ( " &File " ) ;
menu - > addAction ( " &New " , this , SLOT ( actionNew ( ) ) ) ;
menu - > addAction ( " &Open... " , this , SLOT ( actionOpen ( ) ) ) ;
menu - > addAction ( " &Save " , this , SLOT ( actionSave ( ) ) ) ;
menu - > addAction ( " Save &As... " , this , SLOT ( actionSaveAs ( ) ) ) ;
menu - > addAction ( " &Quit " , this , SLOT ( close ( ) ) ) ;
}
{
QMenu * menu = menuBar ( ) - > addMenu ( " &Design " ) ;
2009-06-25 13:49:28 +04:00
menu - > addAction ( " &Compile " , this , SLOT ( actionCompile ( ) ) , QKeySequence ( Qt : : Key_F5 ) ) ;
2009-06-23 23:56:46 +04:00
# ifdef ENABLE_CGAL
2009-06-25 13:49:28 +04:00
menu - > addAction ( " Compile and &Render (CGAL) " , this , SLOT ( actionRenderCGAL ( ) ) , QKeySequence ( Qt : : Key_F6 ) ) ;
2009-06-23 23:56:46 +04:00
# endif
menu - > addAction ( " Display &AST... " , this , SLOT ( actionDisplayAST ( ) ) ) ;
2009-06-24 14:59:15 +04:00
menu - > addAction ( " Display CSG &Tree... " , this , SLOT ( actionDisplayCSGTree ( ) ) ) ;
menu - > addAction ( " Display CSG &Products... " , this , SLOT ( actionDisplayCSGProducts ( ) ) ) ;
2009-06-23 23:56:46 +04:00
menu - > addAction ( " Export as &STL... " , this , SLOT ( actionExportSTL ( ) ) ) ;
menu - > addAction ( " Export as &OFF... " , this , SLOT ( actionExportOFF ( ) ) ) ;
}
{
QMenu * menu = menuBar ( ) - > addMenu ( " &View " ) ;
2009-06-25 02:38:31 +04:00
# ifdef ENABLE_OPENCSG
actViewModeOpenCSG = menu - > addAction ( " OpenCSG " , this , SLOT ( viewModeOpenCSG ( ) ) ) ;
actViewModeOpenCSG - > setCheckable ( true ) ;
# endif
# ifdef ENABLE_CGAL
actViewModeCGALSurface = menu - > addAction ( " CGAL Surfaces " , this , SLOT ( viewModeCGALSurface ( ) ) ) ;
actViewModeCGALGrid = menu - > addAction ( " CGAL Grid Only " , this , SLOT ( viewModeCGALGrid ( ) ) ) ;
actViewModeCGALSurface - > setCheckable ( true ) ;
actViewModeCGALGrid - > setCheckable ( true ) ;
# endif
2009-06-25 12:12:41 +04:00
actViewModeThrownTogether = menu - > addAction ( " Thrown Together " , this , SLOT ( viewModeThrownTogether ( ) ) ) ;
actViewModeThrownTogether - > setCheckable ( true ) ;
2009-06-25 02:38:31 +04:00
2009-06-23 23:56:46 +04:00
menu - > addSeparator ( ) ;
menu - > addAction ( " Top " ) ;
menu - > addAction ( " Bottom " ) ;
menu - > addAction ( " Left " ) ;
menu - > addAction ( " Right " ) ;
menu - > addAction ( " Front " ) ;
menu - > addAction ( " Back " ) ;
menu - > addAction ( " Diagonal " ) ;
menu - > addSeparator ( ) ;
menu - > addAction ( " Perspective " ) ;
menu - > addAction ( " Orthogonal " ) ;
}
s1 = new QSplitter ( Qt : : Horizontal , this ) ;
editor = new QTextEdit ( s1 ) ;
s2 = new QSplitter ( Qt : : Vertical , s1 ) ;
screen = new GLView ( s2 ) ;
console = new QTextEdit ( s2 ) ;
console - > setReadOnly ( true ) ;
console - > append ( " OpenSCAD (www.openscad.at) " ) ;
console - > append ( " Copyright (C) 2009 Clifford Wolf <clifford@clifford.at> " ) ;
console - > append ( " " ) ;
console - > append ( " This program is free software; you can redistribute it and/or modify " ) ;
console - > append ( " it under the terms of the GNU General Public License as published by " ) ;
console - > append ( " the Free Software Foundation; either version 2 of the License, or " ) ;
console - > append ( " (at your option) any later version. " ) ;
console - > append ( " " ) ;
editor - > setTabStopWidth ( 30 ) ;
if ( filename ) {
QString text ;
FILE * fp = fopen ( filename , " rt " ) ;
if ( ! fp ) {
2009-06-24 02:32:08 +04:00
console - > append ( QString ( " Failed to open file: %1 (%2) " ) . arg ( QString ( filename ) , QString ( strerror ( errno ) ) ) ) ;
2009-06-23 23:56:46 +04:00
} else {
char buffer [ 513 ] ;
int rc ;
while ( ( rc = fread ( buffer , 1 , 512 , fp ) ) > 0 ) {
buffer [ rc ] = 0 ;
text + = buffer ;
}
fclose ( fp ) ;
2009-06-24 02:32:08 +04:00
console - > append ( QString ( " Loaded design `%1'. " ) . arg ( QString ( filename ) ) ) ;
2009-06-23 23:56:46 +04:00
}
editor - > setPlainText ( text ) ;
}
2009-06-25 02:38:31 +04:00
# ifdef ENABLE_OPENCSG
viewModeOpenCSG ( ) ;
# else
2009-06-25 12:12:41 +04:00
viewModeThrownTogether ( ) ;
2009-06-25 02:38:31 +04:00
# endif
2009-06-23 23:56:46 +04:00
setCentralWidget ( s1 ) ;
}
MainWindow : : ~ MainWindow ( )
{
if ( root_module )
delete root_module ;
if ( root_node )
delete root_node ;
2009-06-24 14:59:15 +04:00
# ifdef ENABLE_CGAL
2009-06-23 23:56:46 +04:00
if ( root_N )
delete root_N ;
2009-06-24 14:59:15 +04:00
# endif
2009-06-23 23:56:46 +04:00
}
void MainWindow : : actionNew ( )
{
2009-06-24 02:32:08 +04:00
filename = QString ( ) ;
setWindowTitle ( " New Document " ) ;
editor - > setPlainText ( " " ) ;
2009-06-23 23:56:46 +04:00
}
void MainWindow : : actionOpen ( )
{
2009-06-24 02:32:08 +04:00
QString new_filename = QFileDialog : : getOpenFileName ( this , " Open File " , " " , " OpenSCAD Designs (*.scad) " ) ;
if ( ! new_filename . isEmpty ( ) )
{
filename = new_filename ;
setWindowTitle ( filename ) ;
QString text ;
FILE * fp = fopen ( filename . toAscii ( ) . data ( ) , " rt " ) ;
if ( ! fp ) {
console - > append ( QString ( " Failed to open file: %1 (%2) " ) . arg ( QString ( filename ) , QString ( strerror ( errno ) ) ) ) ;
} else {
char buffer [ 513 ] ;
int rc ;
while ( ( rc = fread ( buffer , 1 , 512 , fp ) ) > 0 ) {
buffer [ rc ] = 0 ;
text + = buffer ;
}
fclose ( fp ) ;
console - > append ( QString ( " Loaded design `%1'. " ) . arg ( QString ( filename ) ) ) ;
}
editor - > setPlainText ( text ) ;
}
2009-06-23 23:56:46 +04:00
}
void MainWindow : : actionSave ( )
{
2009-06-24 02:32:08 +04:00
FILE * fp = fopen ( filename . toAscii ( ) . data ( ) , " wt " ) ;
if ( ! fp ) {
console - > append ( QString ( " Failed to open file for writing: %1 (%2) " ) . arg ( QString ( filename ) , QString ( strerror ( errno ) ) ) ) ;
} else {
fprintf ( fp , " %s " , editor - > toPlainText ( ) . toAscii ( ) . data ( ) ) ;
fclose ( fp ) ;
console - > append ( QString ( " Saved design `%1'. " ) . arg ( QString ( filename ) ) ) ;
}
2009-06-23 23:56:46 +04:00
}
void MainWindow : : actionSaveAs ( )
{
2009-06-24 02:32:08 +04:00
QString new_filename = QFileDialog : : getSaveFileName ( this , " Save File " , filename , " OpenSCAD Designs (*.scad) " ) ;
if ( ! new_filename . isEmpty ( ) ) {
filename = new_filename ;
setWindowTitle ( filename ) ;
actionSave ( ) ;
}
2009-06-23 23:56:46 +04:00
}
void MainWindow : : actionCompile ( )
{
2009-06-24 19:39:08 +04:00
console - > append ( " Parsing design (AST generation)... " ) ;
QApplication : : processEvents ( ) ;
2009-06-23 23:56:46 +04:00
if ( root_module ) {
delete root_module ;
root_module = NULL ;
}
root_module = parse ( editor - > toPlainText ( ) . toAscii ( ) . data ( ) , false ) ;
if ( ! root_module ) {
console - > append ( " Compilation failed! " ) ;
return ;
}
2009-06-24 19:39:08 +04:00
console - > append ( " Compiling design (CSG Tree generation)... " ) ;
QApplication : : processEvents ( ) ;
2009-06-23 23:56:46 +04:00
if ( root_node ) {
delete root_node ;
root_node = NULL ;
}
2009-06-24 14:59:15 +04:00
AbstractNode : : idx_counter = 1 ;
2009-06-23 23:56:46 +04:00
root_node = root_module - > evaluate ( & root_ctx , QVector < QString > ( ) , QVector < Value > ( ) , QVector < AbstractNode * > ( ) ) ;
if ( ! root_node ) {
console - > append ( " Compilation failed! " ) ;
return ;
}
2009-06-24 19:39:08 +04:00
console - > append ( " Compiling design (CSG Products generation)... " ) ;
QApplication : : processEvents ( ) ;
if ( root_raw_term ) {
root_raw_term - > unlink ( ) ;
root_raw_term = NULL ;
}
double m [ 16 ] ;
root_raw_term = root_node - > render_csg_term ( m ) ;
if ( ! root_raw_term ) {
console - > append ( " Compilation failed! " ) ;
return ;
}
console - > append ( " Compiling design (CSG Products normalization)... " ) ;
QApplication : : processEvents ( ) ;
if ( root_norm_term ) {
root_norm_term - > unlink ( ) ;
root_norm_term = NULL ;
}
2009-06-25 12:12:41 +04:00
if ( root_chain ) {
delete root_chain ;
root_chain = NULL ;
}
2009-06-24 19:39:08 +04:00
root_norm_term = root_raw_term - > link ( ) ;
2009-06-24 21:40:19 +04:00
while ( 1 ) {
CSGTerm * n = root_norm_term - > normalize ( ) ;
2009-06-24 19:39:08 +04:00
root_norm_term - > unlink ( ) ;
2009-06-24 21:40:19 +04:00
if ( root_norm_term = = n )
break ;
2009-06-24 19:39:08 +04:00
root_norm_term = n ;
2009-06-24 21:40:19 +04:00
}
2009-06-24 19:39:08 +04:00
if ( ! root_norm_term ) {
console - > append ( " Compilation failed! " ) ;
return ;
}
2009-06-25 12:12:41 +04:00
root_chain = new CSGChain ( ) ;
root_chain - > import ( root_norm_term ) ;
2009-06-25 13:49:28 +04:00
screen - > updateGL ( ) ;
2009-06-23 23:56:46 +04:00
console - > append ( " Compilation finished. " ) ;
}
# ifdef ENABLE_CGAL
static void report_func ( const class AbstractNode * , void * vp , int mark )
{
MainWindow * m = ( MainWindow * ) vp ;
QString msg ;
msg . sprintf ( " CSG rendering progress: %.2f%% " , ( mark * 100.0 ) / progress_report_count ) ;
2009-06-24 02:32:08 +04:00
QApplication : : processEvents ( ) ;
2009-06-23 23:56:46 +04:00
m - > console - > append ( msg ) ;
}
void MainWindow : : actionRenderCGAL ( )
{
actionCompile ( ) ;
if ( ! root_module | | ! root_node )
return ;
if ( root_N ) {
delete root_N ;
root_N = NULL ;
}
progress_report_prep ( root_node , report_func , this ) ;
root_N = new CGAL_Nef_polyhedron ( root_node - > render_cgal_nef_polyhedron ( ) ) ;
progress_report_fin ( ) ;
2009-06-25 02:38:31 +04:00
if ( ! actViewModeCGALSurface - > isChecked ( ) & & ! actViewModeCGALGrid - > isChecked ( ) ) {
viewModeCGALSurface ( ) ;
} else {
screen - > updateGL ( ) ;
}
2009-06-23 23:56:46 +04:00
}
# endif /* ENABLE_CGAL */
void MainWindow : : actionDisplayAST ( )
{
QTextEdit * e = new QTextEdit ( NULL ) ;
e - > setTabStopWidth ( 30 ) ;
e - > setWindowTitle ( " AST Dump " ) ;
if ( root_module ) {
e - > setPlainText ( root_module - > dump ( " " , " " ) ) ;
} else {
e - > setPlainText ( " No AST to dump. Please try compiling first... " ) ;
}
e - > show ( ) ;
e - > resize ( 600 , 400 ) ;
}
2009-06-24 14:59:15 +04:00
void MainWindow : : actionDisplayCSGTree ( )
2009-06-23 23:56:46 +04:00
{
QTextEdit * e = new QTextEdit ( NULL ) ;
e - > setTabStopWidth ( 30 ) ;
2009-06-25 12:12:41 +04:00
e - > setWindowTitle ( " CSG Tree Dump " ) ;
2009-06-23 23:56:46 +04:00
if ( root_node ) {
e - > setPlainText ( root_node - > dump ( " " ) ) ;
} else {
e - > setPlainText ( " No CSG to dump. Please try compiling first... " ) ;
}
e - > show ( ) ;
e - > resize ( 600 , 400 ) ;
}
2009-06-24 14:59:15 +04:00
void MainWindow : : actionDisplayCSGProducts ( )
{
QTextEdit * e = new QTextEdit ( NULL ) ;
e - > setTabStopWidth ( 30 ) ;
2009-06-25 12:12:41 +04:00
e - > setWindowTitle ( " CSG Products Dump " ) ;
e - > setPlainText ( QString ( " \n CSG before normalization: \n %1 \n \n \n CSG after normalization: \n %2 \n \n \n CSG rendering chain: \n %3 \n " ) . arg ( root_raw_term ? root_raw_term - > dump ( ) : " N/A " , root_norm_term ? root_norm_term - > dump ( ) : " N/A " , root_chain ? root_chain - > dump ( ) : " N/A " ) ) ;
2009-06-24 14:59:15 +04:00
e - > show ( ) ;
e - > resize ( 600 , 400 ) ;
}
2009-06-23 23:56:46 +04:00
void MainWindow : : actionExportSTL ( )
{
console - > append ( QString ( " Function %1 is not implemented yet! " ) . arg ( QString ( __PRETTY_FUNCTION__ ) ) ) ;
}
void MainWindow : : actionExportOFF ( )
{
console - > append ( QString ( " Function %1 is not implemented yet! " ) . arg ( QString ( __PRETTY_FUNCTION__ ) ) ) ;
}
2009-06-25 02:38:31 +04:00
void MainWindow : : viewModeActionsUncheck ( )
{
# ifdef ENABLE_OPENCSG
actViewModeOpenCSG - > setChecked ( false ) ;
# endif
# ifdef ENABLE_CGAL
actViewModeCGALSurface - > setChecked ( false ) ;
actViewModeCGALGrid - > setChecked ( false ) ;
# endif
2009-06-25 12:12:41 +04:00
actViewModeThrownTogether - > setChecked ( false ) ;
2009-06-25 02:38:31 +04:00
}
# ifdef ENABLE_OPENCSG
2009-06-26 14:56:50 +04:00
class OpenCSGPrim : public OpenCSG : : Primitive
2009-06-25 12:12:41 +04:00
{
public :
2009-06-26 14:56:50 +04:00
OpenCSGPrim ( OpenCSG : : Operation operation , unsigned int convexity ) :
OpenCSG : : Primitive ( operation , convexity ) { }
PolySet * p ;
2009-06-25 13:49:28 +04:00
virtual void render ( ) {
2009-06-26 14:56:50 +04:00
p - > render_surface ( PolySet : : COLOR_NONE ) ;
2009-06-25 13:49:28 +04:00
}
2009-06-25 12:12:41 +04:00
} ;
static void renderGLviaOpenCSG ( void * vp )
{
MainWindow * m = ( MainWindow * ) vp ;
static int glew_initialized = 0 ;
if ( ! glew_initialized ) {
glew_initialized = 1 ;
glewInit ( ) ;
}
2009-06-25 13:49:28 +04:00
2009-06-25 12:12:41 +04:00
if ( m - > root_chain ) {
2009-06-25 13:49:28 +04:00
std : : vector < OpenCSG : : Primitive * > primitives ;
2009-06-26 14:56:50 +04:00
int j = 0 ;
2009-06-25 13:49:28 +04:00
for ( int i = 0 ; ; i + + )
{
bool last = i = = m - > root_chain - > polysets . size ( ) ;
if ( last | | m - > root_chain - > types [ i ] = = CSGTerm : : UNION )
{
OpenCSG : : render ( primitives , OpenCSG : : Goldfeather , OpenCSG : : NoDepthComplexitySampling ) ;
glDepthFunc ( GL_EQUAL ) ;
2009-06-26 14:56:50 +04:00
for ( ; j < i ; j + + ) {
if ( m - > root_chain - > types [ j ] = = CSGTerm : : DIFFERENCE ) {
m - > root_chain - > polysets [ j ] - > render_surface ( PolySet : : COLOR_CUTOUT ) ;
m - > root_chain - > polysets [ j ] - > render_edges ( PolySet : : COLOR_CUTOUT ) ;
} else {
m - > root_chain - > polysets [ j ] - > render_surface ( PolySet : : COLOR_MATERIAL ) ;
m - > root_chain - > polysets [ j ] - > render_edges ( PolySet : : COLOR_MATERIAL ) ;
}
}
for ( unsigned int k = 0 ; k < primitives . size ( ) ; k + + ) {
delete primitives [ k ] ;
2009-06-25 13:49:28 +04:00
}
glDepthFunc ( GL_LESS ) ;
primitives . clear ( ) ;
2009-06-25 12:12:41 +04:00
}
2009-06-25 13:49:28 +04:00
if ( last )
break ;
2009-06-26 14:56:50 +04:00
OpenCSGPrim * prim = new OpenCSGPrim ( m - > root_chain - > types [ i ] = = CSGTerm : : DIFFERENCE ?
OpenCSG : : Subtraction : OpenCSG : : Intersection , 1 ) ;
prim - > p = m - > root_chain - > polysets [ i ] ;
2009-06-25 13:49:28 +04:00
primitives . push_back ( prim ) ;
2009-06-25 12:12:41 +04:00
}
}
}
2009-06-25 02:38:31 +04:00
void MainWindow : : viewModeOpenCSG ( )
{
viewModeActionsUncheck ( ) ;
actViewModeOpenCSG - > setChecked ( true ) ;
2009-06-25 12:12:41 +04:00
screen - > renderfunc = renderGLviaOpenCSG ;
screen - > renderfunc_vp = this ;
2009-06-25 02:38:31 +04:00
screen - > updateGL ( ) ;
}
# endif /* ENABLE_OPENCSG */
# ifdef ENABLE_CGAL
2009-06-25 12:12:41 +04:00
# include <CGAL/Nef_3/OGL_helper.h>
static void renderGLviaCGAL ( void * vp )
{
MainWindow * m = ( MainWindow * ) vp ;
if ( m - > root_N ) {
CGAL : : OGL : : Polyhedron P ;
CGAL : : OGL : : Nef3_Converter < CGAL_Nef_polyhedron > : : convert_to_OGLPolyhedron ( * m - > root_N , & P ) ;
P . init ( ) ;
if ( m - > actViewModeCGALSurface - > isChecked ( ) )
P . set_style ( CGAL : : OGL : : SNC_BOUNDARY ) ;
if ( m - > actViewModeCGALGrid - > isChecked ( ) )
P . set_style ( CGAL : : OGL : : SNC_SKELETON ) ;
P . draw ( ) ;
}
}
2009-06-25 02:38:31 +04:00
void MainWindow : : viewModeCGALSurface ( )
{
viewModeActionsUncheck ( ) ;
actViewModeCGALSurface - > setChecked ( true ) ;
screen - > renderfunc = renderGLviaCGAL ;
screen - > renderfunc_vp = this ;
screen - > updateGL ( ) ;
}
void MainWindow : : viewModeCGALGrid ( )
{
viewModeActionsUncheck ( ) ;
actViewModeCGALGrid - > setChecked ( true ) ;
screen - > renderfunc = renderGLviaCGAL ;
screen - > renderfunc_vp = this ;
screen - > updateGL ( ) ;
}
# endif /* ENABLE_CGAL */
2009-06-25 12:12:41 +04:00
static void renderGLThrownTogether ( void * vp )
2009-06-25 02:38:31 +04:00
{
MainWindow * m = ( MainWindow * ) vp ;
2009-06-25 12:12:41 +04:00
if ( m - > root_chain ) {
glDepthFunc ( GL_LEQUAL ) ;
for ( int i = 0 ; i < m - > root_chain - > polysets . size ( ) ; i + + ) {
if ( m - > root_chain - > types [ i ] = = CSGTerm : : DIFFERENCE ) {
m - > root_chain - > polysets [ i ] - > render_surface ( PolySet : : COLOR_CUTOUT ) ;
m - > root_chain - > polysets [ i ] - > render_edges ( PolySet : : COLOR_CUTOUT ) ;
} else {
m - > root_chain - > polysets [ i ] - > render_surface ( PolySet : : COLOR_MATERIAL ) ;
m - > root_chain - > polysets [ i ] - > render_edges ( PolySet : : COLOR_MATERIAL ) ;
}
}
}
2009-06-25 02:38:31 +04:00
}
2009-06-25 12:12:41 +04:00
void MainWindow : : viewModeThrownTogether ( )
2009-06-25 02:38:31 +04:00
{
viewModeActionsUncheck ( ) ;
2009-06-25 12:12:41 +04:00
actViewModeThrownTogether - > setChecked ( true ) ;
screen - > renderfunc = renderGLThrownTogether ;
2009-06-25 02:38:31 +04:00
screen - > renderfunc_vp = this ;
screen - > updateGL ( ) ;
}
2009-06-23 23:56:46 +04:00