void CGameSetup::LoadStartPositions(bool withoutMap) { if (withoutMap && (startPosType == StartPos_Random || startPosType == StartPos_Fixed)) throw content_error("You need the map to use the map's startpositions"); if (startPosType == StartPos_Random) { // Server syncs these later, so we can use unsynced rng UnsyncedRNG rng; rng.Seed(gameSetupText.length()); rng.Seed((size_t)gameSetupText.c_str()); std::vector<int> teamStartNum(teamStartingData.size()); for (size_t i = 0; i < teamStartingData.size(); ++i) teamStartNum[i] = i; std::random_shuffle(teamStartNum.begin(), teamStartNum.end(), rng); for (size_t i = 0; i < teamStartingData.size(); ++i) teamStartingData[i].teamStartNum = teamStartNum[i]; } else { for (size_t a = 0; a < teamStartingData.size(); ++a) { teamStartingData[a].teamStartNum = (int)a; } } if (startPosType == StartPos_Fixed || startPosType == StartPos_Random) LoadStartPositionsFromMap(); // Show that we havent selected start pos yet if (startPosType == StartPos_ChooseInGame) { for (size_t a = 0; a < teamStartingData.size(); ++a) { teamStartingData[a].startPos.y = -500; } } }
void CGameSetup::LoadStartPositions(bool withoutMap) { TdfParser file(gameSetupText.c_str(), gameSetupText.length()); if (withoutMap && (startPosType == StartPos_Random || startPosType == StartPos_Fixed)) throw content_error("You need the map to use the map's startpositions"); if (startPosType == StartPos_Random) { // Server syncs these later, so we can use unsynced rng UnsyncedRNG rng; rng.Seed(gameSetupText.length()); rng.Seed((size_t)gameSetupText.c_str()); std::vector<int> teamStartNum(teamStartingData.size()); for (size_t i = 0; i < teamStartingData.size(); ++i) teamStartNum[i] = i; std::random_shuffle(teamStartNum.begin(), teamStartNum.end(), rng); for (size_t i = 0; i < teamStartingData.size(); ++i) teamStartingData[i].teamStartNum = teamStartNum[i]; } else { for (size_t a = 0; a < teamStartingData.size(); ++a) { teamStartingData[a].teamStartNum = (int)a; } } if (!withoutMap) LoadStartPositionsFromMap(); // Show that we havent selected start pos yet if (startPosType == StartPos_ChooseInGame) { for (size_t a = 0; a < teamStartingData.size(); ++a) { teamStartingData[a].startPos.y = -500; } } // Load start position from gameSetup script if (startPosType == StartPos_ChooseBeforeGame) { for (size_t a = 0; a < teamStartingData.size(); ++a) { char section[50]; sprintf(section, "GAME\\TEAM%i\\", a); string s(section); std::string xpos = file.SGetValueDef("", s + "StartPosX"); std::string zpos = file.SGetValueDef("", s + "StartPosZ"); if (!xpos.empty()) { teamStartingData[a].startPos.x = atoi(xpos.c_str()); } if (!zpos.empty()) { teamStartingData[a].startPos.z = atoi(zpos.c_str()); } } } }
void CTimeProfiler::AddTime(const std::string& name, unsigned time) { GML_STDMUTEX_LOCK_NOPROF(time); // AddTime std::map<std::string, TimeRecord>::iterator pi; if ( (pi = profile.find(name)) != profile.end() ) { pi->second.total+=time; pi->second.current+=time; pi->second.frames[currentPosition]+=time; } else { profile[name].total=time; profile[name].current=time; profile[name].percent=0; memset(profile[name].frames, 0, 128*sizeof(unsigned)); static UnsyncedRNG rand; rand.Seed(SDL_GetTicks()); profile[name].color.x = rand.RandFloat(); profile[name].color.y = rand.RandFloat(); profile[name].color.z = rand.RandFloat(); profile[name].showGraph=true; } }
void CTimeProfiler::AddTime(const std::string& name, const spring_time time, const bool showGraph) { std::map<std::string, TimeRecord>::iterator pi; if ( (pi = profile.find(name)) != profile.end() ) { // profile already exists //FIXME use atomic ints pi->second.total += time; pi->second.current += time; pi->second.frames[currentPosition] += time; } else { boost::unique_lock<boost::mutex> ulk(m, boost::defer_lock); while (!ulk.try_lock()) {} // create a new profile auto& p = profile[name]; p.total = time; p.current = time; p.percent = 0; memset(p.frames, 0, TimeRecord::frames_size * sizeof(unsigned)); static UnsyncedRNG rand; rand.Seed(spring_tomsecs(spring_gettime())); p.color.x = rand.RandFloat(); p.color.y = rand.RandFloat(); p.color.z = rand.RandFloat(); p.showGraph = showGraph; } }
void CTimeProfiler::AddTime(const std::string& name, unsigned time) { GML_STDMUTEX_LOCK_NOPROF(time); // AddTime std::map<std::string, TimeRecord>::iterator pi; if ( (pi = profile.find(name)) != profile.end() ) { // profile already exists pi->second.total+=time; pi->second.current+=time; pi->second.frames[currentPosition]+=time; } else { // create a new profile profile[name].total=time; profile[name].current=time; profile[name].percent=0; memset(profile[name].frames, 0, TimeRecord::frames_size*sizeof(unsigned)); static UnsyncedRNG rand; rand.Seed(SDL_GetTicks()); profile[name].color.x = rand.RandFloat(); profile[name].color.y = rand.RandFloat(); profile[name].color.z = rand.RandFloat(); // only show "CPU load" by default profile[name].showGraph = (name == "CPU load"); } }
void CGrassDrawer::DrawNearBillboards(const std::vector<InviewNearGrass>& inviewNearGrass) { CVertexArray* va = GetVertexArray(); va->Initialize(); va->EnlargeArrays(inviewNearGrass.size() * numTurfs * 4, 0, VA_SIZE_TN); for (std::vector<InviewNearGrass>::const_iterator gi = inviewNearGrass.begin(); gi != inviewNearGrass.end(); ++gi) { const int x = (*gi).x; const int y = (*gi).y; rng.Seed(y * 1025 + x); for (int a = 0; a < numTurfs; a++) { const float dx = (x + rng.RandFloat()) * gSSsq; const float dy = (y + rng.RandFloat()) * gSSsq; const float col = 1.0f; float3 pos(dx, CGround::GetHeightReal(dx, dy, false) + 0.5f, dy); pos.y -= (CGround::GetSlope(dx, dy, false) * 10.0f + 0.03f); va->AddVertexQTN(pos, 0.0f, 0.0f, float3(-partTurfSize, -partTurfSize, col)); va->AddVertexQTN(pos, 1.0f / 16.0f, 0.0f, float3( partTurfSize, -partTurfSize, col)); va->AddVertexQTN(pos, 1.0f / 16.0f, 1.0f, float3( partTurfSize, partTurfSize, col)); va->AddVertexQTN(pos, 0.0f, 1.0f, float3(-partTurfSize, partTurfSize, col)); } } va->DrawArrayTN(GL_QUADS); }
void CGrassDrawer::CreateGrassDispList(int listNum) { CVertexArray* va = GetVertexArray(); va->Initialize(); rng.Seed(15); for (int a = 0; a < strawPerTurf; ++a) { // draw a single blade const float lngRnd = rng.RandFloat(); const float length = mapInfo->grass.bladeHeight * (1.0f + lngRnd); const float maxAng = mapInfo->grass.bladeAngle * std::max(rng.RandFloat(), 1.f - smoothstep(0.f,1.f,lngRnd)); float3 sideVect(rng.RandFloat() - 0.5f, 0.0f, rng.RandFloat() - 0.5f); sideVect.ANormalize(); float3 bendVect = sideVect.cross(UpVector); // direction to bend into sideVect *= mapInfo->grass.bladeWidth * (-0.15f * lngRnd + 1.0f); const float3 basePos = rng.RandVector2D() * (turfSize - (bendVect * std::sin(maxAng) * length).Length2D()); // select one of the 16 color shadings const float xtexCoord = (rng.RandInt() % 16) / 16.0f; const int numSections = 2 + int(maxAng * 1.2f + length * 0.2f); float3 normalBend = -bendVect; // start btm va->AddVertexTN(basePos + sideVect - float3(0.0f, 3.0f, 0.0f), xtexCoord , 0.f, normalBend); va->AddVertexTN(basePos - sideVect - float3(0.0f, 3.0f, 0.0f), xtexCoord + (1.0f / 16), 0.f, normalBend); for (float h = 0.0f; h < 1.0f; h += (1.0f / numSections)) { const float ang = maxAng * h; const float3 n = (normalBend * std::cos(ang) + UpVector * std::sin(ang)).ANormalize(); const float3 edgePos = (UpVector * std::cos(ang) + bendVect * std::sin(ang)) * length * h; const float3 edgePosL = edgePos - sideVect * (1.0f - h); const float3 edgePosR = edgePos + sideVect * (1.0f - h); va->AddVertexTN(basePos + edgePosR, xtexCoord + (1.0f / 32) * h , h, (n + sideVect * 0.04f).ANormalize()); va->AddVertexTN(basePos + edgePosL, xtexCoord - (1.0f / 32) * h + (1.0f / 16), h, (n - sideVect * 0.04f).ANormalize()); } // end top tip (single triangle) const float3 edgePos = (UpVector * std::cos(maxAng) + bendVect * std::sin(maxAng)) * length; const float3 n = (normalBend * std::cos(maxAng) + UpVector * std::sin(maxAng)).ANormalize(); va->AddVertexTN(basePos + edgePos, xtexCoord + (1.0f / 32), 1.0f, n); // next blade va->EndStrip(); } glNewList(listNum, GL_COMPILE); va->DrawArrayTN(GL_TRIANGLE_STRIP); glEndList(); }
void CGrassDrawer::DrawBillboard(const int x, const int y, const float dist, VA_TYPE_TN* va_tn) { UnsyncedRNG rng; // need our own, cause this function may run threaded rng.Seed(y * mapDims.mapx / grassSquareSize + x); const float rdist = 1.0f + rng.RandFloat() * 0.5f; float alpha = 1.0f - linearstep(maxGrassDist, maxGrassDist + 127.f, dist + 128.f); alpha = std::min(alpha, linearstep(maxDetailedDist, maxDetailedDist + 128.f * rdist, dist)); for (int a = 0; a < numTurfs; a++) { const STurfParams p = GetTurfParams(rng, x, y); float3 pos(p.x, CGround::GetHeightReal(p.x, p.y, false), p.y); pos.y -= CGround::GetSlope(p.x, p.y, false) * 30.0f; va_tn[a * 4 + 0] = { pos, 0.0f, 1.0f, float3(-partTurfSize, -partTurfSize, alpha) }; va_tn[a * 4 + 1] = { pos, 1.0f / 16.0f, 1.0f, float3( partTurfSize, -partTurfSize, alpha) }; va_tn[a * 4 + 2] = { pos, 1.0f / 16.0f, 0.0f, float3( partTurfSize, partTurfSize, alpha) }; va_tn[a * 4 + 3] = { pos, 0.0f, 0.0f, float3(-partTurfSize, partTurfSize, alpha) }; } }
void CGrassBlockDrawer::DrawDetailQuad(const int x, const int y) { const float maxDetailedDist = gd->maxDetailedDist; // blocks close to the camera for (int y2 = y * grassBlockSize; y2 < (y + 1) * grassBlockSize; ++y2) { for (int x2 = x * grassBlockSize; x2 < (x + 1) * grassBlockSize; ++x2) { if (!gd->grassMap[y2 * gs->mapx / grassSquareSize + x2]) { continue; } rng.Seed(y2 * gs->mapx / grassSquareSize + x2); const float dist = GetCamDistOfGrassBlock(x2, y2, false); const float rdist = 1.0f + rng.RandFloat() * 0.5f; //TODO instead of adding grass turfs depending on their distance to the camera, // there should be a fixed sized pool for mesh & billboard turfs // and then we fill these pools with _preference_ for close distance turfs. // So when a map has only less turfs, render them independent of the cam distance as mesh. // -> see Ravaged_2 if (dist < (maxDetailedDist + 128.f * rdist)) { // close grass (render as mesh) CGrassDrawer::InviewNearGrass iv; iv.dist = dist; iv.x = x2; iv.y = y2; inviewGrass.push_back(iv); } if (dist > maxDetailedDist) { // near but not close, save for later drawing CGrassDrawer::InviewNearGrass iv; iv.dist = dist; iv.x = x2; iv.y = y2; inviewNearGrass.push_back(iv); } } } }
void CGrassDrawer::DrawNear(const std::vector<InviewNearGrass>& inviewGrass) { for (const InviewNearGrass& g: inviewGrass) { rng.Seed(g.y * mapDims.mapx / grassSquareSize + g.x); // const float distSq = GetCamDistOfGrassBlock(g.x, g.y, true); const float rdist = 1.0f + rng.RandFloat() * 0.5f; const float alpha = linearstep(maxDetailedDist, maxDetailedDist + 128.f * rdist, g.dist); for (int a = 0; a < numTurfs; a++) { const STurfParams& p = GetTurfParams(rng, g.x, g.y); float3 pos(p.x, CGround::GetHeightReal(p.x, p.y, false), p.y); pos.y -= CGround::GetSlope(p.x, p.y, false) * 30.0f; pos.y -= 2.0f * mapInfo->grass.bladeHeight * alpha; glPushMatrix(); glTranslatef3(pos); glRotatef(p.rotation, 0.0f, 1.0f, 0.0f); glCallList(grassDL); glPopMatrix(); } } }
int main(int argc, char *argv[]) { #ifdef _WIN32 try { #endif SDL_Init(SDL_INIT_TIMER); std::cout << "If you find any errors, report them to mantis or the forums." << std::endl << std::endl; ConfigHandler::Instantiate(); // use the default config file FileSystemHandler::Initialize(false); CGameServer* server = 0; CGameSetup* gameSetup = 0; if (argc == 2) { const std::string script(argv[1]); std::string buf; std::cout << "Loading script from file: " << script << std::endl; ClientSetup settings; CFileHandler fh(argv[1]); if (!fh.FileExists()) throw content_error("script does not exist in given location: " + script); if (!fh.LoadStringData(buf)) throw content_error("script cannot be read: " + script); settings.Init(buf); gameSetup = new CGameSetup(); // to store the gamedata inside if (!gameSetup->Init(buf)) { // read the script provided by cmdline std::cout << "Failed to load script" << std::endl; return 1; } std::cout << "Starting server..." << std::endl; // Create the server, it will run in a separate thread GameData data; UnsyncedRNG rng; rng.Seed(gameSetup->gameSetupText.length()); rng.Seed(script.length()); data.SetRandomSeed(rng.RandInt()); // Use script provided hashes if they exist if (gameSetup->mapHash != 0) { data.SetMapChecksum(gameSetup->mapHash); gameSetup->LoadStartPositions(false); // reduced mode } else { data.SetMapChecksum(archiveScanner->GetArchiveCompleteChecksum(gameSetup->mapName)); CFileHandler f("maps/" + gameSetup->mapName); if (!f.FileExists()) { vfsHandler->AddArchiveWithDeps(gameSetup->mapName, false); } gameSetup->LoadStartPositions(); // full mode } if (gameSetup->modHash != 0) { data.SetModChecksum(gameSetup->modHash); } else { const std::string& modArchive = archiveScanner->ArchiveFromName(gameSetup->modName); const unsigned int modCheckSum = archiveScanner->GetArchiveCompleteChecksum(modArchive); data.SetModChecksum(modCheckSum); } data.SetSetup(gameSetup->gameSetupText); server = new CGameServer(settings.hostIP, settings.hostPort, &data, gameSetup); while (!server->HasFinished()) // check if still running #ifdef _WIN32 Sleep(1000); #else sleep(1); // if so, wait 1 second #endif delete server; // delete the server after usage } else { std::cout << "usage: " << argv[0] << " <full_path_to_script>" << std::endl; } FileSystemHandler::Cleanup(); ConfigHandler::Deallocate(); #ifdef _WIN32 } catch (const std::exception& err) { std::cout << "Exception raised: " << err.what() << std::endl; return 1; } #endif return 0; }
CGrassDrawer::CGrassDrawer() : CEventClient("[GrassDrawer]", 199992, false) , grassOff(false) , blocksX(mapDims.mapx / grassSquareSize / grassBlockSize) , blocksY(mapDims.mapy / grassSquareSize / grassBlockSize) , grassDL(0) , grassBladeTex(0) , farTex(0) , farnearVA(nullptr) , updateBillboards(false) , grassMap(nullptr) { blockDrawer.ResetState(); rng.Seed(15); const int detail = configHandler->GetInt("GrassDetail"); // some ATI drivers crash with grass enabled, default to disabled if ((detail == 0) || ((detail == 7) && globalRendering->haveATI)) { grassOff = true; return; } // needed to create the far tex if (!GLEW_EXT_framebuffer_blit) { grassOff = true; return; } // load grass density from map { MapBitmapInfo grassbm; unsigned char* grassdata = readMap->GetInfoMap("grass", &grassbm); if (!grassdata) { grassOff = true; return; } if (grassbm.width != mapDims.mapx / grassSquareSize || grassbm.height != mapDims.mapy / grassSquareSize) { char b[128]; SNPRINTF(b, sizeof(b), "grass-map has wrong size (%dx%d, should be %dx%d)\n", grassbm.width, grassbm.height, mapDims.mapx / 4, mapDims.mapy / 4); throw std::runtime_error(b); } const int grassMapSize = mapDims.mapx * mapDims.mapy / (grassSquareSize * grassSquareSize); grassMap = new unsigned char[grassMapSize]; memcpy(grassMap, grassdata, grassMapSize); readMap->FreeInfoMap("grass", grassdata); } // create/load blade texture { CBitmap grassBladeTexBM; if (!grassBladeTexBM.Load(mapInfo->grass.bladeTexName)) { // map didn't define a grasstex, so generate one grassBladeTexBM.channels = 4; grassBladeTexBM.Alloc(256,64); for (int a = 0; a < 16; ++a) { CreateGrassBladeTex(&grassBladeTexBM.mem[a * 16 * 4]); } } //grassBladeTexBM.Save("blade.png", false); grassBladeTex = grassBladeTexBM.CreateTexture(true); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } // create shaders * finalize grass.resize(blocksX * blocksY); farnearVA = new CVertexArray; grassDL = glGenLists(1); ChangeDetail(detail); LoadGrassShaders(); configHandler->NotifyOnChange(this); // eventclient autoLinkEvents = true; RegisterLinkedEvents(this); eventHandler.AddClient(this); }
int main(int argc, char *argv[]) { #ifdef _WIN32 try { #endif std::cout << "If you find any errors, report them to mantis or the forums." << std::endl << std::endl; ConfigHandler::Instantiate(""); FileSystemHandler::Cleanup(); FileSystemHandler::Initialize(false); CGameServer* server = 0; CGameSetup* gameSetup = 0; if (argc > 1) { const std::string script(argv[1]); std::cout << "Loading script from file: " << script << std::endl; ClientSetup settings; CFileHandler fh(argv[1]); if (!fh.FileExists()) throw content_error("Setupscript doesn't exists in given location: "+script); std::string buf; if (!fh.LoadStringData(buf)) throw content_error("Setupscript cannot be read: "+script); settings.Init(buf); gameSetup = new CGameSetup(); // to store the gamedata inside if (!gameSetup->Init(buf)) // read the script provided by cmdline { std::cout << "Failed to load script" << std::endl; return 1; } std::cout << "Starting server..." << std::endl; // Create the server, it will run in a separate thread GameData* data = new GameData(); UnsyncedRNG rng; rng.Seed(gameSetup->gameSetupText.length()); rng.Seed(script.length()); data->SetRandomSeed(rng.RandInt()); // Use script provided hashes if they exist if (gameSetup->mapHash != 0) { data->SetMapChecksum(gameSetup->mapHash); gameSetup->LoadStartPositions(false); // reduced mode } else { data->SetMapChecksum(archiveScanner->GetMapChecksum(gameSetup->mapName)); CFileHandler* f = new CFileHandler("maps/" + gameSetup->mapName); if (!f->FileExists()) { std::vector<std::string> ars = archiveScanner->GetArchivesForMap(gameSetup->mapName); if (ars.empty()) { throw content_error("Couldn't find any archives for map '" + gameSetup->mapName + "'."); } for (std::vector<std::string>::iterator i = ars.begin(); i != ars.end(); ++i) { if (!vfsHandler->AddArchive(*i, false)) { throw content_error("Couldn't load archive '" + *i + "' for map '" + gameSetup->mapName + "'."); } } } delete f; gameSetup->LoadStartPositions(); // full mode } if (gameSetup->modHash != 0) { data->SetModChecksum(gameSetup->modHash); } else { const std::string modArchive = archiveScanner->ModNameToModArchive(gameSetup->modName); data->SetModChecksum(archiveScanner->GetModChecksum(modArchive)); } data->SetSetup(gameSetup->gameSetupText); server = new CGameServer(&settings, false, data, gameSetup); while (!server->HasFinished()) // check if still running #ifdef _WIN32 Sleep(1000); #else sleep(1); // if so, wait 1 second #endif delete server; // delete the server after usage } else { std::cout << "usage: spring-dedicated <full_path_to_script>" << std::endl; } FileSystemHandler::Cleanup(); #ifdef _WIN32 } catch (const std::exception& err) { std::cout << "Exception raised: " << err.what() << std::endl; return 1; } #endif return 0; }
int main(int argc, char* argv[]) { try { spring_clock::PushTickRate(); // initialize start time (can safely be done before SDL_Init // since we are not using SDL_GetTicks as our clock anymore) spring_time::setstarttime(spring_time::gettime(true)); CLogOutput::LogSystemInfo(); std::string scriptName; std::string scriptText; ParseCmdLine(argc, argv, &scriptName); GlobalConfig::Instantiate(); FileSystemInitializer::InitializeLogOutput(); FileSystemInitializer::Initialize(); // Initialize crash reporting CrashHandler::Install(); LOG("report any errors to Mantis or the forums."); LOG("loading script from file: %s", scriptName.c_str()); CGameServer* server = NULL; // server will take ownership of these boost::shared_ptr<ClientSetup> dsClientSetup(new ClientSetup()); boost::shared_ptr<GameData> dsGameData(new GameData()); boost::shared_ptr<CGameSetup> dsGameSetup(new CGameSetup()); CFileHandler fh(scriptName); if (!fh.FileExists()) throw content_error("script does not exist in given location: " + scriptName); if (!fh.LoadStringData(scriptText)) throw content_error("script cannot be read: " + scriptName); dsClientSetup->LoadFromStartScript(scriptText); if (!dsGameSetup->Init(scriptText)) { // read the script provided by cmdline LOG_L(L_ERROR, "failed to load script %s", scriptName.c_str()); return 1; } // Create the server, it will run in a separate thread UnsyncedRNG rng; const unsigned seed = time(NULL) % ((spring_gettime().toNanoSecsi() + 1) * 9007); rng.Seed(seed); dsGameData->SetRandomSeed(rng.RandInt()); // Use script provided hashes if they exist if (dsGameSetup->mapHash != 0) { dsGameData->SetMapChecksum(dsGameSetup->mapHash); dsGameSetup->LoadStartPositions(false); // reduced mode } else { dsGameData->SetMapChecksum(archiveScanner->GetArchiveCompleteChecksum(dsGameSetup->mapName)); CFileHandler f("maps/" + dsGameSetup->mapName); if (!f.FileExists()) { vfsHandler->AddArchiveWithDeps(dsGameSetup->mapName, false); } dsGameSetup->LoadStartPositions(); // full mode } if (dsGameSetup->modHash != 0) { dsGameData->SetModChecksum(dsGameSetup->modHash); } else { const std::string& modArchive = archiveScanner->ArchiveFromName(dsGameSetup->modName); const unsigned int modCheckSum = archiveScanner->GetArchiveCompleteChecksum(modArchive); dsGameData->SetModChecksum(modCheckSum); } LOG("starting server..."); dsGameData->SetSetupText(dsGameSetup->setupText); server = new CGameServer(dsClientSetup, dsGameData, dsGameSetup); while (!server->HasGameID()) { // wait until gameID has been generated or // a timeout occurs (if no clients connect) if (server->HasFinished()) { break; } spring_secs(1).sleep(); } while (!server->HasFinished()) { static bool printData = (server->GetDemoRecorder() != NULL); if (printData) { printData = false; const boost::scoped_ptr<CDemoRecorder>& demoRec = server->GetDemoRecorder(); const boost::uint8_t* gameID = (demoRec->GetFileHeader()).gameID; LOG("recording demo: %s", (demoRec->GetName()).c_str()); LOG("using mod: %s", (dsGameSetup->modName).c_str()); LOG("using map: %s", (dsGameSetup->mapName).c_str()); LOG("GameID: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", gameID[0], gameID[1], gameID[2], gameID[3], gameID[4], gameID[5], gameID[6], gameID[7], gameID[8], gameID[9], gameID[10], gameID[11], gameID[12], gameID[13], gameID[14], gameID[15]); } // wait 1 second between checks spring_secs(1).sleep(); } LOG("exiting"); delete server; FileSystemInitializer::Cleanup(); GlobalConfig::Deallocate(); spring_clock::PopTickRate(); LOG("exited"); } CATCH_SPRING_ERRORS return GetExitCode(); }
CGrassDrawer::CGrassDrawer() : grassOff(false) , grassDL(0) , grassBladeTex(0) , farTex(0) , grassMap(nullptr) { const int detail = configHandler->GetInt("GrassDetail"); // some ATI drivers crash with grass enabled, default to disabled if ((detail == 0) || ((detail == 7) && globalRendering->haveATI)) { grassOff = true; return; } if (!GLEW_EXT_framebuffer_blit) { grassOff = true; return; } { MapBitmapInfo grassbm; unsigned char* grassdata = readMap->GetInfoMap("grass", &grassbm); if (!grassdata) { grassOff = true; return; } if (grassbm.width != gs->mapx / grassSquareSize || grassbm.height != gs->mapy / grassSquareSize) { char b[128]; SNPRINTF(b, sizeof(b), "grass-map has wrong size (%dx%d, should be %dx%d)\n", grassbm.width, grassbm.height, gs->mapx / 4, gs->mapy / 4); throw std::runtime_error(b); } const int grassMapSize = gs->mapx * gs->mapy / (grassSquareSize * grassSquareSize); grassMap = new unsigned char[grassMapSize]; memcpy(grassMap, grassdata, grassMapSize); readMap->FreeInfoMap("grass", grassdata); } ChangeDetail(detail); blocksX = gs->mapx / grassSquareSize / grassBlockSize; blocksY = gs->mapy / grassSquareSize / grassBlockSize; rng.Seed(15); grassDL = glGenLists(1); CreateGrassDispList(grassDL); { CBitmap grassBladeTexBM; if (!grassBladeTexBM.Load(mapInfo->grass.grassBladeTexName)) { //! map didn't define a grasstex, so generate one grassBladeTexBM.channels = 4; grassBladeTexBM.Alloc(256,64); for (int a = 0; a < 16; ++a) { CreateGrassBladeTex(&grassBladeTexBM.mem[a * 16 * 4]); } } glGenTextures(1, &grassBladeTex); glBindTexture(GL_TEXTURE_2D, grassBladeTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glBuildMipmaps(GL_TEXTURE_2D, GL_RGBA8, grassBladeTexBM.xsize, grassBladeTexBM.ysize, GL_RGBA, GL_UNSIGNED_BYTE, &grassBladeTexBM.mem[0]); } CreateFarTex(); LoadGrassShaders(); configHandler->NotifyOnChange(this); }
void CGrassBlockDrawer::DrawQuad(int x, int y) { const float maxDetailedDist = gd->maxDetailedDist; CGrassDrawer::NearGrassStruct* nearGrass = gd->nearGrass; if (abs(x - cx) <= gd->detailedBlocks && abs(y - cy) <= gd->detailedBlocks) { //! blocks close to the camera for (int y2 = y * grassBlockSize; y2 < (y + 1) * grassBlockSize; ++y2) { for (int x2 = x * grassBlockSize; x2 < (x + 1) * grassBlockSize; ++x2) { if (gd->grassMap[y2 * gs->mapx / grassSquareSize + x2]) { float3 squarePos((x2 + 0.5f) * gSSsq, 0.0f, (y2 + 0.5f) * gSSsq); squarePos.y = CGround::GetHeightReal(squarePos.x, squarePos.z, false); const float sqdist = (camera->GetPos() - squarePos).SqLength(); CGrassDrawer::NearGrassStruct* ng = &nearGrass[(y2 & 31) * 32 + (x2 & 31)]; if (sqdist < (maxDetailedDist * maxDetailedDist)) { //! close grass, draw directly rng.Seed(y2 * 1025 + x2); for (int a = 0; a < gd->numTurfs; a++) { const float dx = (x2 + rng.RandFloat()) * gSSsq; const float dy = (y2 + rng.RandFloat()) * gSSsq; float3 pos(dx, CGround::GetHeightReal(dx, dy, false), dy); pos.y -= CGround::GetSlope(dx, dy, false) * 10.0f + 0.03f; if (ng->square != y2 * 2048 + x2) { const float3 v = squarePos - camera->GetPos(); ng->rotation = GetHeadingFromVector(v.x, v.z) * 180.0f / 32768 + 180; //FIXME make more random ng->square = y2 * 2048 + x2; } glPushMatrix(); glTranslatef3(pos); glRotatef(ng->rotation, 0.0f, 1.0f, 0.0f); glCallList(gd->grassDL); glPopMatrix(); } } else { //! near but not close, save for later drawing CGrassDrawer::InviewNearGrass iv; iv.dist = sqdist; iv.x = x2; iv.y = y2; inviewNearGrass.push_back(iv); ng->square = -1; } } } } return; } const float3 dif(camera->GetPos().x - ((x + 0.5f) * bMSsq), 0.0f, camera->GetPos().z - ((y + 0.5f) * bMSsq)); const float dist = dif.SqLength2D(); if (dist < Square(gd->maxGrassDist)) { const int curSquare = y * gd->blocksX + x; const int curModSquare = (y & 31) * 32 + (x & 31); CGrassDrawer::GrassStruct* grass = gd->grass + curModSquare; grass->lastSeen = globalRendering->drawFrame; if (grass->square != curSquare) { grass->square = curSquare; delete grass->va; grass->va = NULL; } if (!grass->va) { grass->va = new CVertexArray; grass->pos = float3((x + 0.5f) * bMSsq, CGround::GetHeightReal((x + 0.5f) * bMSsq, (y + 0.5f) * bMSsq, false), (y + 0.5f) * bMSsq); CVertexArray* va = grass->va; va->Initialize(); for (int y2 = y * grassBlockSize; y2 < (y + 1) * grassBlockSize; ++y2) { for (int x2 = x * grassBlockSize; x2 < (x + 1) * grassBlockSize; ++x2) { if (gd->grassMap[y2 * gs->mapx / grassSquareSize + x2]) { rng.Seed(y2 * 1025 + x2); for (int a = 0; a < gd->numTurfs; a++) { const float dx = (x2 + rng.RandFloat()) * gSSsq; const float dy = (y2 + rng.RandFloat()) * gSSsq; const float col = 1.0f; float3 pos(dx, CGround::GetHeightReal(dx, dy, false) + 0.5f, dy); pos.y -= (CGround::GetSlope(dx, dy, false) * 10.0f + 0.03f); va->AddVertexTN(pos, 0.0f, 0.0f, float3(-partTurfSize, -partTurfSize, col)); va->AddVertexTN(pos, 1.0f / 16.0f, 0.0f, float3( partTurfSize, -partTurfSize, col)); va->AddVertexTN(pos, 1.0f / 16.0f, 1.0f, float3( partTurfSize, partTurfSize, col)); va->AddVertexTN(pos, 0.0f, 1.0f, float3(-partTurfSize, partTurfSize, col)); } } } } } CGrassDrawer::InviewGrass ig; ig.num = curModSquare; ig.dist = dif.Length2D(); inviewGrass.push_back(ig); } }