static int flash_erase(struct blocklevel_device *bl, uint64_t dst, uint64_t size) { struct flash_chip *c = container_of(bl, struct flash_chip, bl); struct spi_flash_ctrl *ct = c->ctrl; uint32_t chunk; uint8_t cmd; int rc; /* Some sanity checking */ if (((dst + size) <= dst) || !size || (dst + size) > c->tsize) return FLASH_ERR_PARM_ERROR; /* Check boundaries fit erase blocks */ if ((dst | size) & c->min_erase_mask) return FLASH_ERR_ERASE_BOUNDARY; FL_DBG("LIBFLASH: Erasing 0x%" PRIx64"..0%" PRIx64 "...\n", dst, dst + size); /* Use controller erase if supported */ if (ct->erase) return ct->erase(ct, dst, size); /* Allright, loop as long as there's something to erase */ while(size) { /* How big can we make it based on alignent & size */ fl_get_best_erase(c, dst, size, &chunk, &cmd); /* Poke write enable */ rc = fl_wren(ct); if (rc) return rc; /* Send erase command */ rc = ct->cmd_wr(ct, cmd, true, dst, NULL, 0); if (rc) return rc; /* Wait for write complete */ rc = fl_sync_wait_idle(ct); if (rc) return rc; size -= chunk; dst += chunk; } return 0; }
ModelCoordinate HexGrid::toLayerCoordinates(const ExactModelCoordinate& map_coord) { FL_DBG(_log, LMsg("==============\nConverting map coords ") << map_coord << " to int32_t layer coords..."); ExactModelCoordinate elc = m_inverse_matrix * map_coord; elc.y *= VERTICAL_MULTIP_INV; // approximate conversion using squares instead of hexes if( static_cast<int32_t>(round(elc.y)) & 1 ) elc.x -= 0.5; ExactModelCoordinate lc = ExactModelCoordinate(round(elc.x), round(elc.y), round(elc.z)); int32_t x = static_cast<int32_t>(lc.x); int32_t y = static_cast<int32_t>(lc.y); int32_t z = static_cast<int32_t>(lc.z); // distance of given point from our approximation // If y uneven dx=-dx and dy=-dy double dx,dy; if (y & 1) { dx = elc.x - lc.x; dy = elc.y - lc.y; } else { dx = lc.x - elc.x; dy = lc.y - elc.y; } // adjustment for cases where our approximation lies beyond the hex edge if (ABS(dy) > ((HEX_TO_CORNER - HEX_EDGE_GRADIENT * ABS(dx)) * VERTICAL_MULTIP_INV)) { int8_t ddx, ddy; if (dx>0) ddx = -1; else ddx = 0; if (dy>0) ddy = -1; else ddy = 1; if (y & 1) { ddx = -ddx; ddy = -ddy; } x += ddx; y += ddy; } return ModelCoordinate(x,y,z); }
void ImageManager::removeUnreferenced() { ImageHandleMapIterator it = m_imgHandleMap.begin(), itend = m_imgHandleMap.end(); std::vector<int> imgHandles; int32_t count = 0; for ( ; it != itend; ++it) { if ( it->second.useCount() == 2) { imgHandles.push_back(it->second->getHandle()); count++; } } for (std::vector<int>::iterator it = imgHandles.begin(); it != imgHandles.end(); ++it) { remove(*it); } FL_DBG(_log, LMsg("ImageManager::removeUnreferenced() - ") << "Removed " << count << " unreferenced resources."); }
int blocklevel_raw_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len) { int rc; FL_DBG("%s: 0x%" PRIx64 "\t%p\t0x%" PRIx64 "\n", __func__, pos, buf, len); if (!bl || !bl->read || !buf) { errno = EINVAL; return FLASH_ERR_PARM_ERROR; } rc = reacquire(bl); if (rc) return rc; rc = bl->read(bl, pos, buf, len); release(bl); return rc; }
void Consequent::modify(scalar activationDegree, const TNorm* implication) { if (not isLoaded()) { throw fl::Exception("[consequent error] consequent <" + getText() + "> is not loaded", FL_AT); } for (std::size_t i = 0; i < _conclusions.size(); ++i) { Proposition* proposition = _conclusions.at(i); if (proposition->variable->isEnabled()) { if (not proposition->hedges.empty()) { for (std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin(); rit != proposition->hedges.rend(); ++rit) { activationDegree = (*rit)->hedge(activationDegree); } } OutputVariable * outputVariable = static_cast<OutputVariable*> (proposition->variable); Activated term(proposition->term, activationDegree, implication); outputVariable->fuzzyOutput()->addTerm(term); FL_DBG("Aggregating " << term.toString()); } } }
scalar SmallestOfMaximum::defuzzify(const Term* term, scalar minimum, scalar maximum) const { if (not fl::Op::isFinite(minimum + maximum)) { return fl::nan; } if (maximum - minimum > _resolution) { FL_DBG("[accuracy warning] the resolution <" << _resolution << "> " "is smaller than the range <" << minimum << ", " << maximum << ">. In order to " "improve the accuracy, the resolution should be at least equal to the range."); } scalar dx = (maximum - minimum) / _resolution; scalar x, y; scalar ymax = -1.0, xsmallest = minimum; for (int i = 0; i < _resolution; ++i) { x = minimum + (i + 0.5) * dx; y = term->membership(x); if (Op::isGt(y, ymax)) { xsmallest = x; ymax = y; } } return xsmallest; }
scalar WeightedAverage::defuzzify(const Term* term, scalar minimum, scalar maximum) const { (void) minimum; (void) maximum; const Accumulated* takagiSugeno = dynamic_cast<const Accumulated*> (term); if (not takagiSugeno) { std::ostringstream ss; ss << "[defuzzification error]" << "expected an Accumulated term instead of" << "<" << term->toString() << ">"; throw fl::Exception(ss.str(), FL_AT); } scalar sum = 0.0; scalar weights = 0.0; FL_DBG("Defuzzifying " << takagiSugeno->numberOfTerms() << " output terms"); for (int i = 0; i < takagiSugeno->numberOfTerms(); ++i) { const Thresholded* thresholded = dynamic_cast<const Thresholded*> (takagiSugeno->getTerm(i)); if (not thresholded) { std::ostringstream ss; ss << "[defuzzification error]" << "expected a Thresholded term instead of" << "<" << takagiSugeno->getTerm(i)->toString() << ">"; throw fl::Exception(ss.str(), FL_AT); } scalar w = thresholded->getThreshold(); scalar z = Tsukamoto::tsukamoto(thresholded, takagiSugeno->getMinimum(), takagiSugeno->getMaximum()); //Traditionally, activation is the AlgebraicProduct sum += thresholded->getActivation()->compute(w, z); weights += w; } return sum / weights; }
SubImageFont::SubImageFont(const std::string& filename, const std::string& glyphs) : ImageFontBase() { FL_LOG(_log, LMsg("guichan_image_font, loading ") << filename << " glyphs " << glyphs); //prock - 504 ImagePtr img = ImageManager::instance()->load(filename); int32_t image_id = img->getHandle(); SDL_Surface* surface = img->getSurface(); m_colorkey = RenderBackend::instance()->getColorKey(); if( !surface ) { throw CannotOpenFile(filename); } // Make sure we get 32bit RGB // and copy the Pixelbuffers surface SDL_Surface *tmp = SDL_CreateRGBSurface(SDL_SWSURFACE, surface->w,surface->h,32, RMASK, GMASK, BMASK ,NULLMASK); SDL_BlitSurface(surface,0,tmp,0); surface = tmp; // Prepare the data for extracting the glyphs. uint32_t *pixels = reinterpret_cast<uint32_t*>(surface->pixels); int32_t x, w; x = 0; w=0; SDL_Rect src; src.h = surface->h; src.y = 0; uint32_t separator = pixels[0]; uint32_t colorkey = SDL_MapRGB(surface->format, m_colorkey.r, m_colorkey.g, m_colorkey.b); // if colorkey feature is not enabled then manually find the color key in the font if (!RenderBackend::instance()->isColorKeyEnabled()) { while(x < surface->w && pixels[x] == separator) { ++x; } colorkey = pixels[x]; } // Disable alpha blending, so that we use color keying SDL_SetAlpha(surface,0,255); SDL_SetColorKey(surface,SDL_SRCCOLORKEY,colorkey); FL_DBG(_log, LMsg("image_font") << " glyph separator is " << pprint(reinterpret_cast<void*>(separator)) << " transparent color is " << pprint(reinterpret_cast<void*>(colorkey))); // Finally extract all glyphs std::string::const_iterator text_it = glyphs.begin(); while(text_it != glyphs.end()) { w=0; while(x < surface->w && pixels[x] == separator) ++x; if( x == surface->w ) break; while(x + w < surface->w && pixels[x + w] != separator) ++w; src.x = x; src.w = w; tmp = SDL_CreateRGBSurface(SDL_SWSURFACE, w,surface->h,32, RMASK, GMASK, BMASK ,NULLMASK); SDL_FillRect(tmp,0,colorkey); SDL_BlitSurface(surface,&src,tmp,0); // Disable alpha blending, so that we use colorkeying SDL_SetAlpha(tmp,0,255); SDL_SetColorKey(tmp,SDL_SRCCOLORKEY,colorkey); uint32_t codepoint = utf8::next(text_it, glyphs.end()); m_glyphs[ codepoint ].surface = tmp; x += w; } // Set placeholder glyph // This should actually work ith utf8. if( m_glyphs.find('?') != m_glyphs.end() ) { m_placeholder = m_glyphs['?']; } else { m_placeholder.surface = 0; } mHeight = surface->h; SDL_FreeSurface(surface); }
void Antecedent::load(const std::string& antecedent, fl::Rule* rule, const Engine* engine) { FL_DBG("Antecedent: " << antecedent); unload(); this->_text = antecedent; if (fl::Op::trim(antecedent).empty()) { throw fl::Exception("[syntax error] antecedent is empty", FL_AT); } /* Builds an proposition tree from the antecedent of a fuzzy rule. The rules are: 1) After a variable comes 'is', 2) After 'is' comes a hedge or a term 3) After a hedge comes a hedge or a term 4) After a term comes a variable or an operator */ Function function; std::string postfix = function.toPostfix(antecedent); FL_DBG("Postfix: " << postfix); std::stringstream tokenizer(postfix); std::string token; enum FSM { S_VARIABLE = 1, S_IS = 2, S_HEDGE = 4, S_TERM = 8, S_AND_OR = 16 }; int state = S_VARIABLE; std::stack<Expression*> expressionStack; Proposition* proposition = fl::null; try { while (tokenizer >> token) { if (state bitand S_VARIABLE) { Variable* variable = fl::null; if (engine->hasInputVariable(token)) variable = engine->getInputVariable(token); else if (engine->hasOutputVariable(token)) variable = engine->getOutputVariable(token); if (variable) { proposition = new Proposition; proposition->variable = variable; expressionStack.push(proposition); state = S_IS; FL_DBG("Token <" << token << "> is variable"); continue; } } if (state bitand S_IS) { if (token == Rule::isKeyword()) { state = S_HEDGE bitor S_TERM; FL_DBG("Token <" << token << "> is keyword"); continue; } } if (state bitand S_HEDGE) { Hedge* hedge = rule->getHedge(token); if (not hedge) { HedgeFactory* factory = FactoryManager::instance()->hedge(); if (factory->hasConstructor(token)) { hedge = factory->constructObject(token); rule->addHedge(hedge); } } if (hedge) { proposition->hedges.push_back(hedge); if (dynamic_cast<Any*> (hedge)) { state = S_VARIABLE bitor S_AND_OR; } else { state = S_HEDGE bitor S_TERM; } FL_DBG("Token <" << token << "> is hedge"); continue; } } if (state bitand S_TERM) { if (proposition->variable->hasTerm(token)) { proposition->term = proposition->variable->getTerm(token); state = S_VARIABLE bitor S_AND_OR; FL_DBG("Token <" << token << "> is term"); continue; } } if (state bitand S_AND_OR) { if (token == Rule::andKeyword() or token == Rule::orKeyword()) { if (expressionStack.size() < 2) { std::ostringstream ex; ex << "[syntax error] logical operator <" << token << "> expects two operands," << "but found <" << expressionStack.size() << "> in antecedent"; throw fl::Exception(ex.str(), FL_AT); } Operator* fuzzyOperator = new Operator; fuzzyOperator->name = token; fuzzyOperator->right = expressionStack.top(); expressionStack.pop(); fuzzyOperator->left = expressionStack.top(); expressionStack.pop(); expressionStack.push(fuzzyOperator); state = S_VARIABLE bitor S_AND_OR; FL_DBG("Subtree: " << fuzzyOperator->toString() << "(" << fuzzyOperator->left->toString() << ") " << "(" << fuzzyOperator->right->toString() << ")"); continue; } } //If reached this point, there was an error if ((state bitand S_VARIABLE) or (state bitand S_AND_OR)) { std::ostringstream ex; ex << "[syntax error] antecedent expected variable or logical operator, but found <" << token << ">"; throw fl::Exception(ex.str(), FL_AT); } if (state bitand S_IS) { std::ostringstream ex; ex << "[syntax error] antecedent expected keyword <" << Rule::isKeyword() << ">, but found <" << token << ">"; throw fl::Exception(ex.str(), FL_AT); } if ((state bitand S_HEDGE) or (state bitand S_TERM)) { std::ostringstream ex; ex << "[syntax error] antecedent expected hedge or term, but found <" << token << ">"; throw fl::Exception(ex.str(), FL_AT); } std::ostringstream ex; ex << "[syntax error] unexpected token <" << token << "> in antecedent"; throw fl::Exception(ex.str(), FL_AT); } if (not ((state bitand S_VARIABLE) or (state bitand S_AND_OR))) { //only acceptable final state if (state bitand S_IS) { std::ostringstream ex; ex << "[syntax error] antecedent expected keyword <" << Rule::isKeyword() << "> after <" << token << ">"; throw fl::Exception(ex.str(), FL_AT); } if ((state bitand S_HEDGE) or (state bitand S_TERM)) { std::ostringstream ex; ex << "[syntax error] antecedent expected hedge or term after <" << token << ">"; throw fl::Exception(ex.str(), FL_AT); } } if (expressionStack.size() != 1) { std::vector<std::string> errors; while (expressionStack.size() > 1) { Expression* expression = expressionStack.top(); expressionStack.pop(); errors.push_back(expression->toString()); delete expression; } std::ostringstream ex; ex << "[syntax error] unable to parse the following expressions in antecedent <" << Op::join(errors, " ") << ">"; throw fl::Exception(ex.str(), FL_AT); } } catch (...) { for (std::size_t i = 0; i < expressionStack.size(); ++i) { delete expressionStack.top(); expressionStack.pop(); } throw; } this->_expression = expressionStack.top(); }
static int flash_write(struct blocklevel_device *bl, uint32_t dst, const void *src, uint32_t size, bool verify) { struct flash_chip *c = container_of(bl, struct flash_chip, bl); struct spi_flash_ctrl *ct = c->ctrl; uint32_t todo = size; uint32_t d = dst; const void *s = src; uint8_t vbuf[0x100]; int rc; /* Some sanity checking */ if (((dst + size) <= dst) || !size || (dst + size) > c->tsize) return FLASH_ERR_PARM_ERROR; FL_DBG("LIBFLASH: Writing to 0x%08x..0%08x...\n", dst, dst + size); /* * If the controller supports write and either we are in 3b mode * or we are in 4b *and* the controller supports it, then do a * high level write. */ if ((!c->mode_4b || ct->set_4b) && ct->write) { rc = ct->write(ct, dst, src, size); if (rc) return rc; goto writing_done; } /* Otherwise, go manual if supported */ if (!ct->cmd_wr) return FLASH_ERR_CTRL_CMD_UNSUPPORTED; /* Iterate for each page to write */ while(todo) { uint32_t chunk; /* Handle misaligned start */ chunk = 0x100 - (d & 0xff); if (chunk > todo) chunk = todo; rc = fl_wpage(c, d, s, chunk); if (rc) return rc; d += chunk; s += chunk; todo -= chunk; } writing_done: if (!verify) return 0; /* Verify */ FL_DBG("LIBFLASH: Verifying...\n"); while(size) { uint32_t chunk; chunk = sizeof(vbuf); if (chunk > size) chunk = size; rc = flash_read(bl, dst, vbuf, chunk); if (rc) return rc; if (memcmp(vbuf, src, chunk)) { FL_ERR("LIBFLASH: Miscompare at 0x%08x\n", dst); return FLASH_ERR_VERIFY_FAILURE; } dst += chunk; src += chunk; size -= chunk; } return 0; }
ModelCoordinate HexGrid::toLayerCoordinates(const ExactModelCoordinate& map_coord) { FL_DBG(_log, LMsg("==============\nConverting map coords ") << map_coord << " to int layer coords..."); ExactModelCoordinate elc = m_inverse_matrix * map_coord; elc.y *= VERTICAL_MULTIP_INV; ExactModelCoordinate lc = ExactModelCoordinate(floor(elc.x), floor(elc.y)); double dx = elc.x - lc.x; double dy = elc.y - lc.y; int x = static_cast<int>(lc.x); int y = static_cast<int>(lc.y); FL_DBG(_log, LMsg("elc=") << elc << ", lc=" << lc); FL_DBG(_log, LMsg("x=") << x << ", y=" << y << ", dx=" << dx << ", dy=" << dy); ModelCoordinate result; if ((y % 2) == 0) { FL_DBG(_log, "In even row"); if ((1 - dy) < HEX_EDGE_HALF) { FL_DBG(_log, "In lower rect area"); result = ModelCoordinate(x, y+1); } else if (dy < HEX_EDGE_HALF) { FL_DBG(_log, "In upper rect area"); if (dx > 0.5) { FL_DBG(_log, "...on right"); result = ModelCoordinate(x+1, y); } else { FL_DBG(_log, "...on left"); result = ModelCoordinate(x, y); } } // in middle triangle area else { FL_DBG(_log, "In middle triangle area"); if (dx < 0.5) { FL_DBG(_log, "In left triangles"); if (ptInTriangle(ExactModelCoordinate(dx, dy), ExactModelCoordinate(0, VERTICAL_MULTIP * HEX_EDGE_HALF), ExactModelCoordinate(0, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)), ExactModelCoordinate(0.5, VERTICAL_MULTIP * HEX_EDGE_HALF) )) { FL_DBG(_log, "..upper part"); result = ModelCoordinate(x, y); } else { FL_DBG(_log, "..lower part"); result = ModelCoordinate(x, y+1); } } else { FL_DBG(_log, "In right triangles"); if (ptInTriangle(ExactModelCoordinate(dx, dy), ExactModelCoordinate(1, VERTICAL_MULTIP * HEX_EDGE_HALF), ExactModelCoordinate(1, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)), ExactModelCoordinate(0.5, VERTICAL_MULTIP * HEX_EDGE_HALF) )) { FL_DBG(_log, "..upper part"); result = ModelCoordinate(x+1, y); } else { FL_DBG(_log, "..lower part"); result = ModelCoordinate(x, y+1); } } } } else { FL_DBG(_log, "In uneven row"); if (dy < HEX_EDGE_HALF) { FL_DBG(_log, "In upper rect area"); result = ModelCoordinate(x, y); } else if ((1 - dy) < HEX_EDGE_HALF) { FL_DBG(_log, "In lower rect area"); if (dx > 0.5) { FL_DBG(_log, "...on right"); result = ModelCoordinate(x+1, y+1); } else { FL_DBG(_log, "...on left"); result = ModelCoordinate(x, y+1); } } else { FL_DBG(_log, "In middle triangle area"); if (dx < 0.5) { FL_DBG(_log, "In left triangles"); if (ptInTriangle(ExactModelCoordinate(dx, dy), ExactModelCoordinate(0, VERTICAL_MULTIP * HEX_EDGE_HALF), ExactModelCoordinate(0, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)), ExactModelCoordinate(0.5, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)) )) { FL_DBG(_log, "..lower part"); result = ModelCoordinate(x, y+1); } else { FL_DBG(_log, "..upper part"); result = ModelCoordinate(x, y); } } else { FL_DBG(_log, "In right triangles"); if (ptInTriangle(ExactModelCoordinate(dx, dy), ExactModelCoordinate(1, VERTICAL_MULTIP * HEX_EDGE_HALF), ExactModelCoordinate(1, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)), ExactModelCoordinate(0.5, VERTICAL_MULTIP * (1-HEX_EDGE_HALF)) )) { FL_DBG(_log, "..lower part"); result = ModelCoordinate(x+1, y+1); } else { FL_DBG(_log, "..upper part"); result = ModelCoordinate(x, y); } } } } FL_DBG(_log, LMsg(" result = ") << result); return result; }
static int flash_smart_write(struct blocklevel_device *bl, uint64_t dst, const void *src, uint64_t size) { struct flash_chip *c = container_of(bl, struct flash_chip, bl); uint32_t er_size = c->min_erase_mask + 1; uint32_t end = dst + size; int rc; /* Some sanity checking */ if (end <= dst || !size || end > c->tsize) { FL_DBG("LIBFLASH: Smart write param error\n"); return FLASH_ERR_PARM_ERROR; } FL_DBG("LIBFLASH: Smart writing to 0x%" PRIx64 "..0%" PRIx64 "...\n", dst, dst + size); /* As long as we have something to write ... */ while(dst < end) { uint32_t page, off, chunk; enum sm_comp_res sr; /* Figure out which erase page we are in and read it */ page = dst & ~c->min_erase_mask; off = dst & c->min_erase_mask; FL_DBG("LIBFLASH: reading page 0x%08x..0x%08x...", page, page + er_size); rc = flash_read(bl, page, c->smart_buf, er_size); if (rc) { FL_DBG(" error %d!\n", rc); return rc; } /* Locate the chunk of data we are working on */ chunk = er_size - off; if (size < chunk) chunk = size; /* Compare against what we are writing and ff */ sr = flash_smart_comp(c, src, off, chunk); switch(sr) { case sm_no_change: /* Identical, skip it */ FL_DBG(" same !\n"); break; case sm_need_write: /* Just needs writing over */ FL_DBG(" need write !\n"); rc = flash_write(bl, dst, src, chunk, true); if (rc) { FL_DBG("LIBFLASH: Write error %d !\n", rc); return rc; } break; case sm_need_erase: FL_DBG(" need erase !\n"); rc = flash_erase(bl, page, er_size); if (rc) { FL_DBG("LIBFLASH: erase error %d !\n", rc); return rc; } /* Then update the portion of the buffer and write the block */ memcpy(c->smart_buf + off, src, chunk); rc = flash_write(bl, page, c->smart_buf, er_size, true); if (rc) { FL_DBG("LIBFLASH: write error %d !\n", rc); return rc; } break; } dst += chunk; src += chunk; size -= chunk; } return 0; }
void LayerCache::update(Camera::Transform transform, RenderList& renderlist) { const double OVERDRAW = 2.5; renderlist.clear(); m_needupdate = false; if(!m_layer->areInstancesVisible()) { FL_DBG(_log, "Layer instances hidden"); return; } bool isWarped = transform == Camera::WarpedTransform; if( isWarped ) { fullUpdate(); } Rect viewport = m_camera->getViewPort(); Rect screen_viewport = viewport; double zoom = m_camera->getZoom(); DoublePoint3D viewport_a = m_camera->screenToVirtualScreen(Point3D(viewport.x, viewport.y)); DoublePoint3D viewport_b = m_camera->screenToVirtualScreen(Point3D(viewport.right(), viewport.bottom())); viewport.x = static_cast<int32_t>(std::min(viewport_a.x, viewport_b.x)); viewport.y = static_cast<int32_t>(std::min(viewport_a.y, viewport_b.y)); viewport.w = static_cast<int32_t>(std::max(viewport_a.x, viewport_b.x) - viewport.x); viewport.h = static_cast<int32_t>(std::max(viewport_a.y, viewport_b.y) - viewport.y); uint8_t layer_trans = m_layer->getLayerTransparency(); double zmin = 0.0, zmax = 0.0; // FL_LOG(_log, LMsg("camera-update viewport") << viewport); std::vector<int32_t> index_list; collect(viewport, index_list); for(unsigned i=0; i!=index_list.size(); ++i) { Entry& entry = m_entries[index_list[i]]; // NOTE // An update is forced if the item has an animation/action. // This update only happens if it is _already_ included in the viewport // Nevertheless: Moving instances - which might move into the viewport will be updated // By the layer change listener. if(entry.force_update || !isWarped) { updateEntry(entry); } RenderItem& item = m_instances[entry.instance_index]; InstanceVisual* visual = item.instance->getVisual<InstanceVisual>(); bool visible = (visual->isVisible() != 0); uint8_t instance_trans = visual->getTransparency(); if(!item.image || !visible || (instance_trans == 255 && layer_trans == 0) || (instance_trans == 0 && layer_trans == 255)) { continue; } if(layer_trans != 0) { if(instance_trans != 0) { uint8_t calc_trans = layer_trans - instance_trans; if(calc_trans >= 0) { instance_trans = calc_trans; } else { instance_trans = 0; } } else { instance_trans = layer_trans; } } Point3D screen_point = m_camera->virtualScreenToScreen(item.screenpoint); // NOTE: // One would expect this to be necessary here, // however it works the same without, sofar // m_camera->calculateZValue(screen_point); // item.screenpoint.z = -screen_point.z; item.dimensions.x = screen_point.x; item.dimensions.y = screen_point.y; item.dimensions.w = item.bbox.w; item.dimensions.h = item.bbox.h; item.transparency = 255 - instance_trans; if (zoom != 1.0) { // NOTE: Due to image alignment, there is additional additions on image dimensions // There's probabaly some better solution for this, but works "good enough" for now. // In case additions are removed, gaps appear between tiles. item.dimensions.w = unsigned(double(item.bbox.w) * zoom + OVERDRAW); item.dimensions.h = unsigned(double(item.bbox.h) * zoom + OVERDRAW); } if (!m_need_sorting) { zmin = std::min(zmin, item.screenpoint.z); zmax = std::max(zmax, item.screenpoint.z); } if(item.dimensions.intersects(screen_viewport)) { renderlist.push_back(&item); } } if (m_need_sorting) { InstanceDistanceSort ids; std::stable_sort(renderlist.begin(), renderlist.end(), ids); } else { zmin -= 0.5; zmax += 0.5; // We want to put every z value in [-10,10] range. // To do it, we simply solve // { y1 = a*x1 + b // { y2 = a*x2 + b // where [y1,y2]' = [-10,10]' is required z range, // and [x1,x2]' is expected min,max z coords. double det = zmin - zmax; if (fabs(det) > FLT_EPSILON) { double det_a = -10.0 - 10.0; double det_b = 10.0 * zmin - (-10.0) * zmax; double a = static_cast<float>(det_a / det); double b = static_cast<float>(det_b / det); float estimate = sqrtf(static_cast<float>(renderlist.size())); float stack_delta = fabs(-10.0f - 10.0f) / estimate * 0.1f; RenderList::iterator it = renderlist.begin(); for ( ; it != renderlist.end(); ++it) { double& z = (*it)->screenpoint.z; z = a * z + b; InstanceVisual* vis = (*it)->instance->getVisual<InstanceVisual>(); z += vis->getStackPosition() * stack_delta; } } } // FL_LOG(_log, LMsg("camera-update ") << " N=" <<renderlist.size() << "/" << m_instances.size() << "/" << index_list.size()); }
static bool insert_bl_prot_range(struct blocklevel_range *ranges, struct bl_prot_range range) { int i; uint32_t pos, len; struct bl_prot_range *prot = ranges->prot; pos = range.start; len = range.len; if (len == 0) return true; /* Check for overflow */ if (pos + len < len) return false; for (i = 0; i < ranges->n_prot && len > 0; i++) { if (prot[i].start <= pos && prot[i].start + prot[i].len >= pos + len) { len = 0; break; /* Might as well, the next two conditions can't be true */ } /* Can easily extend this down just by adjusting start */ if (pos <= prot[i].start && pos + len >= prot[i].start) { FL_DBG("%s: extending start down\n", __func__); prot[i].len += prot[i].start - pos; prot[i].start = pos; pos += prot[i].len; if (prot[i].len >= len) len = 0; else len -= prot[i].len; } /* * Jump over this range but the new range might be so big that * theres a chunk after */ if (pos >= prot[i].start && pos < prot[i].start + prot[i].len) { FL_DBG("%s: fits within current range ", __func__); if (prot[i].start + prot[i].len - pos > len) { FL_DBG("but there is some extra at the end\n"); len -= prot[i].start + prot[i].len - pos; pos = prot[i].start + prot[i].len; } else { FL_DBG("\n"); len = 0; } } /* * This condition will be true if the range is smaller than * the current range, therefore it should go here! */ if (pos < prot[i].start && pos + len <= prot[i].start) break; } if (len) { int insert_pos = i; struct bl_prot_range *new_ranges = ranges->prot; FL_DBG("%s: adding 0x%08x..0x%08x\n", __func__, pos, pos + len); if (ranges->n_prot == ranges->total_prot) { new_ranges = realloc(ranges->prot, sizeof(range) * ((ranges->n_prot) + PROT_REALLOC_NUM)); if (!new_ranges) return false; ranges->total_prot += PROT_REALLOC_NUM; } if (insert_pos != ranges->n_prot) for (i = ranges->n_prot; i > insert_pos; i--) memcpy(&new_ranges[i], &new_ranges[i - 1], sizeof(range)); range.start = pos; range.len = len; memcpy(&new_ranges[insert_pos], &range, sizeof(range)); ranges->prot = new_ranges; ranges->n_prot++; prot = new_ranges; } return true; }
int blocklevel_smart_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len) { uint64_t block_size; void *erase_buf; int rc; if (!bl) { errno = EINVAL; return FLASH_ERR_PARM_ERROR; } FL_DBG("%s: 0x%" PRIx64 "\t0x%" PRIx64 "\n", __func__, pos, len); /* Nothing smart needs to be done, pos and len are aligned */ if ((pos & bl->erase_mask) == 0 && (len & bl->erase_mask) == 0) { FL_DBG("%s: Skipping smarts everything is aligned 0x%" PRIx64 " 0x%" PRIx64 "to 0x%08x\n", __func__, pos, len, bl->erase_mask); return blocklevel_erase(bl, pos, len); } block_size = bl->erase_mask + 1; erase_buf = malloc(block_size); if (!erase_buf) { errno = ENOMEM; return FLASH_ERR_MALLOC_FAILED; } rc = reacquire(bl); if (rc) { free(erase_buf); return rc; } if (pos & bl->erase_mask) { /* * base_pos and base_len are the values in the first erase * block that we need to preserve: the region up to pos. */ uint64_t base_pos = pos & ~(bl->erase_mask); uint64_t base_len = pos - base_pos; FL_DBG("%s: preserving 0x%" PRIx64 "..0x%" PRIx64 "\n", __func__, base_pos, base_pos + base_len); /* * Read the entire block in case this is the ONLY block we're * modifying, we may need the end chunk of it later */ rc = bl->read(bl, base_pos, erase_buf, block_size); if (rc) goto out; rc = bl->erase(bl, base_pos, block_size); if (rc) goto out; rc = bl->write(bl, base_pos, erase_buf, base_len); if (rc) goto out; /* * The requested erase fits entirely into this erase block and * so we need to write back the chunk at the end of the block */ if (base_pos + base_len + len < base_pos + block_size) { rc = bl->write(bl, pos + len, erase_buf + base_len + len, block_size - base_len - len); FL_DBG("%s: Early exit, everything was in one erase block\n", __func__); goto out; } pos += block_size - base_len; len -= block_size - base_len; } /* Now we should be aligned, best to double check */ if (pos & bl->erase_mask) { FL_DBG("%s:pos 0x%" PRIx64 " isn't erase_mask 0x%08x aligned\n", __func__, pos, bl->erase_mask); rc = FLASH_ERR_PARM_ERROR; goto out; } if (len & ~(bl->erase_mask)) { rc = bl->erase(bl, pos, len & ~(bl->erase_mask)); if (rc) goto out; pos += len & ~(bl->erase_mask); len -= len & ~(bl->erase_mask); } /* Length should be less than a block now */ if (len > block_size) { FL_DBG("%s: len 0x%" PRIx64 " is still exceeds block_size 0x%" PRIx64 "\n", __func__, len, block_size); rc = FLASH_ERR_PARM_ERROR; goto out; } if (len & bl->erase_mask) { /* * top_pos is the first byte that must be preserved and * top_len is the length from top_pos to the end of the erase * block: the region that must be preserved */ uint64_t top_pos = pos + len; uint64_t top_len = block_size - len; FL_DBG("%s: preserving 0x%" PRIx64 "..0x%" PRIx64 "\n", __func__, top_pos, top_pos + top_len); rc = bl->read(bl, top_pos, erase_buf, top_len); if (rc) goto out; rc = bl->erase(bl, pos, block_size); if (rc) goto out; rc = bl->write(bl, top_pos, erase_buf, top_len); if (rc) goto out; } out: free(erase_buf); release(bl); return rc; }
int blocklevel_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len) { int rc, ecc_protection; struct ecc64 *buffer; uint64_t ecc_pos, ecc_start, ecc_diff, ecc_len; FL_DBG("%s: 0x%" PRIx64 "\t%p\t0x%" PRIx64 "\n", __func__, pos, buf, len); if (!bl || !buf) { errno = EINVAL; return FLASH_ERR_PARM_ERROR; } ecc_protection = ecc_protected(bl, pos, len, &ecc_start); FL_DBG("%s: 0x%" PRIx64 " for 0x%" PRIx64 " ecc=%s\n", __func__, pos, len, ecc_protection ? (ecc_protection == -1 ? "partial" : "yes") : "no"); if (!ecc_protection) return blocklevel_raw_read(bl, pos, buf, len); /* * The region we're reading to has both ecc protection and not. * Perhaps one day in the future blocklevel can cope with this. */ if (ecc_protection == -1) { FL_ERR("%s: Can't cope with partial ecc\n", __func__); errno = EINVAL; return FLASH_ERR_PARM_ERROR; } pos = with_ecc_pos(ecc_start, pos); ecc_pos = ecc_buffer_align(ecc_start, pos); ecc_diff = pos - ecc_pos; ecc_len = ecc_buffer_size(len + ecc_diff); FL_DBG("%s: adjusted_pos: 0x%" PRIx64 ", ecc_pos: 0x%" PRIx64 ", ecc_diff: 0x%" PRIx64 ", ecc_len: 0x%" PRIx64 "\n", __func__, pos, ecc_pos, ecc_diff, ecc_len); buffer = malloc(ecc_len); if (!buffer) { errno = ENOMEM; rc = FLASH_ERR_MALLOC_FAILED; goto out; } rc = blocklevel_raw_read(bl, ecc_pos, buffer, ecc_len); if (rc) goto out; /* * Could optimise and simply call memcpy_from_ecc() if ecc_diff * == 0 but _unaligned checks and bascially does that for us */ if (memcpy_from_ecc_unaligned(buf, buffer, len, ecc_diff)) { errno = EBADF; rc = FLASH_ERR_ECC_INVALID; } out: free(buffer); return rc; }
static int flash_configure(struct flash_chip *c) { struct spi_flash_ctrl *ct = c->ctrl; int rc; /* Crop flash size if necessary */ if (c->tsize > 0x01000000 && !(c->info.flags & FL_CAN_4B)) { FL_ERR("LIBFLASH: Flash chip cropped to 16M, no 4b mode\n"); c->tsize = 0x01000000; } /* If flash chip > 16M, enable 4b mode */ if (c->tsize > 0x01000000) { FL_DBG("LIBFLASH: Flash >16MB, enabling 4B mode...\n"); /* Set flash to 4b mode if we can */ if (ct->cmd_wr) { rc = flash_set_4b(c, true); if (rc) { FL_ERR("LIBFLASH: Failed to set flash 4b mode\n"); return rc; } } /* Set controller to 4b mode if supported */ if (ct->set_4b) { FL_DBG("LIBFLASH: Enabling controller 4B mode...\n"); rc = ct->set_4b(ct, true); if (rc) { FL_ERR("LIBFLASH: Failed to set controller 4b mode\n"); return rc; } } } else { FL_DBG("LIBFLASH: Flash <=16MB, disabling 4B mode...\n"); /* * If flash chip supports 4b mode, make sure we disable * it in case it was left over by the previous user */ if (c->info.flags & FL_CAN_4B) { rc = flash_set_4b(c, false); if (rc) { FL_ERR("LIBFLASH: Failed to" " clear flash 4b mode\n"); return rc; } } /* Set controller to 3b mode if mode switch is supported */ if (ct->set_4b) { FL_DBG("LIBFLASH: Disabling controller 4B mode...\n"); rc = ct->set_4b(ct, false); if (rc) { FL_ERR("LIBFLASH: Failed to" " clear controller 4b mode\n"); return rc; } } } return 0; }
static int flash_identify(struct flash_chip *c) { struct spi_flash_ctrl *ct = c->ctrl; const struct flash_info *info = NULL; uint32_t iid, id_size; #define MAX_ID_SIZE 16 uint8_t id[MAX_ID_SIZE]; int rc, i; if (ct->chip_id) { /* High level controller interface */ id_size = MAX_ID_SIZE; rc = ct->chip_id(ct, id, &id_size); } else rc = fl_chip_id(ct, id, &id_size); if (rc) return rc; if (id_size < 3) return FLASH_ERR_CHIP_UNKNOWN; /* Convert to a dword for lookup */ iid = id[0]; iid = (iid << 8) | id[1]; iid = (iid << 8) | id[2]; FL_DBG("LIBFLASH: Flash ID: %02x.%02x.%02x (%06x)\n", id[0], id[1], id[2], iid); /* Lookup in flash_info */ for (i = 0; i < ARRAY_SIZE(flash_info); i++) { info = &flash_info[i]; if (info->id == iid) break; } if (!info || info->id != iid) return FLASH_ERR_CHIP_UNKNOWN; c->info = *info; c->tsize = info->size; ct->finfo = &c->info; /* * Let controller know about our settings and possibly * override them */ if (ct->setup) { rc = ct->setup(ct, &c->tsize); if (rc) return rc; } /* Calculate min erase granularity */ if (c->info.flags & FL_ERASE_4K) c->min_erase_mask = 0xfff; else if (c->info.flags & FL_ERASE_32K) c->min_erase_mask = 0x7fff; else if (c->info.flags & FL_ERASE_64K) c->min_erase_mask = 0xffff; else { /* No erase size ? oops ... */ FL_ERR("LIBFLASH: No erase sizes !\n"); return FLASH_ERR_CTRL_CONFIG_MISMATCH; } FL_DBG("LIBFLASH: Found chip %s size %dM erase granule: %dK\n", c->info.name, c->tsize >> 20, (c->min_erase_mask + 1) >> 10); return 0; }
int blocklevel_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len) { int rc, ecc_protection; struct ecc64 *buffer; uint64_t ecc_len; uint64_t ecc_start, ecc_pos, ecc_diff; FL_DBG("%s: 0x%" PRIx64 "\t%p\t0x%" PRIx64 "\n", __func__, pos, buf, len); if (!bl || !buf) { errno = EINVAL; return FLASH_ERR_PARM_ERROR; } ecc_protection = ecc_protected(bl, pos, len, &ecc_start); FL_DBG("%s: 0x%" PRIx64 " for 0x%" PRIx64 " ecc=%s\n", __func__, pos, len, ecc_protection ? (ecc_protection == -1 ? "partial" : "yes") : "no"); if (!ecc_protection) return blocklevel_raw_write(bl, pos, buf, len); /* * The region we're writing to has both ecc protection and not. * Perhaps one day in the future blocklevel can cope with this. */ if (ecc_protection == -1) { FL_ERR("%s: Can't cope with partial ecc\n", __func__); errno = EINVAL; return FLASH_ERR_PARM_ERROR; } pos = with_ecc_pos(ecc_start, pos); ecc_pos = ecc_buffer_align(ecc_start, pos); ecc_diff = pos - ecc_pos; ecc_len = ecc_buffer_size(len + ecc_diff); FL_DBG("%s: adjusted_pos: 0x%" PRIx64 ", ecc_pos: 0x%" PRIx64 ", ecc_diff: 0x%" PRIx64 ", ecc_len: 0x%" PRIx64 "\n", __func__, pos, ecc_pos, ecc_diff, ecc_len); buffer = malloc(ecc_len); if (!buffer) { errno = ENOMEM; rc = FLASH_ERR_MALLOC_FAILED; goto out; } if (ecc_diff) { uint64_t start_chunk = ecc_diff; uint64_t end_chunk = BYTES_PER_ECC - ecc_diff; uint64_t end_len = ecc_len - end_chunk; /* * Read the start bytes that memcpy_to_ecc_unaligned() will need * to calculate the first ecc byte */ rc = blocklevel_raw_read(bl, ecc_pos, buffer, start_chunk); if (rc) { errno = EBADF; rc = FLASH_ERR_ECC_INVALID; goto out; } /* * Read the end bytes that memcpy_to_ecc_unaligned() will need * to calculate the last ecc byte */ rc = blocklevel_raw_read(bl, ecc_pos + end_len, ((char *)buffer) + end_len, end_chunk); if (rc) { errno = EBADF; rc = FLASH_ERR_ECC_INVALID; goto out; } if (memcpy_to_ecc_unaligned(buffer, buf, len, ecc_diff)) { errno = EBADF; rc = FLASH_ERR_ECC_INVALID; goto out; } } else { if (memcpy_to_ecc(buffer, buf, len)) { errno = EBADF; rc = FLASH_ERR_ECC_INVALID; goto out; } } rc = blocklevel_raw_write(bl, pos, buffer, ecc_len); out: free(buffer); return rc; }
int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl, struct ffs_handle **ffs, bool mark_ecc) { struct ffs_hdr hdr; struct ffs_hdr blank_hdr; struct ffs_handle *f; uint64_t total_size; int rc, i; if (!ffs || !bl) return FLASH_ERR_PARM_ERROR; *ffs = NULL; rc = blocklevel_get_info(bl, NULL, &total_size, NULL); if (rc) { FL_ERR("FFS: Error %d retrieving flash info\n", rc); return rc; } if (total_size > UINT_MAX) return FLASH_ERR_VERIFY_FAILURE; if ((offset + max_size) < offset) return FLASH_ERR_PARM_ERROR; if ((max_size > total_size)) return FLASH_ERR_PARM_ERROR; /* Read flash header */ rc = blocklevel_read(bl, offset, &hdr, sizeof(hdr)); if (rc) { FL_ERR("FFS: Error %d reading flash header\n", rc); return rc; } /* * Flash controllers can get deconfigured or otherwise upset, when this * happens they return all 0xFF bytes. * An ffs_hdr consisting of all 0xFF cannot be valid and it would be * nice to drop a hint to the user to help with debugging. This will * help quickly differentiate between flash corruption and standard * type 'reading from the wrong place' errors vs controller errors or * reading erased data. */ memset(&blank_hdr, UINT_MAX, sizeof(struct ffs_hdr)); if (memcmp(&blank_hdr, &hdr, sizeof(struct ffs_hdr)) == 0) { FL_ERR("FFS: Reading the flash has returned all 0xFF.\n"); FL_ERR("Are you reading erased flash?\n"); FL_ERR("Is something else using the flash controller?\n"); return FLASH_ERR_BAD_READ; } /* Allocate ffs_handle structure and start populating */ f = malloc(sizeof(*f)); if (!f) return FLASH_ERR_MALLOC_FAILED; memset(f, 0, sizeof(*f)); f->toc_offset = offset; f->max_size = max_size; f->bl = bl; /* Convert and check flash header */ rc = ffs_check_convert_header(&f->hdr, &hdr); if (rc) { FL_INF("FFS: Flash header not found. Code: %d\n", rc); goto out; } /* Check header is sane */ if ((f->hdr.block_size * f->hdr.size) > max_size) { rc = FLASH_ERR_PARM_ERROR; FL_ERR("FFS: Flash header exceeds max flash size\n"); goto out; } if ((f->hdr.entry_size * f->hdr.entry_count) > (f->hdr.block_size * f->hdr.size)) { rc = FLASH_ERR_PARM_ERROR; FL_ERR("FFS: Flash header entries exceeds available blocks\n"); goto out; } /* * Decide how much of the image to grab to get the whole * partition map. */ f->cached_size = f->hdr.block_size * f->hdr.size; /* Check for overflow or a silly size */ if (!f->hdr.size || f->cached_size / f->hdr.size != f->hdr.block_size) { rc= FLASH_ERR_MALLOC_FAILED; FL_ERR("FFS: Cache size overflow (0x%x * 0x%x)\n", f->hdr.block_size, f->hdr.size); goto out; } FL_DBG("FFS: Partition map size: 0x%x\n", f->cached_size); /* Allocate cache */ f->cache = malloc(f->cached_size); if (!f->cache) { rc = FLASH_ERR_MALLOC_FAILED; goto out; } /* Read the cached map */ rc = blocklevel_read(bl, offset, f->cache, f->cached_size); if (rc) { FL_ERR("FFS: Error %d reading flash partition map\n", rc); goto out; } if (mark_ecc) { uint32_t start, total_size; bool ecc; for (i = 0; i < f->hdr.entry_count; i++) { rc = ffs_part_info(f, i, NULL, &start, &total_size, NULL, &ecc); if (rc) { FL_ERR("FFS: Failed to read ffs partition %d\n", i); goto out; } if (ecc) { rc = blocklevel_ecc_protect(bl, start, total_size); if (rc) { FL_ERR("FFS: Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n", start, total_size); goto out; } } /* ecc */ } /* for */ } out: if (rc == 0) *ffs = f; else free(f); return rc; }
int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len) { uint32_t erase_size; const void *write_buf = buf; void *write_buf_start = NULL; uint64_t ecc_start; void *erase_buf; int rc = 0; if (!write_buf || !bl) { errno = EINVAL; return FLASH_ERR_PARM_ERROR; } FL_DBG("%s: 0x%" PRIx64 "\t0x%" PRIx64 "\n", __func__, pos, len); if (!(bl->flags & WRITE_NEED_ERASE)) { FL_DBG("%s: backend doesn't need erase\n", __func__); return blocklevel_write(bl, pos, buf, len); } rc = blocklevel_get_info(bl, NULL, NULL, &erase_size); if (rc) return rc; if (ecc_protected(bl, pos, len, &ecc_start)) { FL_DBG("%s: region has ECC\n", __func__); len = ecc_buffer_size(len); write_buf_start = malloc(len); if (!write_buf_start) { errno = ENOMEM; return FLASH_ERR_MALLOC_FAILED; } if (memcpy_to_ecc(write_buf_start, buf, ecc_buffer_size_minus_ecc(len))) { free(write_buf_start); errno = EBADF; return FLASH_ERR_ECC_INVALID; } write_buf = write_buf_start; } erase_buf = malloc(erase_size); if (!erase_buf) { errno = ENOMEM; rc = FLASH_ERR_MALLOC_FAILED; goto out_free; } rc = reacquire(bl); if (rc) goto out_free; while (len > 0) { uint32_t erase_block = pos & ~(erase_size - 1); uint32_t block_offset = pos & (erase_size - 1); uint32_t size = erase_size > len ? len : erase_size; int cmp; /* Write crosses an erase boundary, shrink the write to the boundary */ if (erase_size < block_offset + size) { size = erase_size - block_offset; } rc = bl->read(bl, erase_block, erase_buf, erase_size); if (rc) goto out; cmp = blocklevel_flashcmp(erase_buf + block_offset, write_buf, size); FL_DBG("%s: region 0x%08x..0x%08x ", __func__, erase_block, erase_size); if (cmp != 0) { FL_DBG("needs "); if (cmp == -1) { FL_DBG("erase and "); bl->erase(bl, erase_block, erase_size); } FL_DBG("write\n"); memcpy(erase_buf + block_offset, write_buf, size); rc = bl->write(bl, erase_block, erase_buf, erase_size); if (rc) goto out; } len -= size; pos += size; write_buf += size; } out: release(bl); out_free: free(write_buf_start); free(erase_buf); return rc; }
ModelCoordinate HexGrid::toLayerCoordinates(const ExactModelCoordinate& map_coord) { FL_DBG(_log, LMsg("==============\nConverting map coords ") << map_coord << " to int32_t layer coords..."); ExactModelCoordinate elc = m_inverse_matrix * map_coord; elc.y *= VERTICAL_MULTIP_INV; return toLayerCoordinatesHelper(elc); }
static int ffs_num_entries(struct ffs_hdr *hdr) { if (hdr->count == 0) FL_DBG("%s returned zero!\n", __func__); return hdr->count; }
VFSDirectory::VFSDirectory(VFS* vfs, const std::string& root) : VFSSource(vfs), m_root(root) { FL_DBG(_log, LMsg("VFSDirectory created with root path ") << m_root); if(!m_root.empty() && *(m_root.end() - 1) != '/') m_root.append(1,'/'); }