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, 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 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; } }
static STurfParams GetTurfParams(UnsyncedRNG& rng, const int x, const int y) { STurfParams result; result.x = (x + rng.RandFloat()) * gSSsq; result.y = (y + rng.RandFloat()) * gSSsq; result.rotation = rng.RandFloat() * 360.f; return result; }
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::CreateGrassBladeTex(unsigned char* buf) { float3 col( mapInfo->grass.color + float3(0.11f * rng.RandFloat(), 0.08f * rng.RandFloat(), 0.11f * rng.RandFloat()) ); col.x = Clamp(col.x, 0.f, 1.f); col.y = Clamp(col.y, 0.f, 1.f); col.z = Clamp(col.z, 0.f, 1.f); SColor* img = reinterpret_cast<SColor*>(buf); for(int y=0;y<64;++y){ for(int x=0;x<16;++x){ const float brightness = (0.4f + 0.6f * (y/63.0f)); img[y*256+x] = SColor(col.r * brightness, col.g * brightness, col.b * brightness, 1.0f); } } }
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(); for (int a = 0; a < strawPerTurf; ++a) { const float maxAng = mapInfo->grass.bladeAngle * rng.RandFloat(); const float length = mapInfo->grass.bladeHeight + mapInfo->grass.bladeHeight * rng.RandFloat(); float3 sideVect(rng.RandFloat() - 0.5f, 0.0f, rng.RandFloat() - 0.5f); sideVect.ANormalize(); float3 forwardVect = sideVect.cross(UpVector); sideVect *= mapInfo->grass.bladeWidth; float3 basePos(30.0f, 0.0f, 30.0f); while (basePos.SqLength2D() > (turfSize * turfSize / 4)) { basePos = float3(rng.RandFloat() - 0.5f, 0.f, rng.RandFloat() - 0.5f) * turfSize; } const float xtexCoord = int(14.9999f * rng.RandFloat()) / 16.0f; const int numSections = 1 + int(maxAng * 5.0f); // draw single blade for (float h = 0; h <= 1.0f; h += (1.0f / numSections)) { const float ang = maxAng * h; const float3 edgePos = (UpVector * std::cos(ang) + forwardVect * std::sin(ang)) * length * h; const float3 edgePosL = edgePos - sideVect * (1.0f - h); const float3 edgePosR = edgePos + sideVect * (1.0f - h); if (h == 0.0f) { // start with a degenerated triangle va->AddVertexT(basePos + edgePosR - float3(0.0f, 0.1f, 0.0f), xtexCoord, h); va->AddVertexT(basePos + edgePosR - float3(0.0f, 0.1f, 0.0f), xtexCoord, h); } else { va->AddVertexT(basePos + edgePosR, xtexCoord, h); } va->AddVertexT(basePos + edgePosL, xtexCoord + (1.0f / 16), h); } // end with a degenerated triangle // -> this way we can render multiple blades in a single GL_TRIANGLE_STRIP const float3 edgePos = (UpVector * std::cos(maxAng) + forwardVect * std::sin(maxAng)) * length; va->AddVertexT(basePos + edgePos, xtexCoord + (1.0f / 32), 1.0f); va->AddVertexT(basePos + edgePos, xtexCoord + (1.0f / 32), 1.0f); } glNewList(listNum, GL_COMPILE); va->DrawArrayT(GL_TRIANGLE_STRIP); glEndList(); }
void CGrassDrawer::CreateGrassBladeTex(unsigned char* buf) { float3 redish = float3(0.95f, 0.70f, 0.4f); float3 col = mix(mapInfo->grass.color, redish, 0.1f * rng.RandFloat()); col.x = Clamp(col.x, 0.f, 1.f); col.y = Clamp(col.y, 0.f, 1.f); col.z = Clamp(col.z, 0.f, 1.f); SColor* img = reinterpret_cast<SColor*>(buf); for (int y=0; y<64; ++y) { for (int x=0; x<16; ++x) { const float brightness = smoothstep(-0.8f, 0.5f, y/63.0f) + ((x%2) == 0 ? 0.035f : 0.0f); const float3 c = col * brightness; img[y*256+x] = SColor(c.r, c.g, c.b, 1.0f); } } }
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(); } } }
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); } }