3dObjectTerrain.cpp
资源名称:gloop.zip [点击查看]
上传用户:shxiangxiu
上传日期:2007-01-03
资源大小:1101k
文件大小:49k
源码类别:
OpenGL
开发平台:
Visual C++
- /////////////////////////////////////////////////////////////////////////////
- // 3dObjectTerrain.cpp : implementation file
- //
- // glOOP (OpenGL Object Oriented Programming library)
- // Copyright (c) Craig Fahrnbach, ImageWare Development, 1997-1999
- // All rights reserved.
- //
- // OpenGL is a registered trademark of Silicon Graphics
- //
- //
- // This program is provided for educational and personal use only and
- // is provided without guarantee or warrantee expressed or implied.
- //
- // Commercial use is strickly prohibited without written permission
- // from ImageWare Development.
- //
- // This program is -not- in the public domain.
- //
- // Adapted from source code, with permission, by: Paul E. Martz
- /////////////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "glOOP.h"
- #include "3dObjectDialog.h"
- #include <math.h>
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- //////////////////////////////////////////////////////////////////
- // C3dObjectTerrain
- IMPLEMENT_DYNAMIC(C3dObjectTerrain, C3dObject)
- /////////////////////////////////////////////////////////////////////////////
- // C3dShape construction
- C3dObjectTerrain::C3dObjectTerrain()
- {
- // Set the attributes to default values..
- m_iType = SHAPE_OBJECT;
- m_szName.Format("Terrain %u", nTerrainObjects++);
- m_bSolidColor = FALSE;
- m_bSmoothNormals = TRUE;
- m_bReflect = FALSE;
- m_bMapTexturesToSubGrid = FALSE;
- m_bApplySubGridTextures = FALSE;
- m_pTextureSnow = NULL;
- m_pTextureRock = NULL;
- m_pTextureGrass = NULL;
- m_pTextureWater = NULL;
- m_iSize = 32;
- m_iTile = 1;
- m_fDepth = 50.0f;
- m_fWidth = 50.0f;
- m_fHeight = 1.1f;
- m_iHeightSeed = 0;
- m_fSeaLevel = 0.3f;
- m_iTerrainGridDisplayList = 0;
- m_iTexImageMap = 0;
- m_ColorSnow.SetColor4f(.95f, .95f, 1.f, 0.f); // White
- m_ColorRock.SetColor4f(.55f, .55f, .6f, 0.f); // Gray
- m_ColorGrass.SetColor4f(.2f, .4f, .2f, 0.f); // Green
- m_ColorWater.SetColor4f(.0f, .25f, .85f, 0.f); // Blue
- // Create our C3dPointArray object
- m_pPointArray = new C3dPointArray;
- ASSERT(m_pPointArray);
- // Create an array of points for our vertices
- if(m_pPointArray->Create((m_iSize+1)*(m_iSize+1)))
- {
- AfxMessageBox("Not enough memory to create array points!", MB_OK);
- m_pPointArray = NULL;
- return;
- }
- // Initialize our terrain vertices (points)
- InitTerrain();
- }
- /////////////////////////////////////////////////////////////////////////////
- // C3DWorld Destructor
- C3dObjectTerrain::~C3dObjectTerrain()
- {
- // Delete our point array
- if(m_pPointArray)
- delete m_pPointArray;
- // Delete our texture maps
- if(m_pTextureSnow)
- DeleteSubTexture(m_pTextureSnow);
- if(m_pTextureRock)
- DeleteSubTexture(m_pTextureRock);
- if(m_pTextureGrass)
- DeleteSubTexture(m_pTextureGrass);
- if(m_pTextureWater)
- DeleteSubTexture(m_pTextureWater);
- // Delete the Terrain Grid DisplayList
- if(m_iTerrainGridDisplayList)
- {
- glDeleteLists(m_iTerrainGridDisplayList, 1);
- m_iTerrainGridDisplayList = 0;
- }
- // Delete the Terrain Image Texturemap
- if(m_iTexImageMap)
- {
- glDeleteLists(m_iTexImageMap, 1);
- m_iTexImageMap = 0;
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- // C3dObjectTerrain Methods or virtual function implimentation
- void C3dObjectTerrain::AddAttributePage(C3dWorld* pWorld, LPVOID pSht)
- {
- C3dObjectPropSheet* pSheet = (C3dObjectPropSheet*)pSht;
- ASSERT(pSheet);
- // Add the page to the property sheet
- pSheet->AddPage(&pSheet->m_TerrainPage);
- // Save the address of this object in the page
- pSheet->m_TerrainPage.m_pObject = this;
- // Add the page to the property sheet
- pSheet->AddPage(&pSheet->m_TerrainColorPage);
- // Save the address of this object in the page
- pSheet->m_TerrainColorPage.m_pObject = this;
- pSheet->m_TerrainColorPage.m_pWorld = pWorld;
- // Add the page to the property sheet
- pSheet->AddPage(&pSheet->m_TerrainTexturePage);
- // Save the address of this object in the page
- pSheet->m_TerrainTexturePage.m_pObject = this;
- }
- int C3dObjectTerrain::LoadBitMapImage(CImageList* pList)
- {
- CBitmap bitmap;
- // If the image index has been stored in this object,
- // return the index.
- if(m_iBMImage > -1)
- return m_iBMImage;
- // If the image index for this object type has been
- // created, store the index for this object and
- // return the index.
- if( iObjectTerrainBMImage > -1) {
- m_iBMImage = iObjectTerrainBMImage;
- return m_iBMImage;
- }
- // The image index for this object type has not been
- // loaded and the object image index has not been
- // stored.
- //
- // Load the bitmap for the non-selected object
- bitmap.LoadBitmap(IDB_OBJECT_TERRAIN);
- m_iBMImage = pList->Add(&bitmap, (COLORREF)0xFFFFFF);
- bitmap.DeleteObject();
- // Load the bitmap for the non-selected object
- bitmap.LoadBitmap(IDB_OBJECT_TERRAIN_SELECTED);
- pList->Add(&bitmap, (COLORREF)0xFFFFFF);
- bitmap.DeleteObject();
- iObjectTerrainBMImage = m_iBMImage;
- return m_iBMImage;
- }
- void C3dObjectTerrain::GetShapeBounds(C3dBoundingBox* pBox)
- {
- if(m_pPointArray)
- m_pPointArray->GetMinMax(pBox);
- // We need to calculate the overall size of the object based
- // on the number of times we have tiled the basic shape
- pBox->m_fMax[X] *= m_iTile;
- pBox->m_fMax[Y] *= m_iTile;
- pBox->m_fMin[X] *= m_iTile;
- pBox->m_fMin[Y] *= m_iTile;
- }
- void C3dObjectTerrain::Serialize(CArchive& ar, int iVersion)
- {
- CString szBuffer;
- if (ar.IsStoring())
- {
- // Save the Object Class header...
- szBuffer.Format("n%sC3dObjectTerrain {n", szIndent);
- ar.WriteString(szBuffer);
- // Save the this objects' specific data...
- szBuffer.Format("%stDepth < %f >n", szIndent, m_fDepth);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stWidth < %f >n", szIndent, m_fWidth);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stHeight < %f >n", szIndent, m_fHeight);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stHeight Seed < %d >n", szIndent, m_iHeightSeed);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stTile < %d >n", szIndent, m_iTile);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stReflectLight < %d >n", szIndent, m_bReflect);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stArraySize < %d >n", szIndent, m_iSize);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stSolid Color < %d >n", szIndent, m_bSolidColor);
- ar.WriteString(szBuffer);
- szBuffer.Format("%stNum Points < %d >n", szIndent, m_pPointArray->m_iNumPoints);
- ar.WriteString(szBuffer);
- for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
- {
- szBuffer.Format("%stt < %f, %f, %f >n", szIndent, m_pPointArray->m_pPoints[i].m_fOrigin[0],
- m_pPointArray->m_pPoints[i].m_fOrigin[1],
- m_pPointArray->m_pPoints[i].m_fOrigin[2]);
- ar.WriteString(szBuffer);
- }
- if(!m_bSolidColor)
- {
- szBuffer.Format("%st[color]n", szIndent);
- ar.WriteString(szBuffer);
- for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
- {
- szBuffer.Format("%stt < %f, %f, %f, %f >n", szIndent, m_pPointArray->m_pPoints[i].m_Color.m_fColor[0],
- m_pPointArray->m_pPoints[i].m_Color.m_fColor[1],
- m_pPointArray->m_pPoints[i].m_Color.m_fColor[2],
- m_pPointArray->m_pPoints[i].m_Color.m_fColor[3]);
- ar.WriteString(szBuffer);
- }
- }
- // Save the base class object data...
- C3dObject::Serialize(ar, iVersion);
- szBuffer.Format("%s}n", szIndent); // end of object def
- ar.WriteString(szBuffer);
- }
- else
- {
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft(); // Remove leading white spaces
- sscanf(szBuffer, "Depth < %f >n", &m_fDepth);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "Width < %f >n", &m_fWidth);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "Height < %f >n", &m_fHeight);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "Height Seed < %d >n", &m_iHeightSeed);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "Tile < %d >n", &m_iTile);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "ReflectLight < %d >n", &m_bReflect);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "ArraySize < %d >n", &m_iSize);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "Solid Color < %d >n", &m_bSolidColor);
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "Num Points < %d >n", &m_pPointArray->m_iNumPoints);
- // Resize our control point array
- if(m_pPointArray->SetArraySize(m_pPointArray->m_iNumPoints))
- {
- AfxMessageBox("Not enough memory to create array points!", MB_OK);
- m_pPointArray = NULL;
- return;
- }
- // Read the shape vertice, or point data
- for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
- {
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "< %f, %f, %f >n", &m_pPointArray->m_pPoints[i].m_fOrigin[X],
- &m_pPointArray->m_pPoints[i].m_fOrigin[Y],
- &m_pPointArray->m_pPoints[i].m_fOrigin[Z]);
- }
- if(!m_bSolidColor)
- {
- ar.ReadString(szBuffer); // [color] header
- // Read the shape vertice, or point data
- for(int i=0; i<m_pPointArray->m_iNumPoints; i++)
- {
- ar.ReadString(szBuffer);
- szBuffer.TrimLeft();
- sscanf(szBuffer, "< %f, %f, %f, %f >n", &m_pPointArray->m_pPoints[i].m_Color.m_fColor[0],
- &m_pPointArray->m_pPoints[i].m_Color.m_fColor[1],
- &m_pPointArray->m_pPoints[i].m_Color.m_fColor[2],
- &m_pPointArray->m_pPoints[i].m_Color.m_fColor[3]);
- }
- // Initialize our terrain color height values
- InitColorHeightValues();
- }
- // Read the base class object data...
- C3dObject::Serialize(ar, iVersion);
- }
- }
- void C3dObjectTerrain::DisplayPoints(C3dWorld* pWorld, C3dCamera* pCamera)
- {
- static BOOL bDisplayMsg = TRUE;
- if(m_iTile>1 && bDisplayMsg)
- {
- AfxMessageBox("To edit the Terrain object points, the 'Tile' membern"
- "variable must be set to one.", MB_OK);
- // Display the message only once per session
- bDisplayMsg = FALSE;
- return;
- }
- if(m_iTile==1)
- {
- // Display all points in our object
- if(m_pPointArray)
- {
- if(m_pPointArray->m_pPoints)
- m_pPointArray->Display(pWorld, pCamera, this, 5.0f, FALSE);
- }
- }
- }
- void C3dObjectTerrain::Build(C3dWorld* pWorld, C3dCamera* pCamera)
- {
- static int iterations = 0;
- static BOOL textureLinear = FALSE;
- GLfloat x, y;
- int i, j;
- if(m_pPointArray == NULL)
- return;
- // This may take a while, so display an hour glass cursor
- CWaitCursor hourglass;
- // The following code is my initial attempt a multi-pass texturing.
- // The intention is to initially generate the image, with the objects
- // texture map, into our m_iTexImageMap texture map. After the initial
- // texture is generated, we will then texture map this image onto the
- // terrain image with m_bReflect set appropriately.
- if(iterations && pWorld && pCamera)
- {
- // Render our initial Terrain and generate our m_iTexImageMap
- // Texture map, rendered using our C3dObject pTexture image
- // if created. (Set prior to calling this function.)
- RenderTextureImageMap(pWorld, pCamera);
- // Playing with sub texture maps
- // RenderTextureMaps();
- // Goes a little faster but looks like crud:
- //glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, (GLfloat) GL_REPLACE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- textureLinear ? (GLfloat) GL_LINEAR : (GLfloat) GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
- textureLinear ? (GLfloat) GL_LINEAR : (GLfloat) GL_NEAREST);
- // Enable Texture mapping, as it may be off at this time
- glEnable (GL_TEXTURE_2D);
- }
- // Build the final display list
- RenderTerrain(TRUE, m_bReflect);
- // Compile and build the list
- glNewList(m_iDisplayLists, GL_COMPILE_AND_EXECUTE);
- // Center our tiled image about the objects' origin
- glPushMatrix();
- glTranslatef((GLfloat)(m_fWidth * (GLfloat)(m_iTile-1))/2.0f,
- (GLfloat)(m_fDepth * (GLfloat)(m_iTile-1))/2.0f,
- 0.0f);
- y = -m_fDepth * (GLfloat)(m_iTile-1);
- for (i=0; i<m_iTile; i++)
- {
- x = -m_fWidth * (GLfloat)(m_iTile-1);
- for (j=0; j<m_iTile; j++)
- {
- glPushMatrix();
- glTranslatef(x, y, 0.0f);
- if(m_iTerrainGridDisplayList)
- glCallList(m_iTerrainGridDisplayList);
- glPopMatrix ();
- x += m_fWidth;
- }
- y += m_fDepth;
- }
- glPopMatrix();
- glEndList();
- // Restore the cursor to its' default
- hourglass.Restore();
- }
- /////////////////////////////////////////////////////////////////////////////
- // C3dObjectTerrain Methods or Implementation
- void C3dObjectTerrain::CopyParameters(C3dObjectTerrain* pObj)
- {
- // Copy this objects parameters to the given terrain object.
- // This function is used by the CPageTerrainColor preview
- // window.
- pObj->m_bApplySubGridTextures = m_bApplySubGridTextures;
- pObj->m_bMapTexturesToSubGrid = m_bMapTexturesToSubGrid;
- pObj->m_bReflect = m_bReflect;
- pObj->m_bSolidColor = m_bSolidColor;
- pObj->m_bSmoothNormals = m_bSmoothNormals;
- pObj->m_fSeaLevel = m_fSeaLevel;
- pObj->m_iHeightSeed = m_iHeightSeed;
- // Since this function is used by the preview window, we want
- // the image to fit 'mostly' within the window, so we will
- // use our default settings. We also want to conserve memory
- // so we will use the default array size setting.
- // pObj->m_fDepth = m_fDepth;
- // pObj->m_fWidth = m_fWidth;
- // pObj->m_fHeight = m_fHeight;
- // pObj->m_iSize = m_iSize;
- pObj->m_ColorSnow.SetColor4fv(&m_ColorSnow);
- pObj->m_ColorRock.SetColor4fv(&m_ColorRock);
- pObj->m_ColorGrass.SetColor4fv(&m_ColorGrass);
- pObj->m_ColorWater.SetColor4fv(&m_ColorWater);
- pObj->m_Color.SetColor4fv(&m_Color);
- }
- void C3dObjectTerrain::RenderTerrain(BOOL bCreateList, BOOL bReflect)
- {
- const int subSize = m_iSize;
- int i, j;
- if(!m_iTerrainGridDisplayList)
- m_iTerrainGridDisplayList = glGenLists(1);// Create the DisplayList(s)
- if(bCreateList)
- {
- // Compile and build the list
- glNewList(m_iTerrainGridDisplayList, GL_COMPILE);
- // Call our TerrainTexImageMap as the Texture map
- glCallList (m_iTexImageMap);
- for (i=0; i<subSize; i++)
- {
- for (j=0; j<subSize; j++)
- {
- DisplayAsTriangleStrip(i, j, bReflect);
- // Multi-level texturing worked best displayed as triangles..
- // DisplayAsTriangles(i, j, bReflect);
- }
- }
- glEndList();
- }
- else
- {
- for (i=0; i<subSize; i++)
- {
- for (j=0; j<subSize; j++)
- DisplayAsTriangleStrip(i, j, bReflect);
- }
- }
- }
- void C3dObjectTerrain::DisplayAsTriangles(int i, int j, BOOL bReflect)
- {
- VECTORF p0, p1, p2, p3, normal[4];
- const int subSize = m_iSize, superSize = m_iSize+1;
- // Get the array points
- VecCopy3f (m_pPointArray->m_pPoints[ i*superSize+j].m_fOrigin, p0);
- VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j].m_fOrigin, p1);
- VecCopy3f (m_pPointArray->m_pPoints[ i*superSize+j+1].m_fOrigin, p2);
- VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j+1].m_fOrigin, p3);
- if(m_bSmoothNormals)
- {
- AvgNormals( i, j, m_pPointArray, &normal[0], TRUE);
- AvgNormals(i+1, j, m_pPointArray, &normal[1], TRUE);
- AvgNormals( i, j+1, m_pPointArray, &normal[2], TRUE);
- AvgNormals(i+1, j+1, m_pPointArray, &normal[3], TRUE);
- }
- else
- {
- CalNormalf(p2, p1, p0, normal[0]);
- CalNormalf(p1, p0, p2, normal[1]);
- CalNormalf(p0, p2, p1, normal[2]);
- CalNormalf(p3, p1, p2, normal[3]);
- }
- glBegin(GL_TRIANGLES);
- SetTextureList(p0, p1, p2);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f (0.f, 0.f);
- else
- SetTextureCoord(i, j);
- if(!m_bSolidColor)
- SetTerrainColor(i, j, bReflect);
- glNormal3fv(normal[0]);
- glVertex3fv(p0);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f (1.f, 0.f);
- else
- SetTextureCoord(i+1, j);
- if(!m_bSolidColor)
- SetTerrainColor(i+1, j, bReflect);
- glNormal3fv(normal[1]);
- glVertex3fv(p1);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f (0.f, 1.f);
- else
- SetTextureCoord(i, j+1);
- if(!m_bSolidColor)
- SetTerrainColor(i, j+1, bReflect);
- glNormal3fv(normal[2]);
- glVertex3fv(p2);
- glEnd();
- glBegin(GL_TRIANGLES);
- SetTextureList(p1, p2, p3);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f (1.f, 0.f);
- else
- SetTextureCoord(i+1, j);
- if(!m_bSolidColor)
- SetTerrainColor(i+1, j, bReflect);
- glNormal3fv(normal[1]);
- glVertex3fv(p1);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f (0.f, 1.f);
- else
- SetTextureCoord(i, j+1);
- if(!m_bSolidColor)
- SetTerrainColor(i, j+1, bReflect);
- glNormal3fv(normal[2]);
- glVertex3fv(p2);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f (1.f, 1.f);
- else
- SetTextureCoord(i+1, j+1);
- if(!m_bSolidColor)
- SetTerrainColor(i+1, j+1, bReflect);
- glNormal3fv(normal[3]);
- glVertex3fv(p3);
- glEnd ();
- }
- void C3dObjectTerrain::DisplayAsTriangleStrip(int i, int j, BOOL bReflect)
- {
- VECTORF p0, p1, p2, p3, normal[4];
- const int subSize = m_iSize, superSize = m_iSize+1;
- // Get the array points
- VecCopy3f (m_pPointArray->m_pPoints[ i*superSize+j].m_fOrigin, p0);
- VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j].m_fOrigin, p1);
- VecCopy3f (m_pPointArray->m_pPoints[ i*superSize+j+1].m_fOrigin, p2);
- VecCopy3f (m_pPointArray->m_pPoints[(i+1)*superSize+j+1].m_fOrigin, p3);
- if(m_bSmoothNormals)
- {
- AvgNormals( i, j, m_pPointArray, &normal[0], TRUE);
- AvgNormals(i+1, j, m_pPointArray, &normal[1], TRUE);
- AvgNormals( i, j+1, m_pPointArray, &normal[2], TRUE);
- AvgNormals(i+1, j+1, m_pPointArray, &normal[3], TRUE);
- }
- else
- {
- CalNormalf(p2, p1, p0, normal[0]);
- CalNormalf(p1, p0, p2, normal[1]);
- CalNormalf(p0, p2, p1, normal[2]);
- CalNormalf(p3, p1, p2, normal[3]);
- }
- glBegin (GL_TRIANGLE_STRIP);
- // SetTextureList(p0, p1, p2);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f(0.f, 0.f);
- else
- SetTextureCoord(i, j);
- if(!m_bSolidColor)
- SetTerrainColor(i, j, bReflect);
- glNormal3fv(normal[0]);
- glVertex3fv(p0);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f(1.f, 0.f);
- else
- SetTextureCoord(i+1, j);
- if(!m_bSolidColor)
- SetTerrainColor(i+1, j, bReflect);
- glNormal3fv(normal[1]);
- glVertex3fv(p1);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f(0.f, 1.f);
- else
- SetTextureCoord(i, j+1);
- if(!m_bSolidColor)
- SetTerrainColor(i, j+1, bReflect);
- glNormal3fv(normal[2]);
- glVertex3fv(p2);
- // SetTextureList(p1, p2, p3);
- if(m_bApplySubGridTextures || m_bMapTexturesToSubGrid)
- glTexCoord2f(1.f, 1.f);
- else
- SetTextureCoord(i+1, j+1);
- if(!m_bSolidColor)
- SetTerrainColor(i+1, j+1, bReflect);
- glNormal3fv(normal[3]);
- glVertex3fv(p3);
- glEnd ();
- }
- void C3dObjectTerrain::RenderTextureMaps()
- {
- // Render our multi-level texture maps
- if(m_pTextureSnow)
- // Apply the Dib Image to our shape..
- m_pTextureSnow->SetTexture();
- if(m_pTextureRock)
- // Apply the Dib Image to our shape..
- m_pTextureRock->SetTexture();
- if(m_pTextureGrass)
- // Apply the Dib Image to our shape..
- m_pTextureGrass->SetTexture();
- if(m_pTextureWater)
- // Apply the Dib Image to our shape..
- m_pTextureWater->SetTexture();
- }
- void C3dObjectTerrain::SetTextureCoord(int i, int j)
- {
- float steps = 1.0f/(float)(m_iSize+1);
- glTexCoord2f(i*steps, j*steps);
- }
- void C3dObjectTerrain::SetTextureList(VECTORF p1, VECTORF p2, VECTORF p3)
- {
- float aveHeight = (p1[Z]+p2[Z]+p3[Z])/3.0f;
- if(m_bMapTexturesToSubGrid)
- {
- if(aveHeight <= m_fWaterHeight)
- {
- if(m_pTextureWater)
- {
- m_pTextureWater->SetTexture();
- return;
- }
- }
- if(aveHeight <= m_fGrassHeight)
- {
- if(m_pTextureGrass)
- {
- m_pTextureGrass->SetTexture();
- return;
- }
- }
- if(aveHeight <= m_fRockHeight)
- {
- if(m_pTextureRock)
- {
- m_pTextureRock->SetTexture();
- return;
- }
- }
- if(aveHeight <= m_fSnowHeight)
- {
- if(m_pTextureSnow)
- {
- m_pTextureSnow->SetTexture();
- return;
- }
- }
- }
- // No Textures, so set our polygon mode to default
- // and disable texture maping.
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glDisable(GL_TEXTURE_2D);
- }
- void C3dObjectTerrain::InitTerrain()
- {
- float scale;
- // Calculate our scale based on its height & width
- scale = (m_fWidth+m_fHeight)/2;
- // Resize our control point array
- if(m_pPointArray->SetArraySize((m_iSize+1)*(m_iSize+1)))
- {
- AfxMessageBox("Not enough memory to create array points!", MB_OK);
- m_pPointArray = NULL;
- return; // function failed
- }
- FillFractualArray (m_pPointArray->m_pPoints, m_iSize, scale, m_fHeight);
- // Initialize our color components
- if(!m_bSolidColor)
- InitTerrainColor();
- }
- void C3dObjectTerrain::AvgNormals(int i, int j, C3dPointArray *fa, VECTORF* pNormal, BOOL bDiagonal)
- {
- VECTORF aveNormal, normals[6];
- VECTORF p1, p2, p3;
- int subSize = m_iSize+1;
- if(i==0 && j==0) // Bottom Left corner
- {
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normals for the other three corners
- AvgNormals(m_iSize, 0, fa, &normals[1], FALSE); // Bottom Right corner
- AvgNormals(m_iSize, m_iSize, fa, &normals[2], FALSE);// Top Right corner
- AvgNormals(0, m_iSize, fa, &normals[3], FALSE); // Top Left corner
- VecAddf(normals[0], normals[1], aveNormal);
- VecAddf(normals[2], aveNormal, aveNormal);
- VecAddf(normals[3], aveNormal, aveNormal);
- aveNormal[X] /= 4.0f;
- aveNormal[Y] /= 4.0f;
- aveNormal[Z] /= 4.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(normals[0], *pNormal);
- return;
- }
- if(i>=m_iSize && j==0) // Bottom Right Corner
- {
- // Average the two normals
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[1]);
- VecAddf(normals[0], normals[1], aveNormal);
- aveNormal[X] /= 2.0f;
- aveNormal[Y] /= 2.0f;
- aveNormal[Z] /= 2.0f;
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normals for the other three corners
- AvgNormals(m_iSize, m_iSize, fa, &normals[2], FALSE);// Top Right corner
- AvgNormals(0, m_iSize, fa, &normals[3], FALSE); // Top Left corner
- AvgNormals(0, 0, fa, &normals[4], FALSE); // Bottom Left corner
- VecAddf(normals[2], aveNormal, aveNormal);
- VecAddf(normals[3], aveNormal, aveNormal);
- VecAddf(normals[4], aveNormal, aveNormal);
- aveNormal[X] /= 4.0f;
- aveNormal[Y] /= 4.0f;
- aveNormal[Z] /= 4.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- if(j>=m_iSize && i>=m_iSize) // Top Right Corner
- {
- // Only one normal
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normals for the other three corners
- AvgNormals(0, m_iSize, fa, &normals[1], FALSE); // Top Left corner
- AvgNormals(0, 0, fa, &normals[2], FALSE); // Bottom Left corner
- AvgNormals(m_iSize, 0, fa, &normals[3], FALSE); // Bottom Right corner
- VecAddf(normals[0], normals[1], aveNormal);
- VecAddf(normals[2], aveNormal, aveNormal);
- VecAddf(normals[3], aveNormal, aveNormal);
- aveNormal[X] /= 4.0f;
- aveNormal[Y] /= 4.0f;
- aveNormal[Z] /= 4.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(normals[0], *pNormal);
- return;
- }
- if(i==0 && j>=m_iSize) // Top Left Corner
- {
- // Average two normals
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[1]);
- VecAddf(normals[0], normals[1], aveNormal);
- aveNormal[X] /= 2.0f;
- aveNormal[Y] /= 2.0f;
- aveNormal[Z] /= 2.0f;
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normals for the other three corners
- AvgNormals(0, 0, fa, &normals[2], FALSE); // Bottom Left corner
- AvgNormals(m_iSize, 0, fa, &normals[3], FALSE); // Bottom Right corner
- AvgNormals(m_iSize, m_iSize, fa, &normals[4], FALSE);// Top Right corner
- VecAddf(normals[2], aveNormal, aveNormal);
- VecAddf(normals[3], aveNormal, aveNormal);
- VecAddf(normals[4], aveNormal, aveNormal);
- aveNormal[X] /= 4.0f;
- aveNormal[Y] /= 4.0f;
- aveNormal[Z] /= 4.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- if(j==0 && i<m_iSize) // Bottom side
- {
- // Average the three bottom normals normals
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[1]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[2]);
- VecAddf(normals[0], normals[1], aveNormal);
- VecAddf(normals[2], aveNormal, aveNormal);
- aveNormal[X] /= 3.0f;
- aveNormal[Y] /= 3.0f;
- aveNormal[Z] /= 3.0f;
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normal for the array point on the Top side
- AvgNormals(i, m_iSize, fa, &normals[3], FALSE);
- VecAddf(normals[3], aveNormal, aveNormal);
- aveNormal[X] /= 2.0f;
- aveNormal[Y] /= 2.0f;
- aveNormal[Z] /= 2.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- if(i>=m_iSize && j<m_iSize) // Right Side
- {
- // Average the three side normals
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[1]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[2]);
- VecAddf(normals[0], normals[1], aveNormal);
- VecAddf(normals[2], aveNormal, aveNormal);
- aveNormal[X] /= 3.0f;
- aveNormal[Y] /= 3.0f;
- aveNormal[Z] /= 3.0f;
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normal for the array point on the Left side
- AvgNormals(0, j, fa, &normals[3], FALSE);
- VecAddf(normals[3], aveNormal, aveNormal);
- aveNormal[X] /= 2.0f;
- aveNormal[Y] /= 2.0f;
- aveNormal[Z] /= 2.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- if(j>=m_iSize && i<m_iSize) // Top side
- {
- // Average three normals
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[1]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[2]);
- VecAddf(normals[0], normals[1], aveNormal);
- VecAddf(normals[2], aveNormal, aveNormal);
- aveNormal[X] /= 3.0f;
- aveNormal[Y] /= 3.0f;
- aveNormal[Z] /= 3.0f;
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normal for the array point on the Bottom side
- AvgNormals(i, 0, fa, &normals[3], FALSE);
- VecAddf(normals[3], aveNormal, aveNormal);
- aveNormal[X] /= 2.0f;
- aveNormal[Y] /= 2.0f;
- aveNormal[Z] /= 2.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- if(i==0 && j<m_iSize) // Left Side
- {
- // Average the three normals on left side
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[1]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[2]);
- VecAddf(normals[0], normals[1], aveNormal);
- VecAddf(normals[2], aveNormal, aveNormal);
- aveNormal[X] /= 3.0f;
- aveNormal[Y] /= 3.0f;
- aveNormal[Z] /= 3.0f;
- if(m_iTile > 1 && bDiagonal)
- {
- // Get the average normal for the array point on the Right side
- AvgNormals(m_iSize, j, fa, &normals[3], FALSE);
- VecAddf(normals[3], aveNormal, aveNormal);
- aveNormal[X] /= 2.0f;
- aveNormal[Y] /= 2.0f;
- aveNormal[Z] /= 2.0f;
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- VecCopy3f(aveNormal, *pNormal);
- return;
- }
- // Point is not on sides of our terrain, so average all
- // six normals.
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[0]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[1]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j+1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[2]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i-1)*subSize+j].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[3]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[i*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[4]);
- VecCopy3f (fa->m_pPoints[i*subSize+j].m_fOrigin, p1);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j-1].m_fOrigin, p2);
- VecCopy3f (fa->m_pPoints[(i+1)*subSize+j].m_fOrigin, p3);
- CalNormalf(p1, p3, p2, normals[5]);
- VecAddf(normals[0], normals[1], aveNormal);
- VecAddf(normals[2], aveNormal, aveNormal);
- VecAddf(normals[3], aveNormal, aveNormal);
- VecAddf(normals[4], aveNormal, aveNormal);
- VecAddf(normals[5], aveNormal, aveNormal);
- aveNormal[X] /= 6.0f;
- aveNormal[Y] /= 6.0f;
- aveNormal[Z] /= 6.0f;
- VecCopy3f(aveNormal, *pNormal);
- }
- // randNum - Return a random floating point number such that
- // (min <= return-value <= max)
- // 32,767 values are possible for any given range.
- //
- float C3dObjectTerrain::RandNum (float min, float max)
- {
- int r;
- float x;
- r = rand ();
- x = (float)(r & 0x7fff) /
- (float)0x7fff;
- return (x * (max - min) + min);
- }
- // fractRand is a useful interface to randnum.
- //
- #define FractRand(v) RandNum (-v, v)
- // powerOf2 - Returns 1 if size is a power of 2. Returns 0 if size is
- // not a power of 2, or is zero.
- //
- int C3dObjectTerrain::PowerOf2 (int size)
- {
- int i, bitcount = 0;
- // Note this code assumes that (sizeof(int)*8) will yield the
- // number of bits in an int. Should be portable to most
- // platforms.
- for (i=0; i<sizeof(int)*8; i++)
- if (size & (1<<i))
- bitcount++;
- if (bitcount == 1)
- // One bit. Must be a power of 2.
- return (1);
- else
- // either size==0, or size not a power of 2. Sorry, Charlie.
- return (0);
- }
- // AvgDiamondVals - Given the i,j location as the center of a diamond,
- // average the data values at the four corners of the diamond and
- // return it. "Stride" represents the distance from the diamond center
- // to a diamond corner.
- //
- float C3dObjectTerrain::AvgDiamondVals (int i, int j, int stride,
- int size, int subSize, C3dPoint *fa)
- {
- /* In this diagram, our input stride is 1, the i,j location is
- indicated by "X", and the four value we want to average are
- "*"s:
- . * .
- * X *
- . * .
- */
- // In order to support tiled surfaces which meet seamless at the
- // edges (that is, they "wrap"), We need to be careful how we
- // calculate averages when the i,j diamond center lies on an edge
- // of the array. The first four 'if' clauses handle these
- // cases. The final 'else' clause handles the general case (in
- // which i,j is not on an edge).
- if (i == 0)
- return ((float) (fa[(i*size) + j-stride].m_fOrigin[Z] +
- fa[(i*size) + j+stride].m_fOrigin[Z] +
- fa[((subSize-stride)*size) + j].m_fOrigin[Z] +
- fa[((i+stride)*size) + j].m_fOrigin[Z]) * .25f);
- else if (i == size-1)
- return ((float) (fa[(i*size) + j-stride].m_fOrigin[Z] +
- fa[(i*size) + j+stride].m_fOrigin[Z] +
- fa[((i-stride)*size) + j].m_fOrigin[Z] +
- fa[((0+stride)*size) + j].m_fOrigin[Z]) * .25f);
- else if (j == 0)
- return ((float) (fa[((i-stride)*size) + j].m_fOrigin[Z] +
- fa[((i+stride)*size) + j].m_fOrigin[Z] +
- fa[(i*size) + j+stride].m_fOrigin[Z] +
- fa[(i*size) + subSize-stride].m_fOrigin[Z]) * .25f);
- else if (j == size-1)
- return ((float) (fa[((i-stride)*size) + j].m_fOrigin[Z] +
- fa[((i+stride)*size) + j].m_fOrigin[Z] +
- fa[(i*size) + j-stride].m_fOrigin[Z] +
- fa[(i*size) + 0+stride].m_fOrigin[Z]) * .25f);
- else
- return ((float) (fa[((i-stride)*size) + j].m_fOrigin[Z] +
- fa[((i+stride)*size) + j].m_fOrigin[Z] +
- fa[(i*size) + j-stride].m_fOrigin[Z] +
- fa[(i*size) + j+stride].m_fOrigin[Z]) * .25f);
- }
- // AvgSquareVals - Given the i,j location as the center of a square,
- // average the data values at the four corners of the square and return
- // it. "Stride" represents half the length of one side of the square.
- float C3dObjectTerrain::AvgSquareVals (int i, int j, int stride, int size, C3dPoint *fa)
- {
- /* In this diagram, our input stride is 1, the i,j location is
- indicated by "*", and the four value we want to average are
- "X"s:
- X . X
- . * .
- X . X
- */
- return ((float) (fa[((i-stride)*size) + j-stride].m_fOrigin[Z] +
- fa[((i-stride)*size) + j+stride].m_fOrigin[Z] +
- fa[((i+stride)*size) + j-stride].m_fOrigin[Z] +
- fa[((i+stride)*size) + j+stride].m_fOrigin[Z]) * .25f);
- }
- // FillFractualArray - Use the diamond-square algorithm to tessalate a
- // grid of float values into a fractal height map.
- //
- void C3dObjectTerrain::FillFractualArray (C3dPoint *fa, int size,
- float heightScale, float h)
- {
- int i, j;
- int stride;
- int oddline;
- int subSize;
- int seedValue;
- float ratio, scale;
- if (!PowerOf2(size) || (size==1))
- {
- // We can't tesselate the array if it is not a power of 2.
- #ifdef DEBUG
- printf ("Error: FillFractualArray: size %d is not a power of 2.n");
- #endif /* DEBUG */
- return;
- }
- // subSize is the dimension of the array in terms of connected line
- // segments, while size is the dimension in terms of number of
- // vertices.
- subSize = size;
- size++;
- // Initialize random number generator
- if(m_iHeightSeed < 0)
- {
- // Seed the random-number generator with current time so that
- // the numbers will be different every time we run.
- seedValue = (unsigned)time( NULL );
- srand( seedValue );
- m_iHeightSeed = seedValue;
- }
- else
- srand (m_iHeightSeed);
- // Set up our roughness constants.
- // Random numbers are always generated in the range 0.0 to 1.0.
- // 'scale' is multiplied by the randum number.
- // 'ratio' is multiplied by 'scale' after each iteration
- // to effectively reduce the random number range.
- ratio = (float) pow ((double)2.0,(double)-h);
- scale = heightScale * ratio;
- /* Seed the first four values. For example, in a 4x4 array, we
- would initialize the data points indicated by '*':
- * . . . *
- . . . . .
- . . . . .
- . . . . .
- * . . . *
- In terms of the "diamond-square" algorithm, this gives us
- "squares".
- We want the four corners of the array to have the same
- point. This will allow us to tile the arrays next to each other
- such that they join seemlessly.
- */
- stride = subSize / 2;
- fa[(0*size)+0].m_fOrigin[Z] = fa[(subSize*size)+0].m_fOrigin[Z] =
- fa[(subSize*size)+subSize].m_fOrigin[Z] =
- fa[(0*size)+subSize].m_fOrigin[Z] = 0.f;
- // Now we add ever-increasing detail based on the "diamond" seeded
- // values. We loop over stride, which gets cut in half at the
- // bottom of the loop. Since it's an int, eventually division by 2
- // will produce a zero result, terminating the loop.
- while (stride)
- {
- /* Take the existing "square" data and produce "diamond"
- data. On the first pass through with a 4x4 matrix, the
- existing data is shown as "X"s, and we need to generate the
- "*" now:
- X . . . X
- . . . . .
- . . * . .
- . . . . .
- X . . . X
- It doesn't look like diamonds. What it actually is, for the
- first pass, is the corners of four diamonds meeting at the
- center of the array. */
- for (i=stride; i<subSize; i+=stride)
- {
- for (j=stride; j<subSize; j+=stride)
- {
- fa[(i * size) + j].m_fOrigin[Z] = scale * FractRand (.5f) +
- AvgSquareVals (i, j, stride, size, fa);
- j += stride;
- }
- i += stride;
- }
- /* Take the existing "diamond" data and make it into
- "squares". Back to our 4X4 example: The first time we
- encounter this code, the existing values are represented by
- "X"s, and the values we want to generate here are "*"s:
- X . * . X
- . . . . .
- * . X . *
- . . . . .
- X . * . X
- i and j represent our (x,y) position in the array. The
- first value we want to generate is at (i=2,j=0), and we use
- "oddline" and "stride" to increment j to the desired value.
- */
- oddline = 0;
- for (i=0; i<subSize; i+=stride)
- {
- oddline = (oddline == 0);
- for (j=0; j<subSize; j+=stride)
- {
- if ((oddline) && !j)
- j+=stride;
- // i and j are setup. Call avgDiamondVals with the
- // current position. It will return the average of the
- // surrounding diamond data points.
- fa[(i * size) + j].m_fOrigin[Z] = scale * FractRand (.5f) +
- AvgDiamondVals (i, j, stride, size, subSize, fa);
- // To wrap edges seamlessly, copy edge values around
- // to other side of array.
- if (i==0)
- fa[(subSize*size) + j].m_fOrigin[Z] =
- fa[(i * size) + j].m_fOrigin[Z];
- if (j==0)
- fa[(i*size) + subSize].m_fOrigin[Z] =
- fa[(i * size) + j].m_fOrigin[Z];
- j+=stride;
- }
- }
- // reduce random number range.
- scale *= ratio;
- stride >>= 1;
- }
- // Now that we have the terrain height values, calculate
- // the width and depth values.
- float width, depth;
- width = -m_fWidth/2.0f;
- // Initialize our terrain color height values
- InitColorHeightValues();
- float seaHeight;
- if(m_fSeaLevel > .0f)
- seaHeight = ((m_fSnowHeight-m_fWaterHeight)*m_fSeaLevel) + m_fWaterHeight;
- for(i=0; i<size; i++)
- {
- depth = -m_fDepth/2.0f;
- for(j=0; j<size; j++)
- {
- fa[(i*size) + j].m_fOrigin[X]=width;
- fa[(i*size) + j].m_fOrigin[Y]=depth;
- if(m_fSeaLevel > .0f)
- {
- if(fa[(i*size) + j].m_fOrigin[Z]<=seaHeight)
- fa[(i*size) + j].m_fOrigin[Z]=seaHeight;
- }
- depth += (m_fDepth/(GLfloat)subSize);
- }
- width += (m_fWidth/(GLfloat)subSize);
- }
- }
- // InitColorHeightValues
- //
- // The h1 and h2 parameters are set to 1/3 and 2/3 of the height values and
- // h3 and h4 will be the max and min height values height values stored in the
- // 2D fract array.
- void C3dObjectTerrain::InitColorHeightValues()
- {
- float min, max;
- int i;
- // Set the min/max initially to very large opposite numbers
- min = (float)LARGE_NUMBER;
- max = (float)-LARGE_NUMBER;
- for (i=0; i<m_pPointArray->m_iNumPoints; i++)
- {
- if(m_pPointArray->m_pPoints[i].m_fOrigin[Z] > max)
- max = m_pPointArray->m_pPoints[i].m_fOrigin[Z];
- else if(m_pPointArray->m_pPoints[i].m_fOrigin[Z] < min)
- min = m_pPointArray->m_pPoints[i].m_fOrigin[Z];
- }
- m_fSnowHeight = max;
- m_fRockHeight = (max - min) * .66f + min;
- m_fGrassHeight = (max - min) * .33f + min;
- m_fWaterHeight = min;
- }
- void C3dObjectTerrain::InitTerrainColor()
- {
- int i;
- // Set our terrain color height values. These settings are then used in
- // our rinky-dink-but-effective coloring, scheme wherein the lower 1/3
- // of terrain is colored dark green, the middle third is colored grey,
- // and the upper third is white. Our sealevel is colored blue.
- InitColorHeightValues();
- for (i=0; i<m_pPointArray->m_iNumPoints; i++)
- {
- float z = m_pPointArray->m_pPoints[i].m_fOrigin[Z];
- if(z > m_fRockHeight)
- m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorSnow);
- else if(z > m_fGrassHeight)
- m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorRock);
- else
- m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorGrass);
- if(m_fSeaLevel > .0f)
- {
- if(z == m_fWaterHeight)
- m_pPointArray->m_pPoints[i].m_Color.SetColor4fv(&m_ColorWater);
- }
- }
- }
- void C3dObjectTerrain::SetTerrainColor(int i, int j, BOOL bReflect)
- {
- static C3dColor LastColor;
- float h1;
- if(i+j != 0)
- {
- // To DRAMATICALLY reduce the size of the display list, and hence, increase
- // the speed, lets' minimize setting the material properties..
- if(m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_Color.Compare(&LastColor))
- // This points color components are identical to the last one set,
- // so there is no need to set the material properties again.
- return;
- }
- h1 = m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_fOrigin[Z];
- if(h1 == m_fWaterHeight || h1 > m_fRockHeight)
- {
- if(bReflect)
- {
- // Set snow material properties
- GLfloat ambColor[] = {0.2f, 0.2f, 0.2f, 1.0f};
- GLfloat difColor[] = {0.8f, 0.8f, 0.8f, 1.0f};
- GLfloat spcColor[] = {0.9f, 0.9f, 0.9f, 1.0f};
- GLfloat emmColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
- // Set material properties to default values
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambColor);
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, difColor);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spcColor);
- glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emmColor);
- glMaterialf(GL_FRONT, GL_SHININESS, 20.0f);
- }
- }
- else
- {
- if(bReflect)
- {
- // All three vertices lay in the horizonal plane, so set its
- // color and water material properties
- GLfloat ambColor[] = {0.2f, 0.2f, 0.2f, 1.0f};
- GLfloat difColor[] = {0.8f, 0.8f, 0.8f, 1.0f};
- GLfloat spcColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
- GLfloat emmColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
- // Set material properties to default values
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambColor);
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, difColor);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spcColor);
- glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emmColor);
- glMaterialf(GL_FRONT, GL_SHININESS, 0.0f);
- }
- }
- glColor4fv(m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_Color.m_fColor);
- // Save the color components
- LastColor.SetColor4fv(&m_pPointArray->m_pPoints[i*(m_iSize+1)+j].m_Color);
- }
- BOOL C3dObjectTerrain::AddSubTexture(LPSTR szFileName, CTexture** pTexture)
- {
- if(*pTexture)
- // If we already have a texture, delete it
- DeleteSubTexture(*pTexture);
- // Create a TextureMap of the appropriate type
- CTexture::CreateTexture(szFileName, the3dEngine.m_hPalette, pTexture);
- if(pTexture)
- {
- CTexture* pText = *pTexture;
- // Is the TextureMap an CTextureAviMovie?
- if( pText->IsKindOf(RUNTIME_CLASS(CTextureAviMovie)) )
- {
- // Create an AVI animation and add to the list
- CAnimAVI* pAnim = new CAnimAVI;
- ASSERT(pAnim);
- m_AnimList.Append(pAnim);
- // Cross link the two objects so that they are 'aware' of
- // each other..
- // Save the CTextureAviMovie pointer
- pAnim->m_pAviMovie = (CTextureAviMovie*)pTexture;
- // Save the CAnimAVI pointer
- CTextureAviMovie* pAviVideo = (CTextureAviMovie*)pTexture;
- pAviVideo->m_pAnimAVI = pAnim;
- }
- return TRUE;
- }
- else
- return FALSE;
- }
- void C3dObjectTerrain::DeleteSubTexture(CTexture* pTexture)
- {
- if(pTexture)
- {
- if( pTexture->IsKindOf(RUNTIME_CLASS(CTextureAviMovie)) )
- {
- // TextureMap is of class type CTextureAviMovie, so find the animation
- // procedure in the list, remove from list and delete it..
- CAnimation* pAnimation = m_AnimList.Find(SZ_ANIMATE_AVI);
- if(pAnimation)
- {
- m_AnimList.Remove(pAnimation);
- delete pAnimation;
- }
- }
- // Now that we have removed any associated object members,
- // delete the texturemap
- delete pTexture;
- pTexture = NULL;
- }
- }
- // renderTeximageMap
- //
- // If the teximage map is dirty, allocate and tesselate a new
- // one. Render it to the screen as lit triangles. Read the
- // image back and set it as a texture map in a display list.
- BOOL C3dObjectTerrain::RenderTextureImageMap(C3dWorld* pWorld, C3dCamera* pCamera)
- {
- UINT pmapDim, smallDim;
- // Find the biggest power of two that will fit
- // in the current window. This is where we will
- // draw the image.
- smallDim = (pCamera->m_iScreenWidth > pCamera->m_iScreenHeight) ?
- pCamera->m_iScreenHeight : pCamera->m_iScreenWidth;
- pmapDim = 1 << (UINT) (log ((float) smallDim) / log (2.));
- // Save our gl States
- glPushAttrib (0xfffffff);
- // Only draw into biggest power of 2 square.
- glViewport (0, 0, pmapDim, pmapDim);
- glMatrixMode (GL_PROJECTION);
- glLoadIdentity ();
- glOrtho (-m_fWidth/2.0f, m_fWidth/2.0f,
- -m_fDepth/2.0f, m_fDepth/2.0f, 0.0f, pCamera->m_fFar);
- glMatrixMode (GL_MODELVIEW);
- glLoadIdentity ();
- // The terrain array is rendered into the XY plane as viewed looking
- // along the -Z axis. We need to move the 'camera' position up in Z
- // so that we don't clip any polygons.
- glTranslatef(0.f, 0.f, -10.f);
- // Init lights now. Light position must be specified
- // after our translation.
- pWorld->InitializeLights(pCamera);
- // Set our state flags
- glDisable (GL_DEPTH_TEST);
- glDisable (GL_FOG);
- glEnable (GL_LIGHTING);
- glDisable (GL_BLEND);
- // Clear our color buffer
- glClear (GL_COLOR_BUFFER_BIT);
- // Render the terrain
- RenderTerrain(FALSE, FALSE);
- // Flush all commands to draw the image
- glFlush ();
- GLubyte *pmap;
- pmap = (GLubyte *) malloc (pmapDim*pmapDim*3);
- if (pmap==NULL)
- return (FALSE);
- // Read the screen pixels
- glReadPixels (0, 0, pmapDim, pmapDim, GL_RGB, GL_UNSIGNED_BYTE, pmap);
- if(!m_iTexImageMap)
- // Create our texture map display list
- m_iTexImageMap = glGenLists(1);// Create the DisplayList(s)
- glNewList(m_iTexImageMap, GL_COMPILE);
- glTexImage2D (GL_TEXTURE_2D, 0, // lod
- 3, // Number of components
- pmapDim, pmapDim, // width, height
- 0, // Border
- GL_RGB, // Format
- GL_UNSIGNED_BYTE, // Type
- pmap); // Pointer to our pixels
- glEndList ();
- // Now that we have our texture map display list,
- // free our pixel memory
- free (pmap);
- // Restore our gl States
- glPopAttrib ();
- // Clear the buffers
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- // Re-position our camera and lights to their original position
- pCamera->ResetView(0, 0);
- pCamera->PositionCamera();
- pWorld->InitializeLights(pCamera);
- return (TRUE);
- }