Code:
// many commented instructions here are found at http://www.sjbaker.org/steve/omniv/opengl_lighting.html
#include <windows.h>
#include <GL/gl.h>
.
.
.
/*/
Lighting ENABLED or DISABLED?: glEnable ( GL_LIGHTING ) ; ...or... glDisable ( GL_LIGHTING ) ;
disabled: all polygons, lines and points will be coloured according to the setting of the various
forms of the glColor command. Those colours will be carried forward without any change other than
is imparted by texture or fog if those are also enabled. Hence:*/
//glColor3f ( 1.0f, 0.0f, 0.0f ) ;//pure red triangle no matter how it is positioned relative to the light source(s).
//glColor3f ( 1.0f, 9.0f, 0.0f ) ;//green back 2 sides, yellow
//glColor3f ( 2.0f, 9.0f, 0.0f ) ;//light green left, yellow top and front
//glColor3f ( 1.0f, 9.0f, 1.0f ) ;//green left and top, green-white front
//glColor3f ( 1.0f, 9.0f, 5.0f ) ;//blue back 2 sides,light blue front
glColor3f ( 1.0f, 9.0f, 0.0f ) ;
/*With GL_LIGHTING enabled, we need to specify more about the surface than just it's colour - we
also need to know how shiney it is, whether it glows in the dark and whether it scatters light
uniformly or in a more directional manner.
The idea is that OpenGL switches over to using the current settings of the current 'material'
instead of the simplistic idea of a polygon 'colour' that is sufficient when lighting is
disabled. We shall soon see that this is an over-simplistic explanation - but keep it firmly in
mind.
/*/
glEnable(GL_LIGHTING);
//glDisable(GL_LIGHTING);
/* AMBIENT - light that comes from all directions equally and is scattered in all directions equally by the polygons in your scene. This isn't quite true of the real world - but it's a good first approximation for light that comes pretty much uniformly from the sky and arrives onto a surface by bouncing off so many other surfaces that it might as well be uniform.
DIFFUSE - light that comes from a particular point source (like the Sun) and hits surfaces with an intensity that depends on whether they face towards the light or away from it. However, once the light radiates from the surface, it does so equally in all directions. It is diffuse lighting that best defines the shape of 3D objects.
SPECULAR - as with diffuse lighting, the light comes from a point souce, but with specular lighting, it is reflected more in the manner of a mirror where most of the light bounces off in a particular direction defined by the surface shape. Specular lighting is what produces the shiney highlights and helps us to distinguish between flat, dull surfaces such as plaster and shiney surfaces like polished plastics and metals.
EMISSION - in this case, the light is actually emitted by the polygon - equally in all directions.*/
glEnable(GL_LIGHT0);//can be 0 through 7, there are three light colours for each light - Ambient, Diffuse and Specular (set with glLight)
glColorMaterial ( GL_FRONT_AND_BACK, GL_DIFFUSE ) ;//To drive the AMBIENT|DIFFUSE|SPECULAR|EMISSION component of the glMaterial using glColor
/*try also:
glMaterial ( GL_FRONT_AND_BACK, GL_EMISSION, ...colours... ) ; or
glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
*/
glEnable(GL_COLOR_MATERIAL);//there are four colors for each surface (set with glMaterial).
// glDisable(GL_COLOR_MATERIAL);
/*The final polygon colour is the sum of all four light components, each of which is formed by
multiplying the glMaterial colour by the glLight colour (modified by the directionality in the
case of Diffuse and Specular). Since there is no Emission colour for the glLight, that is added
to the final colour without modification.
*/
}
void
redraw(void)
{
/* You cannot change glMaterial settings with many of the more advanced polygon rendering
techniques such as Vertex arrays and glDrawElements
*/
/* clear color and depth buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* draw six faces of a cube */
glBegin(GL_QUADS);
/************************************************************* changing sides of cube colors **/
glNormal3f( 1.0F, 0.0F, 1.3F);//color of right front side
//( 1.0F, 0.0F, 1.0F);// normal back 2 sides, darker front right side
//( 0.0F, 0.0F, 1.0F);//light front side, normal other 2 sides
//( 9.9F, 0.0F, 1.0F);//black frontside, normal other 2 sides
// also with 3rd param 0.0F
//( 0.0F, 9.9F, 1.0F);//white front side, normal other 2 sides
// also with 3rd param 9.0F
//vertices of right front side
//a vertex(singular of vertices) is : (polyhedron) The meeting point of three or more faces and an equal number of edges.
//front side, right edge, top
glVertex3f( 0.5F, 0.5F, 0.5F);// (positive x, positive y, positive z)
//front side, left edge, top
glVertex3f(-0.5F, 0.5F, 0.5F);// (negative x, positive y, positive z)
// front side, left edge, bottom
glVertex3f(-0.5F,-0.5F, 0.5F);// (negative x, negative y, positive z)
// front side, right edge, bottom
glVertex3f( 0.5F,-0.5F, 0.5F);// (positive x, negative y, positive z)
// changing these doesn't seem to have affect on either of the other 2 sides
glNormal3f( 0.0F, 0.0F,-1.0F);//color
glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f(-0.5F, 0.5F,-0.5F);
glVertex3f( 0.5F, 0.5F,-0.5F); glVertex3f( 0.5F,-0.5F,-0.5F);
glNormal3f( 0.0F, 1.0F, 0.0F);// color of top side
//vertices of top side
//top side, right edge, rear
glVertex3f( 0.5F, 0.5F, 0.5F);//(positive x, positive y, positive z)
//top side, right edge, front
glVertex3f( 0.5F, 0.5F,-0.5F);//(positive x, positive y, negative z)
//top side, left edge, rear
glVertex3f(-0.5F, 0.5F,-0.5F);//(negative x, positive y, negative z)
//top side, left edge, front
glVertex3f(-0.5F, 0.5F, 0.5F);//(negative x, positive y, positive z)
// changing these doesn't seem to have affect on either of the other 2 sides
glNormal3f( 0.0F,-1.0F, 0.0F);
glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f( 0.5F,-0.5F,-0.5F);
glVertex3f( 0.5F,-0.5F, 0.5F); glVertex3f(-0.5F,-0.5F, 0.5F);
glNormal3f( 1.0F, 0.0F, 0.0F);//
glVertex3f( 0.5F, 0.5F, 0.5F); glVertex3f( 0.5F,-0.5F, 0.5F);
glVertex3f( 0.5F,-0.5F,-0.5F); glVertex3f( 0.5F, 0.5F,-0.5F);
glNormal3f(-1.0F, 0.0F, 0.0F);// color of left front side
//vertices of left front side
//left side, left edge, rear
glVertex3f(-0.5F,-0.5F,-0.5F);//(negative x, negative y, negative z)
//left side, left edge, front
glVertex3f(-0.5F,-0.5F, 0.5F);//(negative x, negative y, positive z)
//?
glVertex3f(-0.5F, 0.5F, 0.5F);//(negative x, positive y, positive z)
//?
glVertex3f(-0.5F, 0.5F,-0.5F);//(negative x, positive y, negative z)
glEnd();
SwapBuffers(hDC);
}
void
resize(void)
{
/* set viewport to cover the window */
glViewport(0, 0, winWidth, winHeight);
}
void
setupPixelFormat(HDC hDC)
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), /* size */
1, /* version */
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER, /* support double-buffering */
PFD_TYPE_RGBA, /* color type */
16, /* preferred color depth */
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
0, /* no alpha buffer */
0, /* alpha bits (ignored) */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
16, /* depth buffer */
0, /* no stencil buffer */
0, /* no auxiliary buffers */
PFD_MAIN_PLANE, /* main layer */
0, /* reserved */
0, 0, 0, /* no layer, visible, damage masks */
};
int pixelFormat;
pixelFormat = ChoosePixelFormat(hDC, &pfd);
if (pixelFormat == 0) {
MessageBox(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error",
MB_ICONERROR | MB_OK);
exit(1);
}
if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) {
MessageBox(WindowFromDC(hDC), "SetPixelFormat failed.", "Error",
MB_ICONERROR | MB_OK);
exit(1);
}
}
void
setupPalette(HDC hDC)
{
int pixelFormat = GetPixelFormat(hDC);
PIXELFORMATDESCRIPTOR pfd;
LOGPALETTE* pPal;
int paletteSize;
DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
if (pfd.dwFlags & PFD_NEED_PALETTE) {
paletteSize = 1 << pfd.cColorBits;
} else {
return;
}
pPal = (LOGPALETTE*)
malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));//dynamic memory allocation (like the keyword new)
pPal->palVersion = 0x300;
pPal->palNumEntries = paletteSize;
/* build a simple RGB color palette */
{
int redMask = (1 << pfd.cRedBits) - 1;
int greenMask = (1 << pfd.cGreenBits) - 1;
int blueMask = (1 << pfd.cBlueBits) - 1;
int i;
for (i=0; i<paletteSize; ++i) {
pPal->palPalEntry[i].peRed =
(((i >> pfd.cRedShift) & redMask) * 255) / redMask;
pPal->palPalEntry[i].peGreen =
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
pPal->palPalEntry[i].peBlue =
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
pPal->palPalEntry[i].peFlags = 0;
}
}
hPalette = CreatePalette(pPal);
free(pPal);
if (hPalette) {
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
}
}
LRESULT APIENTRY
WndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message) {
case WM_CREATE:
/* initialize OpenGL rendering */
hDC = GetDC(hWnd);
setupPixelFormat(hDC);
setupPalette(hDC);
hGLRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hGLRC);
init();
return 0;
case WM_DESTROY:
/* finish OpenGL rendering */
if (hGLRC) {
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hGLRC);
}
if (hPalette) {
DeleteObject(hPalette);
}
ReleaseDC(hWnd, hDC);
PostQuitMessage(0);
return 0;
case WM_SIZE:
/* track window size changes */
if (hGLRC) {
winWidth = (int) LOWORD(lParam);
winHeight = (int) HIWORD(lParam);
resize();
return 0;
}
case WM_PALETTECHANGED:
/* realize palette if this is *not* the current window */
if (hGLRC && hPalette && (HWND) wParam != hWnd) {
UnrealizeObject(hPalette);
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
redraw();
break;
}
break;
case WM_QUERYNEWPALETTE:
/* realize palette if this is the current window */
if (hGLRC && hPalette) {
UnrealizeObject(hPalette);
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
redraw();
return TRUE;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
if (hGLRC) {
redraw();
}
EndPaint(hWnd, &ps);
return 0;
}
break;
case WM_CHAR:
/* handle keyboard input */
switch ((int)wParam) {
case VK_ESCAPE:
DestroyWindow(hWnd);
return 0;
default:
break;
}
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
.
.
.
/*
Good Settings.
With this huge range of options, it can be hard to pick sensible default values for these things.
My advice for a starting point is to:
* Set GL_LIGHT_0's position to something like 45 degrees to the 'vertical'.
Coordinate (1,1,0) should work nicely in most cases.
* Set GL_LIGHT_0's Ambient color to 0,0,0,1
* Set GL_LIGHT_0's Diffuse color to 1,1,1,1
* Set GL_LIGHT_0's Specular color to 1,1,1,1
* Set the glLightModel's global ambient to 0.2,0.2,0.2,1 (this is the default).
* Don't set any other glLight or glLightModel options - just let them default.
* Enable GL_LIGHTING and GL_LIGHT_0.
* Enable GL_COLOR_MATERIAL and set glColorMaterial to GL_AMBIENT_AND_DIFFUSE. This means
that glMaterial will control the polygon's specular and emission colours and the ambient and
diffuse will both be set using glColor.
* Set the glMaterial's Specular colour to 1,1,1,1
* Set the glMaterial's Emission colour to 0,0,0,1
* Set the glColor to whatever colour you want each polygon to basically appear to be.
That sets the Ambient and Diffuse to the same value which is what you generally want.
*/