PDA

View Full Version : Help with Textured Heightfield Terrain



scryedzxp
04-12-2006, 11:10 PM
I'm having trouble getting my heightfield terrain to work properly. I'm using the code from the 'OpenGL Game Programming' book and when I run it, I get white horizontal bars across my window. Can someone help me out and tell me what's wrong?

Here's the program (I'm using VS.NET 03, by the way):
(my test2, land, water bitmaps are 32X32 pixels. test2.bmp is grayscale while land.bmp and water.bmp have color in them)

#define WIN32_LEAN_AND_MEAN // trim the excess fat from Windows

////// Includes
#include <windows.h> // standard Windows app include
#include <gl/gl.h> // standard OpenGL include
#include <gl/glu.h> // OpenGL utilties
//#include <gl/glaux.h> // OpenGL auxiliary functions
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

////// Defines
#define BITMAP_ID 0x4D42
#define MAP_X 32
#define MAP_Z 32
#define MAP_SCALE 20.0f
#define PI 3.14159

////// Global Variables
HDC g_HDC; // global device context
bool fullScreen = false; //true = full screen; false = windowed
bool keyPressed[256]; //holds true for keys that are pressed

float angle = 0.0f; //camera angle
float radians = 0.0f; //camera angle in radians
float waterHeight = 154.0f; //height of water
bool waterDir = true; //used to animate water
//true = up, false = down

//////Mouse/Camera Variables
int mouseX, mouseY; //mouse coordinates
float cameraX, cameraY, cameraZ; //camera coordinates
float lookX, lookY, lookZ; //camera look-at coordinates

////// Textrue Information
BITMAPINFOHEADER bitmapInfoHeader; //temp bitmap info header
BITMAPINFOHEADER landInfo; //land texture info header
BITMAPINFOHEADER waterInfo; //water texture info header

unsigned char* imageData; //the map image data
unsigned char* landTexture; //land texture data
unsigned char* waterTexture; //water texture data
unsigned int land; //the land texture object
unsigned int water; //the water texture object

////// Terrain Data
float terrain[MAP_X][MAP_Z][3];


// function to set the pixel format for the device context
void SetupPixelFormat(HDC hDC)
{
int nPixelFormat; // our pixel format index

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 buffering support
PFD_TYPE_RGBA, // RGBA color mode
32, // 32 bit color mode
0, 0, 0, 0, 0, 0, // ignore color bits, non-palettized 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
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main drawing plane
0, // reserved
0, 0, 0 }; // layer masks ignored

nPixelFormat = ChoosePixelFormat(hDC, &amp;pfd); // choose best matching pixel format

SetPixelFormat(hDC, nPixelFormat, &amp;pfd); // set pixel format to device context
}

// 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
int oldMouseX, oldMouseY; //old mouse coordinates

switch(message)
{
case WM_QUIT:
return 0;
break;
case WM_CREATE: // window is being created

hDC = GetDC(hwnd); // get current window's device context
g_HDC = hDC;
SetupPixelFormat(hDC); // call our pixel format setup function

// 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);

// send WM_QUIT to message queue
PostQuitMessage(0);

return 0;
break;

case WM_SIZE:
height = HIWORD(lParam); // retrieve width and height
width = LOWORD(lParam);

if (height==0) // don't want a divide by zero
{
height=1;
}

glViewport(0, 0, width, height); // reset the viewport to new dimensions
glMatrixMode(GL_PROJECTION); // set projection matrix current matrix
glLoadIdentity(); // reset projection matrix

// calculate aspect ratio of window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);

glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity(); // reset modelview matrix

return 0;
break;

case WM_KEYDOWN: //is a key pressed?
keyPressed[wParam] = true;
return 0;
break;

case WM_KEYUP:
keyPressed[wParam] = false;
return 0;
break;

case WM_MOUSEMOVE:
//save old mouse coordinates
oldMouseX = mouseX;
oldMouseY = mouseY;

//get mouse cooridnates from Windows
mouseX = LOWORD(1);
mouseY = HIWORD(1);

//these linies limit the camera's range
if( mouseY < 200 )
mouseY = 200;
if( mouseY > 450 )
mouseY = 450;

if( (mouseX - oldMouseX) > 0 ) //mouse moved to the right
angle += 3.0f;
else if( (mouseX - oldMouseX) < 0 ) //mouse moved to the left
angle -= 3.0f;

return 0;
break;

default:
break;
}

return (DefWindowProc(hwnd, message, wParam, lParam));
}

unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER * bitmapInfoHeader)
{
FILE *filePtr; //the file pointer
BITMAPFILEHEADER bitmapFileHeader; //bitmap file header
unsigned char *bitmapImage; //bitmap image data
int imageIdx = 0; //image index counter
unsigned char tempRGB; //swap variable

//open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if( filePtr == NULL)
return NULL;

//read the bitmap file header
fread(&amp;bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);

//verify that this is a bitmap by checking for the universal bitmap id
if( bitmapFileHeader.bfType != BITMAP_ID )
{
fclose(filePtr);
return NULL;
}

//read the bitmap information header
fread(bitmapInfoHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);

//move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);

//allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);

//verify memory allocation
if(!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}

//read in the bitmap image data
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);

//make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
return NULL;
}

//swap the R and B values to get RGB since the bitmap color format is in BGR
for( imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3 )
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}

//close the file and return the bitmap image data
fclose(filePtr);

return bitmapImage;
}

void InitializeTerrain()
{
// loop through all of the heightfield points, calculating the coordinates for each point
for (int z = 0; z < MAP_Z; z++)
{
for (int x = 0; x < MAP_X; x++)
{
terrain[x][z][0] = float(x)*MAP_SCALE;
terrain[x][z][1] = (float)imageData[(z*MAP_Z+x)*3];
terrain[x][z][2] = -float(z)*MAP_SCALE;
}
}
}

bool LoadTextures()
{
//load the land-texture data
landTexture = LoadBitmapFile("test2.bmp", &amp;landInfo);
if (!landTexture)
return false;

//load the water-texture data
waterTexture = LoadBitmapFile("water.bmp", &amp;waterInfo);
if (!waterTexture)
return false;

//generate the land texture as a mipmap
glGenTextures(1, &amp;land);
glBindTexture(GL_TEXTURE_2D, land);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, landInfo.biWidth, landInfo.biHeight, GL_RGB, GL_UNSIGNED_BYTE, landTexture);

//generate the water texture as a mipmap
glGenTextures(1, &amp;water);
glBindTexture(GL_TEXTURE_2D, water);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, waterInfo.biWidth, waterInfo.biHeight, GL_RGB, GL_UNSIGNED_BYTE, waterTexture);

return true;
}

void Render()
{
radians = float(PI*(angle-90.0f)/180.0f);

//calculate the camera's position
cameraX = lookX + sin(radians)*mouseY; //multiplying by mouseY makes the
cameraZ = lookZ + cos(radians)*mouseY; //camera get closer/
//farther away with mouseY
cameraY = lookY + mouseY/2.0f;

//calculate the camera look-at cooridnates as the center of the terrain map
lookX = (MAP_X*MAP_SCALE)/2.0f;
lookY = 150.0f;
lookZ = -(MAP_Z*MAP_SCALE)/2.0f;

//clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

//set the camera position
gluLookAt(cameraX, cameraY, cameraZ, lookX, lookY, lookZ, 0.0, 1.0, 0.0);

//set the current texture to the land texture
glBindTexture(GL_TEXTURE_2D, land);

//we are going to loop through all of our terrain's data points,
//but we only want to draw one triangle strip for each set along the x axis.
for (int z = 0; z < MAP_Z-1; z++ )
{
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < MAP_X-1; x++ )
{
//for each vertex, we calculate the grayscale shade color,
//we set the texture coordinate, and we draw the vertex.

/*
the vertices are drawn in this order:

0 --->1
/
/
/
2 --->3
*/

//draw vertex 0
glColor3f(terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(terrain[x][z][0], terrain[x][z][1], terrain[x][z][2]);

//draw vertex 1
glTexCoord2f(1.0f,0.0f);
glColor3f(terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f);
glVertex3f(terrain[x+1][z][0], terrain[x+1][z][1], terrain[x+1][z][2]);

//draw vertex 2
glTexCoord2f(0.0f,1.0f);
glColor3f(terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f);
glVertex3f(terrain[x][z+1][0], terrain[x][z+1][1], terrain[x][z+1][2]);

//draw vertex 3
glColor3f(terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f);
glTexCoord2f(1.0f,1.0f);
glVertex3f(terrain[x+1][z+1][0], terrain[x+1][z+1][1], terrain[x+1][z+1][2]);
}
glEnd();
}

//enable blending
glEnable(GL_BLEND);

//enable read-only depth buffer
glDepthMask(GL_FALSE);

//set the blend function to what we use for transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

glColor4f(0.5f, 0.5f, 1.0f, 0.7f); //set color to a transparent blue
glBindTexture(GL_TEXTURE_2D, water); //set texture to the water texture

//draw water as one large quad surface
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); //lower-left corner
glVertex3f(terrain[0][0][0], waterHeight, terrain[0][0][2]);

glTexCoord2f(10.0f, 0.0f); //lower-right corner
glVertex3f(terrain[MAP_X-1][0][0], waterHeight, terrain[MAP_X-1][0][2]);

glTexCoord2f(10.0f, 10.0f); //upper-right corner
glVertex3f(terrain[MAP_X-1][MAP_Z-1][0], waterHeight, terrain[MAP_X-1][MAP_Z-1][2]);

glTexCoord2f(10.0f, 10.0f); //upper-left corner
glVertex3f(terrain[0][MAP_Z-1][0], waterHeight, terrain[0][MAP_Z-1][2]);
glEnd();

//set back to normal depth buffer mode (writeable)
glDepthMask(GL_TRUE);

//disable blending
glDisable(GL_BLEND);

//animate the water
if( waterHeight > 155.0f )
waterDir = false;
else if( waterHeight < 154.0f )
waterDir = true;

if( waterDir )
waterHeight += 0.01f;
else
waterHeight -= 0.01f;

glFlush();
SwapBuffers(g_HDC); //bring back buffer to foreground
}

void Initialize()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //clear to black
glShadeModel(GL_SMOOTH); //use smooth shading
glEnable(GL_DEPTH_TEST); //hidden surface removal
glEnable(GL_CULL_FACE); //do not calculate inside of polys
glFrontFace(GL_CCW); //counterclockwise polygons are out

glEnable(GL_TEXTURE_2D); //enable 2D texturing
imageData = LoadBitmapFile("test2.bmp", &amp;bitmapInfoHeader);

//initialize the terrain data and load the textures
InitializeTerrain();
LoadTextures();
}
// the main windows entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX windowClass; // window class
HWND hwnd; // window handle
MSG msg; // message
bool done; // flag saying when our app is complete
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
RECT windowRect;

// temp var's
int width = 800;
int height = 600;
int bits = 32;

fullScreen = FALSE;

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 the window class structure
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // default icon
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // default arrow
windowClass.hbrBackground = NULL; // don't need background
windowClass.lpszMenuName = NULL; // no menu
windowClass.lpszClassName = "MyClass";
windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // windows logo small icon

// register the windows class
if (!RegisterClassEx(&amp;windowClass))
return 0;

if (fullScreen) // fullscreen?
{
DEVMODE dmScreenSettings; // device mode
memset(&amp;dmScreenSettings,0,sizeof(dmScreenSettings ));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width; // screen width
dmScreenSettings.dmPelsHeight = height; // screen height
dmScreenSettings.dmBitsPerPel = bits; // bits per pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWID TH|DM_PELSHEIGHT;

//
if (ChangeDisplaySettings(&amp;dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
// setting display mode failed, switch to windowed
MessageBox(NULL, "Display mode failed", NULL, MB_OK);
fullScreen=FALSE;
}
}

if (fullScreen) // Are We Still In Fullscreen Mode?
{
dwExStyle=WS_EX_APPWINDOW; // Window Extended Style
dwStyle=WS_POPUP; // Windows Style
ShowCursor(FALSE); // Hide Mouse Pointer
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style
}

AdjustWindowRectEx(&amp;windowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size

// class registered, so now create our window
hwnd = CreateWindowEx(NULL, // extended style
"MyClass", // class name
"OpenGL Application", // app name
dwStyle | WS_CLIPCHILDREN |
WS_CLIPSIBLINGS,
0, 0, // x,y coordinate
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top, // width, height
NULL, // handle to parent
NULL, // handle to menu
hInstance, // application instance
NULL); // no extra params

// check if window creation failed (hwnd would equal NULL)
if (!hwnd)
return 0;

ShowWindow(hwnd, SW_SHOW); // display the window
UpdateWindow(hwnd); // update the window

done = false; // intialize the loop condition variable

//BITMAPINFOHEADER bitmapInfoHeader; //bitmap info header
//unsigned char* bitmapData; //the bitmap data

//bitmapData = LoadBitmapFile("test.bmp", &amp;bitmapInfoHeader);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//glRasterPos2i(100,100);
//glDrawPixels(bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);

Initialize();

// main message loop
while (!done)
{
PeekMessage(&amp;msg, hwnd, NULL, NULL, PM_REMOVE);

if (msg.message == WM_QUIT) // do we receive a WM_QUIT message?
done = true; // if so, time to quit the application
else
{
// do rendering here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear screen and depth buffer
glLoadIdentity(); // reset modelview matrix

//angle = angle + 0.1f; // increase our rotation angle counter
//if (angle >= 360.0f) // if we've gone in a circle, reset counter
//angle = 0.0f;

Render();
SwapBuffers(g_HDC); // bring backbuffer to foreground

TranslateMessage(&amp;msg); // translate and dispatch to event queue
DispatchMessage(&amp;msg);
}
}

if (fullScreen)
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}

return msg.wParam;
}

jide
04-13-2006, 03:36 AM
If you can target some portions of your code it might help.

earthquad
04-13-2006, 08:51 AM
agreed. this is definitely a case of "less is more".

at a glance one problem area is you strip loop. when you run across your strip rows (or columns) there's no need to issue 4 vertex commands, only 2. try doing your zigzag from (x,z) to (x,z+1), or from (x,z+1) to (x,z), where x is in [0,xmax] and z is in [0,zmax) (since we add 1 to z).

surely it wasn't in the book this way.

scryedzxp
04-13-2006, 09:51 AM
Sorry about that, guys. These functions are the ones that deal with the heightfield (I took the camera code out, as well). As for the strip loop, that's how it is in the book.



#define WIN32_LEAN_AND_MEAN // trim the excess fat from Windows

////// Includes
#include <windows.h> // standard Windows app include
#include <gl/gl.h> // standard OpenGL include
#include <gl/glu.h> // OpenGL utilties
//#include <gl/glaux.h> // OpenGL auxiliary functions
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

////// Defines
#define BITMAP_ID 0x4D42
#define MAP_X 32
#define MAP_Z 32
#define MAP_SCALE 20.0f
#define PI 3.14159

////// Global Variables
HDC g_HDC; // global device context
bool fullScreen = false; //true = full screen; false = windowed
bool keyPressed[256]; //holds true for keys that are pressed

float angle = 0.0f; //camera angle
float radians = 0.0f; //camera angle in radians
float waterHeight = 154.0f; //height of water
bool waterDir = true; //used to animate water
//true = up, false = down

////// Textrue Information
BITMAPINFOHEADER bitmapInfoHeader; //temp bitmap info header
BITMAPINFOHEADER landInfo; //land texture info header
BITMAPINFOHEADER waterInfo; //water texture info header

unsigned char* imageData; //the map image data
unsigned char* landTexture; //land texture data
unsigned char* waterTexture; //water texture data
unsigned int land; //the land texture object
unsigned int water; //the water texture object

////// Terrain Data
float terrain[MAP_X][MAP_Z][3];

unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER * bitmapInfoHeader)
{
FILE *filePtr; //the file pointer
BITMAPFILEHEADER bitmapFileHeader; //bitmap file header
unsigned char *bitmapImage; //bitmap image data
int imageIdx = 0; //image index counter
unsigned char tempRGB; //swap variable

//open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if( filePtr == NULL)
return NULL;

//read the bitmap file header
fread(&amp;bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);

//verify that this is a bitmap by checking for the universal bitmap id
if( bitmapFileHeader.bfType != BITMAP_ID )
{
fclose(filePtr);
return NULL;
}

//read the bitmap information header
fread(bitmapInfoHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);

//move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);

//allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);

//verify memory allocation
if(!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}

//read in the bitmap image data
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);

//make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
return NULL;
}

//swap the R and B values to get RGB since the bitmap color format is in BGR
for( imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3 )
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}

//close the file and return the bitmap image data
fclose(filePtr);

return bitmapImage;
}

void InitializeTerrain()
{
// loop through all of the heightfield points, calculating the coordinates for each point
for (int z = 0; z < MAP_Z; z++)
{
for (int x = 0; x < MAP_X; x++)
{
terrain[x][z][0] = float(x)*MAP_SCALE;
terrain[x][z][1] = (float)imageData[(z*MAP_Z+x)*3];
terrain[x][z][2] = -float(z)*MAP_SCALE;
}
}
}

bool LoadTextures()
{
//load the land-texture data
landTexture = LoadBitmapFile("test2.bmp", &amp;landInfo);
if (!landTexture)
return false;

//load the water-texture data
waterTexture = LoadBitmapFile("water.bmp", &amp;waterInfo);
if (!waterTexture)
return false;

//generate the land texture as a mipmap
glGenTextures(1, &amp;land);
glBindTexture(GL_TEXTURE_2D, land);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, landInfo.biWidth, landInfo.biHeight, GL_RGB, GL_UNSIGNED_BYTE, landTexture);

//generate the water texture as a mipmap
glGenTextures(1, &amp;water);
glBindTexture(GL_TEXTURE_2D, water);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, waterInfo.biWidth, waterInfo.biHeight, GL_RGB, GL_UNSIGNED_BYTE, waterTexture);

return true;
}

void Render()
{
//clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

//set the current texture to the land texture
glBindTexture(GL_TEXTURE_2D, land);

//we are going to loop through all of our terrain's data points,
//but we only want to draw one triangle strip for each set along the x axis.
for (int z = 0; z < MAP_Z-1; z++ )
{
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < MAP_X-1; x++ )
{
//for each vertex, we calculate the grayscale shade color,
//we set the texture coordinate, and we draw the vertex.

/*
the vertices are drawn in this order:

0 --->1
/
/
/
2 --->3
*/

//draw vertex 0
glColor3f(terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(terrain[x][z][0], terrain[x][z][1], terrain[x][z][2]);

//draw vertex 1
glTexCoord2f(1.0f,0.0f);
glColor3f(terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f);
glVertex3f(terrain[x+1][z][0], terrain[x+1][z][1], terrain[x+1][z][2]);

//draw vertex 2
glTexCoord2f(0.0f,1.0f);
glColor3f(terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f);
glVertex3f(terrain[x][z+1][0], terrain[x][z+1][1], terrain[x][z+1][2]);

//draw vertex 3
glColor3f(terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f);
glTexCoord2f(1.0f,1.0f);
glVertex3f(terrain[x+1][z+1][0], terrain[x+1][z+1][1], terrain[x+1][z+1][2]);
}
glEnd();
}

//enable blending
glEnable(GL_BLEND);

//enable read-only depth buffer
glDepthMask(GL_FALSE);

//set the blend function to what we use for transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

glColor4f(0.5f, 0.5f, 1.0f, 0.7f); //set color to a transparent blue
glBindTexture(GL_TEXTURE_2D, water); //set texture to the water texture

//draw water as one large quad surface
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); //lower-left corner
glVertex3f(terrain[0][0][0], waterHeight, terrain[0][0][2]);

glTexCoord2f(10.0f, 0.0f); //lower-right corner
glVertex3f(terrain[MAP_X-1][0][0], waterHeight, terrain[MAP_X-1][0][2]);

glTexCoord2f(10.0f, 10.0f); //upper-right corner
glVertex3f(terrain[MAP_X-1][MAP_Z-1][0], waterHeight, terrain[MAP_X-1][MAP_Z-1][2]);

glTexCoord2f(10.0f, 10.0f); //upper-left corner
glVertex3f(terrain[0][MAP_Z-1][0], waterHeight, terrain[0][MAP_Z-1][2]);
glEnd();

//set back to normal depth buffer mode (writeable)
glDepthMask(GL_TRUE);

//disable blending
glDisable(GL_BLEND);

//animate the water
if( waterHeight > 155.0f )
waterDir = false;
else if( waterHeight < 154.0f )
waterDir = true;

if( waterDir )
waterHeight += 0.01f;
else
waterHeight -= 0.01f;

glFlush();
SwapBuffers(g_HDC); //bring back buffer to foreground
}

void Initialize()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //clear to black
glShadeModel(GL_SMOOTH); //use smooth shading
glEnable(GL_DEPTH_TEST); //hidden surface removal
glEnable(GL_CULL_FACE); //do not calculate inside of polys
glFrontFace(GL_CCW); //counterclockwise polygons are out

glEnable(GL_TEXTURE_2D); //enable 2D texturing
imageData = LoadBitmapFile("test2.bmp", &amp;bitmapInfoHeader);

//initialize the terrain data and load the textures
InitializeTerrain();
LoadTextures();
}

earthquad
04-13-2006, 11:51 AM
which book did you take this code from?

one of these?

http://glbook.gamedev.net/

Mars_999
04-13-2006, 12:11 PM
If you can post a screeshot that would help out alot...

scryedzxp
04-13-2006, 12:56 PM
earthquad, yes. it's the one entitled 'OpenGL Game Programming'

Mars_9999, of what?

jide
04-13-2006, 01:21 PM
Of you smiling near your computer :D

earthquad
04-13-2006, 01:24 PM
well, there's a beginning opengl game programming, more opengl game programming, just plain opengl game programming, and last, but certainly not least, opengl es game development. although i'm pretty sure you aren't referring to the latter.

Mars_999
04-13-2006, 02:30 PM
Originally posted by scryedzxp:
earthquad, yes. it's the one entitled 'OpenGL Game Programming'

Mars_9999, of what? Of what the messed up rendering looks like. If you can't host it use

http://imageshack.us/

to host a screenshot.

scryedzxp
04-13-2006, 03:18 PM
very very weird. I didn't save the changes I made yesterday so I applied the same changes just a couple of minutes ago and the horizontal bars are gone! However, it still looks weird. What's going on?

earthquad, it's the plain opengl game programming.

Mars_9999, here's the new results:
http://img212.imageshack.us/img212/9788/results7xh.png

I really think it has something to do with the bitmaps I'm using. Here's what they look like:
(test2.bmp)
http://img133.imageshack.us/img133/3858/test22nu.png

(land.bmp)
http://img73.imageshack.us/img73/2841/land1on.png

(water.bmp)
http://img73.imageshack.us/img73/5177/water1fc.png

The 3 bitmaps are 32x31. The book says to use 32x32, but I really don't think it matters.

Joe the Programmer
04-14-2006, 04:17 PM
I always thought that bitmap dimensions had to be in powers of 2.

Serge K
04-15-2006, 12:15 AM
> fread(bitmapInfoHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
> ...
> bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);

Is it a typo? (shouldn't it be BITMAPINFOHEADER?)
Even if it is BITMAPINFOHEADER - using biSizeImage still make no sense.
This field is normally used to store the compressed size, for bitmaps without compression biSizeImage is often ==0.
(and malloc(0) does produce valid pointer...)


> //swap the R and B values to get RGB since the bitmap color format is in BGR

What for? :confused:
Just use GL_BGR as format of the pixel data.
(or GL_BGR_EXT if you stuck with OpenGL 1.1 header)


> for( imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3 )
Besides using biSizeImage, this is ok - in case if the image width is multiplie of 4.


> The 3 bitmaps are 32x31. The book says to use 32x32, but I really don't think it matters.

As long as you call gluBuild2DMipmaps - it should work even if there is no support for non-power-of-2 textures.
It does resampling itself.

scryedzxp
04-15-2006, 07:23 PM
I got it working. Thanks for the help, Serge K. The book I was using had so many typos in it.