Biblioteka OpenGL umożliwia mieszanie kolorów (ang. blending), czyli ustalanie wynikowego koloru piksela jako kombinacji koloru źródłowego (Rs , Gs , Bs , As ) oraz koloru przeznaczenia (Rd , Gd , Bd , Ad ) przechowywanego w buforze kolorów. Z uwagi na dużą rolę w mieszaniu kolorów dotychczas przez nas nieużywanej składowej alfa (A) koloru, w literaturze można się także spotkać z angielskim określeniem tej techniki alfa blending.
Mieszanie kolorów wykorzystywane jest m.in. do uzyskania takich efektów jak przezroczystość, antyaliasing i odbicie.
Włączanie i wyłączanie mieszania kolorów
Mieszanie kolorów jest w bibliotece OpenGL domyślnie wyłączone. Aktywacja mieszania kolorów wymaga wywołania funkcji glEnable z parametrem
GL_BLEND. Analogicznie Wywołanie funkcji glDisable z tym samym parametrem spowoduje wyłączenie mieszania kolorów.
Z uwagi na korzystania ze składowych alfa kolorów, technika mieszania kolorów nie jest dostępna, gdy biblioteka OpenGL pracuje w trybie indeksu kolorów.
Równanie mieszania kolorów
Domyślnie kolor wynikowy (R, G, B, A) obliczany jest na podstawie poniższego równania mieszania kolorów (ang. blend equation):
w którym (Sr , Sg , Sb , Sa ) i (Dr , Dg , Db , Da ) stanowią odpowiednio współczynniki mieszania dla koloru źródłowego i koloru przeznaczenia. W razie potrzeby wartości składowych (R, G, B, A) koloru wynikowego odcinane są do przedziału [0, 1], stąd spotykana inna, bardziej poprawna matematycznie, forma zapisu tego równania:
Wybór innego niż domyślne równania mieszania kolorów umożliwia funkcja:
void glBlendEquation( GLenum mode )
której parametr mode może przyjąć jedną z poniższych wartości:
Zauważmy, że równania opisane stałymi
GL_MIN,
GL_MAX i LOGIC OP nie korzystają ze współczynników mieszania.
Operacje logiczne na bitach składowych pikseli są domyślnie wyłączone. Włączenie operacji logicznych w przypadku, gdy bufor kolorów działa w trybie RGB, wymaga wywołania funkcji glEnable z parametrem
GL_COLOR_LOGIC_OP. Operacje logiczne można także wykonywać na indeksach kolorów, gdy bufor kolorów pracuje w trybie indeksowym. Wymaga to wywołania funkcji glEnable z parametrem
GL_INDEX_LOGIC_OP.
Wybór operacji logicznej umożliwia funkcja:
void glLogicOp( GLenum opcode )
której wartości parametru opcode i odpowiadające im operacje logiczne na bitach składowej koloru źródłowego s i bitach składowej koloru przeznaczenia d przedstawia tabela 1. Operacja logiczna różnicy symetrycznej XOR oznaczono symbolem „⊕.” Operacją domyślną jest
GL_COPYTabela 1: Operacje logiczne na bitach składowych kolorów
Funkcja glBlendEquation i związana z nią możliwość zmiany równania mieszania kolorów została wprowadzona w wersji 1.2 biblioteki OpenGL jako część składową opcjonalnego zbioru funkcji odpowiedzialnych za przetwarzanie obrazów (ang. imaging subset), ujętą w jednym rozszerzeniu ARB imaging. Wcześniej funkcjonalność tę obejmowały rozszerzenia: EXT blend logic op (równanie
GL_LOGIC_OP), EXT blend subtract (równania
GL_FUNC_SUBTRACT i
GL_FUNC_REVERSE_SUBTRACT) i EXT blend minmax (równania
GL_MIN i GL -
MAX). W wersji 1.4 OpenGL funkcja glBlendEquation stała się częścią obowiązkowej specyfikacji biblioteki.
W wersji 2.0 biblioteki OpenGL ponownie rozszerzono możliwości modyfikacji równania mieszania kolorów. Dodana funkcja:
void glBlendEquationSeparate( enum modeRGB, enum modeAlpha )
umożliwia odrębne określenie równania mieszania dla składowych RGB (parametr modeRGB) i składowej alfa (parametr modeAlpha). Każdy z tych parametrów może przyjmować niezależnie takie same wartości jak parametr funkcji glBlendEquation. Oczywiście, dla obu parametrów wartością domyślną jest
GL_FUNC_ADD. Wcześniej funkcjonalność tę udostępniało rozszerzenie EXT blend equation separate oraz mało znane rozszerzenie ATI blend equation separate. Co ciekawe rozszerzenie firmy ATI zostało opracowane wcześniej, ale z uwagi na niezgodność (!) z przyjętymi w bibliotece OpenGL konwencjami nazewniczymi, nie zostało zaakceptowane przez innych członków ARB.
Współczynniki mieszania kolorów
Część z przedstawionych równań mieszania korzystała ze współczynników mieszania kolorów dla koloru źródłowego (Sr , Sg , Sb , Sa ) i koloru przeznaczenia (Dr , Dg , Db , Da ). Do określania wartości tych współczynników biblioteka OpenGL posiada specjalne funkcje. Podstawową z nich jest:
void glBlendFunc( GLenum src, GLenum dst )
której parametry src i dst określają sposób obliczania współczynników mieszania kolorów. Zestawienie dopuszczalnych wartości tych parametrów przedstawia tabela 2.
Tabela 2: Wartości parametrów funkcji glBlendFunc
Wartość początkowa dla parametru src wynosi
GL_ONE. Wartość początkowa dla parametru dst wynosi
GL_ZERO.
Stała
GL_SRC_ALPHA_SATURATE może być stosowana wyłącznie jako wartość parametru src. Pozostałe wartości można stosować do obu parametrów funkcji glBlendFunc. Całkowitą dowolność w ich wyborze wprowadzono dopiero w wersji 1.4 biblioteki OpenGL. W wcześniejszych wersjach OpenGL parametr sfactor nie mógł przyjmować wartości SRC COLOR i ONE MINUS - SRC COLOR, a parametr dfactor wartości DST COLOR i ONE MINUS DST COLOR. Natomiast możliwość taką udostępniało początkowo rozszerzenie NV blend - square.
Podobnie jak w przypadku definiowania odrębnych równań mieszania kolorów dla składowych RGB i składowej alfa, OpenGL od wersji 1.4 umożliwia zdefiniowanie odrębnych współczynników mieszania kolorów dla składowych RGB koloru źródłowego i koloru przeznaczenia oraz dla składowych alfa obu kolorów. Wymaga to wywołania funkcji:
void glBlendFuncSeparate( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha )
której parametry srcRGB i dstRGB określają współczynniki mieszania składowych RGB koloru źródłowego i koloru przeznaczenia, a parametry srcAlpha i dstAlpha współczynniki mieszania składowych alfa tych kolorów. Parametry funkcji glBlendFuncSeparate pozostają takie same jak parametry funkcji glBlendFunc. Analogiczne są także ograniczenia dotyczące stosowania stałej
GL_SRC_ALPHA_SATURATE tylko w zakresie parametrów srcRGB i srcAlpha. Podobnie wartość początkowa parametrów srcRGB i srcAlpha wynosi
GL_ONE, a parametrów dstRGB i dstAlpha -
GL_ZERO. Całość była wcześniej ujęta w rozszerzeniu EXT blend func separate.
Ostatnim wymagającym opisu elementem mechanizmu mieszania kolorów są wymienione w tabeli 2 stałe:
GL_CONSTANT_COLOR,
GL_ONE_MINUS - CONSTANT COLOR,
GL_CONSTANT_ALPHA i
GL_ONE_MINUS_CONSTANT_ALPHA, powiązane z wartościami (Rc, Gc, Bc, Ac). Ich użycie umożliwia wybranie dowolnej wartości współczynników mieszania składowych RGBA, a wartości te definiuje się przy użyciu funkcji:
void glBlendColor( clampf red, clampf green, clampf blue, clampf alpha )
Wartość początkowa współczynników (Rc, Gc, Bc, Ac) wynosi (0, 0, 0, 0).
Stałe
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR,
GL_CONSTANT - ALPHA i
GL_ONE_MINUS_CONSTANT_ALPHA zostały wprowadzone w wersji 1.2 biblioteki OpenGL jako część składowa wspomnianego wyżej opcjonalnego zbioru funkcji przetwarzania obrazów (rozszerzenie ARB imaging). Wcześniej ich obsługę wprowadzono w rozszerzeniu EXT blend color. Stałe te wprowadzono do obowiązkowej części specyfikacji w wersji 1.4 biblioteki OpenGL.
Programy przykładowe
Pierwszy program przykładowy (plik rownanie_mieszania_kolorow.cpp) przedstawia efekty działania wybranych równań mieszania kolorów. Okno programu (rysunek 1) podzielone jest na dwie części. Lewa część, pokolorowana na niebiesko, zawiera nazwy zastosowanych równań mieszania kolorów. Prawa część okna jest pokolorowana na zielono. Na wysokości każdego napisu określającego nazwę równania mieszania kolorów program rysuje prostokąt czerwony przecinający zarówno niebieską jak i zieloną część okna. Daje to możliwość wizualnego porównania efektów działania poszczególnych równań mieszania kolorów. Dodatkowo na prostokątach wynikowych wypisane są szesnastkowo wartość składowych RGB.
Plik rownanie_mieszania_kolorow.cpp
#include <GL/glut.h>
#include <GL/glext.h>
#ifndef WIN32
#define GLX_GLXEXT_LEGACY
#include <GL/glx.h>
#define wglGetProcAddress glXGetProcAddressARB
#endif
#include <stdlib.h>
#include <stdio.h>
#include "colors.h"
PFNGLBLENDEQUATIONEXTPROC glBlendEquation = NULL;
enum
{
EXIT
};
const int func_count = 23;
char * func[ func_count ] =
{
"SOURCE",
"DEST",
"ADD",
"MIN",
"MAX",
"SUBTRACT",
"REVERSE_SUBTRACT",
"CLEAR",
"SET",
"COPY",
"COPY_INVERTED",
"NOOP",
"INVERT",
"AND",
"NAND",
"OR",
"NOR",
"XOR",
"EQUIV",
"AND_REVERSE",
"AND_INVERTED",
"OR_REVERSE",
"OR_INVERTED"
};
void DrawString( const char * string )
{
int i;
for( i = 0; string[ i ]; i++ )
glutBitmapCharacter( GLUT_BITMAP_9_BY_15, string[ i ] );
}
void DrawString( GLint x, GLint y, char * string )
{
glRasterPos2i( x, y );
int len = strlen( string );
for( int i = 0; i < len; i++ )
glutBitmapCharacter( GLUT_BITMAP_9_BY_15, string[ i ] );
}
void DisplayScene()
{
int width = glutGet( GLUT_WINDOW_WIDTH );
int height = glutGet( GLUT_WINDOW_HEIGHT );
if( width == 0 || height == 0 )
return;
glClearColor( 0.0, 1.0, 0.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glColor4fv( Blue );
glRecti( 0, 0, 180 +( width - 200 ) / 2, height );
int stepy = height / func_count;
int y = height -( stepy - 15 ) / 2 - 15;
glColor4fv( Red );
glRecti( 180, height - 1 * stepy, width - 20, height - 0 * stepy );
glEnable( GL_BLEND );
glBlendFunc( GL_ONE, GL_ONE );
glRecti( 180, height - 2 * stepy, width - 20, height - 1 * stepy );
glBlendEquation( GL_FUNC_ADD );
glRectf( 180, height - 3 * stepy, width - 20, height - 2 * stepy );
glBlendEquation( GL_MIN );
glRectf( 180, height - 4 * stepy, width - 20, height - 3 * stepy );
glBlendEquation( GL_MAX );
glRectf( 180, height - 5 * stepy, width - 20, height - 4 * stepy );
glBlendEquation( GL_FUNC_SUBTRACT );
glRectf( 180, height - 6 * stepy, width - 20, height - 5 * stepy );
glBlendEquation( GL_FUNC_REVERSE_SUBTRACT );
glRectf( 180, height - 7 * stepy, width - 20, height - 6 * stepy );
glBlendFunc( GL_ONE, GL_ZERO );
glEnable( GL_COLOR_LOGIC_OP );
glLogicOp( GL_CLEAR );
glRectf( 180, height - 8 * stepy, width - 20, height - 7 * stepy );
glLogicOp( GL_SET );
glRectf( 180, height - 9 * stepy, width - 20, height - 8 * stepy );
glLogicOp( GL_COPY );
glRectf( 180, height - 10 * stepy, width - 20, height - 9 * stepy );
glLogicOp( GL_COPY_INVERTED );
glRectf( 180, height - 11 * stepy, width - 20, height - 10 * stepy );
glLogicOp( GL_NOOP );
glRectf( 180, height - 12 * stepy, width - 20, height - 11 * stepy );
glLogicOp( GL_INVERT );
glRectf( 180, height - 13 * stepy, width - 20, height - 12 * stepy );
glLogicOp( GL_AND );
glRectf( 180, height - 14 * stepy, width - 20, height - 13 * stepy );
glLogicOp( GL_NAND );
glRectf( 180, height - 15 * stepy, width - 20, height - 14 * stepy );
glLogicOp( GL_OR );
glRectf( 180, height - 16 * stepy, width - 20, height - 15 * stepy );
glLogicOp( GL_NOR );
glRectf( 180, height - 17 * stepy, width - 20, height - 16 * stepy );
glLogicOp( GL_XOR );
glRectf( 180, height - 18 * stepy, width - 20, height - 17 * stepy );
glLogicOp( GL_EQUIV );
glRectf( 180, height - 19 * stepy, width - 20, height - 18 * stepy );
glLogicOp( GL_AND_REVERSE );
glRectf( 180, height - 20 * stepy, width - 20, height - 19 * stepy );
glLogicOp( GL_AND_INVERTED );
glRectf( 180, height - 21 * stepy, width - 20, height - 20 * stepy );
glLogicOp( GL_OR_REVERSE );
glRectf( 180, height - 22 * stepy, width - 20, height - 21 * stepy );
glLogicOp( GL_OR_INVERTED );
glRectf( 180, height - 23 * stepy, width - 20, height - 22 * stepy );
glDisable( GL_COLOR_LOGIC_OP );
glDisable( GL_BLEND );
GLubyte rgb[ 3 ];
char string[ 20 ];
for( int i = 0; i < func_count; i++ )
{
glColor4fv( White );
DrawString( 10, y, func[ i ] );
glReadPixels( 180, height -( i + 1 ) * stepy, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb );
sprintf( string, "(%2X,%2X,%2X)", rgb[ 0 ], rgb[ 1 ], rgb[ 2 ] );
glColor3ub( 255 - rgb[ 0 ], 255 - rgb[ 1 ], 255 - rgb[ 2 ] );
DrawString( 210, y, string );
glReadPixels( width - 21, height -( i + 1 ) * stepy, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb );
sprintf( string, "(%2X,%2X,%2X)", rgb[ 0 ], rgb[ 1 ], rgb[ 2 ] );
glColor3ub( 255 - rgb[ 0 ], 255 - rgb[ 1 ], 255 - rgb[ 2 ] );
DrawString( width - 140, y, string );
y -= stepy;
}
glFlush();
glutSwapBuffers();
}
void Reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0, width, 0, height );
DisplayScene();
}
void Menu( int value )
{
if( value == EXIT )
exit( 0 );
}
void ExtensionSetup()
{
const char * version =( char * ) glGetString( GL_VERSION );
int major = 0, minor = 0;
if( sscanf( version, "%d.%d", & major, & minor ) != 2 )
{
#ifndef WIN32
printf( "Błędny format wersji OpenGL\n" );
#else
printf( "Bledny format wersji OpenGL\n" );
#endif
exit( 0 );
}
if( major > 1 || minor >= 4 )
{
glBlendEquation =
( PFNGLBLENDEQUATIONPROC ) wglGetProcAddress( "glBlendEquation" );
}
else
if( glutExtensionSupported( "GL_EXT_blend_minmax" ) &&
glutExtensionSupported( "GL_EXT_blend_logic_op" ) &&
glutExtensionSupported( "GL_EXT_blend_subtract" ) )
{
glBlendEquation =
( PFNGLBLENDEQUATIONPROC ) wglGetProcAddress( "glBlendEquationEXT" );
}
else
{
printf( "Brak rozszerzenia EXT_blend_minmax!\n" );
printf( "Brak rozszerzenia EXT_blend_logic_op!\n" );
printf( "Brak rozszerzenia EXT_blend_subtract!\n" );
exit( 0 );
}
}
int main( int argc, char * argv[] )
{
glutInit( & argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
glutInitWindowSize( 500, 600 );
#ifdef WIN32
glutCreateWindow( "Równanie mieszania kolorów" );
#else
glutCreateWindow( "Rownanie mieszania kolorow" );
#endif
glutDisplayFunc( DisplayScene );
glutReshapeFunc( Reshape );
glutCreateMenu( Menu );
#ifdef WIN32
glutAddMenuEntry( "Wyjście", EXIT );
#else
glutAddMenuEntry( "Wyjscie", EXIT );
#endif
glutAttachMenu( GLUT_RIGHT_BUTTON );
ExtensionSetup();
glutMainLoop();
return 0;
}
Drugi i ostatni przykładowy program (plik przezroczystosc.cpp) przedstawia sposób uzyskiwania efektu przezroczystości przy użyciu mieszania kolorów. Program wyświetla cztery kule (patrz rysunek 2), z których dwie są nieprzezroczyste a dwie częściowo przezroczyste. Wykorzystano przy tym definicje materiałów zawarte w pliku materials.h. Obiekty można obracać za pomocą lewego przycisku myszki.
Aby uzyskać prawidłowo działający efekt przezroczystości obiektów trzeba wykonać szereg operacji. Przede wszystkim w pierwszej kolejności rysujemy wszystkie obiekty nieprzezroczyste. Przed przystąpieniem do rysowania obiektów przezroczystych trzeba włączyć mieszanie kolorów oraz ustawić współczynniki mieszania kolorów na
GL_SRC_ALPHA dla koloru źródłowego i
GL_ONE_MINUS_SRC_ALPHA dla koloru przeznaczenia. Korzystanie z mieszania kolorów przy rysowaniu obiektów trójwymiarowych wymaga także wyłączenia zapisu współrzędnych z do bufora głębokości przy użyciu opisywanej już funkcji glDepthMask. Niestety aby obiekty przezroczyste były prawidłowo renderowane należy je rysować w kolejności od najdalej położonego względem osi Z.
Poprawne posortowanie większej ilości obiektów 3D może być głównym problemem przy korzystaniu z efektu przezroczystości. W przykładowym programie o kolejności rysowania dwóch przezroczystych kul decyduje wartość kąta obrotu wokół osi X (graniczne wartości kątów dobrano eksperymentalnie). Jest to oczywiście rozwiązanie dostosowane do realiów wyświetlanej sceny i nie ma niestety żadnych cech uniwersalności.
Warto jeszcze dodać, że przezroczysta kula rysowana jest w specjalny sposób. Polega to na dwukrotnym rysowaniu kuli - pierwszy raz z wyłączeniem rysowania tylnych stron wielokątów (funkcja glCullFace), i drugi raz z wyłączeniem rysowania przednich stron wielokątów. W połączeniu z włączoną opcją oświetlenia obu stron wielokątów daje to w efekcie prawidłowy obraz bez żadnych niekorzystnych efektów związanych ze sposobem definiowania obiektów przez bibliotekę GLUT.
Plik przezroczystosc.cpp
#include <GL/glut.h>
#include <GL/glu.h>
#include <stdlib.h>
#include "materials.h"
enum
{
FULL_WINDOW,
ASPECT_1_1,
EXIT
};
int aspect = FULL_WINDOW;
const GLdouble left = - 2.0;
const GLdouble right = 2.0;
const GLdouble bottom = - 2.0;
const GLdouble top = 2.0;
const GLdouble near = 3.0;
const GLdouble far = 7.0;
GLfloat rotatex = 0.0;
GLfloat rotatey = 0.0;
int button_state = GLUT_UP;
int button_x, button_y;
GLint GOLD_SPHERE;
GLint RUBY_SPHERE;
void Display()
{
glClearColor( 1.0, 1.0, 1.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable( GL_DEPTH_TEST );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glLightModelf( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
glTranslatef( 0, 0, -( near + far ) / 2 );
glRotatef( rotatex, 1.0, 0.0, 0.0 );
glRotatef( rotatey, 0.0, 1.0, 0.0 );
glPushMatrix();
glTranslatef( 1.2, 0.0, 0.0 );
glCallList( GOLD_SPHERE );
glPopMatrix();
glPushMatrix();
glTranslatef( - 1.2, 0.0, 0.0 );
glCallList( GOLD_SPHERE );
glPopMatrix();
glLightModelf( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glDepthMask( GL_FALSE );
glPushMatrix();
int anglex =( int ) rotatex % 360;
if( anglex < 0 )
anglex += 360;
if( anglex > 50 && anglex < 130 )
glTranslatef( 0.0, - 1.2, 0.0 );
else
glTranslatef( 0.0, 1.2, 0.0 );
glCallList( RUBY_SPHERE );
glPopMatrix();
glPushMatrix();
if( anglex > 50 && anglex < 130 )
glTranslatef( 0.0, 1.2, 0.0 );
else
glTranslatef( 0.0, - 1.2, 0.0 );
glCallList( RUBY_SPHERE );
glPopMatrix();
glDepthMask( GL_TRUE );
glFlush();
glutSwapBuffers();
}
void Reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
if( aspect == ASPECT_1_1 )
{
if( width < height && width > 0 )
glFrustum( left, right, bottom * height / width, top * height / width, near, far );
else
if( width >= height && height > 0 )
glFrustum( left * width / height, right * width / height, bottom, top, near, far );
}
else
glFrustum( left, right, bottom, top, near, far );
Display();
}
void MouseButton( int button, int state, int x, int y )
{
if( button == GLUT_LEFT_BUTTON )
{
button_state = state;
if( state == GLUT_DOWN )
{
button_x = x;
button_y = y;
}
}
}
void MouseMotion( int x, int y )
{
if( button_state == GLUT_DOWN )
{
rotatey += 30 *( right - left ) / glutGet( GLUT_WINDOW_WIDTH ) *( x - button_x );
button_x = x;
rotatex -= 30 *( top - bottom ) / glutGet( GLUT_WINDOW_HEIGHT ) *( button_y - y );
button_y = y;
glutPostRedisplay();
}
}
void Menu( int value )
{
switch( value )
{
case FULL_WINDOW:
aspect = FULL_WINDOW;
Reshape( glutGet( GLUT_WINDOW_WIDTH ), glutGet( GLUT_WINDOW_HEIGHT ) );
break;
case ASPECT_1_1:
aspect = ASPECT_1_1;
Reshape( glutGet( GLUT_WINDOW_WIDTH ), glutGet( GLUT_WINDOW_HEIGHT ) );
break;
case EXIT:
exit( 0 );
}
}
void GenerateDisplayLists()
{
GOLD_SPHERE = glGenLists( 1 );
glNewList( GOLD_SPHERE, GL_COMPILE );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, GoldAmbient );
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, GoldDiffuse );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, GoldSpecular );
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, GoldShininess );
glutSolidSphere( 0.8, 20, 20 );
glEndList();
RUBY_SPHERE = glGenLists( 1 );
glNewList( RUBY_SPHERE, GL_COMPILE );
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, RubyAmbient );
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, RubyDiffuse );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, RubySpecular );
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, RubyShininess );
glEnable( GL_CULL_FACE );
glCullFace( GL_BACK );
glutSolidSphere( 0.8, 20, 20 );
glCullFace( GL_FRONT );
glutSolidSphere( 0.8, 20, 20 );
glDisable( GL_CULL_FACE );
glEndList();
}
int main( int argc, char * argv[] )
{
glutInit( & argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
glutInitWindowSize( 500, 500 );
#ifdef WIN32
glutCreateWindow( "Przezroczystość" );
#else
glutCreateWindow( "Przezroczystosc" );
#endif
glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glutMouseFunc( MouseButton );
glutMotionFunc( MouseMotion );
glutCreateMenu( Menu );
int MenuAspect = glutCreateMenu( Menu );
#ifdef WIN32
glutAddMenuEntry( "Aspekt obrazu - całe okno", FULL_WINDOW );
#else
glutAddMenuEntry( "Aspekt obrazu - cale okno", FULL_WINDOW );
#endif
glutAddMenuEntry( "Aspekt obrazu 1:1", ASPECT_1_1 );
glutCreateMenu( Menu );
glutAddSubMenu( "Aspekt obrazu", MenuAspect );
#ifdef WIN32
glutAddMenuEntry( "Wyjście", EXIT );
#else
glutAddMenuEntry( "Wyjscie", EXIT );
#endif
glutAttachMenu( GLUT_RIGHT_BUTTON );
GenerateDisplayLists();
glutMainLoop();
return 0;
}