std::unique_ptr<Bucket> CircleLayer::createBucket(StyleBucketParameters& parameters) const { auto bucket = std::make_unique<CircleBucket>(parameters.mode); parameters.eachFilteredFeature(filter, [&] (const auto& feature) { bucket->addGeometry(getGeometries(feature)); }); return std::move(bucket); }
std::unique_ptr<Bucket> CircleLayer::createBucket(StyleBucketParameters& parameters) const { auto bucket = std::make_unique<CircleBucket>(parameters.mode); auto& name = bucketName(); parameters.eachFilteredFeature(filter, [&] (const auto& feature, std::size_t index, const std::string& layerName) { auto geometries = getGeometries(feature); bucket->addGeometry(geometries); parameters.featureIndex.insert(geometries, index, layerName, name); }); return std::move(bucket); }
void FeatureIndex::addFeature( std::unordered_map<std::string, std::vector<Feature>>& result, const IndexedSubfeature& indexedFeature, const GeometryCollection& queryGeometry, const optional<std::vector<std::string>>& filterLayerIDs, const GeometryTile& geometryTile, const CanonicalTileID& tileID, const style::Style& style, const float bearing, const float pixelsToTileUnits) const { auto& layerIDs = bucketLayerIDs.at(indexedFeature.bucketName); if (filterLayerIDs && !vectorsIntersect(layerIDs, *filterLayerIDs)) { return; } auto sourceLayer = geometryTile.getLayer(indexedFeature.sourceLayerName); assert(sourceLayer); auto geometryTileFeature = sourceLayer->getFeature(indexedFeature.index); assert(geometryTileFeature); for (const auto& layerID : layerIDs) { if (filterLayerIDs && !vectorContains(*filterLayerIDs, layerID)) { continue; } auto styleLayer = style.getLayer(layerID); if (!styleLayer || (!styleLayer->is<style::SymbolLayer>() && !styleLayer->baseImpl->queryIntersectsGeometry(queryGeometry, geometryTileFeature->getGeometries(), bearing, pixelsToTileUnits))) { continue; } result[layerID].push_back(convertFeature(*geometryTileFeature, tileID)); } }
std::vector<SymbolFeature> SymbolBucket::processFeatures(const GeometryTileLayer& layer, const FilterExpression& filter, GlyphStore &glyphStore) { const bool has_text = !layout.text.field.empty() && !layout.text.font.empty(); const bool has_icon = !layout.icon.image.empty(); std::vector<SymbolFeature> features; if (!has_text && !has_icon) { return features; } // Determine and load glyph ranges std::set<GlyphRange> ranges; for (std::size_t i = 0; i < layer.featureCount(); i++) { auto feature = layer.getFeature(i); GeometryTileFeatureExtractor extractor(*feature); if (!evaluate(filter, extractor)) continue; SymbolFeature ft; auto getValue = [&feature](const std::string& key) -> std::string { auto value = feature->getValue(key); return value ? toString(*value) : std::string(); }; if (has_text) { std::string u8string = util::replaceTokens(layout.text.field, getValue); if (layout.text.transform == TextTransformType::Uppercase) { u8string = platform::uppercase(u8string); } else if (layout.text.transform == TextTransformType::Lowercase) { u8string = platform::lowercase(u8string); } ft.label = util::utf8_to_utf32::convert(u8string); if (ft.label.size()) { // Loop through all characters of this text and collect unique codepoints. for (char32_t chr : ft.label) { ranges.insert(getGlyphRange(chr)); } } } if (has_icon) { ft.sprite = util::replaceTokens(layout.icon.image, getValue); } if (ft.label.length() || ft.sprite.length()) { auto &multiline = ft.geometry; GeometryCollection geometryCollection = feature->getGeometries(); for (auto& line : geometryCollection) { multiline.emplace_back(); for (auto& point : line) { multiline.back().emplace_back(point.x, point.y); } } features.push_back(std::move(ft)); } } if (layout.placement == PlacementType::Line) { util::mergeLines(features); } if (glyphStore.requestGlyphRangesIfNeeded(layout.text.font, ranges)) { needsGlyphs_ = true; return {}; } return features; }
void GameRenderer::renderWorld(GameWorld* world, const ViewCamera &camera, float alpha) { _renderAlpha = alpha; _renderWorld = world; // Store the input camera, _camera = camera; setupRender(); glBindVertexArray( vao ); float tod = world->getHour() + world->getMinute()/60.f; // Requires a float 0-24 auto weatherID = static_cast<WeatherLoader::WeatherCondition>(world->state->basic.nextWeather * 24); auto weather = world->data->weatherLoader.getWeatherData(weatherID, tod); glm::vec3 skyTop = weather.skyTopColor; glm::vec3 skyBottom = weather.skyBottomColor; glm::vec3 ambient = weather.ambientColor; glm::vec3 dynamic = weather.directLightColor; float theta = (tod/(60.f * 24.f) - 0.5f) * 2 * 3.14159265; glm::vec3 sunDirection{ sin(theta), 0.0, cos(theta), }; sunDirection = glm::normalize(sunDirection); _camera.frustum.near = world->state->cameraNear; _camera.frustum.far = weather.farClipping; auto view = _camera.getView(); auto proj = _camera.frustum.projection(); Renderer::SceneUniformData sceneParams { proj, view, glm::vec4{ambient, 0.0f}, glm::vec4{dynamic, 0.0f}, glm::vec4(skyBottom, 1.f), glm::vec4(camera.position, 0.f), weather.fogStart, camera.frustum.far }; renderer->setSceneParameters(sceneParams); renderer->clear(glm::vec4(skyBottom, 1.f)); _camera.frustum.update(proj * view); if (cullOverride) { cullingCamera.frustum.update( cullingCamera.frustum.projection() * cullingCamera.getView()); } culled = 0; renderer->useProgram(worldProg); //=============================================================== // Render List Construction //--------------------------------------------------------------- RW_PROFILE_BEGIN("RenderList"); // This is sequential at the moment, it should be easy to make it // run in parallel with a good threading system. RenderList renderList; // Naive optimisation, assume 10% hitrate renderList.reserve(world->allObjects.size() * 0.5f); RW_PROFILE_BEGIN("Build"); ObjectRenderer objectRenderer(_renderWorld, (cullOverride ? cullingCamera : _camera), _renderAlpha, getMissingTexture()); // World Objects for (auto object : world->allObjects) { objectRenderer.buildRenderList(object, renderList); } RW_PROFILE_END(); renderer->pushDebugGroup("Objects"); renderer->pushDebugGroup("RenderList"); // Also parallelizable RW_PROFILE_BEGIN("Sort"); std::sort(renderList.begin(), renderList.end(), [](const Renderer::RenderInstruction& a, const Renderer::RenderInstruction&b) { return a.sortKey < b.sortKey; }); RW_PROFILE_END(); RW_PROFILE_BEGIN("Draw"); renderer->drawBatched(renderList); RW_PROFILE_END(); renderer->popDebugGroup(); profObjects = renderer->popDebugGroup(); RW_PROFILE_END(); // Render arrows above anything that isn't radar only (or hidden) ModelRef& arrowModel = world->data->models["arrow"]; if( arrowModel && arrowModel->resource ) { auto arrowTex = world->data->textures[{"copblue",""}]; auto arrowFrame = arrowModel->resource->findFrame( "arrow" ); for( auto& blip : world->state->radarBlips ) { if( blip.second.display == BlipData::Show ) { glm::mat4 model; if( blip.second.target > 0 ) { // TODO restore arrows /*auto& pool = world->getTypeObjectPool(blip.second.target); auto object = pool.find(blip.second.target); if( object ) { model = object->getTimeAdjustedTransform( _renderAlpha ); }*/ } else { model = glm::translate( model, blip.second.coord ); } float a = world->getGameTime() * glm::pi<float>(); model = glm::translate( model, glm::vec3(0.f, 0.f, 2.5f + glm::sin( a ) * 0.5f) ); model = glm::rotate( model, a, glm::vec3(0.f, 0.f, 1.f) ); model = glm::scale( model, glm::vec3(1.5f, 1.5f, 1.5f) ); Renderer::DrawParameters dp; dp.textures = {arrowTex->getName()}; dp.ambient = 1.f; dp.colour = glm::u8vec4(255, 255, 255, 255); auto geom = arrowModel->resource->geometries[arrowFrame->getGeometries()[0]]; Model::SubGeometry& sg = geom->subgeom[0]; dp.start = sg.start; dp.count = sg.numIndices; dp.diffuse = 1.f; renderer->draw( model, &geom->dbuff, dp ); } } } // Draw goal indicators glDepthMask(GL_FALSE); renderer->useProgram( particleProg ); for(auto& i : world->getAreaIndicators()) { renderAreaIndicator( &i ); } glDepthMask(GL_TRUE); renderer->pushDebugGroup("Water"); water.render(this, world); profWater = renderer->popDebugGroup(); renderer->pushDebugGroup("Sky"); glBindVertexArray( vao ); Renderer::DrawParameters dp; dp.start = 0; dp.count = skydomeSegments * skydomeRows * 6; renderer->useProgram(skyProg); renderer->setUniform(skyProg, "TopColor", glm::vec4(skyTop, 1.f)); renderer->setUniform(skyProg, "BottomColor", glm::vec4(skyBottom, 1.f)); renderer->draw(glm::mat4(), &skyDbuff, dp); profSky = renderer->popDebugGroup(); renderer->pushDebugGroup("Effects"); renderEffects(world); profEffects = renderer->popDebugGroup(); glDisable(GL_DEPTH_TEST); GLuint splashTexName = 0; auto fc = world->state->fadeColour; if((fc.r + fc.g + fc.b) == 0 && world->state->currentSplash.size() > 0) { auto splash = world->data->findTexture(world->state->currentSplash); if ( splash ) { splashTexName = splash->getName(); } } if( (world->state->isCinematic || world->state->currentCutscene ) && splashTexName != 0 ) { renderLetterbox(); } float fadeTimer = world->getGameTime() - world->state->fadeStart; if( fadeTimer < world->state->fadeTime || !world->state->fadeOut ) { glUseProgram(ssRectProgram); glUniform2f(ssRectOffset, 0.f, 0.f); glUniform2f(ssRectSize, 1.f, 1.f); glUniform1i(ssRectTexture, 0); if(splashTexName != 0) { glBindTexture(GL_TEXTURE_2D, splashTexName); fc = glm::u16vec3(0, 0, 0); } else { glBindTexture(GL_TEXTURE_2D, 0); } float fadeFrac = 0.f; if( world->state->fadeTime > 0.f ) { fadeFrac = std::min(fadeTimer / world->state->fadeTime, 1.f); } float a = world->state->fadeOut ? 1.f - fadeFrac : fadeFrac; glm::vec4 fadeNormed(fc.r / 255.f, fc.g/ 255.f, fc.b/ 255.f, a); glUniform4fv(ssRectColour, 1, glm::value_ptr(fadeNormed)); glBindVertexArray( ssRectDraw.getVAOName() ); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } if( (world->state->isCinematic || world->state->currentCutscene ) && splashTexName == 0 ) { renderLetterbox(); } renderPostProcess(); glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray( 0 ); }
void SymbolBucket::parseFeatures(const GeometryTileLayer& layer, const Filter& filter) { const bool has_text = !layout.textField.value.empty() && !layout.textFont.value.empty(); const bool has_icon = !layout.iconImage.value.empty(); if (!has_text && !has_icon) { return; } auto layerName = layer.getName(); // Determine and load glyph ranges const GLsizei featureCount = static_cast<GLsizei>(layer.featureCount()); for (GLsizei i = 0; i < featureCount; i++) { auto feature = layer.getFeature(i); FilterEvaluator evaluator(*feature); if (!Filter::visit(filter, evaluator)) continue; SymbolFeature ft; ft.index = i; auto getValue = [&feature](const std::string& key) -> std::string { auto value = feature->getValue(key); if (!value) return std::string(); if (value->is<std::string>()) return value->get<std::string>(); if (value->is<bool>()) return value->get<bool>() ? "true" : "false"; if (value->is<int64_t>()) return util::toString(value->get<int64_t>()); if (value->is<uint64_t>()) return util::toString(value->get<uint64_t>()); if (value->is<double>()) return util::toString(value->get<double>()); return "null"; }; if (has_text) { std::string u8string = util::replaceTokens(layout.textField, getValue); if (layout.textTransform == TextTransformType::Uppercase) { u8string = platform::uppercase(u8string); } else if (layout.textTransform == TextTransformType::Lowercase) { u8string = platform::lowercase(u8string); } ft.label = util::utf8_to_utf32::convert(u8string); if (!ft.label.empty()) { // Loop through all characters of this text and collect unique codepoints. for (char32_t chr : ft.label) { ranges.insert(getGlyphRange(chr)); } } } if (has_icon) { ft.sprite = util::replaceTokens(layout.iconImage, getValue); } if (ft.label.length() || ft.sprite.length()) { auto &multiline = ft.geometry; GeometryCollection geometryCollection = getGeometries(*feature); for (auto& line : geometryCollection) { multiline.emplace_back(); for (auto& point : line) { multiline.back().emplace_back(point.x, point.y); } } features.push_back(std::move(ft)); } } if (layout.symbolPlacement == SymbolPlacementType::Line) { util::mergeLines(features); } }