| 1 | /* |
|---|
| 2 | ================================================================================= |
|---|
| 3 | This file is part of Cafu, the open-source game engine and graphics engine |
|---|
| 4 | for multiplayer, cross-platform, real-time 3D action. |
|---|
| 5 | Copyright (C) 2002-2012 Carsten Fuchs Software. |
|---|
| 6 | |
|---|
| 7 | Cafu is free software: you can redistribute it and/or modify it under the terms |
|---|
| 8 | of the GNU General Public License as published by the Free Software Foundation, |
|---|
| 9 | either version 3 of the License, or (at your option) any later version. |
|---|
| 10 | |
|---|
| 11 | Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
|---|
| 12 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
|---|
| 13 | PURPOSE. See the GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with Cafu. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | |
|---|
| 18 | For support and more information about Cafu, visit us at <http://www.cafu.de>. |
|---|
| 19 | ================================================================================= |
|---|
| 20 | */ |
|---|
| 21 | |
|---|
| 22 | /***************************/ |
|---|
| 23 | /*** Cafu Terrain Viewer ***/ |
|---|
| 24 | /***************************/ |
|---|
| 25 | |
|---|
| 26 | #include <stdio.h> |
|---|
| 27 | #include <float.h> |
|---|
| 28 | #include <string.h> |
|---|
| 29 | |
|---|
| 30 | #include "ConsoleCommands/Console.hpp" |
|---|
| 31 | #include "ConsoleCommands/ConsoleStdout.hpp" |
|---|
| 32 | #include "FileSys/FileManImpl.hpp" |
|---|
| 33 | #include "MaterialSystem/MapComposition.hpp" |
|---|
| 34 | #include "MaterialSystem/MaterialManager.hpp" |
|---|
| 35 | #include "MaterialSystem/MaterialManagerImpl.hpp" |
|---|
| 36 | #include "MaterialSystem/Mesh.hpp" |
|---|
| 37 | #include "MaterialSystem/Renderer.hpp" |
|---|
| 38 | #include "MaterialSystem/TextureMap.hpp" |
|---|
| 39 | #include "Math3D/Plane3.hpp" |
|---|
| 40 | #include "Math3D/Matrix.hpp" |
|---|
| 41 | #include "OpenGL/OpenGLWindow.hpp" |
|---|
| 42 | #include "Templates/Array.hpp" |
|---|
| 43 | #include "Terrain/Terrain.hpp" |
|---|
| 44 | #include "Util/Util.hpp" |
|---|
| 45 | #include "PlatformAux.hpp" |
|---|
| 46 | |
|---|
| 47 | #include "zlib.h" |
|---|
| 48 | |
|---|
| 49 | #ifdef _WIN32 |
|---|
| 50 | #define WIN32_LEAN_AND_MEAN |
|---|
| 51 | #include <windows.h> |
|---|
| 52 | #include <direct.h> |
|---|
| 53 | #if defined(_MSC_VER) |
|---|
| 54 | #if (_MSC_VER<1300) |
|---|
| 55 | #define for if (false) ; else for |
|---|
| 56 | #endif |
|---|
| 57 | #endif |
|---|
| 58 | #else |
|---|
| 59 | #include <dlfcn.h> |
|---|
| 60 | #define FreeLibrary dlclose |
|---|
| 61 | #endif |
|---|
| 62 | |
|---|
| 63 | |
|---|
| 64 | static cf::ConsoleStdoutT ConsoleStdout; |
|---|
| 65 | cf::ConsoleI* Console=&ConsoleStdout; |
|---|
| 66 | |
|---|
| 67 | static cf::FileSys::FileManImplT FileManImpl; |
|---|
| 68 | cf::FileSys::FileManI* cf::FileSys::FileMan=&FileManImpl; |
|---|
| 69 | |
|---|
| 70 | MaterialManagerI* MaterialManager=NULL; |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | #define DEG2RAD(x) ((3.1415927f / 180.0f) * (x)) |
|---|
| 74 | #define SQR(x) ((x) * (x)) |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | std::string BaseDirectoryName="Games/DeathMatch"; |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | void Usage() |
|---|
| 81 | { |
|---|
| 82 | printf("\n"); |
|---|
| 83 | printf("\nUSAGE: TerrainViewer -t=HeightMapName -m=MaterialName [OPTIONS]\n"); |
|---|
| 84 | printf("\n"); |
|---|
| 85 | printf("\nMANDATORY PARAMETERS:\n"); |
|---|
| 86 | printf("\n"); |
|---|
| 87 | printf("-t=MyHeightMap specifies the name of the desired terrain (heightmap image).\n"); |
|---|
| 88 | printf("\n"); |
|---|
| 89 | printf("-m=MyMaterial specifies the name of the desired material, which must be\n"); |
|---|
| 90 | printf(" defined in one of the material script files (see below).\n"); |
|---|
| 91 | printf("\n"); |
|---|
| 92 | printf("\nOPTIONS:\n"); |
|---|
| 93 | printf("\n"); |
|---|
| 94 | printf("-bd=base/dir specifies the base directory from which I look both for material\n"); |
|---|
| 95 | printf(" scripts and the materials associated textures.\n"); |
|---|
| 96 | printf(" The default (if you don't use -bd) is %s\n", BaseDirectoryName.c_str()); |
|---|
| 97 | printf("\n"); |
|---|
| 98 | printf("-ms=MyMatScript.cmat specifies the material script that contains a definition\n"); |
|---|
| 99 | printf(" of \"MyMaterial\" (see above). You may use -ms several times, making me look\n"); |
|---|
| 100 | printf(" into each specified script for a definition of the material.\n"); |
|---|
| 101 | printf(" If you do not use -ms at all, I'll look into ALL material scripts that I can\n"); |
|---|
| 102 | printf(" find in %s/Materials, so you probably don't need it as well.\n", BaseDirectoryName.c_str()); |
|---|
| 103 | printf("\n"); |
|---|
| 104 | printf("-bm runs a simple benchmark. Mostly intended for development purposes.\n"); |
|---|
| 105 | printf("\n"); |
|---|
| 106 | |
|---|
| 107 | exit(0); |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | |
|---|
| 111 | int main(int ArgC, char* ArgV[]) |
|---|
| 112 | { |
|---|
| 113 | const char* TerrainName =NULL; |
|---|
| 114 | const char* MaterialName ="wireframe"; // The "wireframe" material is defined in file "meta.cmat". |
|---|
| 115 | bool BenchMarkMode=false; |
|---|
| 116 | bool UseSOARX =false; // SOARX is the new SOAR implementation. |
|---|
| 117 | ArrayT<const char*> MaterialScriptNames; |
|---|
| 118 | |
|---|
| 119 | |
|---|
| 120 | printf("\nCafu Engine Terrain Viewer (%s)\n\n", __DATE__); |
|---|
| 121 | |
|---|
| 122 | // Initialize the FileMan by mounting the default file system. |
|---|
| 123 | // Note that specifying "./" (instead of "") as the file system description effectively prevents the use of |
|---|
| 124 | // absolute paths like "D:\abc\someDir\someFile.xy" or "/usr/bin/xy". This however should be fine for this application. |
|---|
| 125 | cf::FileSys::FileMan->MountFileSystem(cf::FileSys::FS_TYPE_LOCAL_PATH, "./", ""); |
|---|
| 126 | cf::FileSys::FileMan->MountFileSystem(cf::FileSys::FS_TYPE_ZIP_ARCHIVE, "Games/DeathMatch/Textures/TechDemo.zip", "Games/DeathMatch/Textures/TechDemo/", "Ca3DE"); |
|---|
| 127 | cf::FileSys::FileMan->MountFileSystem(cf::FileSys::FS_TYPE_ZIP_ARCHIVE, "Games/DeathMatch/Textures/SkyDomes.zip", "Games/DeathMatch/Textures/SkyDomes/", "Ca3DE"); |
|---|
| 128 | |
|---|
| 129 | // Process the command line options. |
|---|
| 130 | for (int ArgNr=1; ArgNr<ArgC; ArgNr++) |
|---|
| 131 | { |
|---|
| 132 | if (_strnicmp(ArgV[ArgNr], "-t=" , 3)==0) TerrainName=ArgV[ArgNr]+3; |
|---|
| 133 | else if (_strnicmp(ArgV[ArgNr], "-m=" , 3)==0) MaterialName=ArgV[ArgNr]+3; |
|---|
| 134 | else if (_strnicmp(ArgV[ArgNr], "-bd=", 4)==0) BaseDirectoryName=ArgV[ArgNr]+4; |
|---|
| 135 | else if (_strnicmp(ArgV[ArgNr], "-ms=", 4)==0) MaterialScriptNames.PushBack(ArgV[ArgNr]+4); |
|---|
| 136 | else if (_stricmp (ArgV[ArgNr], "-bm" )==0) BenchMarkMode=true; |
|---|
| 137 | else if (_stricmp (ArgV[ArgNr], "-sx" )==0) UseSOARX=true; |
|---|
| 138 | else |
|---|
| 139 | { |
|---|
| 140 | printf("Sorry, I don't know what option \"%s\" means.\n", ArgV[ArgNr]); |
|---|
| 141 | Usage(); |
|---|
| 142 | } |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | if (TerrainName==NULL) |
|---|
| 146 | { |
|---|
| 147 | printf("Hmm. Specifying a terrain name wouldn't hurt...\n"); |
|---|
| 148 | printf("Please use the -t option in order to specify the desired terrain!\n"); |
|---|
| 149 | Usage(); |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | // Setup the global Material Manager pointer. |
|---|
| 153 | static MaterialManagerImplT MatManImpl; |
|---|
| 154 | |
|---|
| 155 | MaterialManager=&MatManImpl; |
|---|
| 156 | |
|---|
| 157 | // Register the material script files with the material manager. |
|---|
| 158 | if (MaterialScriptNames.Size()==0) |
|---|
| 159 | { |
|---|
| 160 | // The -ms option has not been used, so register all material script files in BaseDirectoryName/Materials. |
|---|
| 161 | MaterialManager->RegisterMaterialScriptsInDir(BaseDirectoryName+"/Materials", BaseDirectoryName+"/"); |
|---|
| 162 | } |
|---|
| 163 | else |
|---|
| 164 | { |
|---|
| 165 | // Material script files have been specified - register them now. |
|---|
| 166 | for (unsigned long MSNNr=0; MSNNr<MaterialScriptNames.Size(); MSNNr++) |
|---|
| 167 | MaterialManager->RegisterMaterialScript(BaseDirectoryName+"/"+MaterialScriptNames[MSNNr], BaseDirectoryName+"/"); |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | // Get the desired material. |
|---|
| 171 | MaterialT* TerrainMaterial=MaterialManager->GetMaterial(MaterialName); |
|---|
| 172 | |
|---|
| 173 | if (TerrainMaterial==NULL) |
|---|
| 174 | { |
|---|
| 175 | printf("Sorry, I have not been able to get material \"%s\"\n", MaterialName); |
|---|
| 176 | printf("from the registered material script files. Possible causes:\n"); |
|---|
| 177 | printf("- the material is not defined in any of the script files (material name typo?)\n"); |
|---|
| 178 | printf("- the material script file(s) could not be opened (script file name typo?)\n"); |
|---|
| 179 | printf("- the material script file contains bugs, i.e. syntax errors.\n"); |
|---|
| 180 | |
|---|
| 181 | return 0; |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | try |
|---|
| 186 | { |
|---|
| 187 | const unsigned long FRAMES_FOR_BENCHMARK=1000; |
|---|
| 188 | const Vector3fT TerrainResolution(160.0f, 160.0f, 50.0f*255.0f); |
|---|
| 189 | TerrainT TerrainNew(TerrainName, TerrainResolution); |
|---|
| 190 | const double STEPDIST_FOR_BENCHMARK=TerrainNew.GetSize()*1.2*TerrainResolution.x/FRAMES_FOR_BENCHMARK; |
|---|
| 191 | |
|---|
| 192 | |
|---|
| 193 | // Open OpenGL-Window. |
|---|
| 194 | const char* ErrorMsg=SingleOpenGLWindow->Open("Cafu Terrain Viewer 1.2", BenchMarkMode ? 1280 : 800, BenchMarkMode ? 1024 : 600, 32, BenchMarkMode); |
|---|
| 195 | |
|---|
| 196 | if (ErrorMsg) |
|---|
| 197 | { |
|---|
| 198 | printf("\nUnable to open OpenGL window: %s\n", ErrorMsg); |
|---|
| 199 | return 0; |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | |
|---|
| 203 | // Get the renderer with the highest preference number that is supported. |
|---|
| 204 | HMODULE RendererDLL; |
|---|
| 205 | MatSys::Renderer=PlatformAux::GetBestRenderer(RendererDLL); |
|---|
| 206 | |
|---|
| 207 | if (MatSys::Renderer==NULL || RendererDLL==NULL) { printf("No renderer loaded.\n"); SingleOpenGLWindow->Close(); return 0; } |
|---|
| 208 | MatSys::Renderer->Initialize(); |
|---|
| 209 | |
|---|
| 210 | |
|---|
| 211 | // Get the TextureMapManager from the RendererDLL. |
|---|
| 212 | MatSys::TextureMapManagerI* TextureMapManager=PlatformAux::GetTextureMapManager(RendererDLL); |
|---|
| 213 | |
|---|
| 214 | if (TextureMapManager==NULL) { printf("No TextureMapManager obtained.\n"); FreeLibrary(RendererDLL); SingleOpenGLWindow->Close(); return 0; } |
|---|
| 215 | |
|---|
| 216 | |
|---|
| 217 | MatSys::RenderMaterialT* TerrainRenderMat=MatSys::Renderer->RegisterMaterial(TerrainMaterial); |
|---|
| 218 | |
|---|
| 219 | MatSys::Renderer->SetCurrentMaterial(TerrainRenderMat); |
|---|
| 220 | |
|---|
| 221 | |
|---|
| 222 | // As the terrain shaders require (cmat materials to specify) a lightmap, provide one here. |
|---|
| 223 | char Data[]={ 255, 255, 255, 255, 255, 255, 0, 0, |
|---|
| 224 | 255, 255, 255, 255, 255, 255, 0, 0 }; |
|---|
| 225 | |
|---|
| 226 | MatSys::Renderer->SetCurrentLightMap(TextureMapManager->GetTextureMap2D(Data, 2, 2, 3, true, MapCompositionT(MapCompositionT::Linear, MapCompositionT::Linear))); |
|---|
| 227 | MatSys::Renderer->SetCurrentLightDirMap(NULL); // The MatSys provides a default for LightDirMaps when NULL is set. |
|---|
| 228 | |
|---|
| 229 | |
|---|
| 230 | MatSys::Renderer->ClearColor(0.0f, 0.0f, 0.4f, 0.0f); |
|---|
| 231 | |
|---|
| 232 | |
|---|
| 233 | |
|---|
| 234 | /* This is how it used to be. |
|---|
| 235 | We now try it via the vertex indices directly... */ |
|---|
| 236 | |
|---|
| 237 | const float res0=160.0; |
|---|
| 238 | const float res1=160.0; |
|---|
| 239 | |
|---|
| 240 | // BBmin and BBmax are BBs for the xy-plane, z is not needed here. |
|---|
| 241 | // Also note that the y-components have been multiplied by -1, or otherwise the texture gets flipped. |
|---|
| 242 | const float BBmin[2]={ -res0*0.5f*(TerrainNew.GetSize()-1), res1*0.5f*(TerrainNew.GetSize()-1) }; |
|---|
| 243 | const float BBmax[2]={ res0*0.5f*(TerrainNew.GetSize()-1), -res1*0.5f*(TerrainNew.GetSize()-1) }; |
|---|
| 244 | |
|---|
| 245 | const float Plane1[4]={ 1.0f/(BBmax[0]-BBmin[0]), 0.0f, 0.0f, -BBmin[0]/(BBmax[0]-BBmin[0]) }; |
|---|
| 246 | const float Plane2[4]={ 0.0f, 1.0f/(BBmax[1]-BBmin[1]), 0.0f, -BBmin[1]/(BBmax[1]-BBmin[1]) }; |
|---|
| 247 | |
|---|
| 248 | MatSys::Renderer->SetGenPurposeRenderingParam( 4, Plane1[0]); |
|---|
| 249 | MatSys::Renderer->SetGenPurposeRenderingParam( 5, Plane1[1]); |
|---|
| 250 | MatSys::Renderer->SetGenPurposeRenderingParam( 6, Plane1[2]); |
|---|
| 251 | MatSys::Renderer->SetGenPurposeRenderingParam( 7, Plane1[3]); |
|---|
| 252 | MatSys::Renderer->SetGenPurposeRenderingParam( 8, Plane2[0]); |
|---|
| 253 | MatSys::Renderer->SetGenPurposeRenderingParam( 9, Plane2[1]); |
|---|
| 254 | MatSys::Renderer->SetGenPurposeRenderingParam(10, Plane2[2]); |
|---|
| 255 | MatSys::Renderer->SetGenPurposeRenderingParam(11, Plane2[3]); |
|---|
| 256 | |
|---|
| 257 | |
|---|
| 258 | |
|---|
| 259 | TerrainT::ViewInfoT VI; |
|---|
| 260 | |
|---|
| 261 | VI.cull=true; // perform view culling when set |
|---|
| 262 | bool VI_morph=true; // perform geomorphing when set |
|---|
| 263 | |
|---|
| 264 | // Master Game Loop |
|---|
| 265 | TimerT Timer; |
|---|
| 266 | unsigned long FrameCounter=0; |
|---|
| 267 | unsigned long GeomCRC=adler32(0, NULL, 0); // We use Adler-32 instead of CRC-32, as Adler is faster but just as reliable. |
|---|
| 268 | Vector3fT ViewerPos=BenchMarkMode ? Vector3fT(TerrainNew.GetVertices()[0])+Vector3fT(0, 0, 4000.0f) : Vector3fT(0, -500.0f, 1000.0f); |
|---|
| 269 | float Heading=BenchMarkMode ? 55.0f : 0.0f; |
|---|
| 270 | float Pitch =BenchMarkMode ? 25.0f : 0.0f; |
|---|
| 271 | |
|---|
| 272 | while (true) |
|---|
| 273 | { |
|---|
| 274 | // Rufe die Nachrichten der Windows-Nachrichtenschlange ab. |
|---|
| 275 | if (SingleOpenGLWindow->HandleWindowMessages()) break; |
|---|
| 276 | |
|---|
| 277 | MatSys::Renderer->BeginFrame(Timer.GetSecondsSinceCtor()); |
|---|
| 278 | |
|---|
| 279 | // MatSys::Renderer->GetModifyMatrix(MatSys::RendererI::MODEL_TO_WORLD)=MatrixT(); |
|---|
| 280 | |
|---|
| 281 | MatSys::Renderer->SetMatrix(MatSys::RendererI::WORLD_TO_VIEW, MatrixT::GetRotateXMatrix(-90.0f)); |
|---|
| 282 | MatSys::Renderer->RotateX (MatSys::RendererI::WORLD_TO_VIEW, Pitch ); |
|---|
| 283 | MatSys::Renderer->RotateZ (MatSys::RendererI::WORLD_TO_VIEW, Heading); |
|---|
| 284 | MatSys::Renderer->Translate(MatSys::RendererI::WORLD_TO_VIEW, -ViewerPos.x, -ViewerPos.y, -ViewerPos.z); |
|---|
| 285 | |
|---|
| 286 | // if (TextureName==NULL) glColor3f(0.6, 1.0, 0.5); |
|---|
| 287 | // if (TextureName==NULL) glDisable(GL_POLYGON_OFFSET_FILL); |
|---|
| 288 | // if (TextureName==NULL) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); |
|---|
| 289 | |
|---|
| 290 | |
|---|
| 291 | const float tau =4.0; // Error tolerance in pixel. |
|---|
| 292 | // const float tau_min=tau; |
|---|
| 293 | // const float tau_max=VI_morph ? (3.0/2.0)*tau_min : tau_min; |
|---|
| 294 | // The basic formula for fov_x is from soar/main.c, reshape_callback function, rearranged for fov_x. |
|---|
| 295 | // The 67.5 is a fixed value from OpenGLWindow.cpp. |
|---|
| 296 | const float fov_x =2.0f*atan(float(SingleOpenGLWindow->GetWidth())/float(SingleOpenGLWindow->GetHeight())*tan(DEG2RAD(67.5f)/2.0f)); |
|---|
| 297 | const float kappa =tau/SingleOpenGLWindow->GetWidth() * fov_x; |
|---|
| 298 | |
|---|
| 299 | VI.nu =kappa>0.0 ? 1.0f/kappa : FLT_MAX; // inverse of error tolerance in radians |
|---|
| 300 | VI.nu_min=2.0f/3.0f*VI.nu; // lower morph parameter |
|---|
| 301 | VI.nu_max= VI.nu; // upper morph parameter |
|---|
| 302 | |
|---|
| 303 | VI.viewpoint=ViewerPos; |
|---|
| 304 | |
|---|
| 305 | // Set up VI.viewplanes (clip planes) for view frustum culling. |
|---|
| 306 | MatrixT mpv=MatSys::Renderer->GetMatrix(MatSys::Renderer->PROJECTION)*MatSys::Renderer->GetMatrixModelView(); |
|---|
| 307 | |
|---|
| 308 | // Compute view frustum planes. |
|---|
| 309 | for (unsigned long i=0; i<5; i++) |
|---|
| 310 | { |
|---|
| 311 | // m can be used to easily minify / shrink the view frustum. |
|---|
| 312 | // The values should be between 0 and 8: 0 is the default (no minification), 8 is the reasonable maximum. |
|---|
| 313 | const char m=0; |
|---|
| 314 | const float d=(i<4 && m>0) ? 1.0f-0.75f*m/8.0f : 1.0f; |
|---|
| 315 | float plane[4]; |
|---|
| 316 | |
|---|
| 317 | for (unsigned long j=0; j<4; j++) |
|---|
| 318 | plane[j]=((i & 1) ? mpv.m[i/2][j] : -mpv.m[i/2][j]) - d*mpv.m[3][j]; |
|---|
| 319 | |
|---|
| 320 | const float l=sqrt(SQR(plane[0])+SQR(plane[1])+SQR(plane[2])); |
|---|
| 321 | |
|---|
| 322 | VI.viewplanes[i]=Plane3fT(Vector3fT(plane[0]/l, plane[1]/l, plane[2]/l), -plane[3]/l); |
|---|
| 323 | } |
|---|
| 324 | |
|---|
| 325 | |
|---|
| 326 | static MatSys::MeshT TerrainMesh(MatSys::MeshT::TriangleStrip); |
|---|
| 327 | TerrainMesh.Vertices.Overwrite(); |
|---|
| 328 | |
|---|
| 329 | if (UseSOARX) |
|---|
| 330 | { |
|---|
| 331 | ArrayT<Vector3fT>& VectorStrip=TerrainNew.ComputeVectorStrip(VI); |
|---|
| 332 | |
|---|
| 333 | // With SOARX, the vector strip begins as usual and as expected with the first vector. |
|---|
| 334 | for (unsigned long VNr=0; VNr<VectorStrip.Size(); VNr++) |
|---|
| 335 | { |
|---|
| 336 | TerrainMesh.Vertices.PushBackEmpty(); |
|---|
| 337 | TerrainMesh.Vertices[VNr].SetOrigin(VectorStrip[VNr]); |
|---|
| 338 | |
|---|
| 339 | // Update the geometry-CRC. We use Adler-32 instead of CRC-32, as Adler is faster but just as reliable. |
|---|
| 340 | GeomCRC=adler32(GeomCRC, (Bytef*)&VectorStrip[VNr].z, sizeof(VectorStrip[VNr].z)); |
|---|
| 341 | } |
|---|
| 342 | } |
|---|
| 343 | else |
|---|
| 344 | { |
|---|
| 345 | if (VI_morph) |
|---|
| 346 | { |
|---|
| 347 | ArrayT<Vector3fT>& VectorStripNew=TerrainNew.ComputeVectorStripByMorphing(VI); |
|---|
| 348 | |
|---|
| 349 | // Note that the first VectorT at VectorStrip[0] must be skipped! |
|---|
| 350 | for (unsigned long VNr=1; VNr<VectorStripNew.Size(); VNr++) |
|---|
| 351 | { |
|---|
| 352 | TerrainMesh.Vertices.PushBackEmpty(); |
|---|
| 353 | TerrainMesh.Vertices[TerrainMesh.Vertices.Size()-1].SetOrigin(VectorStripNew[VNr]); |
|---|
| 354 | |
|---|
| 355 | // Update the geometry-CRC. We use Adler-32 instead of CRC-32, as Adler is faster but just as reliable. |
|---|
| 356 | GeomCRC=adler32(GeomCRC, (Bytef*)&VectorStripNew[VNr].z, sizeof(VectorStripNew[VNr].z)); |
|---|
| 357 | } |
|---|
| 358 | } |
|---|
| 359 | else |
|---|
| 360 | { |
|---|
| 361 | ArrayT<unsigned long>& IdxStripNew=TerrainNew.ComputeIndexStripByRefinement(VI); |
|---|
| 362 | |
|---|
| 363 | // Note that the first index at IdxStrip[0] must be skipped! |
|---|
| 364 | const TerrainT::VertexT* Vertices=TerrainNew.GetVertices(); |
|---|
| 365 | |
|---|
| 366 | for (unsigned long IdxNr=1; IdxNr<IdxStripNew.Size(); IdxNr++) |
|---|
| 367 | { |
|---|
| 368 | TerrainMesh.Vertices.PushBackEmpty(); |
|---|
| 369 | TerrainMesh.Vertices[TerrainMesh.Vertices.Size()-1].SetOrigin(Vertices[IdxStripNew[IdxNr]]); |
|---|
| 370 | |
|---|
| 371 | // Update the geometry-CRC. We use Adler-32 instead of CRC-32, as Adler is faster but just as reliable. |
|---|
| 372 | GeomCRC=adler32(GeomCRC, (Bytef*)&IdxStripNew[IdxNr], sizeof(IdxStripNew[IdxNr])); |
|---|
| 373 | } |
|---|
| 374 | } |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | MatSys::Renderer->RenderMesh(TerrainMesh); |
|---|
| 378 | |
|---|
| 379 | // if (TextureName==NULL) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); |
|---|
| 380 | // if (TextureName==NULL) glEnable(GL_POLYGON_OFFSET_FILL); |
|---|
| 381 | |
|---|
| 382 | |
|---|
| 383 | double DeltaTime=Timer.GetSecondsSinceLastCall(); |
|---|
| 384 | |
|---|
| 385 | float MoveSpeed=1000.0f*float(DeltaTime); |
|---|
| 386 | float RotSpeed = 90.0f*float(DeltaTime); |
|---|
| 387 | |
|---|
| 388 | |
|---|
| 389 | MatSys::Renderer->EndFrame(); |
|---|
| 390 | SingleOpenGLWindow->SwapBuffers(); |
|---|
| 391 | |
|---|
| 392 | FrameCounter++; |
|---|
| 393 | |
|---|
| 394 | CaKeyboardEventT KE; |
|---|
| 395 | bool QuitProgram=false; |
|---|
| 396 | |
|---|
| 397 | while (SingleOpenGLWindow->GetNextKeyboardEvent(KE)>0) |
|---|
| 398 | { |
|---|
| 399 | if (KE.Type!=CaKeyboardEventT::CKE_KEYDOWN) continue; |
|---|
| 400 | if (KE.Key==CaKeyboardEventT::CK_ESCAPE) QuitProgram=true; |
|---|
| 401 | if (KE.Key==CaKeyboardEventT::CK_C ) { VI.cull =!VI.cull; printf("View frustum culling is %s.\n", VI.cull ? "ON" : "OFF"); } |
|---|
| 402 | if (KE.Key==CaKeyboardEventT::CK_M ) { VI_morph=!VI_morph; printf("Geo-morphing is %s\n", VI_morph ? "ON" : "OFF"); } |
|---|
| 403 | } |
|---|
| 404 | |
|---|
| 405 | if (QuitProgram) break; |
|---|
| 406 | if (BenchMarkMode && FrameCounter==FRAMES_FOR_BENCHMARK) break; |
|---|
| 407 | |
|---|
| 408 | |
|---|
| 409 | if (BenchMarkMode) |
|---|
| 410 | { |
|---|
| 411 | const float vx=float(STEPDIST_FOR_BENCHMARK)*sin(Heading/180.0f*3.1415926f); |
|---|
| 412 | const float vy=float(STEPDIST_FOR_BENCHMARK)*cos(Heading/180.0f*3.1415926f); |
|---|
| 413 | |
|---|
| 414 | ViewerPos=ViewerPos+Vector3fT(vx, vy, 0); |
|---|
| 415 | } |
|---|
| 416 | else |
|---|
| 417 | { |
|---|
| 418 | const float vx=MoveSpeed*sin(Heading/180.0f*3.1415926f); |
|---|
| 419 | const float vy=MoveSpeed*cos(Heading/180.0f*3.1415926f); |
|---|
| 420 | |
|---|
| 421 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_UP ] || SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_W]) ViewerPos=ViewerPos+Vector3fT( vx, vy, 0); |
|---|
| 422 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_DOWN ] || SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_S]) ViewerPos=ViewerPos+Vector3fT(-vx, -vy, 0); |
|---|
| 423 | if ( SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_A]) ViewerPos=ViewerPos+Vector3fT(-vy, vx, 0); |
|---|
| 424 | if ( SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_D]) ViewerPos=ViewerPos+Vector3fT( vy, -vx, 0); |
|---|
| 425 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_INSERT] || SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_R]) ViewerPos.z+=MoveSpeed; |
|---|
| 426 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_DELETE] || SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_F]) ViewerPos.z-=MoveSpeed; |
|---|
| 427 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_LEFT ] ) Heading-=RotSpeed; |
|---|
| 428 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_RIGHT ] ) Heading+=RotSpeed; |
|---|
| 429 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_PGUP ] ) Pitch-=RotSpeed; |
|---|
| 430 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_PGDN ] ) Pitch+=RotSpeed; |
|---|
| 431 | if (SingleOpenGLWindow->GetKeyboardState()[CaKeyboardEventT::CK_END ] ) Pitch=0.0; |
|---|
| 432 | } |
|---|
| 433 | } |
|---|
| 434 | |
|---|
| 435 | const double TotalTime=Timer.GetSecondsSinceCtor(); |
|---|
| 436 | printf("Average frame-rate was: %.2f FPS (%lu frames in %.2f seconds)\n", double(FrameCounter)/TotalTime, FrameCounter, TotalTime); |
|---|
| 437 | printf("Geo-morphing was: %s\n", VI_morph ? " ON" : "OFF"); |
|---|
| 438 | printf("Frustum culling was: %s\n", VI.cull ? " ON" : "OFF"); |
|---|
| 439 | printf("Geometry CRC was: 0x%lX\n", GeomCRC); |
|---|
| 440 | |
|---|
| 441 | // Clean-up. |
|---|
| 442 | MatSys::Renderer->FreeMaterial(TerrainRenderMat); |
|---|
| 443 | MatSys::Renderer->Release(); |
|---|
| 444 | MatSys::Renderer=NULL; |
|---|
| 445 | FreeLibrary(RendererDLL); |
|---|
| 446 | SingleOpenGLWindow->Close(); |
|---|
| 447 | } |
|---|
| 448 | catch (const TerrainT::InitError& /*E*/) |
|---|
| 449 | { |
|---|
| 450 | printf("\nEither \"%s\" could not be found, not be read,\n", TerrainName); |
|---|
| 451 | printf("is not square, is smaller than 3 pixels, or not of size 2^n+1. Sorry.\n"); |
|---|
| 452 | } |
|---|
| 453 | |
|---|
| 454 | return 0; |
|---|
| 455 | } |
|---|