There hadnt been any reply to my problem. Nonetheless, i solved it but end up with more new problems, which i hope some kind souls would help.
1.I realise where is the lighting problem, but i am not sure why . gluLookAt() sort of change the world coordinate that my light position move along with it. It finally work if i specify the spotlight position after gluLookAt().
2.But the next problem i have is that although i want the spotlight to be on the right of the cube, and direction towards the cube. The spotlight appears on the left side of the cube instead. In initialize(), i clearly specify my light position to {3.0, 0.0, 0.0, 1.0} and light direction to {-1.0, 0.0, 0.0}.
Can someone see the problem?
3.One last thing, if i call the function printString() right before glFlush(), all my reflection is gone.
Here is the full code, so that u can compile:
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
HDC g_HDC;
float angle = 0.0f;
bool fullscreen = false;
// for font variables
unsigned int listbase;
GLYPHMETRICSFLOAT gmf[256];
unsigned int CreateOutlineFont(char *fontName, int fontSize, float depth)
{
HFONT hFont;
unsigned int base;
base = glGenLists(256);
if(stricmp(fontName,"symbol")==0)
{hFont = CreateFont(fontSize,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,
SYMBOL_CHARSET, OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,
ANTIALIASED_QUALITY,FF_DONTCARE|DEFAULT_PITCH,fontName);
}
else
{hFont = CreateFont(fontSize,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,
ANSI_CHARSET, OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,
ANTIALIASED_QUALITY,FF_DONTCARE|DEFAULT_PITCH,fontName);
}
if(!hFont)
return 0;
SelectObject(g_HDC,hFont);
wglUseFontOutlines(g_HDC,0,255,base,0.0f,depth,WGL_FONT_POLYGONS,gmf);
return base;
}
void drawCube()
{
// vertex array for cube
static float cubeVertex[4][3] = {{1.0,1.0,1.0}, {-1.0,1.0,1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}};
static float cubeNormal[4][3] = {{1.0,1.0,1.0}, {-1.0,1.0,1.0}, {-1.0,-1.0,1.0}, {1.0,-1.0,1.0}};
static float cubeColor[4][3] = {{1.0,1.0,0.0}, {1.0,1.0,0.0}, {1.0,1.0,0.0}, {1.0,1.0,0.0}};
// register the array
glColorPointer(3,GL_FLOAT,0,cubeColor);
glNormalPointer(GL_FLOAT,0,cubeNormal);
glVertexPointer(3,GL_FLOAT,0,cubeVertex);
// front face
glPushMatrix();
glDrawArrays(GL_QUADS,0,4);
glPopMatrix();
// left face
glPushMatrix();
glRotatef(-90.0,0.0,1.0,0.0);
glDrawArrays(GL_QUADS,0,4);
glPopMatrix();
// right face
glPushMatrix();
glRotatef(90.0,0.0,1.0,0.0);
glDrawArrays(GL_QUADS,0,4);
glPopMatrix();
// back face
glPushMatrix();
glRotatef(180.0,0.0,1.0,0.0);
glDrawArrays(GL_QUADS,0,4);
glPopMatrix();
// top face
glPushMatrix();
glRotatef(-90.0,1.0,0.0,0.0);
glDrawArrays(GL_QUADS,0,4);
glPopMatrix();
// bottom face
glPushMatrix();
glRotatef(90.0,1.0,0.0,0.0);
glDrawArrays(GL_QUADS,0,4);
glPopMatrix();
}
void drawFloor()
{
// vertex array for floor
static float floorVertex[4][3] = {{10.0, -2.0, -10.0},{-10.0, -2.0, -10.0},{-10.0, -2.0, 10.0},{10.0,-2.0,10.0}};
static float floorNormal[4][3] = {{0.0, 1.0, 0.0},{0.0, 1.0, 0.0},{0.0, 1.0, 0.0},{0.0, 1.0, 0.0}};
static float floorColor[4][4] = {{0.0,0.0,1.0,0.6}, {0.0,0.0,1.0,0.6}, {0.0,0.0,1.0,0.6}, {0.0,0.0,1.0,0.6}};
// register the array
glColorPointer(4,GL_FLOAT,0,floorColor);
glNormalPointer(GL_FLOAT,0,floorNormal);
glVertexPointer(3,GL_FLOAT,0,floorVertex);
glDrawArrays(GL_QUADS,0,4);
}
void initialize()
{
// LIGHT0 properties
float ambientlight[] = {1.0,1.0,1.0,1.0}; // positional light
float diffuselight[] = {1.0,1.0,1.0,1.0};
float specularlight[] = {1.0,1.0,1.0,1.0};
float positionlight[] = {3.0, 0.0, 0.0, 1.0};
float directionlight[] = {-1.0, 0.0, 0.0};
glClearColor(0.0f,0.0f,0.0f,0.0f);
glLoadIdentity();
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_NORMALIZE);
glFrontFace(GL_CCW);
glEnable(GL_LIGHTING);
// use color tracking
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
//setup LIGHT0
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientlight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuselight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specularlight);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,directionlight); // direction of spot light
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,30.0f); // angle of spotlight
glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,10.0f); // focus of spot light
glEnable(GL_LIGHT0);
// enable vertex array
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
// for fonts
listbase = CreateOutlineFont("Arial",10,0.25f);
}
void printString(unsigned int base, char *str)
{
if(str==NULL)return;
glPushMatrix();
glTranslatef(-5.0,5.0,0.0);
// draw text
glPushAttrib(GL_LIST_BIT);
glListBase(base);
glCallLists(strlen(str),GL_UNSIGNED_BYTE,str);
glPopAttrib();
glPopMatrix();
}
void clearfont(unsigned int base)
{
glDeleteLists(base,256);
}
void render()
{
float positionlight[] = {3.0, 0.0, 0.0, 1.0};
// clear screen, depth and stencil buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
// set camera
gluLookAt(0.0, 6.0, 20.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);
glLightfv(GL_LIGHT0,GL_POSITION,positionlight);
if(angle>360.0)
angle = 0.0f;
angle+=0.2f;
// disable depth testing
glDisable(GL_DEPTH_TEST);
// disable modification of all color component
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
// enable stencil testing
glEnable(GL_STENCIL_TEST);
// setup non visible floor with stencil buffer as 1
glStencilOp(GL_REPLACE, GL_REPLACE , GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 1);
// draw non visible floor
glPushMatrix();
drawFloor();
glPopMatrix();
// enable modification of all color component
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
// enable depth test
glEnable(GL_DEPTH_TEST);
// stencil buffering of reflection
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc(GL_EQUAL, 1, 1);
// draw reflection
glPushMatrix();
glRotatef(angle,0.0,1.0,0.0);
glRotatef(-180,1.0,0.0,0.0);
glTranslatef(0.0,4.0,0.0);
drawCube();
glPopMatrix();
// disable stencil testing
glDisable(GL_STENCIL_TEST);
// draw actual floor
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPushMatrix();
drawFloor();
glPopMatrix();
glDisable(GL_BLEND);
// draw actual cube
glPushMatrix();
glRotatef(angle,0.0,1.0,0.0);
drawCube();
glPopMatrix();
// printString(listbase, "My First Reflection");
glFlush();
SwapBuffers(g_HDC);
}
void PixelFormat(HDC hDC)
{
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // SIZE OF STRUCTURE
1, // DEFAULT VERSION
PFD_DRAW_TO_WINDOW | // WINDOW-DRAWING SUPPORT
PFD_SUPPORT_OPENGL | // OPENGL SUPPORT
PFD_DOUBLEBUFFER, // DOUBLE-BUFFFERING SUPPORT
PFD_TYPE_RGBA, // RGBA COLOR SUPPORT
64, // 64-BIT COLOR MODE
0, 0, 0, 0, 0, 0, // IGNORE COLOR BITS, NON PALLETIZED MODE
0, // NO ALPHA BUFFER
0, // IGNORE SHIFT BIT
0, // NO ACCUMULATION BUFFER
0, 0, 0, 0, // IGNORE ACCUMULATION BITS
16, // 16-BIT Z-BUFFER SIZE
16, // NO STENCIL BUFFER
0, // NO AUXILIARY BUFFER
PFD_MAIN_PLANE, // MAIN DRAWING PLANE
0, // RESERVED
0, 0, 0}; // LAYER MASKS IGNORED
//choose best-matching pixel format
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
//set pixel format to device context
SetPixelFormat(hDC, nPixelFormat, &pfd);
}
// the Windows Procedure event handler
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HGLRC hRC; // rendering context
static HDC hDC; // device context
int width, height; // window width and height
switch(message)
{
case WM_CREATE:
hDC = GetDC(hwnd);
g_HDC = hDC;
PixelFormat(hDC);
// create rendering context and make it current
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
return 0;
break;
case WM_CLOSE: // windows is closing
// deselect rendering context and delete it
wglMakeCurrent(hDC, NULL);
wglDeleteContext(hRC);
// delete device context
ReleaseDC(hwnd,hDC);
// send WM_QUIT to message queue
PostQuitMessage(0);
return 0;
break;
case WM_SIZE:
height = HIWORD(lParam);
width = LOWORD(lParam);
if(height == 0)
height = 1;
// reset viewport to new dimensions
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// calculate aspect ratio of window
gluPerspective(54.0f,(GLfloat)width/(GLfloat)height, 1.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity();
return 0;
break;
default: break;
}
return (DefWindowProc(hwnd, message, wParam, lParam));
}
// the main Windows entry point
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wc; // window class
HWND hwnd; // window handle
MSG msg; // message in msg queue
bool done; // for while loop
DWORD dwExstyle; // window extended style
DWORD dwstyle; // window style
RECT windowRect;
// screen/display attributes
int width = 800;
int height = 600;
int bits = 32;
windowRect.left = (long)0; // set left value to 0
windowRect.right = (long)width; // set right value to requested width
windowRect.top = (long)0; // set top value to 0
windowRect.bottom = (long)height; // set bottom value to requested height
//fill out windows class structure
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyClass";
wc.hIconSm = LoadIcon(NULL,IDI_WINLOGO);
// register windows class
if(!RegisterClassEx(&wc))
return 0;
if(fullscreen)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = bits;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{//setting display mode failed,switched to windowed
MessageBox(NULL, "Display mode failed", NULL, MB_OK);
fullscreen = FALSE;
}
}
if(fullscreen)
{
dwExstyle = WS_EX_APPWINDOW; // window extended style
dwstyle = WS_POPUP; // windows style
ShowCursor(false);
}
else
{dwExstyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE ; // window extended style
dwstyle = WS_OVERLAPPEDWINDOW;
}
AdjustWindowRectEx(&windowRect, dwstyle, FALSE, dwExstyle);
// class registered, so create window
hwnd = CreateWindowEx(NULL, "MyClass", // class name
"Just for practice", // title of window
dwstyle | WS_CLIPCHILDREN |
WS_CLIPSIBLINGS,
0,0, // x,y coordinates
windowRect.right - windowRect.left, // width
windowRect.bottom - windowRect.top, // height
NULL, // handle to parent
NULL, // handle to child
hInstance, // application instance
NULL); // no extra params
// check if window created failed
if(!hwnd)
return 0;
ShowWindow(hwnd, SW_SHOW); // display window
UpdateWindow(hwnd); // update window
done = false;
// main message loop
initialize();
while(!done)
{
PeekMessage(&msg,hwnd,NULL,NULL,PM_REMOVE);
if(msg.message == WM_QUIT)
{done = true;
}
else
{
render();
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if(fullscreen)
{
ChangeDisplaySettings(NULL,0); // switch back to desktop
ShowCursor(TRUE);
}
clearfont(listbase);
return msg.wParam;
}