//***************************************************************************** void BTerrainBlock::CreateTileData(int nRes) { // calculate normals for collision detection int nRenderSize = (2 << nRes); // Reallocate memory for tile data if(m_pTiles) { delete [] m_pTiles; } m_pTiles = new BTerrainTile[nRenderSize * nRenderSize]; // create normals (and friction) for(int nY = 0; nY < nRenderSize; ++nY) { for(int nX = 0; nX < nRenderSize; ++nX) { BVector v1, v2, v3, v4; v1.Set(0, 0, -HeightAt(nX * m_nStep, nY * m_nStep)); v2.Set(m_dTileSize, 0, -HeightAt((nX + 1) * m_nStep, nY * m_nStep)); v3.Set(0, m_dTileSize, -HeightAt(nX * m_nStep, (nY + 1) * m_nStep)); v4.Set(m_dTileSize, m_dTileSize, -HeightAt((nX + 1) * m_nStep, (nY + 1) * m_nStep)); m_pTiles[nY * nRenderSize + nX].m_vNormal1 = (v1 - v2).CrossProduct(v4 - v2); m_pTiles[nY * nRenderSize + nX].m_vNormal1.ToUnitLength(); m_pTiles[nY * nRenderSize + nX].m_vNormal2 = (v4 - v3).CrossProduct(v1 - v3); m_pTiles[nY * nRenderSize + nX].m_vNormal2.ToUnitLength(); m_pTiles[nY * nRenderSize + nX].m_dFriction = g_dSceneFriction; } } }
void TerrainWrapper::ManagePlayerCollision(Controller*ctrl, bool null_gravity) { Camera * camera = static_cast<Camera*>(ctrl->Get("Camera")); GLfloat terrain_height = HeightAt(terra, camera->GetInfo()->getCameraPos().x, camera->GetInfo()->getCameraPos().z); if (camera->GetInfo()->getCameraPos().y < terrain_height) camera->GetInfo()->SetCameraY(terrain_height); if (!null_gravity) camera->GetInfo()->SetCameraY(terrain_height); }
//***************************************************************************** BVector BTerrainBlock::GetNormalAtTile(int nX, int nY, int nRes) { // Returns the normal at the given resolution-specific point // Normal is the average of the neighboring normals: // // Y // // ^ // | A B C // | D xy E // | F G H // +---------> X // BVector vToA, vToB, vToC, vToD, vToE, vToF, vToG, vToH; BVector vNormal(0, 0, 0); int nTileSize = 1 << (m_nMaxRes - nRes); double dTileSize = m_dSize / double(2 << nRes); double dTileSize2 = m_dSize / double(2 << m_nMaxRes); double dHeightAtXY = HeightAt(nX, nY); // First calculate vectors to neighboring points vToA.Set(-dTileSize, dTileSize, dHeightAtXY - HeightAt(nX - nTileSize, nY + nTileSize, true, dTileSize2)); vToA.ToUnitLength(); vToB.Set(0, dTileSize, dHeightAtXY - HeightAt(nX, nY + nTileSize, true, dTileSize2)); vToB.ToUnitLength(); vToC.Set(dTileSize, dTileSize, dHeightAtXY - HeightAt(nX + nTileSize, nY + nTileSize, true, dTileSize2)); vToC.ToUnitLength(); vToF.Set(-dTileSize, -dTileSize, dHeightAtXY - HeightAt(nX - nTileSize, nY - nTileSize, true, dTileSize2)); vToF.ToUnitLength(); vToG.Set(0, -dTileSize, dHeightAtXY - HeightAt(nX, nY - nTileSize, true, dTileSize2)); vToG.ToUnitLength(); vToH.Set(dTileSize, -dTileSize, dHeightAtXY - HeightAt(nX + nTileSize, nY - nTileSize, true, dTileSize2)); vToH.ToUnitLength(); vToD.Set(-dTileSize, 0, dHeightAtXY - HeightAt(nX - nTileSize, nY, true, dTileSize2)); vToD.ToUnitLength(); vToE.Set(dTileSize, 0, dHeightAtXY - HeightAt(nX + nTileSize, nY, true, dTileSize2)); vToE.ToUnitLength(); // Then create and sum normals together vNormal += vToA.CrossProduct(vToB); vNormal += vToB.CrossProduct(vToC); vNormal += vToG.CrossProduct(vToF); vNormal += vToH.CrossProduct(vToG); vNormal += vToE.CrossProduct(vToH); vNormal += vToC.CrossProduct(vToE); vNormal += vToF.CrossProduct(vToD); vNormal += vToD.CrossProduct(vToA); vNormal.ToUnitLength(); return vNormal; }
//***************************************************************************** void BTerrainBlock::CreateDisplayListsOfRes(int nRes, bool bOverride, bool bWireframe, bool bNormals) { // Creates display lists for the given resolution m_nDisplayLists = 1; // For test use only one pass if(m_nDisplayListBase == -1) { // create new list only if not already created. Otherwise use the existing list. m_nDisplayListBase = glGenLists(1); } // Render the triangles in the block into the display list BVector vPoint, vNormal; if(bOverride) { glNewList(m_nDisplayListBase, GL_COMPILE_AND_EXECUTE); } else { glNewList(m_nDisplayListBase, GL_COMPILE); } int nRenderSize = (2 << nRes) + 1; int nSizeRatio = (1 << (m_nMaxRes - nRes)); double dScaler = 1.0 / double(nRenderSize - 1) * m_dSize; int nX, nY, nXStart = 0, nYStart = 0, nXEnd = nRenderSize, nYEnd = nRenderSize - 1; m_dTileSize = m_dSize / (2 << nRes); m_nStep = nSizeRatio; m_nTriangles = -2; if(bWireframe) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); OpenGL_SetColor(0, 0, 0, 1); for(nY = nYStart; nY < nYEnd; ++nY) { glBegin(GL_TRIANGLE_STRIP); for(nX = nXStart; nX < nXEnd; ++nX) { vPoint.Set(m_vCorner.m_dX + double(nX) * dScaler, m_vCorner.m_dY + double(nY + 1) * dScaler, -HeightAt(nX * nSizeRatio, (nY + 1) * nSizeRatio)); // Set vertex glVertex3f(vPoint.m_dX, vPoint.m_dY, vPoint.m_dZ); vPoint.Set(m_vCorner.m_dX + double(nX) * dScaler, m_vCorner.m_dY + double(nY) * dScaler, -HeightAt(nX * nSizeRatio, nY * nSizeRatio)); // Set vertex glVertex3f(vPoint.m_dX, vPoint.m_dY, vPoint.m_dZ); m_nTriangles += 2; } glEnd(); } OpenGL_SetColor(1, 1, 1, 1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } double dR = -1.0, dG = -1.0, dB = -1.0; BVector dNormalOld(0, 0, 0); glColor3ub(255, 255, 255); for(nY = nYStart; nY < nYEnd; ++nY) { glBegin(GL_TRIANGLE_STRIP); for(nX = nXStart; nX < nXEnd; ++nX) { vPoint.Set(m_vCorner.m_dX + double(nX) * dScaler, m_vCorner.m_dY + double(nY + 1) * dScaler, -HeightAt(nX * nSizeRatio, (nY + 1) * nSizeRatio)); vNormal = GetNormalAtTile(nX * nSizeRatio, (nY + 1) * nSizeRatio, nRes); // Set normal, texture coordinate and vertex double dNewR, dNewG, dNewB; //BTerrain::GetColorForHeight(-vPoint.m_dZ, dNewR, dNewG, dNewB); //if((dNewR != dR) || (dNewG != dG) || (dNewB != dB)) { // glColor3f(dNewR, dNewG, dNewB); //glColor3ub(GLubyte(dNewR * 255.0), GLubyte(dNewG * 255.0), GLubyte(dNewB * 255.0)); // dR = dNewR; // dG = dNewG; // dB = dNewB; //} if((dNormalOld - vNormal).Length() > 0.001) { glNormal3f(vNormal.m_dX, vNormal.m_dY, vNormal.m_dZ); dNormalOld = vNormal; } SetTextureCoordinate(vPoint); glVertex3f(vPoint.m_dX, vPoint.m_dY, vPoint.m_dZ); vPoint.Set(m_vCorner.m_dX + double(nX) * dScaler, m_vCorner.m_dY + double(nY) * dScaler, -HeightAt(nX * nSizeRatio, nY * nSizeRatio)); vNormal = GetNormalAtTile(nX * nSizeRatio, nY * nSizeRatio, nRes); // Set normal, texture coordinate and vertex //BTerrain::GetColorForHeight(-vPoint.m_dZ, dNewR, dNewG, dNewB); //if((dNewR != dR) || (dNewG != dG) || (dNewB != dB)) { // glColor3f(dNewR, dNewG, dNewB); //glColor3ub(GLubyte(dNewR * 255.0), GLubyte(dNewG * 255.0), GLubyte(dNewB * 255.0)); //dR = dNewR; //dG = dNewG; //dB = dNewB; //} if((dNormalOld - vNormal).Length() > 0.001) { glNormal3f(vNormal.m_dX, vNormal.m_dY, vNormal.m_dZ); dNormalOld = vNormal; } SetTextureCoordinate(vPoint); glVertex3f(vPoint.m_dX, vPoint.m_dY, vPoint.m_dZ); m_nTriangles += 2; } glEnd(); } if(bNormals) { OpenGL_SetColor(0.5, 0, 0, 1); for(nY = nYStart; nY < nYEnd + 1; ++nY) { glBegin(GL_LINES); for(nX = nXStart; nX < nXEnd; ++nX) { vPoint.Set(m_vCorner.m_dX + double(nX) * dScaler, m_vCorner.m_dY + double(nY) * dScaler, -HeightAt(nX * nSizeRatio, nY * nSizeRatio)); vNormal = GetNormalAtTile(nX * nSizeRatio, nY * nSizeRatio, nRes) * 10.0; glVertex3f(vPoint.m_dX, vPoint.m_dY, vPoint.m_dZ); vPoint += vNormal; glVertex3f(vPoint.m_dX, vPoint.m_dY, vPoint.m_dZ); } glEnd(); } OpenGL_SetColor(1, 1, 1, 1); } glEndList(); m_nDisplayListRes = nRes; m_bDisplayListValid = true; if(m_nTriangles == -2) { m_nTriangles = 0; } // Create tile data (such as normals and friction information etc.) CreateTileData(nRes); }
float EC_Hydrax::HeightAt(float x, float z) const { return HeightAt(float3(x, 0.f, z)); }
void Terrain() { // Allocate the offscreen bitmap offMap = CreateBitmap(256, 200); if (!offMap) return; // Allocate the surface maps if (!ISurface()) return; // Build tables BuildProjectionTable(); // Attempt to randomize gSeed = time(NULL) + clock(); // Generate the fractal surface Fractify(0, 0, 256, 256); Smoothify(); // Build obelisk for (int j=-3; j<4; j++) for (int i=-3; i<4; i++) Point(128+i, 128+j) = 240; // Generate the palette BuildPalette(); // Colorize the surface (w/ sealevel parameter) Colorize(80); // Initialize values int elev = 10 << (YFIX+FIX); gX = gY = gZ = 0; gY = HeightAt(gX, gZ) + elev; // Do some display int mx, my; char q = 0, clr=0; int c, f = 0; char msg[80]; clock_t clk = clock(); while (!q) { // Count the frame f++; //------------Refresh the display------------- // Clear the offmap ClearScreen(254, 256, 200, offMap); // Draw the surface Caster(); // Copy the offmap to the screen Display(offMap, 256, 200); //------------Handle user input------------- MouseMove(&mx, &my); if (mx || my) { gZ -= my; gZ = gZ & 4095; gX += mx; gX = gX & 4095; gY = HeightAt(gX, gZ) + elev; } else if (kbhit()) { c = getch(); switch (c) { case 0: c = getch(); switch (c) { case UP_ARROW_KEY: gZ += 1; break; case DN_ARROW_KEY: gZ -= 1; break; case LF_ARROW_KEY: gX -= 1; break; case RT_ARROW_KEY: gX += 1; break; } break; case 'w': elev += 8; break; case 'x': elev -= 8; break; case ESC_KEY: q = 1; break; } gZ &= 4095; gX &= 4095; gY = HeightAt(gX, gZ) + elev; } } clk = clock() - clk; _settextposition(1, 2); _settextcolor(255); sprintf(msg, "Frames: %ld, Time: %5.2fs, FPS: %5.2f\n", f, clk/(float)CLOCKS_PER_SEC, f * (float)CLOCKS_PER_SEC / clk); _outtext(msg); }