<commit_before>/*

    Image Uploader -  free application for uploading images/files to the Internet

    Copyright 2007-2018 Sergey Svistunov (zenden2k@yandex.ru)

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

*/

#include "OutputCodeGenerator.h"
#include "Utils/CoreUtils.h"

ZOutputCodeGenerator::ZOutputCodeGenerator()
{
	m_PreferDirectLinks = true;
	m_lang = clPlain;
	m_CodeType = ctLinks;
}

void ZOutputCodeGenerator::setLang(CodeLang lang)
{
	m_lang = lang;
}

void ZOutputCodeGenerator::setType(CodeType type)
{
	m_CodeType = type;
}

std::string ZOutputCodeGenerator::generate(const std::vector<ZUploadObject>& items)
{
   std::string result ="";
	for(int i=0; i < items.size(); i++)
	{
		if(i) result += "\r\n";
		result += generateCodeForItem(items[i], i);
	}
	return result;
}

std::string ZOutputCodeGenerator::generateCodeForItem(const ZUploadObject& item, int index)
{
	if(m_lang == clPlain)
      return item.directUrl.empty()?item.viewUrl:item.directUrl;
	else
	{
      if((m_CodeType == ctClickableThumbnails || m_CodeType == ctTableOfThumbnails) && !item.thumbUrl.empty())
         return link(item.directUrl, image(item.thumbUrl));
      else if (m_CodeType == ctImages && !item.directUrl.empty())
         return image(item.directUrl);
      else
        // if (m_CodeType == ctLinks ||  item.directUrl.empty())
            return link(item.directUrl.empty()?item.viewUrl:item.directUrl, IuCoreUtils::ExtractFileName(item.displayFileName));
	}
   return "";
}

std::string ZOutputCodeGenerator::image(std::string url)
{
	if (m_lang == clBBCode)
		return "[img]" + url +"[/img]";
	else  return "";
}

std::string ZOutputCodeGenerator::link(std::string url, std::string body)
{
	if (m_lang == clBBCode)
		return "[url=" + url +"]"+body+"[/url]";
	else  return ""+body+"";
}

void ZOutputCodeGenerator::setPreferDirectLinks(bool prefer)
{
	m_PreferDirectLinks = prefer;
}
<commit_msg>Fixed output code generation in CLI, closes #238<commit_after>/*

    Image Uploader -  free application for uploading images/files to the Internet

    Copyright 2007-2018 Sergey Svistunov (zenden2k@yandex.ru)

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

*/

#include "OutputCodeGenerator.h"
#include "Utils/CoreUtils.h"

ZOutputCodeGenerator::ZOutputCodeGenerator()
{
	m_PreferDirectLinks = true;
	m_lang = clPlain;
	m_CodeType = ctLinks;
}

void ZOutputCodeGenerator::setLang(CodeLang lang)
{
	m_lang = lang;
}

void ZOutputCodeGenerator::setType(CodeType type)
{
	m_CodeType = type;
}

std::string ZOutputCodeGenerator::generate(const std::vector<ZUploadObject>& items)
{
   std::string result ="";
	for(int i=0; i < items.size(); i++)
	{
		if(i) result += "\r\n";
		result += generateCodeForItem(items[i], i);
	}
	return result;
}

std::string ZOutputCodeGenerator::generateCodeForItem(const ZUploadObject& item, int index)
{
	if(m_lang == clPlain)
      return item.directUrl.empty()?item.viewUrl:item.directUrl;
	else
	{
      if((m_CodeType == ctClickableThumbnails || m_CodeType == ctTableOfThumbnails) && !item.thumbUrl.empty())
          return link(item.directUrl.empty() ? item.viewUrl : item.directUrl, image(item.thumbUrl));
      else if (m_CodeType == ctImages && !item.directUrl.empty())
         return image(item.directUrl);
      else
        // if (m_CodeType == ctLinks ||  item.directUrl.empty())
            return link(item.directUrl.empty()?item.viewUrl:item.directUrl, IuCoreUtils::ExtractFileName(item.displayFileName));
	}
   return "";
}

std::string ZOutputCodeGenerator::image(std::string url)
{
	if (m_lang == clBBCode)
		return "[img]" + url +"[/img]";
	else  return "";
}

std::string ZOutputCodeGenerator::link(std::string url, std::string body)
{
	if (m_lang == clBBCode)
		return "[url=" + url +"]"+body+"[/url]";
	else  return ""+body+"";
}

void ZOutputCodeGenerator::setPreferDirectLinks(bool prefer)
{
	m_PreferDirectLinks = prefer;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/rendering/InlineBox.h"

#include "core/rendering/InlineFlowBox.h"
#include "core/rendering/PaintInfo.h"
#include "core/rendering/RenderBlockFlow.h"
#include "core/rendering/RootInlineBox.h"
#include "platform/Partitions.h"
#include "platform/fonts/FontMetrics.h"

#ifndef NDEBUG
#include <stdio.h>
#endif

using namespace std;

namespace WebCore {

struct SameSizeAsInlineBox {
    virtual ~SameSizeAsInlineBox() { }
    void* a[4];
    FloatPoint b;
    float c;
    uint32_t d : 32;
#ifndef NDEBUG
    bool f;
#endif
};

COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);

#ifndef NDEBUG

InlineBox::~InlineBox()
{
    if (!m_hasBadParent && m_parent)
        m_parent->setHasBadChildList();
}

#endif

void InlineBox::remove()
{
    if (parent())
        parent()->removeChild(this);
}

void* InlineBox::operator new(size_t sz)
{
    return partitionAlloc(Partitions::getRenderingPartition(), sz);
}

void InlineBox::operator delete(void* ptr)
{
    partitionFree(ptr);
}

#ifndef NDEBUG
const char* InlineBox::boxName() const
{
    return "InlineBox";
}

void InlineBox::showTreeForThis() const
{
    renderer().showTreeForThis();
}

void InlineBox::showLineTreeForThis() const
{
    renderer().containingBlock()->showLineTreeAndMark(this, "*");
}

void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
{
    int printedCharacters = 0;
    if (this == markedBox1)
        printedCharacters += fprintf(stderr, "%s", markedLabel1);
    if (this == markedBox2)
        printedCharacters += fprintf(stderr, "%s", markedLabel2);
    if (&renderer() == obj)
        printedCharacters += fprintf(stderr, "*");
    for (; printedCharacters < depth * 2; printedCharacters++)
        fputc(' ', stderr);

    showBox(printedCharacters);
}

void InlineBox::showBox(int printedCharacters) const
{
    printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
    for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
        fputc(' ', stderr);
    fprintf(stderr, "\t%s %p\n", renderer().renderName(), &renderer());
}
#endif

float InlineBox::logicalHeight() const
{
    if (hasVirtualLogicalHeight())
        return virtualLogicalHeight();

    if (renderer().isText())
        return m_bitfields.isText() ? renderer().style(isFirstLineStyle())->fontMetrics().height() : 0;
    if (renderer().isBox() && parent())
        return isHorizontal() ? toRenderBox(renderer()).height().toFloat() : toRenderBox(renderer()).width().toFloat();

    ASSERT(isInlineFlowBox());
    RenderBoxModelObject* flowObject = boxModelObject();
    const FontMetrics& fontMetrics = renderer().style(isFirstLineStyle())->fontMetrics();
    float result = fontMetrics.height();
    if (parent())
        result += flowObject->borderAndPaddingLogicalHeight();
    return result;
}

int InlineBox::baselinePosition(FontBaseline baselineType) const
{
    return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
}

LayoutUnit InlineBox::lineHeight() const
{
    return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
}

int InlineBox::caretMinOffset() const
{
    return renderer().caretMinOffset();
}

int InlineBox::caretMaxOffset() const
{
    return renderer().caretMaxOffset();
}

void InlineBox::dirtyLineBoxes()
{
    markDirty();
    for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
        curr->markDirty();
}

void InlineBox::deleteLine()
{
    if (!m_bitfields.extracted() && renderer().isBox())
        toRenderBox(renderer()).setInlineBoxWrapper(0);
    destroy();
}

void InlineBox::extractLine()
{
    m_bitfields.setExtracted(true);
    if (renderer().isBox())
        toRenderBox(renderer()).setInlineBoxWrapper(0);
}

void InlineBox::attachLine()
{
    m_bitfields.setExtracted(false);
    if (renderer().isBox())
        toRenderBox(renderer()).setInlineBoxWrapper(this);
}

void InlineBox::adjustPosition(float dx, float dy)
{
    m_topLeft.move(dx, dy);

    if (renderer().isReplaced())
        toRenderBox(renderer()).move(dx, dy);
}

void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
{
    if (!paintInfo.shouldPaintWithinRoot(&renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
        return;

    LayoutPoint childPoint = paintOffset;
    if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
        childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);

    RenderBlock::paintAsInlineBlock(&renderer(), paintInfo, childPoint);
}

bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
{
    // Hit test all phases of replaced elements atomically, as though the replaced element established its
    // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
    // specification.)
    LayoutPoint childPoint = accumulatedOffset;
    if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
        childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);

    return renderer().hitTest(request, result, locationInContainer, childPoint);
}

const RootInlineBox& InlineBox::root() const
{
    if (m_parent)
        return m_parent->root();
    ASSERT(isRootInlineBox());
    return static_cast<const RootInlineBox&>(*this);
}

RootInlineBox& InlineBox::root()
{
    if (m_parent)
        return m_parent->root();
    ASSERT(isRootInlineBox());
    return static_cast<RootInlineBox&>(*this);
}

bool InlineBox::nextOnLineExists() const
{
    if (!m_bitfields.determinedIfNextOnLineExists()) {
        m_bitfields.setDeterminedIfNextOnLineExists(true);

        if (!parent())
            m_bitfields.setNextOnLineExists(false);
        else if (nextOnLine())
            m_bitfields.setNextOnLineExists(true);
        else
            m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
    }
    return m_bitfields.nextOnLineExists();
}

InlineBox* InlineBox::nextLeafChild() const
{
    InlineBox* leaf = 0;
    for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
        leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
    if (!leaf && parent())
        leaf = parent()->nextLeafChild();
    return leaf;
}

InlineBox* InlineBox::prevLeafChild() const
{
    InlineBox* leaf = 0;
    for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
        leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
    if (!leaf && parent())
        leaf = parent()->prevLeafChild();
    return leaf;
}

InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
{
    InlineBox* leaf = nextLeafChild();
    if (leaf && leaf->isLineBreak())
        return 0;
    return leaf;
}

InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
{
    InlineBox* leaf = prevLeafChild();
    if (leaf && leaf->isLineBreak())
        return 0;
    return leaf;
}

RenderObject::SelectionState InlineBox::selectionState()
{
    return renderer().selectionState();
}

bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
{
    // Non-replaced elements can always accommodate an ellipsis.
    if (!renderer().isReplaced())
        return true;

    IntRect boxRect(left(), 0, m_logicalWidth, 10);
    IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
    return !(boxRect.intersects(ellipsisRect));
}

float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
{
    // Use -1 to mean "we didn't set the position."
    truncatedWidth += logicalWidth();
    return -1;
}

void InlineBox::clearKnownToHaveNoOverflow()
{
    m_bitfields.setKnownToHaveNoOverflow(false);
    if (parent() && parent()->knownToHaveNoOverflow())
        parent()->clearKnownToHaveNoOverflow();
}

FloatPoint InlineBox::locationIncludingFlipping()
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return FloatPoint(x(), y());
    RenderBlockFlow& block = root().block();
    if (block.style()->isHorizontalWritingMode())
        return FloatPoint(x(), block.height() - height() - y());

    return FloatPoint(block.width() - width() - x(), y());
}

void InlineBox::flipForWritingMode(FloatRect& rect)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return;
    root().block().flipForWritingMode(rect);
}

FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return point;
    return root().block().flipForWritingMode(point);
}

void InlineBox::flipForWritingMode(LayoutRect& rect)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return;
    root().block().flipForWritingMode(rect);
}

LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return point;
    return root().block().flipForWritingMode(point);
}

} // namespace WebCore

#ifndef NDEBUG

void showTree(const WebCore::InlineBox* b)
{
    if (b)
        b->showTreeForThis();
}

void showLineTree(const WebCore::InlineBox* b)
{
    if (b)
        b->showLineTreeForThis();
}

#endif
<commit_msg>Add more details to showLineTree() output<commit_after>/*
 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/rendering/InlineBox.h"

#include "core/rendering/InlineFlowBox.h"
#include "core/rendering/PaintInfo.h"
#include "core/rendering/RenderBlockFlow.h"
#include "core/rendering/RootInlineBox.h"
#include "platform/Partitions.h"
#include "platform/fonts/FontMetrics.h"

#ifndef NDEBUG
#include <stdio.h>
#endif

using namespace std;

namespace WebCore {

struct SameSizeAsInlineBox {
    virtual ~SameSizeAsInlineBox() { }
    void* a[4];
    FloatPoint b;
    float c;
    uint32_t d : 32;
#ifndef NDEBUG
    bool f;
#endif
};

COMPILE_ASSERT(sizeof(InlineBox) == sizeof(SameSizeAsInlineBox), InlineBox_size_guard);

#ifndef NDEBUG

InlineBox::~InlineBox()
{
    if (!m_hasBadParent && m_parent)
        m_parent->setHasBadChildList();
}

#endif

void InlineBox::remove()
{
    if (parent())
        parent()->removeChild(this);
}

void* InlineBox::operator new(size_t sz)
{
    return partitionAlloc(Partitions::getRenderingPartition(), sz);
}

void InlineBox::operator delete(void* ptr)
{
    partitionFree(ptr);
}

#ifndef NDEBUG
const char* InlineBox::boxName() const
{
    return "InlineBox";
}

void InlineBox::showTreeForThis() const
{
    renderer().showTreeForThis();
}

void InlineBox::showLineTreeForThis() const
{
    renderer().containingBlock()->showLineTreeAndMark(this, "*");
}

void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
{
    int printedCharacters = 0;
    if (this == markedBox1)
        printedCharacters += fprintf(stderr, "%s", markedLabel1);
    if (this == markedBox2)
        printedCharacters += fprintf(stderr, "%s", markedLabel2);
    if (&renderer() == obj)
        printedCharacters += fprintf(stderr, "*");
    for (; printedCharacters < depth * 2; printedCharacters++)
        fputc(' ', stderr);

    showBox(printedCharacters);
}

void InlineBox::showBox(int printedCharacters) const
{
    printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
    for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
        fputc(' ', stderr);
    fprintf(stderr, "\t%s %p {pos=%g,%g size=%g,%g} baseline=%i/%i\n",
        renderer().renderName(), &renderer(), x(), y(), width(), height(),
        baselinePosition(AlphabeticBaseline),
        baselinePosition(IdeographicBaseline));
}
#endif

float InlineBox::logicalHeight() const
{
    if (hasVirtualLogicalHeight())
        return virtualLogicalHeight();

    if (renderer().isText())
        return m_bitfields.isText() ? renderer().style(isFirstLineStyle())->fontMetrics().height() : 0;
    if (renderer().isBox() && parent())
        return isHorizontal() ? toRenderBox(renderer()).height().toFloat() : toRenderBox(renderer()).width().toFloat();

    ASSERT(isInlineFlowBox());
    RenderBoxModelObject* flowObject = boxModelObject();
    const FontMetrics& fontMetrics = renderer().style(isFirstLineStyle())->fontMetrics();
    float result = fontMetrics.height();
    if (parent())
        result += flowObject->borderAndPaddingLogicalHeight();
    return result;
}

int InlineBox::baselinePosition(FontBaseline baselineType) const
{
    return boxModelObject()->baselinePosition(baselineType, m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
}

LayoutUnit InlineBox::lineHeight() const
{
    return boxModelObject()->lineHeight(m_bitfields.firstLine(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
}

int InlineBox::caretMinOffset() const
{
    return renderer().caretMinOffset();
}

int InlineBox::caretMaxOffset() const
{
    return renderer().caretMaxOffset();
}

void InlineBox::dirtyLineBoxes()
{
    markDirty();
    for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent())
        curr->markDirty();
}

void InlineBox::deleteLine()
{
    if (!m_bitfields.extracted() && renderer().isBox())
        toRenderBox(renderer()).setInlineBoxWrapper(0);
    destroy();
}

void InlineBox::extractLine()
{
    m_bitfields.setExtracted(true);
    if (renderer().isBox())
        toRenderBox(renderer()).setInlineBoxWrapper(0);
}

void InlineBox::attachLine()
{
    m_bitfields.setExtracted(false);
    if (renderer().isBox())
        toRenderBox(renderer()).setInlineBoxWrapper(this);
}

void InlineBox::adjustPosition(float dx, float dy)
{
    m_topLeft.move(dx, dy);

    if (renderer().isReplaced())
        toRenderBox(renderer()).move(dx, dy);
}

void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
{
    if (!paintInfo.shouldPaintWithinRoot(&renderer()) || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection))
        return;

    LayoutPoint childPoint = paintOffset;
    if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
        childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);

    RenderBlock::paintAsInlineBlock(&renderer(), paintInfo, childPoint);
}

bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
{
    // Hit test all phases of replaced elements atomically, as though the replaced element established its
    // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
    // specification.)
    LayoutPoint childPoint = accumulatedOffset;
    if (parent()->renderer().style()->isFlippedBlocksWritingMode()) // Faster than calling containingBlock().
        childPoint = renderer().containingBlock()->flipForWritingModeForChild(&toRenderBox(renderer()), childPoint);

    return renderer().hitTest(request, result, locationInContainer, childPoint);
}

const RootInlineBox& InlineBox::root() const
{
    if (m_parent)
        return m_parent->root();
    ASSERT(isRootInlineBox());
    return static_cast<const RootInlineBox&>(*this);
}

RootInlineBox& InlineBox::root()
{
    if (m_parent)
        return m_parent->root();
    ASSERT(isRootInlineBox());
    return static_cast<RootInlineBox&>(*this);
}

bool InlineBox::nextOnLineExists() const
{
    if (!m_bitfields.determinedIfNextOnLineExists()) {
        m_bitfields.setDeterminedIfNextOnLineExists(true);

        if (!parent())
            m_bitfields.setNextOnLineExists(false);
        else if (nextOnLine())
            m_bitfields.setNextOnLineExists(true);
        else
            m_bitfields.setNextOnLineExists(parent()->nextOnLineExists());
    }
    return m_bitfields.nextOnLineExists();
}

InlineBox* InlineBox::nextLeafChild() const
{
    InlineBox* leaf = 0;
    for (InlineBox* box = nextOnLine(); box && !leaf; box = box->nextOnLine())
        leaf = box->isLeaf() ? box : toInlineFlowBox(box)->firstLeafChild();
    if (!leaf && parent())
        leaf = parent()->nextLeafChild();
    return leaf;
}

InlineBox* InlineBox::prevLeafChild() const
{
    InlineBox* leaf = 0;
    for (InlineBox* box = prevOnLine(); box && !leaf; box = box->prevOnLine())
        leaf = box->isLeaf() ? box : toInlineFlowBox(box)->lastLeafChild();
    if (!leaf && parent())
        leaf = parent()->prevLeafChild();
    return leaf;
}

InlineBox* InlineBox::nextLeafChildIgnoringLineBreak() const
{
    InlineBox* leaf = nextLeafChild();
    if (leaf && leaf->isLineBreak())
        return 0;
    return leaf;
}

InlineBox* InlineBox::prevLeafChildIgnoringLineBreak() const
{
    InlineBox* leaf = prevLeafChild();
    if (leaf && leaf->isLineBreak())
        return 0;
    return leaf;
}

RenderObject::SelectionState InlineBox::selectionState()
{
    return renderer().selectionState();
}

bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
{
    // Non-replaced elements can always accommodate an ellipsis.
    if (!renderer().isReplaced())
        return true;

    IntRect boxRect(left(), 0, m_logicalWidth, 10);
    IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
    return !(boxRect.intersects(ellipsisRect));
}

float InlineBox::placeEllipsisBox(bool, float, float, float, float& truncatedWidth, bool&)
{
    // Use -1 to mean "we didn't set the position."
    truncatedWidth += logicalWidth();
    return -1;
}

void InlineBox::clearKnownToHaveNoOverflow()
{
    m_bitfields.setKnownToHaveNoOverflow(false);
    if (parent() && parent()->knownToHaveNoOverflow())
        parent()->clearKnownToHaveNoOverflow();
}

FloatPoint InlineBox::locationIncludingFlipping()
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return FloatPoint(x(), y());
    RenderBlockFlow& block = root().block();
    if (block.style()->isHorizontalWritingMode())
        return FloatPoint(x(), block.height() - height() - y());

    return FloatPoint(block.width() - width() - x(), y());
}

void InlineBox::flipForWritingMode(FloatRect& rect)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return;
    root().block().flipForWritingMode(rect);
}

FloatPoint InlineBox::flipForWritingMode(const FloatPoint& point)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return point;
    return root().block().flipForWritingMode(point);
}

void InlineBox::flipForWritingMode(LayoutRect& rect)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return;
    root().block().flipForWritingMode(rect);
}

LayoutPoint InlineBox::flipForWritingMode(const LayoutPoint& point)
{
    if (!renderer().style()->isFlippedBlocksWritingMode())
        return point;
    return root().block().flipForWritingMode(point);
}

} // namespace WebCore

#ifndef NDEBUG

void showTree(const WebCore::InlineBox* b)
{
    if (b)
        b->showTreeForThis();
}

void showLineTree(const WebCore::InlineBox* b)
{
    if (b)
        b->showLineTreeForThis();
}

#endif
<|endoftext|>


<commit_before>
/* @doc \file Object to generate a file following AMELIF format.

   Copyright (c) 2010
   @author Olivier Stasse
   JRL-Japan, CNRS/AIST

   All rights reserved.

   Please refers to file License.txt for details on the license.

*/
#include "GenerateRobotForAMELIF.h"
#include <cmath>

using namespace std;

namespace {
	double FilterPrecision(double x)
	{
		x *= 1e6;
		x =floor(x+0.5);
		x *= 1e-6;
		return x;
	}

	void ComputeEulerAngles(const matrix3d &aRotationMatrix, vector3d &EulerAngles)
	{
		double r11 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,0,0);
		double r12 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,0,1);
		double r13 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,0,2);

		double r21 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,1,0);

		double r31 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,2,0);
		double r32 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,2,1);
		double r33 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,2,2);

		if (fabs(fabs(r31)-1.0)>1e-8)
		{

			double Y1 = -asin(r31);
			double Y2 = M_PI - Y1;
			Y2 = fmod(Y2,M_PI);
			double c0_1 = cos(Y1);
			double c0_2 = cos(Y2);

			double X1 = atan2(r32/c0_1,r33/c0_1);
			double X2 = atan2(r32/c0_2,r33/c0_2);

			double c0;
			if (fabs(X1)<fabs(X2))
			{
				EulerAngles(1) = Y1;
				EulerAngles(0) = X1;
				c0 = c0_1;
			}
			else
			{
				EulerAngles(1) = Y2;
				EulerAngles(0) = X2;
				c0 = c0_2;
			}

			EulerAngles(2) = atan2(r21/c0,r11/c0);

		}
		else
		{
			EulerAngles(2) = 0;
			double d = atan2(r12,r13);
			d = fmod(d,M_PI);
			if (fabs(r31+1.0)<1e-8)
			{
				EulerAngles(1) = M_PI/2;
				EulerAngles(0) = d;
			}
			else
			{
				EulerAngles(1) = -M_PI/2;
				EulerAngles(0) = -d;
			}
		}
	}
}

namespace dynamicsJRLJapan {

  GenerateRobotForAMELIF::GenerateRobotForAMELIF()
  {
  }

  GenerateRobotForAMELIF::~GenerateRobotForAMELIF()
  {
  }

  void GenerateRobotForAMELIF::Header(ostream &os)
  {
    os << "<!DOCTYPE MultiBody SYSTEM \"./AMELIFMultiBody.xsd\">" << endl;
  }

  void GenerateRobotForAMELIF::StaticParameters(CjrlJoint *aJoint,
						ostream &os,
						string &shifttab)
  {
    MAL_S4x4_MATRIX(aTransformation,double);
    MAL_S4x4_MATRIX(FinalTransformation,double);
    aTransformation = aJoint->currentTransformation();
    unsigned int indexparent=0;

    /* Compute transformation in local coordinates */
    CjrlJoint *parentJoint = aJoint->parentJoint();
    if (parentJoint!=0)
      {
	MAL_S4x4_MATRIX(parentTransformation,double);
	parentTransformation = parentJoint->currentTransformation();

	MAL_S4x4_MATRIX(invParentTransformation,double);
	MAL_S4x4_INVERSE(parentTransformation,invParentTransformation,double);
	MAL_S4x4_C_eq_A_by_B(FinalTransformation,invParentTransformation,aTransformation);
      }
    else
      FinalTransformation = aTransformation;

    /* Project rotation axis */

    matrix3d aRotation;
    vector3d anAxis, EulerAngles;
    for(unsigned int i=0;i<3;i++)
      {
	for(unsigned int j=0;j<3;j++)
	  MAL_S3x3_MATRIX_ACCESS_I_J(aRotation,i,j) =
	    MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,i,j);
      }

    ComputeEulerAngles(aRotation, EulerAngles);

    os << shifttab
       << "  <StaticParameters> "
       << MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,0,3) << " "
       << MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,1,3) << " "
       << MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,2,3) << " "
       << FilterPrecision(EulerAngles(0) * 180.0/M_PI) << " "
       << FilterPrecision(EulerAngles(1) * 180.0/M_PI) << " "
       << FilterPrecision(EulerAngles(2) * 180.0/M_PI)
       << "</StaticParameters>"
	   << std::endl;
  }

  void GenerateRobotForAMELIF::GenerateJoint(CjrlJoint *aJoint,
					     ostream &os,
					     string shifttab, unsigned int &gindex)
  {
	os.precision(15);
	if (aJoint->rankInConfiguration() == 0)
	{
		gindex++;
		// Call the sons.
		for(unsigned int i=0;i<aJoint->countChildJoints();i++)
			GenerateJoint(aJoint->childJoint(i),os,shifttab,gindex);
		return;
	}

    // Joint name and type.
    os << shifttab << "<Joint id=\""
       << aJoint->rankInConfiguration() ;
    if (gindex==0)
      os << "\" type=\"revolute\"";
    else
      os << "\" type=\"revolute\"";

    os << " axis=\"x\" " ;

    if (aJoint->parentJoint()!=0)
      os << "innerId=\""<<aJoint->parentJoint()->rankInConfiguration();

    os << "\" outerId=\""<<aJoint->rankInConfiguration()
       << "\"> " << endl;

    // Label
    os << shifttab << "  JOINT_"
       << aJoint->rankInConfiguration()
       << "  " << endl;

    // Static parameters
    StaticParameters(aJoint, os, shifttab);

    // Position min and max.
    os << shifttab << "  <PositionMin>"
       << FilterPrecision(aJoint->lowerBound(0)  * 180.0/M_PI)
       <<"</PositionMin>" << endl;

    os << shifttab << "  <PositionMax>"
       << FilterPrecision(aJoint->upperBound(0) * 180.0/M_PI)
       << "</PositionMax>" << endl;

    // Close the joint description
    os << shifttab << "</Joint>"<< endl;

    gindex++;

    // Call the sons.
    for(unsigned int i=0;i<aJoint->countChildJoints();i++)
      {
	GenerateJoint(aJoint->childJoint(i),os,shifttab,gindex);
      }

  }

  void GenerateRobotForAMELIF::GenerateBody(CjrlJoint *aJoint,
					    ostream &os,
					    string shifttab,
					    unsigned int &gindex)
  {
	os.precision(15);
    CjrlBody *aBody= aJoint->linkedBody();
    if (aBody==0)
      return;

    os << shifttab << "<Body id=\""
       << aJoint->rankInConfiguration()
       << "\">" << endl;

    // Label
    os << shifttab << "  LINK_"
       << aJoint->rankInConfiguration()
       << "" << endl;

	// Mass
	const double mass = aBody->mass();
    os << shifttab << "  <Mass>"<< mass <<"</Mass>" << endl;

    // CoM
    const  vector3d lcom = aBody->localCenterOfMass();
    os << shifttab << "  <CoM>"
       << MAL_S3_VECTOR_ACCESS(lcom,0) << " "
       << MAL_S3_VECTOR_ACCESS(lcom,1) << " "
       << MAL_S3_VECTOR_ACCESS(lcom,2) << "</CoM>" << endl;

    // Inertia
    os << shifttab << "  <Inertia>" ;
    matrix3d Inertia = aBody->inertiaMatrix();

    for(unsigned int i=0;i<3;i++)
      for(unsigned int j=0;j<3;j++)
	os << MAL_S3x3_MATRIX_ACCESS_I_J(Inertia,i,j) << " ";
    os << "</Inertia>" << endl;

    // Geometric file.
	const std::vector< std::string > & urls = m_AccessToData[gindex].getURLs();
	for(unsigned i=0; i < urls.size(); ++i)
		os << shifttab << "  <File>" << urls[i] << "</File>" << endl;

    gindex++;
    // Close body description.
    os << shifttab << "" << endl;

    // Call the sons.
    for(unsigned int i=0;i<aJoint->countChildJoints();i++)
      {
	GenerateBody(aJoint->childJoint(i),os,shifttab,gindex);
      }

  }

  void GenerateRobotForAMELIF::SetAccessToData(vector<BodyGeometricalData> &AccessToData)
  {
    m_AccessToData = AccessToData;
  }

  void GenerateRobotForAMELIF::GenerateBodies(ostream &os,
					      string shifttab)
  {
    CjrlJoint *RootJoint = m_HDR->rootJoint();
    string lshifttab = shifttab+"  ";
    os << shifttab << "<Bodies>" << endl;
    unsigned int gindex=0;
    GenerateBody(RootJoint,os, lshifttab,gindex);
    os << shifttab << "</Bodies>" << endl;
  }

  void GenerateRobotForAMELIF::GenerateJoints(ostream &os,
					      string shifttab)
  {
    CjrlJoint *RootJoint = m_HDR->rootJoint();
    string lshifttab = shifttab+"  ";
    os << shifttab << "<Joints>" << endl;
    unsigned int gindex=0;
    GenerateJoint(RootJoint,os, lshifttab,gindex);
    os << shifttab << "</Joints>" << endl;
  }

  void GenerateRobotForAMELIF::GenerateRobot(std::string &RobotName,
					     CjrlHumanoidDynamicRobot *aHDR)
  {
    m_HDR = aHDR;
    ofstream aof;

    string FileName = RobotName;
    FileName += ".xml";

    aof.open(FileName.c_str(),fstream::out);
    if (!aof.is_open())
      return;

    Header(aof);

    string shifttab;
    aof << "<MultiBody>" << endl;
    shifttab = "  ";
    aof << shifttab << "<Root id=\"0\" />" << endl;
    GenerateBodies(aof, shifttab);
    GenerateJoints(aof, shifttab);
    aof << "</MultiBody>" << endl;

    aof.close();
  }
};
<commit_msg>Fix warning at compile time.<commit_after>
/* @doc \file Object to generate a file following AMELIF format.

   Copyright (c) 2010
   @author Olivier Stasse
   JRL-Japan, CNRS/AIST

   All rights reserved.

   Please refers to file License.txt for details on the license.

*/
#include "GenerateRobotForAMELIF.h"
#include <cmath>

using namespace std;

namespace {
	double FilterPrecision(double x)
	{
		x *= 1e6;
		x =floor(x+0.5);
		x *= 1e-6;
		return x;
	}

	void ComputeEulerAngles(const matrix3d &aRotationMatrix, vector3d &EulerAngles)
	{
		double r11 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,0,0);
		double r12 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,0,1);
		double r13 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,0,2);

		double r21 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,1,0);

		double r31 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,2,0);
		double r32 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,2,1);
		double r33 = MAL_S3x3_MATRIX_ACCESS_I_J(aRotationMatrix,2,2);

		if (fabs(fabs(r31)-1.0)>1e-8)
		{

			double Y1 = -asin(r31);
			double Y2 = M_PI - Y1;
			Y2 = fmod(Y2,M_PI);
			double c0_1 = cos(Y1);
			double c0_2 = cos(Y2);

			double X1 = atan2(r32/c0_1,r33/c0_1);
			double X2 = atan2(r32/c0_2,r33/c0_2);

			double c0;
			if (fabs(X1)<fabs(X2))
			{
				EulerAngles(1) = Y1;
				EulerAngles(0) = X1;
				c0 = c0_1;
			}
			else
			{
				EulerAngles(1) = Y2;
				EulerAngles(0) = X2;
				c0 = c0_2;
			}

			EulerAngles(2) = atan2(r21/c0,r11/c0);

		}
		else
		{
			EulerAngles(2) = 0;
			double d = atan2(r12,r13);
			d = fmod(d,M_PI);
			if (fabs(r31+1.0)<1e-8)
			{
				EulerAngles(1) = M_PI/2;
				EulerAngles(0) = d;
			}
			else
			{
				EulerAngles(1) = -M_PI/2;
				EulerAngles(0) = -d;
			}
		}
	}
}

namespace dynamicsJRLJapan {

  GenerateRobotForAMELIF::GenerateRobotForAMELIF()
  {
  }

  GenerateRobotForAMELIF::~GenerateRobotForAMELIF()
  {
  }

  void GenerateRobotForAMELIF::Header(ostream &os)
  {
    os << "<!DOCTYPE MultiBody SYSTEM \"./AMELIFMultiBody.xsd\">" << endl;
  }

  void GenerateRobotForAMELIF::StaticParameters(CjrlJoint *aJoint,
						ostream &os,
						string &shifttab)
  {
    MAL_S4x4_MATRIX(aTransformation,double);
    MAL_S4x4_MATRIX(FinalTransformation,double);
    aTransformation = aJoint->currentTransformation();

    /* Compute transformation in local coordinates */
    CjrlJoint *parentJoint = aJoint->parentJoint();
    if (parentJoint!=0)
      {
	MAL_S4x4_MATRIX(parentTransformation,double);
	parentTransformation = parentJoint->currentTransformation();

	MAL_S4x4_MATRIX(invParentTransformation,double);
	MAL_S4x4_INVERSE(parentTransformation,invParentTransformation,double);
	MAL_S4x4_C_eq_A_by_B(FinalTransformation,invParentTransformation,aTransformation);
      }
    else
      FinalTransformation = aTransformation;

    /* Project rotation axis */

    matrix3d aRotation;
    vector3d anAxis, EulerAngles;
    for(unsigned int i=0;i<3;i++)
      {
	for(unsigned int j=0;j<3;j++)
	  MAL_S3x3_MATRIX_ACCESS_I_J(aRotation,i,j) =
	    MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,i,j);
      }

    ComputeEulerAngles(aRotation, EulerAngles);

    os << shifttab
       << "  <StaticParameters> "
       << MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,0,3) << " "
       << MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,1,3) << " "
       << MAL_S4x4_MATRIX_ACCESS_I_J(FinalTransformation,2,3) << " "
       << FilterPrecision(EulerAngles(0) * 180.0/M_PI) << " "
       << FilterPrecision(EulerAngles(1) * 180.0/M_PI) << " "
       << FilterPrecision(EulerAngles(2) * 180.0/M_PI)
       << "</StaticParameters>"
	   << std::endl;
  }

  void GenerateRobotForAMELIF::GenerateJoint(CjrlJoint *aJoint,
					     ostream &os,
					     string shifttab, unsigned int &gindex)
  {
	os.precision(15);
	if (aJoint->rankInConfiguration() == 0)
	{
		gindex++;
		// Call the sons.
		for(unsigned int i=0;i<aJoint->countChildJoints();i++)
			GenerateJoint(aJoint->childJoint(i),os,shifttab,gindex);
		return;
	}

    // Joint name and type.
    os << shifttab << "<Joint id=\""
       << aJoint->rankInConfiguration() ;
    if (gindex==0)
      os << "\" type=\"revolute\"";
    else
      os << "\" type=\"revolute\"";

    os << " axis=\"x\" " ;

    if (aJoint->parentJoint()!=0)
      os << "innerId=\""<<aJoint->parentJoint()->rankInConfiguration();

    os << "\" outerId=\""<<aJoint->rankInConfiguration()
       << "\"> " << endl;

    // Label
    os << shifttab << "  JOINT_"
       << aJoint->rankInConfiguration()
       << "  " << endl;

    // Static parameters
    StaticParameters(aJoint, os, shifttab);

    // Position min and max.
    os << shifttab << "  <PositionMin>"
       << FilterPrecision(aJoint->lowerBound(0)  * 180.0/M_PI)
       <<"</PositionMin>" << endl;

    os << shifttab << "  <PositionMax>"
       << FilterPrecision(aJoint->upperBound(0) * 180.0/M_PI)
       << "</PositionMax>" << endl;

    // Close the joint description
    os << shifttab << "</Joint>"<< endl;

    gindex++;

    // Call the sons.
    for(unsigned int i=0;i<aJoint->countChildJoints();i++)
      {
	GenerateJoint(aJoint->childJoint(i),os,shifttab,gindex);
      }

  }

  void GenerateRobotForAMELIF::GenerateBody(CjrlJoint *aJoint,
					    ostream &os,
					    string shifttab,
					    unsigned int &gindex)
  {
	os.precision(15);
    CjrlBody *aBody= aJoint->linkedBody();
    if (aBody==0)
      return;

    os << shifttab << "<Body id=\""
       << aJoint->rankInConfiguration()
       << "\">" << endl;

    // Label
    os << shifttab << "  LINK_"
       << aJoint->rankInConfiguration()
       << "" << endl;

	// Mass
	const double mass = aBody->mass();
    os << shifttab << "  <Mass>"<< mass <<"</Mass>" << endl;

    // CoM
    const  vector3d lcom = aBody->localCenterOfMass();
    os << shifttab << "  <CoM>"
       << MAL_S3_VECTOR_ACCESS(lcom,0) << " "
       << MAL_S3_VECTOR_ACCESS(lcom,1) << " "
       << MAL_S3_VECTOR_ACCESS(lcom,2) << "</CoM>" << endl;

    // Inertia
    os << shifttab << "  <Inertia>" ;
    matrix3d Inertia = aBody->inertiaMatrix();

    for(unsigned int i=0;i<3;i++)
      for(unsigned int j=0;j<3;j++)
	os << MAL_S3x3_MATRIX_ACCESS_I_J(Inertia,i,j) << " ";
    os << "</Inertia>" << endl;

    // Geometric file.
	const std::vector< std::string > & urls = m_AccessToData[gindex].getURLs();
	for(unsigned i=0; i < urls.size(); ++i)
		os << shifttab << "  <File>" << urls[i] << "</File>" << endl;

    gindex++;
    // Close body description.
    os << shifttab << "" << endl;

    // Call the sons.
    for(unsigned int i=0;i<aJoint->countChildJoints();i++)
      {
	GenerateBody(aJoint->childJoint(i),os,shifttab,gindex);
      }

  }

  void GenerateRobotForAMELIF::SetAccessToData(vector<BodyGeometricalData> &AccessToData)
  {
    m_AccessToData = AccessToData;
  }

  void GenerateRobotForAMELIF::GenerateBodies(ostream &os,
					      string shifttab)
  {
    CjrlJoint *RootJoint = m_HDR->rootJoint();
    string lshifttab = shifttab+"  ";
    os << shifttab << "<Bodies>" << endl;
    unsigned int gindex=0;
    GenerateBody(RootJoint,os, lshifttab,gindex);
    os << shifttab << "</Bodies>" << endl;
  }

  void GenerateRobotForAMELIF::GenerateJoints(ostream &os,
					      string shifttab)
  {
    CjrlJoint *RootJoint = m_HDR->rootJoint();
    string lshifttab = shifttab+"  ";
    os << shifttab << "<Joints>" << endl;
    unsigned int gindex=0;
    GenerateJoint(RootJoint,os, lshifttab,gindex);
    os << shifttab << "</Joints>" << endl;
  }

  void GenerateRobotForAMELIF::GenerateRobot(std::string &RobotName,
					     CjrlHumanoidDynamicRobot *aHDR)
  {
    m_HDR = aHDR;
    ofstream aof;

    string FileName = RobotName;
    FileName += ".xml";

    aof.open(FileName.c_str(),fstream::out);
    if (!aof.is_open())
      return;

    Header(aof);

    string shifttab;
    aof << "<MultiBody>" << endl;
    shifttab = "  ";
    aof << shifttab << "<Root id=\"0\" />" << endl;
    GenerateBodies(aof, shifttab);
    GenerateJoints(aof, shifttab);
    aof << "</MultiBody>" << endl;

    aof.close();
  }
};
<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/DBusProxyFactory>
#include "TelepathyQt4/dbus-proxy-factory-internal.h"

#include "TelepathyQt4/_gen/dbus-proxy-factory-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/Account>
#include <TelepathyQt4/Connection>
#include <TelepathyQt4/DBusProxy>
#include <TelepathyQt4/Feature>
#include <TelepathyQt4/ReadyObject>
#include <TelepathyQt4/PendingReady>

#include <QDBusConnection>

namespace Tp
{

struct DBusProxyFactory::Private
{
    Private(const QDBusConnection &bus)
        : bus(bus), cache(new Cache) {}

    ~Private()
    {
        delete cache;
    }

    QDBusConnection bus;
    Cache *cache;
};

DBusProxyFactory::DBusProxyFactory(const QDBusConnection &bus)
    : mPriv(new Private(bus))
{
}

DBusProxyFactory::~DBusProxyFactory()
{
    delete mPriv;
}

const QDBusConnection &DBusProxyFactory::dbusConnection() const
{
    return mPriv->bus;
}

SharedPtr<RefCounted> DBusProxyFactory::cachedProxy(const QString &busName,
        const QString &objectPath) const
{
    QString finalName = finalBusNameFrom(busName);
    return mPriv->cache->get(Cache::Key(finalName, objectPath));
}

PendingReady *DBusProxyFactory::nowHaveProxy(const SharedPtr<RefCounted> &proxy, bool created) const
{
    Q_ASSERT(!proxy.isNull());

    // I really hate the casts needed in this function - we must really do something about the
    // DBusProxy class hierarchy so that every DBusProxy(Something) is always a ReadyObject and a
    // RefCounted, in the API/ABI break - then most of these proxyMisc-> things become just proxy->

    DBusProxy *proxyProxy = dynamic_cast<DBusProxy *>(proxy.data());
    ReadyObject *proxyReady = dynamic_cast<ReadyObject *>(proxy.data());

    Features specificFeatures = featuresFor(proxy);

    // TODO: lookup existing prepareOp, if any, from a private mapping
    PendingOperation *prepareOp = NULL;

    if (created) {
        mPriv->cache->put(Cache::Key(proxyProxy->busName(), proxyProxy->objectPath()), proxy);
        prepareOp = prepare(proxy);
        // TODO: insert to private prepare op mapping and make sure it's removed when it finishes/is
        // destroyed
    }

    if (prepareOp || (!specificFeatures.isEmpty() && !proxyReady->isReady(specificFeatures))) {
        return new PendingReady(prepareOp, specificFeatures, proxy, proxyProxy);
    }

    // No features requested or they are all ready - optimize a bit by not calling ReadinessHelper
    PendingReady *readyOp = new PendingReady(0, specificFeatures, proxy, proxyProxy);
    readyOp->setFinished();
    return readyOp;
}

PendingOperation *DBusProxyFactory::prepare(const SharedPtr<RefCounted> &object) const
{
    // Nothing we could think about needs doing
    return NULL;
}

DBusProxyFactory::Cache::Cache()
{
}

DBusProxyFactory::Cache::~Cache()
{
}

SharedPtr<RefCounted> DBusProxyFactory::Cache::get(const Key &key) const
{
    SharedPtr<RefCounted> counted(proxies.value(key));

    if (!counted || !dynamic_cast<DBusProxy *>(counted.data())->isValid()) {
        // Weak pointer invalidated or proxy invalidated during this mainloop iteration and we still
        // haven't got the invalidated() signal for it
        return SharedPtr<RefCounted>();
    }

    return counted;
}

void DBusProxyFactory::Cache::put(const Key &key, const SharedPtr<RefCounted> &obj)
{
    Q_ASSERT(!proxies.contains(key));

    // This sucks because DBusProxy is not RefCounted...
    connect(dynamic_cast<DBusProxy*>(obj.data()),
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(onProxyInvalidated(Tp::DBusProxy*)));

    debug() << "Inserting to factory cache proxy for" << key;

    proxies.insert(key, obj);
}

void DBusProxyFactory::Cache::onProxyInvalidated(Tp::DBusProxy *proxy)
{
    Key key(proxy->busName(), proxy->objectPath());

    // Not having it would indicate invalidated() signaled twice for the same proxy, or us having
    // connected to two proxies with the same key, neither of which should happen
    Q_ASSERT(proxies.contains(key));

    debug() << "Removing from factory cache invalidated proxy for" << key;

    proxies.remove(key);
}

struct FixedFeatureFactory::Private
{
    Features features;
};

FixedFeatureFactory::FixedFeatureFactory(const QDBusConnection &bus)
    : DBusProxyFactory(bus), mPriv(new Private)
{
}

FixedFeatureFactory::~FixedFeatureFactory()
{
    delete mPriv;
}

Features FixedFeatureFactory::features() const
{
    return mPriv->features;
}

void FixedFeatureFactory::addFeature(const Feature &feature)
{
    addFeatures(Features(feature));
}

void FixedFeatureFactory::addFeatures(const Features &features)
{
    mPriv->features.unite(features);
}

Features FixedFeatureFactory::featuresFor(const SharedPtr<RefCounted> &proxy) const
{
    Q_UNUSED(proxy);

    return features();
}

AccountFactoryPtr AccountFactory::create(const QDBusConnection &bus)
{
    return AccountFactoryPtr(new AccountFactory(bus));
}

AccountFactoryPtr AccountFactory::coreFactory(const QDBusConnection &bus)
{
    AccountFactoryPtr factory(create(bus));

    factory->addFeature(Account::FeatureCore);

    return factory;
}

AccountFactory::AccountFactory(const QDBusConnection &bus)
    : FixedFeatureFactory(bus)
{
}

AccountFactory::~AccountFactory()
{
}

PendingReady *AccountFactory::proxy(const QString &busName, const QString &objectPath,
            const ConnectionFactoryConstPtr &connFactory,
            const ChannelFactoryConstPtr &chanFactory) const
{
    SharedPtr<RefCounted> proxy = cachedProxy(busName, objectPath);
    if (proxy) {
        return nowHaveProxy(proxy, false);
    }

    proxy = Account::create(dbusConnection(), busName, objectPath/*, connFactory, chanFactory*/);
    return nowHaveProxy(proxy, true);
}

QString AccountFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const
{
    return uniqueOrWellKnown;
}

ConnectionFactoryPtr ConnectionFactory::create(const QDBusConnection &bus)
{
    return ConnectionFactoryPtr(new ConnectionFactory(bus));
}

ConnectionFactory::ConnectionFactory(const QDBusConnection &bus)
    : FixedFeatureFactory(bus)
{
}

ConnectionFactory::~ConnectionFactory()
{
}

PendingReady *ConnectionFactory::proxy(const QString &busName, const QString &objectPath,
            const ChannelFactoryConstPtr &chanFactory) const
{
    SharedPtr<RefCounted> proxy = cachedProxy(busName, objectPath);
    if (proxy) {
        return nowHaveProxy(proxy, false);
    }

    proxy = Connection::create(dbusConnection(), busName, objectPath/*, chanFactory*/);
    return nowHaveProxy(proxy, true);
}

QString ConnectionFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const
{
    return StatefulDBusProxy::uniqueNameFrom(dbusConnection(), uniqueOrWellKnown);
}

}
<commit_msg>Assert on the DBusProxyFactory dynamic_casts succeeding as appropriate<commit_after>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/DBusProxyFactory>
#include "TelepathyQt4/dbus-proxy-factory-internal.h"

#include "TelepathyQt4/_gen/dbus-proxy-factory-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/Account>
#include <TelepathyQt4/Connection>
#include <TelepathyQt4/DBusProxy>
#include <TelepathyQt4/Feature>
#include <TelepathyQt4/ReadyObject>
#include <TelepathyQt4/PendingReady>

#include <QDBusConnection>

namespace Tp
{

struct DBusProxyFactory::Private
{
    Private(const QDBusConnection &bus)
        : bus(bus), cache(new Cache) {}

    ~Private()
    {
        delete cache;
    }

    QDBusConnection bus;
    Cache *cache;
};

DBusProxyFactory::DBusProxyFactory(const QDBusConnection &bus)
    : mPriv(new Private(bus))
{
}

DBusProxyFactory::~DBusProxyFactory()
{
    delete mPriv;
}

const QDBusConnection &DBusProxyFactory::dbusConnection() const
{
    return mPriv->bus;
}

SharedPtr<RefCounted> DBusProxyFactory::cachedProxy(const QString &busName,
        const QString &objectPath) const
{
    QString finalName = finalBusNameFrom(busName);
    return mPriv->cache->get(Cache::Key(finalName, objectPath));
}

PendingReady *DBusProxyFactory::nowHaveProxy(const SharedPtr<RefCounted> &proxy, bool created) const
{
    Q_ASSERT(!proxy.isNull());

    // I really hate the casts needed in this function - we must really do something about the
    // DBusProxy class hierarchy so that every DBusProxy(Something) is always a ReadyObject and a
    // RefCounted, in the API/ABI break - then most of these proxyMisc-> things become just proxy->

    DBusProxy *proxyProxy = dynamic_cast<DBusProxy *>(proxy.data());
    ReadyObject *proxyReady = dynamic_cast<ReadyObject *>(proxy.data());

    Q_ASSERT(proxyProxy != NULL);
    Q_ASSERT(proxyReady != NULL);

    Features specificFeatures = featuresFor(proxy);

    // TODO: lookup existing prepareOp, if any, from a private mapping
    PendingOperation *prepareOp = NULL;

    if (created) {
        mPriv->cache->put(Cache::Key(proxyProxy->busName(), proxyProxy->objectPath()), proxy);
        prepareOp = prepare(proxy);
        // TODO: insert to private prepare op mapping and make sure it's removed when it finishes/is
        // destroyed
    }

    if (prepareOp || (!specificFeatures.isEmpty() && !proxyReady->isReady(specificFeatures))) {
        return new PendingReady(prepareOp, specificFeatures, proxy, proxyProxy);
    }

    // No features requested or they are all ready - optimize a bit by not calling ReadinessHelper
    PendingReady *readyOp = new PendingReady(0, specificFeatures, proxy, proxyProxy);
    readyOp->setFinished();
    return readyOp;
}

PendingOperation *DBusProxyFactory::prepare(const SharedPtr<RefCounted> &object) const
{
    // Nothing we could think about needs doing
    return NULL;
}

DBusProxyFactory::Cache::Cache()
{
}

DBusProxyFactory::Cache::~Cache()
{
}

SharedPtr<RefCounted> DBusProxyFactory::Cache::get(const Key &key) const
{
    SharedPtr<RefCounted> counted(proxies.value(key));

    // We already assert for it being a DBusProxy in put()
    if (!counted || !dynamic_cast<DBusProxy *>(counted.data())->isValid()) {
        // Weak pointer invalidated or proxy invalidated during this mainloop iteration and we still
        // haven't got the invalidated() signal for it
        return SharedPtr<RefCounted>();
    }

    return counted;
}

void DBusProxyFactory::Cache::put(const Key &key, const SharedPtr<RefCounted> &obj)
{
    Q_ASSERT(!proxies.contains(key));

    DBusProxy *proxyProxy = dynamic_cast<DBusProxy *>(obj.data());
    Q_ASSERT(proxyProxy != NULL);

    // This sucks because DBusProxy is not RefCounted...
    connect(proxyProxy,
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(onProxyInvalidated(Tp::DBusProxy*)));

    debug() << "Inserting to factory cache proxy for" << key;

    proxies.insert(key, obj);
}

void DBusProxyFactory::Cache::onProxyInvalidated(Tp::DBusProxy *proxy)
{
    Key key(proxy->busName(), proxy->objectPath());

    // Not having it would indicate invalidated() signaled twice for the same proxy, or us having
    // connected to two proxies with the same key, neither of which should happen
    Q_ASSERT(proxies.contains(key));

    debug() << "Removing from factory cache invalidated proxy for" << key;

    proxies.remove(key);
}

struct FixedFeatureFactory::Private
{
    Features features;
};

FixedFeatureFactory::FixedFeatureFactory(const QDBusConnection &bus)
    : DBusProxyFactory(bus), mPriv(new Private)
{
}

FixedFeatureFactory::~FixedFeatureFactory()
{
    delete mPriv;
}

Features FixedFeatureFactory::features() const
{
    return mPriv->features;
}

void FixedFeatureFactory::addFeature(const Feature &feature)
{
    addFeatures(Features(feature));
}

void FixedFeatureFactory::addFeatures(const Features &features)
{
    mPriv->features.unite(features);
}

Features FixedFeatureFactory::featuresFor(const SharedPtr<RefCounted> &proxy) const
{
    Q_UNUSED(proxy);

    return features();
}

AccountFactoryPtr AccountFactory::create(const QDBusConnection &bus)
{
    return AccountFactoryPtr(new AccountFactory(bus));
}

AccountFactoryPtr AccountFactory::coreFactory(const QDBusConnection &bus)
{
    AccountFactoryPtr factory(create(bus));

    factory->addFeature(Account::FeatureCore);

    return factory;
}

AccountFactory::AccountFactory(const QDBusConnection &bus)
    : FixedFeatureFactory(bus)
{
}

AccountFactory::~AccountFactory()
{
}

PendingReady *AccountFactory::proxy(const QString &busName, const QString &objectPath,
            const ConnectionFactoryConstPtr &connFactory,
            const ChannelFactoryConstPtr &chanFactory) const
{
    SharedPtr<RefCounted> proxy = cachedProxy(busName, objectPath);
    if (proxy) {
        return nowHaveProxy(proxy, false);
    }

    proxy = Account::create(dbusConnection(), busName, objectPath/*, connFactory, chanFactory*/);
    return nowHaveProxy(proxy, true);
}

QString AccountFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const
{
    return uniqueOrWellKnown;
}

ConnectionFactoryPtr ConnectionFactory::create(const QDBusConnection &bus)
{
    return ConnectionFactoryPtr(new ConnectionFactory(bus));
}

ConnectionFactory::ConnectionFactory(const QDBusConnection &bus)
    : FixedFeatureFactory(bus)
{
}

ConnectionFactory::~ConnectionFactory()
{
}

PendingReady *ConnectionFactory::proxy(const QString &busName, const QString &objectPath,
            const ChannelFactoryConstPtr &chanFactory) const
{
    SharedPtr<RefCounted> proxy = cachedProxy(busName, objectPath);
    if (proxy) {
        return nowHaveProxy(proxy, false);
    }

    proxy = Connection::create(dbusConnection(), busName, objectPath/*, chanFactory*/);
    return nowHaveProxy(proxy, true);
}

QString ConnectionFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const
{
    return StatefulDBusProxy::uniqueNameFrom(dbusConnection(), uniqueOrWellKnown);
}

}
<|endoftext|>


<commit_before>//
// SceneOSG.cpp
//
// Implementation of vtScene for the OSG library
//
// Copyright (c) 2001-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "ProjectedShadows.h"

#include <osg/LightSource>
#include <osg/PolygonMode>
#include <osg/Switch>
#include <osg/Fog>
#include <osgDB/Registry>
#include <time.h>		// clock() & CLOCKS_PER_SEC

#ifdef __FreeBSD__
#  include <sys/types.h>
#  include <sys/time.h>
#  include <sys/resource.h>
#endif

#include <iostream>
#include "vtdata/vtLog.h"

using namespace osg;

///////////////////////////////////////////////////////////////
// Trap for OSG messages
//

class OsgMsgTrap : public std::streambuf
{
public:
	inline virtual int_type overflow(int_type c = std::streambuf::traits_type::eof())
	{
		if (c == std::streambuf::traits_type::eof()) return std::streambuf::traits_type::not_eof(c);
		g_Log._Log((char) c);
		return c;
	}
} g_Trap;

///////////////////////////////////////////////////////////////

// There is always and only one global vtScene object
vtScene g_Scene;

vtScene::vtScene() : vtSceneBase()
{
	m_bInitialized = false;
	m_bWireframe = false;
	m_bWinInfo = false;
}

vtScene::~vtScene()
{
	// Do not release camera, that is left for the application.
}

vtScene *vtGetScene()
{
	return &g_Scene;
}

float vtGetTime()
{
	return g_Scene.GetTime();
}

float vtGetFrameTime()
{
	return g_Scene.GetFrameTime();
}

void vtScene::SetBgColor(RGBf color)
{
	Vec4 color2;
	v2s(color, color2);
	m_pOsgSceneView->setBackgroundColor(color2);
}

bool vtScene::Init()
{
	// Redirect cout messages (where OSG sends its messages) to our own log
	std::cout.rdbuf(&g_Trap);
	std::cerr.rdbuf(&g_Trap);

	SetCamera(new vtCamera());

	m_pOsgSceneView = new osgUtil::SceneView();
	m_pOsgSceneView->setDefaults();

	// OSG 0.9.0 and newer
	m_pOsgSceneView->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);

	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::NO_SCENEVIEW_LIGHT);

	// OSG 0.9.2 and newer: turn off "small feature culling"
	m_pOsgSceneView->setCullingMode( m_pOsgSceneView->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

	m_bInitialized = true;

	_initialTick = _timer.tick();
	_frameTick = _initialTick;

	return true;
}

void vtScene::Shutdown()
{
	vtNode::ClearOsgModelCache();
	osgDB::Registry::instance()->clearObjectCache();
}

void vtScene::DoUpdate()
{
	if (!m_bInitialized)
		return;

	_lastFrameTick = _frameTick;
	_frameTick = _timer.tick();

	DoEngines();

	// As of OSG 0.9.5, we need to store our own camera params and recreate
	//  the projection matrix each frame.
	float aspect;
	if (m_WindowSize.x == 0 || m_WindowSize.y == 0)		// safety
		aspect = 1.0;
	else
		aspect = (float) m_WindowSize.x / m_WindowSize.y;

	if (m_pCamera->IsOrtho())
	{
		// Arguments are left, right, bottom, top, zNear, zFar
		float w2 = m_pCamera->GetWidth() /2;
		float h2 = w2 / aspect;
		m_pOsgSceneView->setProjectionMatrixAsOrtho(-w2, w2, -h2, h2,
			m_pCamera->GetHither(), m_pCamera->GetYon());
	}
	else
	{
		float fov_x = m_pCamera->GetFOV();
		float a = tan (fov_x/2);
		float b = a / aspect;
		float fov_y_div2 = atan(b);
		float fov_y_deg = RadiansToDegrees(fov_y_div2 * 2);

		m_pOsgSceneView->setProjectionMatrixAsPerspective(fov_y_deg,
			aspect, m_pCamera->GetHither(), m_pCamera->GetYon());
	}

	// And apply the rotation and translation of the camera itself
	osg::Matrix &mat2 = m_pCamera->m_pTransform->getMatrix();
	osg::Matrix imat;
	imat.invert(mat2);
	m_pOsgSceneView->setViewMatrix(imat);

	CalcCullPlanes();

	m_pOsgSceneView->setViewport(0, 0, m_WindowSize.x, m_WindowSize.y);
	m_pOsgSceneView->cull();
	m_pOsgSceneView->draw();
}

void vtScene::SetRoot(vtGroup *pRoot)
{
	if (pRoot)
		m_pOsgSceneRoot = pRoot->GetOsgGroup();
	else
		m_pOsgSceneRoot = NULL;
	if (m_pOsgSceneView != NULL)
		m_pOsgSceneView->setSceneData(m_pOsgSceneRoot.get());
	m_pRoot = pRoot;
}

/**
 * Convert window coordinates (in pixels) to a ray from the camera
 * in world coordinates.
 */
bool vtScene::CameraRay(const IPoint2 &win, FPoint3 &pos, FPoint3 &dir)
{
	Vec3 near_point, far_point, diff;

	// call the handy OSG function
	m_pOsgSceneView->projectWindowXYIntoObject(win.x, m_WindowSize.y-win.y, near_point, far_point);

	diff = far_point - near_point;
	diff.normalize();

	s2v(near_point, pos);
	s2v(diff, dir);

	return true;
}

// Debugging helper
void LogCullPlanes(FPlane *planes)
{
	for (int i = 0; i < 4; i++)
		VTLOG(" plane %d: %.3f %.3f %.3f %.3f\n", i, planes[i].x, planes[i].y, planes[i].z, planes[i].w);
	VTLOG("\n");
}

void vtScene::CalcCullPlanes()
{
#if 0
	// Non-API-Specific code - will work correctly as long as the Camera
	// methods are fully functional.
	FMatrix4 mat;
	m_pCamera->GetTransform1(mat);

	assert(( m_WindowSize.x > 0 ) && ( m_WindowSize.y > 0 ));

	double fov = m_pCamera->GetFOV();

	double aspect = (float)m_WindowSize.y / m_WindowSize.x;
	double hither = m_pCamera->GetHither();

	double a = hither * tan(fov / 2);
	double b = a * aspect;

	FPoint3 vec_l(-a, 0, -hither);
	FPoint3 vec_r(a, 0, -hither);
	FPoint3 vec_t(0, b, -hither);
	FPoint3 vec_b(0, -b, -hither);

	vec_l.Normalize();
	vec_r.Normalize();
	vec_t.Normalize();
	vec_b.Normalize();

	FPoint3 up(0.0f, 1.0f, 0.0f);
	FPoint3 right(1.0f, 0.0f, 0.0f);

	FPoint3 temp;

	FPoint3 center;
	FPoint3 norm_l, norm_r, norm_t, norm_b;

	temp = up.Cross(vec_l);
	mat.TransformVector(temp, norm_l);

	temp = vec_r.Cross(up);
	mat.TransformVector(temp, norm_r);

	temp = right.Cross(vec_t);
	mat.TransformVector(temp, norm_t);

	temp = vec_b.Cross(right);
	mat.TransformVector(temp, norm_b);

	mat.Transform(FPoint3(0.0f, 0.0f, 0.0f), center);

	// set up m_cullPlanes in world coordinates!
	m_cullPlanes[0].Set(center, norm_l);
	m_cullPlanes[1].Set(center, norm_r);
	m_cullPlanes[2].Set(center, norm_t);
	m_cullPlanes[3].Set(center, norm_b);
#else
	// Get the view frustum clipping planes directly from OSG

	// OSG 0.8.44
//	const ClippingVolume &clipvol = pCam->m_pOsgCamera->getClippingVolume();
	// OSG 0.8.45
//	const ClippingVolume &clipvol = hack_global_state->getClippingVolume();
	// OSG 0.9.0
	// clipvol1 is the global camera frustum (in world coordinates)
//	const Polytope &clipvol1 = pCam->m_pOsgCamera->getViewFrustum();
	// OSG 0.9.6
	// clipvol2 is the camera's frustum after it's been transformed to the
	//		local coordinates.
//	const Polytope &clipvol2 = hack_global_state->getViewFrustum();
//	const Polytope::PlaneList &planes = clipvol2.getPlaneList();
	// Actually no - we can't get the planes from the state, because
	//  the state includes the funny modelview matrix used to scale
	//  the heightfield.  We must get it from the 'scene' instead.

	osg::Matrixd &_projection = m_pOsgSceneView->getProjectionMatrix();
	osg::Matrixd &_modelView = m_pOsgSceneView->getViewMatrix();

	Polytope tope;
	tope.setToUnitFrustum();
	tope.transformProvidingInverse((_modelView)*(_projection));

	const Polytope::PlaneList &planes = tope.getPlaneList();

	int i = 0;
	for (Polytope::PlaneList::const_iterator itr=planes.begin();
		itr!=planes.end(); ++itr)
	{
		// make a copy of the clipping plane
		Plane plane = *itr;

		// extract the OSG plane to our own structure
		Vec4 pvec = plane.asVec4();
		m_cullPlanes[i++].Set(-pvec.x(), -pvec.y(), -pvec.z(), -pvec.w());
	}
#endif

	// For debugging
//	LogCullPlanes(m_cullPlanes);
}

void vtScene::DrawFrameRateChart()
{
	static float fps[100];
	static int s = 0;
	fps[s] = GetFrameRate();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

//	glMatrixMode(GL_PROJECTION);
//	glLoadIdentity();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glColor3f(1.0f, 1.0f, 0.0f);

	glBegin(GL_LINE_STRIP);
	for (int i = 1; i <= 100; i++)
	{
		glVertex3f(-1.0 + i/200.0f, -1.0f + fps[(s+i)%100]/200.0f, 0.0f);
	}
	glEnd();

	s++;
	if (s == 100) s = 0;
}

void vtScene::SetGlobalWireframe(bool bWire)
{
	m_bWireframe = bWire;

	// Set the scene's global PolygonMode attribute, which will affect all
	// other materials in the scene, except those which explicitly override
	// the attribute themselves.
	StateSet *global_state = m_pOsgSceneView->getGlobalStateSet();
	PolygonMode *npm = new PolygonMode();
	if (m_bWireframe)
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::LINE);
	else
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::FILL);
	global_state->setAttributeAndModes(npm, StateAttribute::ON);
}

bool vtScene::GetGlobalWireframe()
{
	return m_bWireframe;
}

void vtScene::SetShadowedNode(vtTransform *pLight, vtNode *pShadowNode,
							  vtTransform *pTransform, int iRez)
{
	if (!m_pShadowVisitor.valid())
		m_pShadowVisitor = new CreateProjectedShadowTextureCullCallback(pShadowNode->GetOsgNode(), iRez);
	else
		m_pShadowVisitor->SetShadower(pShadowNode->GetOsgNode());
		m_pShadowVisitor->SetInitialLightPosition(v2s(-(pLight->GetDirection()) * 10000));
		pTransform->GetOsgNode()->setCullCallback(m_pShadowVisitor.get());
#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(new MyDrawCallback);
	}
#endif
}

void vtScene::UnsetShadowedNode(vtTransform *pTransform)
{
	pTransform->GetOsgNode()->setCullCallback(NULL);
#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(NULL);
	}
#endif
}

void vtScene::UpdateShadowLightDirection(vtTransform *pLight)
{
	if (m_pShadowVisitor.valid())
	{
		m_pShadowVisitor.get()->SetLightPosition(v2s(-(pLight->GetDirection()) * 10000));
	}
}

////////////////////////////////////////

<commit_msg>chg to setClearColor for OSG 0.9.7<commit_after>//
// SceneOSG.cpp
//
// Implementation of vtScene for the OSG library
//
// Copyright (c) 2001-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "ProjectedShadows.h"

#include <osg/LightSource>
#include <osg/PolygonMode>
#include <osg/Switch>
#include <osg/Fog>
#include <osgDB/Registry>
#include <time.h>		// clock() & CLOCKS_PER_SEC

#ifdef __FreeBSD__
#  include <sys/types.h>
#  include <sys/time.h>
#  include <sys/resource.h>
#endif

#include <iostream>
#include "vtdata/vtLog.h"

using namespace osg;

///////////////////////////////////////////////////////////////
// Trap for OSG messages
//

class OsgMsgTrap : public std::streambuf
{
public:
	inline virtual int_type overflow(int_type c = std::streambuf::traits_type::eof())
	{
		if (c == std::streambuf::traits_type::eof()) return std::streambuf::traits_type::not_eof(c);
		g_Log._Log((char) c);
		return c;
	}
} g_Trap;

///////////////////////////////////////////////////////////////

// There is always and only one global vtScene object
vtScene g_Scene;

vtScene::vtScene() : vtSceneBase()
{
	m_bInitialized = false;
	m_bWireframe = false;
	m_bWinInfo = false;
}

vtScene::~vtScene()
{
	// Do not release camera, that is left for the application.
}

vtScene *vtGetScene()
{
	return &g_Scene;
}

float vtGetTime()
{
	return g_Scene.GetTime();
}

float vtGetFrameTime()
{
	return g_Scene.GetFrameTime();
}

void vtScene::SetBgColor(RGBf color)
{
	Vec4 color2;
	v2s(color, color2);
	m_pOsgSceneView->setClearColor(color2);
}

bool vtScene::Init()
{
	// Redirect cout messages (where OSG sends its messages) to our own log
	std::cout.rdbuf(&g_Trap);
	std::cerr.rdbuf(&g_Trap);

	SetCamera(new vtCamera());

	m_pOsgSceneView = new osgUtil::SceneView();
	m_pOsgSceneView->setDefaults();

	// OSG 0.9.0 and newer
	m_pOsgSceneView->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);

	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::NO_SCENEVIEW_LIGHT);

	// OSG 0.9.2 and newer: turn off "small feature culling"
	m_pOsgSceneView->setCullingMode( m_pOsgSceneView->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

	m_bInitialized = true;

	_initialTick = _timer.tick();
	_frameTick = _initialTick;

	return true;
}

void vtScene::Shutdown()
{
	vtNode::ClearOsgModelCache();
	osgDB::Registry::instance()->clearObjectCache();
}

void vtScene::DoUpdate()
{
	if (!m_bInitialized)
		return;

	_lastFrameTick = _frameTick;
	_frameTick = _timer.tick();

	DoEngines();

	// As of OSG 0.9.5, we need to store our own camera params and recreate
	//  the projection matrix each frame.
	float aspect;
	if (m_WindowSize.x == 0 || m_WindowSize.y == 0)		// safety
		aspect = 1.0;
	else
		aspect = (float) m_WindowSize.x / m_WindowSize.y;

	if (m_pCamera->IsOrtho())
	{
		// Arguments are left, right, bottom, top, zNear, zFar
		float w2 = m_pCamera->GetWidth() /2;
		float h2 = w2 / aspect;
		m_pOsgSceneView->setProjectionMatrixAsOrtho(-w2, w2, -h2, h2,
			m_pCamera->GetHither(), m_pCamera->GetYon());
	}
	else
	{
		float fov_x = m_pCamera->GetFOV();
		float a = tan (fov_x/2);
		float b = a / aspect;
		float fov_y_div2 = atan(b);
		float fov_y_deg = RadiansToDegrees(fov_y_div2 * 2);

		m_pOsgSceneView->setProjectionMatrixAsPerspective(fov_y_deg,
			aspect, m_pCamera->GetHither(), m_pCamera->GetYon());
	}

	// And apply the rotation and translation of the camera itself
	osg::Matrix &mat2 = m_pCamera->m_pTransform->getMatrix();
	osg::Matrix imat;
	imat.invert(mat2);
	m_pOsgSceneView->setViewMatrix(imat);

	CalcCullPlanes();

	m_pOsgSceneView->setViewport(0, 0, m_WindowSize.x, m_WindowSize.y);
	m_pOsgSceneView->cull();
	m_pOsgSceneView->draw();
}

void vtScene::SetRoot(vtGroup *pRoot)
{
	if (pRoot)
		m_pOsgSceneRoot = pRoot->GetOsgGroup();
	else
		m_pOsgSceneRoot = NULL;
	if (m_pOsgSceneView != NULL)
		m_pOsgSceneView->setSceneData(m_pOsgSceneRoot.get());
	m_pRoot = pRoot;
}

/**
 * Convert window coordinates (in pixels) to a ray from the camera
 * in world coordinates.
 */
bool vtScene::CameraRay(const IPoint2 &win, FPoint3 &pos, FPoint3 &dir)
{
	Vec3 near_point, far_point, diff;

	// call the handy OSG function
	m_pOsgSceneView->projectWindowXYIntoObject(win.x, m_WindowSize.y-win.y, near_point, far_point);

	diff = far_point - near_point;
	diff.normalize();

	s2v(near_point, pos);
	s2v(diff, dir);

	return true;
}

// Debugging helper
void LogCullPlanes(FPlane *planes)
{
	for (int i = 0; i < 4; i++)
		VTLOG(" plane %d: %.3f %.3f %.3f %.3f\n", i, planes[i].x, planes[i].y, planes[i].z, planes[i].w);
	VTLOG("\n");
}

void vtScene::CalcCullPlanes()
{
#if 0
	// Non-API-Specific code - will work correctly as long as the Camera
	// methods are fully functional.
	FMatrix4 mat;
	m_pCamera->GetTransform1(mat);

	assert(( m_WindowSize.x > 0 ) && ( m_WindowSize.y > 0 ));

	double fov = m_pCamera->GetFOV();

	double aspect = (float)m_WindowSize.y / m_WindowSize.x;
	double hither = m_pCamera->GetHither();

	double a = hither * tan(fov / 2);
	double b = a * aspect;

	FPoint3 vec_l(-a, 0, -hither);
	FPoint3 vec_r(a, 0, -hither);
	FPoint3 vec_t(0, b, -hither);
	FPoint3 vec_b(0, -b, -hither);

	vec_l.Normalize();
	vec_r.Normalize();
	vec_t.Normalize();
	vec_b.Normalize();

	FPoint3 up(0.0f, 1.0f, 0.0f);
	FPoint3 right(1.0f, 0.0f, 0.0f);

	FPoint3 temp;

	FPoint3 center;
	FPoint3 norm_l, norm_r, norm_t, norm_b;

	temp = up.Cross(vec_l);
	mat.TransformVector(temp, norm_l);

	temp = vec_r.Cross(up);
	mat.TransformVector(temp, norm_r);

	temp = right.Cross(vec_t);
	mat.TransformVector(temp, norm_t);

	temp = vec_b.Cross(right);
	mat.TransformVector(temp, norm_b);

	mat.Transform(FPoint3(0.0f, 0.0f, 0.0f), center);

	// set up m_cullPlanes in world coordinates!
	m_cullPlanes[0].Set(center, norm_l);
	m_cullPlanes[1].Set(center, norm_r);
	m_cullPlanes[2].Set(center, norm_t);
	m_cullPlanes[3].Set(center, norm_b);
#else
	// Get the view frustum clipping planes directly from OSG

	// OSG 0.8.44
//	const ClippingVolume &clipvol = pCam->m_pOsgCamera->getClippingVolume();
	// OSG 0.8.45
//	const ClippingVolume &clipvol = hack_global_state->getClippingVolume();
	// OSG 0.9.0
	// clipvol1 is the global camera frustum (in world coordinates)
//	const Polytope &clipvol1 = pCam->m_pOsgCamera->getViewFrustum();
	// OSG 0.9.6
	// clipvol2 is the camera's frustum after it's been transformed to the
	//		local coordinates.
//	const Polytope &clipvol2 = hack_global_state->getViewFrustum();
//	const Polytope::PlaneList &planes = clipvol2.getPlaneList();
	// Actually no - we can't get the planes from the state, because
	//  the state includes the funny modelview matrix used to scale
	//  the heightfield.  We must get it from the 'scene' instead.

	osg::Matrixd &_projection = m_pOsgSceneView->getProjectionMatrix();
	osg::Matrixd &_modelView = m_pOsgSceneView->getViewMatrix();

	Polytope tope;
	tope.setToUnitFrustum();
	tope.transformProvidingInverse((_modelView)*(_projection));

	const Polytope::PlaneList &planes = tope.getPlaneList();

	int i = 0;
	for (Polytope::PlaneList::const_iterator itr=planes.begin();
		itr!=planes.end(); ++itr)
	{
		// make a copy of the clipping plane
		Plane plane = *itr;

		// extract the OSG plane to our own structure
		Vec4 pvec = plane.asVec4();
		m_cullPlanes[i++].Set(-pvec.x(), -pvec.y(), -pvec.z(), -pvec.w());
	}
#endif

	// For debugging
//	LogCullPlanes(m_cullPlanes);
}

void vtScene::DrawFrameRateChart()
{
	static float fps[100];
	static int s = 0;
	fps[s] = GetFrameRate();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

//	glMatrixMode(GL_PROJECTION);
//	glLoadIdentity();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glColor3f(1.0f, 1.0f, 0.0f);

	glBegin(GL_LINE_STRIP);
	for (int i = 1; i <= 100; i++)
	{
		glVertex3f(-1.0 + i/200.0f, -1.0f + fps[(s+i)%100]/200.0f, 0.0f);
	}
	glEnd();

	s++;
	if (s == 100) s = 0;
}

void vtScene::SetGlobalWireframe(bool bWire)
{
	m_bWireframe = bWire;

	// Set the scene's global PolygonMode attribute, which will affect all
	// other materials in the scene, except those which explicitly override
	// the attribute themselves.
	StateSet *global_state = m_pOsgSceneView->getGlobalStateSet();
	PolygonMode *npm = new PolygonMode();
	if (m_bWireframe)
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::LINE);
	else
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::FILL);
	global_state->setAttributeAndModes(npm, StateAttribute::ON);
}

bool vtScene::GetGlobalWireframe()
{
	return m_bWireframe;
}

void vtScene::SetShadowedNode(vtTransform *pLight, vtNode *pShadowNode,
							  vtTransform *pTransform, int iRez)
{
	if (!m_pShadowVisitor.valid())
		m_pShadowVisitor = new CreateProjectedShadowTextureCullCallback(pShadowNode->GetOsgNode(), iRez);
	else
		m_pShadowVisitor->SetShadower(pShadowNode->GetOsgNode());
		m_pShadowVisitor->SetInitialLightPosition(v2s(-(pLight->GetDirection()) * 10000));
		pTransform->GetOsgNode()->setCullCallback(m_pShadowVisitor.get());
#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(new MyDrawCallback);
	}
#endif
}

void vtScene::UnsetShadowedNode(vtTransform *pTransform)
{
	pTransform->GetOsgNode()->setCullCallback(NULL);
#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(NULL);
	}
#endif
}

void vtScene::UpdateShadowLightDirection(vtTransform *pLight)
{
	if (m_pShadowVisitor.valid())
	{
		m_pShadowVisitor.get()->SetLightPosition(v2s(-(pLight->GetDirection()) * 10000));
	}
}

////////////////////////////////////////

<|endoftext|>


<commit_before>// Copyright 2010 Jens-Michael Hoffmann <jmho@c-xx.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library. If not, see <http://www.gnu.org/licenses/>.

#include "TileLoader.h"

#include <QtCore/QDateTime>
#include <QtCore/QFileInfo>
#include <QtCore/QMetaType>
#include <QtGui/QImage>

#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "MarbleDebug.h"
#include "MarbleDirs.h"
#include "TileLoaderHelper.h"

Q_DECLARE_METATYPE( Marble::DownloadUsage )

namespace Marble
{

TileLoader::TileLoader( HttpDownloadManager * const downloadManager )
{
    qRegisterMetaType<DownloadUsage>( "DownloadUsage" );
    connect( this, SIGNAL( downloadTile( QUrl, QString, QString, DownloadUsage )),
             downloadManager, SLOT( addJob( QUrl, QString, QString, DownloadUsage )));
    connect( downloadManager, SIGNAL( downloadComplete( QByteArray, QString )),
             SLOT( updateTile( QByteArray, QString )));
}

void TileLoader::setTextureLayers( const QVector<const GeoSceneTexture *> &textureLayers )
{
    foreach ( const GeoSceneTexture *texture, textureLayers ) {
        const uint hash = qHash( texture->sourceDir() );
        m_textureLayers.insert( hash, texture );
    }
}

// If the tile is locally available:
//     - if not expired: create TextureTile, set state to "uptodate", return it => done
//     - if expired: create TextureTile, state is set to Expired by default, trigger dl,

QImage TileLoader::loadTile( GeoSceneTexture const *textureLayer, TileId const & tileId, DownloadUsage const usage )
{
    QString const fileName = tileFileName( textureLayer, tileId );
    TileStatus status = tileStatus( textureLayer, tileId );
    if ( status != Missing ) {
        // check if an update should be triggered

        if ( status == Available ) {
            mDebug() << Q_FUNC_INFO << tileId << "StateUptodate";
        } else {
            Q_ASSERT( status == Expired );
            mDebug() << Q_FUNC_INFO << tileId << "StateExpired";
            triggerDownload( textureLayer, tileId, usage );
        }

        QImage const image( fileName );
        if ( !image.isNull() ) {
            // file is there, so create and return a tile object in any case
            return image;
        }
    }

    // tile was not locally available => trigger download and look for tiles in other levels
    // for scaling
    QImage replacementTile = scaledLowerLevelTile( tileId );
    Q_ASSERT( !replacementTile.isNull() );

    triggerDownload( textureLayer, tileId, usage );

    return replacementTile;
}

// This method triggers a download of the given tile (without checking
// expiration). It is called by upper layer (StackedTileLoader) when the tile
// that should be reloaded is currently loaded in memory.
//
// post condition
//     - download is triggered
void TileLoader::downloadTile( GeoSceneTexture const *textureLayer, TileId const &tileId, DownloadUsage const usage )
{
    triggerDownload( textureLayer, tileId, usage );
}

int TileLoader::maximumTileLevel( GeoSceneTexture const & texture )
{
    // if maximum tile level is configured in the DGML files,
    // then use it, otherwise use old detection code.
    if ( texture.maximumTileLevel() >= 0 ) {
        return texture.maximumTileLevel();
    }

    int maximumTileLevel = -1;
    const QFileInfo themeStr( texture.themeStr() );
    const QString tilepath = themeStr.isAbsolute() ? themeStr.absoluteFilePath() : MarbleDirs::path( texture.themeStr() );
    //    mDebug() << "StackedTileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks
                                                        | QDir::NoDotAndDotDot );

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        bool ok = true;
        const int value = (*it).toInt( &ok, 10 );

        if ( ok && value > maximumTileLevel )
            maximumTileLevel = value;
    }

    //    mDebug() << "Detected maximum tile level that contains data: "
    //             << maxtilelevel;
    return maximumTileLevel + 1;
}

bool TileLoader::baseTilesAvailable( GeoSceneTexture const & texture )
{
    const int  levelZeroColumns = texture.levelZeroColumns();
    const int  levelZeroRows    = texture.levelZeroRows();

    bool result = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; result && column < levelZeroColumns; ++column ) {
        for ( int row = 0; result && row < levelZeroRows; ++row ) {
            const TileId id( texture.sourceDir(), 0, column, row );
            const QString tilepath = tileFileName( &texture, id );
            result &= QFile::exists( tilepath );
        }
    }

    return result;
}

TileLoader::TileStatus TileLoader::tileStatus( GeoSceneTexture const *textureLayer, const TileId &tileId )
{
    QString const fileName = tileFileName( textureLayer, tileId );
    QFileInfo fileInfo( fileName );
    if ( !fileInfo.exists() ) {
        return Missing;
    }

    const QDateTime lastModified = fileInfo.lastModified();
    const int expireSecs = textureLayer->expire();
    const bool isExpired = lastModified.secsTo( QDateTime::currentDateTime() ) >= expireSecs;
    return isExpired ? Expired : Available;
}

void TileLoader::updateTile( QByteArray const & data, QString const & tileId )
{
    TileId const id = TileId::fromString( tileId );

    QImage const tileImage = QImage::fromData( data );
    if ( tileImage.isNull() )
        return;

    emit tileCompleted( id, tileImage );
}

inline GeoSceneTexture const * TileLoader::findTextureLayer( TileId const & id ) const
{
    GeoSceneTexture const * const textureLayer = m_textureLayers.value( id.mapThemeIdHash(), 0 );
    Q_ASSERT( textureLayer );
    return textureLayer;
}

QString TileLoader::tileFileName( GeoSceneTexture const * textureLayer, TileId const & tileId )
{
    QString const fileName = textureLayer->relativeTileFileName( tileId );
    QFileInfo const dirInfo( fileName );
    return dirInfo.isAbsolute() ? fileName : MarbleDirs::path( fileName );
}

void TileLoader::triggerDownload( GeoSceneTexture const *textureLayer, TileId const &id, DownloadUsage const usage )
{
    QUrl const sourceUrl = textureLayer->downloadUrl( id );
    QString const destFileName = textureLayer->relativeTileFileName( id );
    emit downloadTile( sourceUrl, destFileName, id.toString(), usage );
}

QImage TileLoader::scaledLowerLevelTile( TileId const & id ) const
{
    mDebug() << Q_FUNC_INFO << id;
    GeoSceneTexture const * const textureLayer = findTextureLayer( id );

    for ( int level = qMax<int>( 0, id.zoomLevel() - 1 ); level >= 0; --level ) {
        int const deltaLevel = id.zoomLevel() - level;
        TileId const replacementTileId( id.mapThemeIdHash(), level,
                                        id.x() >> deltaLevel, id.y() >> deltaLevel );
        QString const fileName = tileFileName( textureLayer, replacementTileId );
        mDebug() << "TileLoader::scaledLowerLevelTile" << "trying" << fileName;
        QImage toScale( fileName );

        if ( level == 0 && toScale.isNull() ) {
            mDebug() << "No level zero tile installed in map theme dir. Falling back to a transparent image for now.";
            GeoSceneTexture const * const textureLayer = findTextureLayer( replacementTileId );
            QSize tileSize = textureLayer->tileSize();
            Q_ASSERT( !tileSize.isEmpty() ); // assured by textureLayer
            toScale = QImage( tileSize, QImage::Format_ARGB32_Premultiplied );
            toScale.fill( qRgba( 0, 0, 0, 0 ) );
        }

        if ( !toScale.isNull() ) {
            // which rect to scale?
            int const restTileX = id.x() % ( 1 << deltaLevel );
            int const restTileY = id.y() % ( 1 << deltaLevel );
            int const partWidth = toScale.width() >> deltaLevel;
            int const partHeight = toScale.height() >> deltaLevel;
            int const startX = restTileX * partWidth;
            int const startY = restTileY * partHeight;
            mDebug() << "QImage::copy:" << startX << startY << partWidth << partHeight;
            QImage const part = toScale.copy( startX, startY, partWidth, partHeight );
            mDebug() << "QImage::scaled:" << toScale.size();
            return part.scaled( toScale.size() );
        }
    }

    Q_ASSERT_X( false, "scaled image", "level zero image missing" ); // not reached
    return QImage();
}

}

#include "TileLoader.moc"
<commit_msg>reuse textureLayer from above<commit_after>// Copyright 2010 Jens-Michael Hoffmann <jmho@c-xx.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library. If not, see <http://www.gnu.org/licenses/>.

#include "TileLoader.h"

#include <QtCore/QDateTime>
#include <QtCore/QFileInfo>
#include <QtCore/QMetaType>
#include <QtGui/QImage>

#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "MarbleDebug.h"
#include "MarbleDirs.h"
#include "TileLoaderHelper.h"

Q_DECLARE_METATYPE( Marble::DownloadUsage )

namespace Marble
{

TileLoader::TileLoader( HttpDownloadManager * const downloadManager )
{
    qRegisterMetaType<DownloadUsage>( "DownloadUsage" );
    connect( this, SIGNAL( downloadTile( QUrl, QString, QString, DownloadUsage )),
             downloadManager, SLOT( addJob( QUrl, QString, QString, DownloadUsage )));
    connect( downloadManager, SIGNAL( downloadComplete( QByteArray, QString )),
             SLOT( updateTile( QByteArray, QString )));
}

void TileLoader::setTextureLayers( const QVector<const GeoSceneTexture *> &textureLayers )
{
    foreach ( const GeoSceneTexture *texture, textureLayers ) {
        const uint hash = qHash( texture->sourceDir() );
        m_textureLayers.insert( hash, texture );
    }
}

// If the tile is locally available:
//     - if not expired: create TextureTile, set state to "uptodate", return it => done
//     - if expired: create TextureTile, state is set to Expired by default, trigger dl,

QImage TileLoader::loadTile( GeoSceneTexture const *textureLayer, TileId const & tileId, DownloadUsage const usage )
{
    QString const fileName = tileFileName( textureLayer, tileId );
    TileStatus status = tileStatus( textureLayer, tileId );
    if ( status != Missing ) {
        // check if an update should be triggered

        if ( status == Available ) {
            mDebug() << Q_FUNC_INFO << tileId << "StateUptodate";
        } else {
            Q_ASSERT( status == Expired );
            mDebug() << Q_FUNC_INFO << tileId << "StateExpired";
            triggerDownload( textureLayer, tileId, usage );
        }

        QImage const image( fileName );
        if ( !image.isNull() ) {
            // file is there, so create and return a tile object in any case
            return image;
        }
    }

    // tile was not locally available => trigger download and look for tiles in other levels
    // for scaling
    QImage replacementTile = scaledLowerLevelTile( tileId );
    Q_ASSERT( !replacementTile.isNull() );

    triggerDownload( textureLayer, tileId, usage );

    return replacementTile;
}

// This method triggers a download of the given tile (without checking
// expiration). It is called by upper layer (StackedTileLoader) when the tile
// that should be reloaded is currently loaded in memory.
//
// post condition
//     - download is triggered
void TileLoader::downloadTile( GeoSceneTexture const *textureLayer, TileId const &tileId, DownloadUsage const usage )
{
    triggerDownload( textureLayer, tileId, usage );
}

int TileLoader::maximumTileLevel( GeoSceneTexture const & texture )
{
    // if maximum tile level is configured in the DGML files,
    // then use it, otherwise use old detection code.
    if ( texture.maximumTileLevel() >= 0 ) {
        return texture.maximumTileLevel();
    }

    int maximumTileLevel = -1;
    const QFileInfo themeStr( texture.themeStr() );
    const QString tilepath = themeStr.isAbsolute() ? themeStr.absoluteFilePath() : MarbleDirs::path( texture.themeStr() );
    //    mDebug() << "StackedTileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks
                                                        | QDir::NoDotAndDotDot );

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        bool ok = true;
        const int value = (*it).toInt( &ok, 10 );

        if ( ok && value > maximumTileLevel )
            maximumTileLevel = value;
    }

    //    mDebug() << "Detected maximum tile level that contains data: "
    //             << maxtilelevel;
    return maximumTileLevel + 1;
}

bool TileLoader::baseTilesAvailable( GeoSceneTexture const & texture )
{
    const int  levelZeroColumns = texture.levelZeroColumns();
    const int  levelZeroRows    = texture.levelZeroRows();

    bool result = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; result && column < levelZeroColumns; ++column ) {
        for ( int row = 0; result && row < levelZeroRows; ++row ) {
            const TileId id( texture.sourceDir(), 0, column, row );
            const QString tilepath = tileFileName( &texture, id );
            result &= QFile::exists( tilepath );
        }
    }

    return result;
}

TileLoader::TileStatus TileLoader::tileStatus( GeoSceneTexture const *textureLayer, const TileId &tileId )
{
    QString const fileName = tileFileName( textureLayer, tileId );
    QFileInfo fileInfo( fileName );
    if ( !fileInfo.exists() ) {
        return Missing;
    }

    const QDateTime lastModified = fileInfo.lastModified();
    const int expireSecs = textureLayer->expire();
    const bool isExpired = lastModified.secsTo( QDateTime::currentDateTime() ) >= expireSecs;
    return isExpired ? Expired : Available;
}

void TileLoader::updateTile( QByteArray const & data, QString const & tileId )
{
    TileId const id = TileId::fromString( tileId );

    QImage const tileImage = QImage::fromData( data );
    if ( tileImage.isNull() )
        return;

    emit tileCompleted( id, tileImage );
}

inline GeoSceneTexture const * TileLoader::findTextureLayer( TileId const & id ) const
{
    GeoSceneTexture const * const textureLayer = m_textureLayers.value( id.mapThemeIdHash(), 0 );
    Q_ASSERT( textureLayer );
    return textureLayer;
}

QString TileLoader::tileFileName( GeoSceneTexture const * textureLayer, TileId const & tileId )
{
    QString const fileName = textureLayer->relativeTileFileName( tileId );
    QFileInfo const dirInfo( fileName );
    return dirInfo.isAbsolute() ? fileName : MarbleDirs::path( fileName );
}

void TileLoader::triggerDownload( GeoSceneTexture const *textureLayer, TileId const &id, DownloadUsage const usage )
{
    QUrl const sourceUrl = textureLayer->downloadUrl( id );
    QString const destFileName = textureLayer->relativeTileFileName( id );
    emit downloadTile( sourceUrl, destFileName, id.toString(), usage );
}

QImage TileLoader::scaledLowerLevelTile( TileId const & id ) const
{
    mDebug() << Q_FUNC_INFO << id;
    GeoSceneTexture const * const textureLayer = findTextureLayer( id );

    for ( int level = qMax<int>( 0, id.zoomLevel() - 1 ); level >= 0; --level ) {
        int const deltaLevel = id.zoomLevel() - level;
        TileId const replacementTileId( id.mapThemeIdHash(), level,
                                        id.x() >> deltaLevel, id.y() >> deltaLevel );
        QString const fileName = tileFileName( textureLayer, replacementTileId );
        mDebug() << "TileLoader::scaledLowerLevelTile" << "trying" << fileName;
        QImage toScale( fileName );

        if ( level == 0 && toScale.isNull() ) {
            mDebug() << "No level zero tile installed in map theme dir. Falling back to a transparent image for now.";
            QSize tileSize = textureLayer->tileSize();
            Q_ASSERT( !tileSize.isEmpty() ); // assured by textureLayer
            toScale = QImage( tileSize, QImage::Format_ARGB32_Premultiplied );
            toScale.fill( qRgba( 0, 0, 0, 0 ) );
        }

        if ( !toScale.isNull() ) {
            // which rect to scale?
            int const restTileX = id.x() % ( 1 << deltaLevel );
            int const restTileY = id.y() % ( 1 << deltaLevel );
            int const partWidth = toScale.width() >> deltaLevel;
            int const partHeight = toScale.height() >> deltaLevel;
            int const startX = restTileX * partWidth;
            int const startY = restTileY * partHeight;
            mDebug() << "QImage::copy:" << startX << startY << partWidth << partHeight;
            QImage const part = toScale.copy( startX, startY, partWidth, partHeight );
            mDebug() << "QImage::scaled:" << toScale.size();
            return part.scaled( toScale.size() );
        }
    }

    Q_ASSERT_X( false, "scaled image", "level zero image missing" ); // not reached
    return QImage();
}

}

#include "TileLoader.moc"
<|endoftext|>