<commit_before>// This software is part of OpenMono, see http://developer.openmono.com
// Released under the MIT license, see LICENSE.txt

#include "text_render.h"
#include <view.h>

using namespace mono::display;

TextRender::TextRender(IDisplayController *displayCtrl)
{
    this->dispCtrl = displayCtrl;
    foregroundColor = ui::View::StandardTextColor;
    backgroundColor = ui::View::StandardBackgroundColor;
    hAlignment = ALIGN_LEFT;
    vAlignment = ALIGN_MIDDLE;
}

TextRender::TextRender(IDisplayController *displayCtrl, Color foreground, Color background)
{
    this->dispCtrl = displayCtrl;
    foregroundColor = foreground;
    backgroundColor = background;
    hAlignment = ALIGN_LEFT;
    vAlignment = ALIGN_MIDDLE;
}

TextRender::TextRender(const DisplayPainter &painter)
{
    dispCtrl = painter.DisplayController();
    foregroundColor = painter.ForegroundColor();
    backgroundColor = painter.BackgroundColor();
    hAlignment = ALIGN_LEFT;
    vAlignment = ALIGN_MIDDLE;
}

void TextRender::drawInRect(geo::Rect rect, String text, const MonoFont &fontFace)
{
    if (dispCtrl == 0)
        return;

    dispCtrl->setWindow(rect.X(), rect.Y(), rect.Width(), rect.Height());
    int cnt = 0;
    char c = text[cnt];
    mono::geo::Point offset = rect.Point();

    while (c != '\0' && offset.X()+fontFace.glyphWidth <= rect.X2())
    {
        if (c == '\n')
        {
            offset.appendY(fontFace.glyphHeight);
            switch (hAlignment) {
                case ALIGN_LEFT:
                    offset.setX(rect.X());
                    break;
                case ALIGN_CENTER:
                {
                    int remainder = text.Length() - cnt+1;
                    if (rect.Width() > remainder*fontFace.glyphWidth)
                        offset.setX( rect.X() + (rect.Width() - remainder*fontFace.glyphWidth) / 2 );
                    break;
                }
                case ALIGN_RIGHT:
                {
                    int remainder = text.Length() - cnt+1;
                    if (rect.Width() > remainder*fontFace.glyphWidth)
                        offset.setX( rect.X() + (rect.Width() - remainder*fontFace.glyphWidth) );
                    break;
                }
                default:
                    break;
            }
        }
        else if (c == ' ')
        {
            offset.appendX(fontFace.glyphWidth - (fontFace.glyphWidth >> 2));
        }
        else
        {
            this->drawChar(offset, c, fontFace, rect);
            offset.appendX(fontFace.glyphWidth);
        }

        c = text[++cnt];
    }
}

mono::geo::Size TextRender::renderDimension(String text, const MonoFont &fontFace)
{
    char *ptr = text.stringData;
    int newLines = 1;
    int currentLine = 0, longestLine = 0;

    while (*ptr != '\0') {

        if (*ptr == '\n')
        {
            newLines++;
            currentLine = 0;
        }
        currentLine++;

        if (currentLine > longestLine)
            longestLine = currentLine;

        ptr++;
    }
    geo::Size dimensions(longestLine*fontFace.glyphWidth,newLines*fontFace.glyphHeight);
    return dimensions;
}

void TextRender::drawChar(geo::Point position, char character, const MonoFont &font, geo::Rect const &boundingRect)
{
    int glyphHeight = font.glyphHeight;
    int glyphWidth = font.glyphWidth;
    int totalWidth = font.bitmapWidth;

    if((position.X() >= boundingRect.X2())    || // Clip right
       (position.Y() >= boundingRect.Y2())   || // Clip bottom
       ((position.X() + glyphWidth - 1) < 0)         || // Clip left
       ((position.Y() + glyphHeight - 1) < 0))           // Clip top
        return;

    uint8_t maxPxVal = font.bitrate*font.bitrate-1;
    uint8_t pxScale = 255/maxPxVal;
    uint8_t pixelPerByte = 8/font.bitrate;
    geo::Rect bRct = geo::Rect(boundingRect.X(), boundingRect.Y(), boundingRect.Width(), boundingRect.Height()-1);

    for (int yi=0; yi<glyphHeight; yi++) {

        uint16_t lineOffset = (character-font.characterOffset)*glyphWidth+yi*totalWidth;

        geo::Point pos = geo::Point(position.X(),position.Y()+yi);
        if (!bRct.contains(pos))
            break;

        dispCtrl->setCursor(position.X(), position.Y()+yi);

        for (int xi=0; xi<glyphWidth; xi++) {

            uint32_t pixelOffset = lineOffset+xi;
            uint32_t byteOffset = pixelOffset / pixelPerByte;
            uint8_t shiftOffset = (pixelPerByte - 1) - (pixelOffset % pixelPerByte);
            uint8_t rawByte = font.bitmap[byteOffset];
            uint8_t twoBitIntensity = (rawByte >> (shiftOffset*font.bitrate)) & (font.bitrate == 4 ? 0xF : 0x3);

            uint16_t intensity = twoBitIntensity * pxScale;

            writePixel((uint8_t)(255-intensity));
        }
    }
}

void TextRender::drawInRect(const geo::Rect &rect, String text, const GFXfont &fontFace, bool lineLayout)
{
    if (dispCtrl == 0)
        return;
    if (text.Length() == 0)
        return;

    dispCtrl->setWindow(rect.X(), rect.Y(), rect.Width(), rect.Height());
    int cnt = 0;
    char c = text[cnt];

    geo::Rect offset = renderInRect(rect, text, fontFace, lineLayout);
    geo::Rect dim = offset;

    GFXglyph *glyph = &fontFace.glyph[c - fontFace.first];

    int lineHeight;
    if (lineLayout)
        lineHeight = fontFace.yAdvance;
    else
        lineHeight = dim.Height() - calcUnderBaseline(text, fontFace);

    while (c != '\0')
    {
        if (c == '\n')
        {
            offset.appendY(fontFace.yAdvance);
            // +1 to skip newline char
            uint32_t textWidth = remainingTextlineWidth(fontFace, text.stringData+cnt+1);
            offset.setX(rect.X());

            if (rect.Width() - textWidth > 0)
            {
                switch (hAlignment) {
                    case ALIGN_CENTER:
                        offset.setX(rect.X() + (rect.Width() - textWidth)/2 );
                        break;
                    case ALIGN_RIGHT:
                        offset.setX(rect.X() + rect.Width() - textWidth );
                        break;
                    default:
                        break;
                }
            }
        }
        else if (c == ' ')
        {
            offset.appendX(glyph->xAdvance);
        }
        else if (offset.X()+glyph->width <= rect.X2())
        {
            this->drawChar(offset, fontFace, glyph, rect, lineHeight);
            offset.appendX(glyph->xAdvance);
        }

        c = text[++cnt];
        glyph = &fontFace.glyph[c - fontFace.first];
    }
}

void TextRender::drawChar(const geo::Point &position, const GFXfont &gfxFont, const GFXglyph *glyph, geo::Rect const &bounds, int lineHeight)
{
    uint8_t  *bitmap = (uint8_t *)gfxFont.bitmap;

    uint16_t bo = glyph->bitmapOffset;
    uint8_t  w  = glyph->width,
             h  = glyph->height;
    int8_t   xo = glyph->xOffset,
             yo = glyph->yOffset;

    mono::geo::Rect glyphBounds(position.X() + xo,
                                position.Y() + lineHeight + yo,
                                w, h);

    if (!bounds.contains(glyphBounds, true))
        return;

    uint8_t  xx, yy, bits, bit = 0;
    bool rePosCursor = false;

    for(yy=0; yy<h; yy++) {
        dispCtrl->setCursor(position.X() + xo, position.Y() + yy + lineHeight + glyph->yOffset);

        for(xx=0; xx<w; xx++) {
            if(!(bit++ & 7)) {
                bits = bitmap[bo++];
            }
            if(bits & 0x80) {
                //writePixel(255);
                //dispCtrl->write(foregroundColor);
                if (rePosCursor)
                    dispCtrl->setCursor(position.X() + xo + xx,
                                        position.Y() + yy + lineHeight + glyph->yOffset);
                dispCtrl->write(foregroundColor);
                // (x+xo+xx, y+yo+yy, color);
            }
            else
                rePosCursor = true;

            bits <<= 1;
        }
    }
}

mono::geo::Size TextRender::renderDimension(String text, const GFXfont &fontFace, bool lineLayout)
{
    char *ptr = text.stringData;
    int newLines = 1;
    int currentLine = 0, longestLine = 0;
    int maxOverBase = 0;
    int maxUnderBase = 0;
    int lastAdvanceDiff = 0;
    int bestAdvanceDiff = 0;

    while (*ptr != '\0') {

        if (*ptr == '\n')
        {
            newLines++;
            maxUnderBase = 0; // theres a new line, discard prev. lines undershoot
            currentLine = 0;

            if (lastAdvanceDiff > bestAdvanceDiff)
                bestAdvanceDiff = lastAdvanceDiff;

            ptr++;
            continue;
        }

        GFXglyph glyph = fontFace.glyph[*ptr - fontFace.first];
        currentLine += glyph.xAdvance;
        lastAdvanceDiff = glyph.xOffset + glyph.width - glyph.xAdvance;

        if (maxOverBase < -glyph.yOffset)
            maxOverBase = -glyph.yOffset;
        if (maxUnderBase < glyph.height + glyph.yOffset)
            maxUnderBase = glyph.height + glyph.yOffset;

        if (currentLine + lastAdvanceDiff > longestLine)
            longestLine = currentLine + lastAdvanceDiff;

        ptr++;
    }

    int height, width;
    if (!lineLayout) {
        width = longestLine;
        height = maxOverBase + maxUnderBase;
    }
    else {
        if (lastAdvanceDiff > bestAdvanceDiff)
            bestAdvanceDiff = lastAdvanceDiff;

        width = longestLine;
        height = newLines*fontFace.yAdvance+maxUnderBase;
    }

    geo::Size dimensions(width, height);
    return dimensions;
}

mono::geo::Rect TextRender::renderInRect(const geo::Rect &rect, mono::String text, const GFXfont &fontFace, bool lineLayout)
{
    char c = text[0];
    geo::Size dim = this->renderDimension(text, fontFace, lineLayout);
    mono::geo::Point offset = rect.Point();
    GFXglyph *glyph = &fontFace.glyph[c - fontFace.first];

    if (glyph->xOffset < 0)
        offset.setX(offset.X()+glyph->xOffset);

    if (dim.Height() < rect.Height())
    {
        switch (vAlignment) {
            case ALIGN_MIDDLE:
                offset.setY(offset.Y() + (rect.Height() - dim.Height())/2 );
                break;
            case ALIGN_BOTTOM:
                offset.setY(offset.Y() + rect.Height() - dim.Height() );
                break;
            default:
                break;
        }
    }

    uint32_t textWidth = remainingTextlineWidth(fontFace, text.stringData);
    if (dim.Width() < rect.Width())
    {
        switch (hAlignment) {
            case ALIGN_CENTER:
                offset.setX(rect.X() + (rect.Width() - textWidth)/2 );
                break;
            case ALIGN_RIGHT:
                offset.setX(rect.X() + rect.Width() - textWidth );
                break;
            default:
                break;
        }
    }

    return geo::Rect(offset, dim);
}

int TextRender::calcUnderBaseline(mono::String text, const GFXfont &font)
{
    char *ptr = text.stringData;
    int maxUndershoot = 0;

    while (*ptr != '\0' && *ptr != '\n') {
        GFXglyph glyph = font.glyph[*ptr - font.first];

        if (maxUndershoot < glyph.height + glyph.yOffset)
            maxUndershoot = glyph.height + glyph.yOffset;

        ptr++;
    }

    return maxUndershoot;
}

void TextRender::writePixel(uint8_t intensity, bool bg)
{
    Color c;
    if (bg)
        c = backgroundColor.alphaBlend(intensity, foregroundColor);
    else
        c = foregroundColor.alphaBlend(intensity, backgroundColor);

    dispCtrl->write(c);
}

uint32_t TextRender::remainingTextlineWidth(const GFXfont &font, const char *text)
{
    uint32_t w = 0;
    int lastAdvanceDiff;

    while (*text != 0 && *text != '\n') {
        GFXglyph glyph = font.glyph[*text - font.first];
        w += glyph.xAdvance;
        lastAdvanceDiff = glyph.xOffset + glyph.width - glyph.xAdvance;
        text++;
    }

    return w + lastAdvanceDiff;
}

/// MARK: Accessors

void TextRender::setForeground(Color fg)
{
    foregroundColor = fg;
}

void TextRender::setBackground(Color bg)
{
    backgroundColor = bg;
}

void TextRender::setAlignment(TextRender::HorizontalAlignment align)
{
    hAlignment = align;
}

void TextRender::setAlignment(TextRender::VerticalAlignmentType vAlign)
{
    vAlignment = vAlign;
}

Color TextRender::Foreground() const
{
    return foregroundColor;
}

Color TextRender::Background() const
{
    return backgroundColor;
}

TextRender::HorizontalAlignment TextRender::Alignment() const
{
    return hAlignment;
}

TextRender::VerticalAlignmentType TextRender::VerticalAlignment() const
{
    return vAlignment;
}
<commit_msg>support for negative offset in first character<commit_after>// This software is part of OpenMono, see http://developer.openmono.com
// Released under the MIT license, see LICENSE.txt

#include "text_render.h"
#include <view.h>

using namespace mono::display;

TextRender::TextRender(IDisplayController *displayCtrl)
{
    this->dispCtrl = displayCtrl;
    foregroundColor = ui::View::StandardTextColor;
    backgroundColor = ui::View::StandardBackgroundColor;
    hAlignment = ALIGN_LEFT;
    vAlignment = ALIGN_MIDDLE;
}

TextRender::TextRender(IDisplayController *displayCtrl, Color foreground, Color background)
{
    this->dispCtrl = displayCtrl;
    foregroundColor = foreground;
    backgroundColor = background;
    hAlignment = ALIGN_LEFT;
    vAlignment = ALIGN_MIDDLE;
}

TextRender::TextRender(const DisplayPainter &painter)
{
    dispCtrl = painter.DisplayController();
    foregroundColor = painter.ForegroundColor();
    backgroundColor = painter.BackgroundColor();
    hAlignment = ALIGN_LEFT;
    vAlignment = ALIGN_MIDDLE;
}

void TextRender::drawInRect(geo::Rect rect, String text, const MonoFont &fontFace)
{
    if (dispCtrl == 0)
        return;

    dispCtrl->setWindow(rect.X(), rect.Y(), rect.Width(), rect.Height());
    int cnt = 0;
    char c = text[cnt];
    mono::geo::Point offset = rect.Point();

    while (c != '\0' && offset.X()+fontFace.glyphWidth <= rect.X2())
    {
        if (c == '\n')
        {
            offset.appendY(fontFace.glyphHeight);
            switch (hAlignment) {
                case ALIGN_LEFT:
                    offset.setX(rect.X());
                    break;
                case ALIGN_CENTER:
                {
                    int remainder = text.Length() - cnt+1;
                    if (rect.Width() > remainder*fontFace.glyphWidth)
                        offset.setX( rect.X() + (rect.Width() - remainder*fontFace.glyphWidth) / 2 );
                    break;
                }
                case ALIGN_RIGHT:
                {
                    int remainder = text.Length() - cnt+1;
                    if (rect.Width() > remainder*fontFace.glyphWidth)
                        offset.setX( rect.X() + (rect.Width() - remainder*fontFace.glyphWidth) );
                    break;
                }
                default:
                    break;
            }
        }
        else if (c == ' ')
        {
            offset.appendX(fontFace.glyphWidth - (fontFace.glyphWidth >> 2));
        }
        else
        {
            this->drawChar(offset, c, fontFace, rect);
            offset.appendX(fontFace.glyphWidth);
        }

        c = text[++cnt];
    }
}

mono::geo::Size TextRender::renderDimension(String text, const MonoFont &fontFace)
{
    char *ptr = text.stringData;
    int newLines = 1;
    int currentLine = 0, longestLine = 0;

    while (ptr != 0 && *ptr != '\0') {

        if (*ptr == '\n')
        {
            newLines++;
            currentLine = 0;
        }
        currentLine++;

        if (currentLine > longestLine)
            longestLine = currentLine;

        ptr++;
    }
    geo::Size dimensions(longestLine*fontFace.glyphWidth,newLines*fontFace.glyphHeight);
    return dimensions;
}

void TextRender::drawChar(geo::Point position, char character, const MonoFont &font, geo::Rect const &boundingRect)
{
    int glyphHeight = font.glyphHeight;
    int glyphWidth = font.glyphWidth;
    int totalWidth = font.bitmapWidth;

    if((position.X() >= boundingRect.X2())    || // Clip right
       (position.Y() >= boundingRect.Y2())   || // Clip bottom
       ((position.X() + glyphWidth - 1) < 0)         || // Clip left
       ((position.Y() + glyphHeight - 1) < 0))           // Clip top
        return;

    uint8_t maxPxVal = font.bitrate*font.bitrate-1;
    uint8_t pxScale = 255/maxPxVal;
    uint8_t pixelPerByte = 8/font.bitrate;
    geo::Rect bRct = geo::Rect(boundingRect.X(), boundingRect.Y(), boundingRect.Width(), boundingRect.Height()-1);

    for (int yi=0; yi<glyphHeight; yi++) {

        uint16_t lineOffset = (character-font.characterOffset)*glyphWidth+yi*totalWidth;

        geo::Point pos = geo::Point(position.X(),position.Y()+yi);
        if (!bRct.contains(pos))
            break;

        dispCtrl->setCursor(position.X(), position.Y()+yi);

        for (int xi=0; xi<glyphWidth; xi++) {

            uint32_t pixelOffset = lineOffset+xi;
            uint32_t byteOffset = pixelOffset / pixelPerByte;
            uint8_t shiftOffset = (pixelPerByte - 1) - (pixelOffset % pixelPerByte);
            uint8_t rawByte = font.bitmap[byteOffset];
            uint8_t twoBitIntensity = (rawByte >> (shiftOffset*font.bitrate)) & (font.bitrate == 4 ? 0xF : 0x3);

            uint16_t intensity = twoBitIntensity * pxScale;

            writePixel((uint8_t)(255-intensity));
        }
    }
}

void TextRender::drawInRect(const geo::Rect &rect, String text, const GFXfont &fontFace, bool lineLayout)
{
    if (dispCtrl == 0)
        return;
    if (text.Length() == 0)
        return;

    dispCtrl->setWindow(rect.X(), rect.Y(), rect.Width(), rect.Height());
    int cnt = 0;
    char c = text[cnt];

    geo::Rect offset = renderInRect(rect, text, fontFace, lineLayout);
    geo::Rect dim = offset;

    GFXglyph *glyph = &fontFace.glyph[c - fontFace.first];

    bool firstCharInLine = true;
    int lineHeight;
    if (lineLayout)
        lineHeight = fontFace.yAdvance;
    else
        lineHeight = dim.Height() - calcUnderBaseline(text, fontFace);

    while (c != '\0')
    {
        if (c == '\n')
        {
            firstCharInLine = true;
            offset.appendY(fontFace.yAdvance);
            // +1 to skip newline char
            uint32_t textWidth = remainingTextlineWidth(fontFace, text.stringData+cnt+1);
            offset.setX(rect.X());

            if (rect.Width() - textWidth > 0)
            {
                switch (hAlignment) {
                    case ALIGN_CENTER:
                        offset.setX(rect.X() + (rect.Width() - textWidth)/2 );
                        break;
                    case ALIGN_RIGHT:
                        offset.setX(rect.X() + rect.Width() - textWidth );
                        break;
                    default:
                        break;
                }
            }
        }
        else if (c == ' ')
        {
            offset.appendX(glyph->xAdvance);
        }
        else if (offset.X()+glyph->width <= rect.X2())
        {
            if (firstCharInLine)
                offset.appendX( -glyph->xOffset);
            this->drawChar(offset, fontFace, glyph, rect, lineHeight);
            offset.appendX(glyph->xAdvance);
        }

        firstCharInLine = false;
        c = text[++cnt];
        glyph = &fontFace.glyph[c - fontFace.first];
    }
}

void TextRender::drawChar(const geo::Point &position, const GFXfont &gfxFont, const GFXglyph *glyph, geo::Rect const &bounds, int lineHeight)
{
    uint8_t  *bitmap = (uint8_t *)gfxFont.bitmap;

    uint16_t bo = glyph->bitmapOffset;
    uint8_t  w  = glyph->width,
             h  = glyph->height;
    int8_t   xo = glyph->xOffset,
             yo = glyph->yOffset;

    mono::geo::Rect glyphBounds(position.X() + xo,
                                position.Y() + lineHeight + yo,
                                w, h);

    if (!bounds.contains(glyphBounds, true))
        return;

    uint8_t  xx, yy, bits, bit = 0;
    bool rePosCursor = false;

    for(yy=0; yy<h; yy++) {
        dispCtrl->setCursor(position.X() + xo, position.Y() + yy + lineHeight + glyph->yOffset);

        for(xx=0; xx<w; xx++) {
            if(!(bit++ & 7)) {
                bits = bitmap[bo++];
            }
            if(bits & 0x80) {
                //writePixel(255);
                //dispCtrl->write(foregroundColor);
                if (rePosCursor)
                    dispCtrl->setCursor(position.X() + xo + xx,
                                        position.Y() + yy + lineHeight + glyph->yOffset);
                dispCtrl->write(foregroundColor);
                // (x+xo+xx, y+yo+yy, color);
            }
            else
                rePosCursor = true;

            bits <<= 1;
        }
    }
}

mono::geo::Size TextRender::renderDimension(String text, const GFXfont &fontFace, bool lineLayout)
{
    char *ptr = text.stringData;
    int newLines = 1;
    int currentLine = 0, longestLine = 0;
    int maxOverBase = 0;
    int maxUnderBase = 0;
    int lastAdvanceDiff = 0;
    int bestAdvanceDiff = 0;
    int firstCharOffset = 0;
    bool isFirstChar = true;

    while (*ptr != '\0') {

        if (*ptr == '\n')
        {
            newLines++;
            maxUnderBase = 0; // theres a new line, discard prev. lines undershoot
            currentLine = 0;
            isFirstChar = true;

            if (lastAdvanceDiff > bestAdvanceDiff)
                bestAdvanceDiff = lastAdvanceDiff;

            ptr++;
            continue;
        }

        GFXglyph glyph = fontFace.glyph[*ptr - fontFace.first];
        currentLine += glyph.xAdvance;
        lastAdvanceDiff = glyph.xOffset + glyph.width - glyph.xAdvance;

        if (isFirstChar)
        {
            firstCharOffset =  - glyph.xOffset;
            isFirstChar = false;
        }

        if (maxOverBase < -glyph.yOffset)
            maxOverBase = -glyph.yOffset;
        if (maxUnderBase < glyph.height + glyph.yOffset)
            maxUnderBase = glyph.height + glyph.yOffset;

        if (currentLine + lastAdvanceDiff + firstCharOffset > longestLine)
            longestLine = currentLine + lastAdvanceDiff + firstCharOffset;

        ptr++;
    }

    int height, width;
    if (!lineLayout) {
        width = longestLine;
        height = maxOverBase + maxUnderBase;
    }
    else {
        if (lastAdvanceDiff > bestAdvanceDiff)
            bestAdvanceDiff = lastAdvanceDiff;

        width = longestLine;
        height = newLines*fontFace.yAdvance+maxUnderBase;
    }

    geo::Size dimensions(width, height);
    return dimensions;
}

mono::geo::Rect TextRender::renderInRect(const geo::Rect &rect, mono::String text, const GFXfont &fontFace, bool lineLayout)
{
    char c = text[0];
    geo::Size dim = this->renderDimension(text, fontFace, lineLayout);
    mono::geo::Point offset = rect.Point();
    GFXglyph *glyph = &fontFace.glyph[c - fontFace.first];

//    if (glyph->xOffset < 0)
//    {
//        //first character has negative offset, append to total width
//        dim.setWidth(dim.Width() - glyph->xOffset);
//    }

    if (dim.Height() < rect.Height())
    {
        switch (vAlignment) {
            case ALIGN_MIDDLE:
                offset.setY(offset.Y() + (rect.Height() - dim.Height())/2 );
                break;
            case ALIGN_BOTTOM:
                offset.setY(offset.Y() + rect.Height() - dim.Height() );
                break;
            default:
                break;
        }
    }

    uint32_t textWidth = remainingTextlineWidth(fontFace, text.stringData);
    if (dim.Width() < rect.Width())
    {
        switch (hAlignment) {
            case ALIGN_CENTER:
                offset.setX(rect.X() + (rect.Width() - textWidth)/2 );
                break;
            case ALIGN_RIGHT:
                offset.setX(rect.X() + rect.Width() - textWidth );
                break;
            default:
                break;
        }
    }

    return geo::Rect(offset, dim);
}

int TextRender::calcUnderBaseline(mono::String text, const GFXfont &font)
{
    char *ptr = text.stringData;
    int maxUndershoot = 0;

    while (*ptr != '\0' && *ptr != '\n') {
        GFXglyph glyph = font.glyph[*ptr - font.first];

        if (maxUndershoot < glyph.height + glyph.yOffset)
            maxUndershoot = glyph.height + glyph.yOffset;

        ptr++;
    }

    return maxUndershoot;
}

void TextRender::writePixel(uint8_t intensity, bool bg)
{
    Color c;
    if (bg)
        c = backgroundColor.alphaBlend(intensity, foregroundColor);
    else
        c = foregroundColor.alphaBlend(intensity, backgroundColor);

    dispCtrl->write(c);
}

uint32_t TextRender::remainingTextlineWidth(const GFXfont &font, const char *text)
{
    uint32_t w = 0;
    int lastAdvanceDiff;

    while (*text != 0 && *text != '\n') {
        GFXglyph glyph = font.glyph[*text - font.first];
        w += glyph.xAdvance;
        lastAdvanceDiff = glyph.xOffset + glyph.width - glyph.xAdvance;
        text++;
    }

    return w + lastAdvanceDiff;
}

/// MARK: Accessors

void TextRender::setForeground(Color fg)
{
    foregroundColor = fg;
}

void TextRender::setBackground(Color bg)
{
    backgroundColor = bg;
}

void TextRender::setAlignment(TextRender::HorizontalAlignment align)
{
    hAlignment = align;
}

void TextRender::setAlignment(TextRender::VerticalAlignmentType vAlign)
{
    vAlignment = vAlign;
}

Color TextRender::Foreground() const
{
    return foregroundColor;
}

Color TextRender::Background() const
{
    return backgroundColor;
}

TextRender::HorizontalAlignment TextRender::Alignment() const
{
    return hAlignment;
}

TextRender::VerticalAlignmentType TextRender::VerticalAlignment() const
{
    return vAlignment;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * \file
 */

#include <wx/app.h>
#include <wx/timer.h>
#include "visualization_frame.h"
#include "wx_log_rosout.h"
#include <ogre_tools/initialization.h>

#include <ros/ros.h>

#include <boost/thread.hpp>
#include <boost/program_options.hpp>
#include <signal.h>

#include <OGRE/OgreHighLevelGpuProgramManager.h>
#include <std_srvs/Empty.h>

#ifdef __WXMAC__
#include <ApplicationServices/ApplicationServices.h>
#endif

namespace po = boost::program_options;

namespace rviz
{

bool reloadShaders(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::HighLevelGpuProgramManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  return true;
}

class VisualizerApp : public wxApp
{
public:
  char** local_argv_;
  VisualizationFrame* frame_;
  volatile bool continue_;
  boost::thread signal_handler_thread_;
  wxTimer timer_;
  ros::NodeHandlePtr nh_;
  ros::ServiceServer reload_shaders_service_;

  VisualizerApp()
  : timer_(this)
  {
  }

  void onTimer(wxTimerEvent&)
  {
    if (!continue_)
    {
      frame_->Close();
    }
  }

  bool OnInit()
  {
#ifdef __WXMAC__
    ProcessSerialNumber PSN;
    GetCurrentProcess(&PSN);
    TransformProcessType(&PSN,kProcessTransformToForegroundApplication);
    SetFrontProcess(&PSN);
#endif

    wxLog::SetActiveTarget(new wxLogRosout());

    // block kill signals on all threads, since this also disables signals in threads
    // created by this one (the main thread)
    sigset_t sig_set;
    sigemptyset(&sig_set);
    sigaddset(&sig_set, SIGKILL);
    sigaddset(&sig_set, SIGTERM);
    sigaddset(&sig_set, SIGQUIT);
    sigaddset(&sig_set, SIGINT);
    pthread_sigmask(SIG_BLOCK, &sig_set, NULL);

    // Start up our signal handler
    continue_ = true;
    signal_handler_thread_ = boost::thread(boost::bind(&VisualizerApp::signalHandler, this));

    ogre_tools::initializeOgre();

    // create our own copy of argv, with regular char*s.
    local_argv_ =  new char*[ argc ];
    for ( int i = 0; i < argc; ++i )
    {
      local_argv_[ i ] = strdup( wxString( argv[ i ] ).mb_str() );
    }

    ros::init(argc, local_argv_, "rviz", ros::init_options::AnonymousName | ros::init_options::NoSigintHandler);
    nh_.reset(new ros::NodeHandle);

    po::options_description options;
    options.add_options()
             ("help,h", "Produce this help message")
             ("display-config,d", po::value<std::string>(), "A display config file (.vcg) to load")
             ("target-frame,t", po::value<std::string>(), "Set the target frame")
             ("fixed-frame,f", po::value<std::string>(), "Set the fixed frame");
    po::variables_map vm;
    std::string display_config, target_frame, fixed_frame;
    try
    {
      po::store(po::parse_command_line(argc, local_argv_, options), vm);
      po::notify(vm);

      if (vm.count("help"))
      {
        std::cout << "rviz command line options:\n" << options;
        return false;
      }

      if (vm.count("display-config"))
      {
        display_config = vm["display-config"].as<std::string>();
      }

      if (vm.count("target-frame"))
      {
        target_frame = vm["target-frame"].as<std::string>();
      }

      if (vm.count("fixed-frame"))
      {
        fixed_frame = vm["fixed-frame"].as<std::string>();
      }
    }
    catch (std::exception& e)
    {
      ROS_ERROR("Error parsing command line: %s", e.what());
      return false;
    }

    frame_ = new VisualizationFrame(NULL);
    frame_->initialize(display_config, fixed_frame, target_frame);

    SetTopWindow(frame_);
    frame_->Show();

    Connect(timer_.GetId(), wxEVT_TIMER, wxTimerEventHandler(VisualizerApp::onTimer), NULL, this);
    timer_.Start(100);

    ros::NodeHandle private_nh("~");
    reload_shaders_service_ = private_nh.advertiseService("reload_shaders", reloadShaders);

    return true;
  }

  int OnExit()
  {
    timer_.Stop();
    continue_ = false;

    raise(SIGQUIT);

    signal_handler_thread_.join();

    for ( int i = 0; i < argc; ++i )
    {
      free( local_argv_[ i ] );
    }
    delete [] local_argv_;

    ogre_tools::cleanupOgre();

    return 0;
  }

  void signalHandler()
  {
    sigset_t signal_set;
    while(continue_)
    {
      // Wait for any signals
      sigfillset(&signal_set);

#if defined(__WXMAC__)
      int sig;
      sigwait(&signal_set, &sig);
#else
      struct timespec ts = {0, 100000000};
      int sig = sigtimedwait(&signal_set, NULL, &ts);
#endif

      switch( sig )
      {
      case SIGKILL:
      case SIGTERM:
      case SIGQUIT:
      case SIGINT:
        {
          ros::shutdown();
          continue_ = false;
          return;
        }
        break;

      default:
        break;
      }
    }
  }
};

DECLARE_APP(VisualizerApp);

} // namespace rviz

IMPLEMENT_APP(rviz::VisualizerApp);
<commit_msg>Add command-line option to enable Ogre.log now that it's suppressed by default<commit_after>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * \file
 */

#include <wx/app.h>
#include <wx/timer.h>
#include "visualization_frame.h"
#include "wx_log_rosout.h"
#include <ogre_tools/initialization.h>

#include <ros/ros.h>

#include <boost/thread.hpp>
#include <boost/program_options.hpp>
#include <signal.h>

#include <OGRE/OgreHighLevelGpuProgramManager.h>
#include <std_srvs/Empty.h>

#ifdef __WXMAC__
#include <ApplicationServices/ApplicationServices.h>
#endif

namespace po = boost::program_options;

namespace rviz
{

bool reloadShaders(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::HighLevelGpuProgramManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  return true;
}

class VisualizerApp : public wxApp
{
public:
  char** local_argv_;
  VisualizationFrame* frame_;
  volatile bool continue_;
  boost::thread signal_handler_thread_;
  wxTimer timer_;
  ros::NodeHandlePtr nh_;
  ros::ServiceServer reload_shaders_service_;

  VisualizerApp()
  : timer_(this)
  {
  }

  void onTimer(wxTimerEvent&)
  {
    if (!continue_)
    {
      frame_->Close();
    }
  }

  bool OnInit()
  {
#ifdef __WXMAC__
    ProcessSerialNumber PSN;
    GetCurrentProcess(&PSN);
    TransformProcessType(&PSN,kProcessTransformToForegroundApplication);
    SetFrontProcess(&PSN);
#endif

    wxLog::SetActiveTarget(new wxLogRosout());

    // block kill signals on all threads, since this also disables signals in threads
    // created by this one (the main thread)
    sigset_t sig_set;
    sigemptyset(&sig_set);
    sigaddset(&sig_set, SIGKILL);
    sigaddset(&sig_set, SIGTERM);
    sigaddset(&sig_set, SIGQUIT);
    sigaddset(&sig_set, SIGINT);
    pthread_sigmask(SIG_BLOCK, &sig_set, NULL);

    // Start up our signal handler
    continue_ = true;
    signal_handler_thread_ = boost::thread(boost::bind(&VisualizerApp::signalHandler, this));

    // create our own copy of argv, with regular char*s.
    local_argv_ =  new char*[ argc ];
    for ( int i = 0; i < argc; ++i )
    {
      local_argv_[ i ] = strdup( wxString( argv[ i ] ).mb_str() );
    }

    ros::init(argc, local_argv_, "rviz", ros::init_options::AnonymousName | ros::init_options::NoSigintHandler);
    nh_.reset(new ros::NodeHandle);

    po::options_description options;
    options.add_options()
             ("help,h", "Produce this help message")
             ("display-config,d", po::value<std::string>(), "A display config file (.vcg) to load")
             ("target-frame,t", po::value<std::string>(), "Set the target frame")
             ("fixed-frame,f", po::value<std::string>(), "Set the fixed frame")
             ("ogre-log,l", "Enable the Ogre.log file (output in cwd)");
    po::variables_map vm;
    std::string display_config, target_frame, fixed_frame;
    bool enable_ogre_log = false;
    try
    {
      po::store(po::parse_command_line(argc, local_argv_, options), vm);
      po::notify(vm);

      if (vm.count("help"))
      {
        std::cout << "rviz command line options:\n" << options;
        return false;
      }

      if (vm.count("display-config"))
      {
        display_config = vm["display-config"].as<std::string>();
      }

      if (vm.count("target-frame"))
      {
        target_frame = vm["target-frame"].as<std::string>();
      }

      if (vm.count("fixed-frame"))
      {
        fixed_frame = vm["fixed-frame"].as<std::string>();
      }

      if (vm.count("ogre-log"))
      {
        enable_ogre_log = true;
      }
    }
    catch (std::exception& e)
    {
      ROS_ERROR("Error parsing command line: %s", e.what());
      return false;
    }

    ogre_tools::initializeOgre(enable_ogre_log);

    frame_ = new VisualizationFrame(NULL);
    frame_->initialize(display_config, fixed_frame, target_frame);

    SetTopWindow(frame_);
    frame_->Show();

    Connect(timer_.GetId(), wxEVT_TIMER, wxTimerEventHandler(VisualizerApp::onTimer), NULL, this);
    timer_.Start(100);

    ros::NodeHandle private_nh("~");
    reload_shaders_service_ = private_nh.advertiseService("reload_shaders", reloadShaders);

    return true;
  }

  int OnExit()
  {
    timer_.Stop();
    continue_ = false;

    raise(SIGQUIT);

    signal_handler_thread_.join();

    for ( int i = 0; i < argc; ++i )
    {
      free( local_argv_[ i ] );
    }
    delete [] local_argv_;

    ogre_tools::cleanupOgre();

    return 0;
  }

  void signalHandler()
  {
    sigset_t signal_set;
    while(continue_)
    {
      // Wait for any signals
      sigfillset(&signal_set);

#if defined(__WXMAC__)
      int sig;
      sigwait(&signal_set, &sig);
#else
      struct timespec ts = {0, 100000000};
      int sig = sigtimedwait(&signal_set, NULL, &ts);
#endif

      switch( sig )
      {
      case SIGKILL:
      case SIGTERM:
      case SIGQUIT:
      case SIGINT:
        {
          ros::shutdown();
          continue_ = false;
          return;
        }
        break;

      default:
        break;
      }
    }
  }
};

DECLARE_APP(VisualizerApp);

} // namespace rviz

IMPLEMENT_APP(rviz::VisualizerApp);
<|endoftext|>


<commit_before>/*
 * Copyright 2011, Blender Foundation.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "mesh.h"
#include "object.h"
#include "scene.h"

#include "blender_sync.h"
#include "blender_util.h"

#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"

#include "util_foreach.h"

CCL_NAMESPACE_BEGIN

/* Find/Add */

static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
{
	if(std == Attribute::STD_NONE)
		return false;

	foreach(uint shader, mesh->used_shaders)
		if(scene->shaders[shader]->attributes.find(std))
			return true;

	return false;
}

static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
{
	if(name == ustring())
		return false;

	foreach(uint shader, mesh->used_shaders)
		if(scene->shaders[shader]->attributes.find(name))
			return true;

	return false;
}

static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
{
	/* create vertices */
	BL::Mesh::vertices_iterator v;

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
		mesh->verts.push_back(get_float3(v->co()));

	/* create vertex normals */
	Attribute *attr_N = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
	float3 *N = attr_N->data_float3();

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
		*N= get_float3(v->normal());

	/* create faces */
	BL::Mesh::tessfaces_iterator f;
	vector<int> nverts;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
		int4 vi = get_int4(f->vertices_raw());
		int n = (vi[3] == 0)? 3: 4;
		int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
		int shader = used_shaders[mi];
		bool smooth = f->use_smooth();

		mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);

		if(n == 4)
			mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);

		nverts.push_back(n);
	}

	/* create generated coordinates. todo: we should actually get the orco
	   coordinates from modifiers, for now we use texspace loc/size which
	   is available in the api. */
	if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) {
		Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED);
		float3 loc = get_float3(b_mesh.texspace_location());
		float3 size = get_float3(b_mesh.texspace_size());

		if(size.x != 0.0f) size.x = 0.5f/size.x;
		if(size.y != 0.0f) size.y = 0.5f/size.y;
		if(size.z != 0.0f) size.z = 0.5f/size.z;

		loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);

		float3 *fdata = attr->data_float3();
		BL::Mesh::vertices_iterator v;
		size_t i = 0;

		for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
			fdata[i++] = get_float3(v->co())*size - loc;
	}

	/* create vertex color attributes */
	{
		BL::Mesh::tessface_vertex_colors_iterator l;

		for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
			if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
				continue;

			Attribute *attr = mesh->attributes.add(
				ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER);

			BL::MeshColorLayer::data_iterator c;
			float3 *fdata = attr->data_float3();
			size_t i = 0;

			for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
				fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
				fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
				fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));

				if(nverts[i] == 4) {
					fdata[3] = fdata[0];
					fdata[4] = fdata[2];
					fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
					fdata += 6;
				}
				else
					fdata += 3;
			}
		}
	}

	/* create uv map attributes */
	{
		BL::Mesh::tessface_uv_textures_iterator l;

		for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
			Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
			ustring name = ustring(l->name().c_str());

			if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std)))
				continue;

			Attribute *attr;

			if(l->active_render())
				attr = mesh->attributes.add(std, name);
			else
				attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);

			BL::MeshTextureFaceLayer::data_iterator t;
			float3 *fdata = attr->data_float3();
			size_t i = 0;

			for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
				fdata[0] =  get_float3(t->uv1());
				fdata[1] =  get_float3(t->uv2());
				fdata[2] =  get_float3(t->uv3());
				fdata += 3;

				if(nverts[i] == 4) {
					fdata[0] =  get_float3(t->uv1());
					fdata[1] =  get_float3(t->uv3());
					fdata[2] =  get_float3(t->uv4());
					fdata += 3;
				}
			}
		}
	}
}

static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
{
	/* create subd mesh */
	SubdMesh sdmesh;

	/* create vertices */
	BL::Mesh::vertices_iterator v;

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
		sdmesh.add_vert(get_float3(v->co()));

	/* create faces */
	BL::Mesh::tessfaces_iterator f;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
		int4 vi = get_int4(f->vertices_raw());
		int n= (vi[3] == 0)? 3: 4;
		//int shader = used_shaders[f->material_index()];

		if(n == 4)
			sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
		/*else
			sdmesh.add_face(vi[0], vi[1], vi[2]);*/
	}

	/* finalize subd mesh */
	sdmesh.link_boundary();

	/* subdivide */
	DiagSplit dsplit;
	dsplit.camera = NULL;
	dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");

	sdmesh.tessellate(&dsplit, false, mesh, used_shaders[0], true);
}

/* Sync */

Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool holdout, bool object_updated)
{
	/* test if we can instance or if the object is modified */
	BL::ID b_ob_data = b_ob.data();
	BL::ID key = (object_is_modified(b_ob) || holdout)? b_ob: b_ob_data;

	/* find shader indices */
	vector<uint> used_shaders;

	BL::Object::material_slots_iterator slot;
	for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
		BL::Material material_override = render_layer.material_override;

		if(holdout)
			find_shader(PointerRNA_NULL, used_shaders, scene->default_holdout);
		else if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			find_shader(slot->material(), used_shaders, scene->default_surface);
	}

	if(used_shaders.size() == 0)
		used_shaders.push_back(scene->default_surface);

	/* test if we need to sync */
	Mesh *mesh;

	if(!mesh_map.sync(&mesh, key)) {
		/* if transform was applied to mesh, need full update */
		if(object_updated && mesh->transform_applied);
		/* test if shaders changed, these can be object level so mesh
		   does not get tagged for recalc */
		else if(mesh->used_shaders != used_shaders);
		else {
			/* even if not tagged for recalc, we may need to sync anyway
			 * because the shader needs different mesh attributes */
			bool attribute_recalc = false;

			foreach(uint shader, mesh->used_shaders)
				if(scene->shaders[shader]->need_update_attributes)
					attribute_recalc = true;

			if(!attribute_recalc)
				return mesh;
		}
	}

	/* ensure we only sync instanced meshes once */
	if(mesh_synced.find(mesh) != mesh_synced.end())
		return mesh;

	mesh_synced.insert(mesh);

	/* create derived mesh */
	BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
	PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");

	vector<Mesh::Triangle> oldtriangle = mesh->triangles;

	mesh->clear();
	mesh->used_shaders = used_shaders;
	mesh->name = ustring(b_ob_data.name().c_str());

	if(b_mesh) {
		if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
			create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
		else
			create_mesh(scene, mesh, b_mesh, used_shaders);

		/* free derived mesh */
		object_remove_mesh(b_data, b_mesh);
	}

	/* displacement method */
	if(cmesh.data) {
		int method = RNA_enum_get(&cmesh, "displacement_method");

		if(method == 0 || !experimental)
			mesh->displacement_method = Mesh::DISPLACE_BUMP;
		else if(method == 1)
			mesh->displacement_method = Mesh::DISPLACE_TRUE;
		else
			mesh->displacement_method = Mesh::DISPLACE_BOTH;
	}

	/* tag update */
	bool rebuild = false;

	if(oldtriangle.size() != mesh->triangles.size())
		rebuild = true;
	else if(oldtriangle.size()) {
		if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
			rebuild = true;
	}

	mesh->tag_update(scene, rebuild);

	return mesh;
}

CCL_NAMESPACE_END

<commit_msg>Fix #30896: cycles mask layer not working for objects without material assigned.<commit_after>/*
 * Copyright 2011, Blender Foundation.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "mesh.h"
#include "object.h"
#include "scene.h"

#include "blender_sync.h"
#include "blender_util.h"

#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"

#include "util_foreach.h"

CCL_NAMESPACE_BEGIN

/* Find/Add */

static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
{
	if(std == Attribute::STD_NONE)
		return false;

	foreach(uint shader, mesh->used_shaders)
		if(scene->shaders[shader]->attributes.find(std))
			return true;

	return false;
}

static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
{
	if(name == ustring())
		return false;

	foreach(uint shader, mesh->used_shaders)
		if(scene->shaders[shader]->attributes.find(name))
			return true;

	return false;
}

static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
{
	/* create vertices */
	BL::Mesh::vertices_iterator v;

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
		mesh->verts.push_back(get_float3(v->co()));

	/* create vertex normals */
	Attribute *attr_N = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
	float3 *N = attr_N->data_float3();

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
		*N= get_float3(v->normal());

	/* create faces */
	BL::Mesh::tessfaces_iterator f;
	vector<int> nverts;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
		int4 vi = get_int4(f->vertices_raw());
		int n = (vi[3] == 0)? 3: 4;
		int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
		int shader = used_shaders[mi];
		bool smooth = f->use_smooth();

		mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);

		if(n == 4)
			mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);

		nverts.push_back(n);
	}

	/* create generated coordinates. todo: we should actually get the orco
	   coordinates from modifiers, for now we use texspace loc/size which
	   is available in the api. */
	if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) {
		Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED);
		float3 loc = get_float3(b_mesh.texspace_location());
		float3 size = get_float3(b_mesh.texspace_size());

		if(size.x != 0.0f) size.x = 0.5f/size.x;
		if(size.y != 0.0f) size.y = 0.5f/size.y;
		if(size.z != 0.0f) size.z = 0.5f/size.z;

		loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);

		float3 *fdata = attr->data_float3();
		BL::Mesh::vertices_iterator v;
		size_t i = 0;

		for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
			fdata[i++] = get_float3(v->co())*size - loc;
	}

	/* create vertex color attributes */
	{
		BL::Mesh::tessface_vertex_colors_iterator l;

		for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
			if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
				continue;

			Attribute *attr = mesh->attributes.add(
				ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER);

			BL::MeshColorLayer::data_iterator c;
			float3 *fdata = attr->data_float3();
			size_t i = 0;

			for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
				fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
				fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
				fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));

				if(nverts[i] == 4) {
					fdata[3] = fdata[0];
					fdata[4] = fdata[2];
					fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
					fdata += 6;
				}
				else
					fdata += 3;
			}
		}
	}

	/* create uv map attributes */
	{
		BL::Mesh::tessface_uv_textures_iterator l;

		for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
			Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
			ustring name = ustring(l->name().c_str());

			if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std)))
				continue;

			Attribute *attr;

			if(l->active_render())
				attr = mesh->attributes.add(std, name);
			else
				attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);

			BL::MeshTextureFaceLayer::data_iterator t;
			float3 *fdata = attr->data_float3();
			size_t i = 0;

			for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
				fdata[0] =  get_float3(t->uv1());
				fdata[1] =  get_float3(t->uv2());
				fdata[2] =  get_float3(t->uv3());
				fdata += 3;

				if(nverts[i] == 4) {
					fdata[0] =  get_float3(t->uv1());
					fdata[1] =  get_float3(t->uv3());
					fdata[2] =  get_float3(t->uv4());
					fdata += 3;
				}
			}
		}
	}
}

static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
{
	/* create subd mesh */
	SubdMesh sdmesh;

	/* create vertices */
	BL::Mesh::vertices_iterator v;

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
		sdmesh.add_vert(get_float3(v->co()));

	/* create faces */
	BL::Mesh::tessfaces_iterator f;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
		int4 vi = get_int4(f->vertices_raw());
		int n= (vi[3] == 0)? 3: 4;
		//int shader = used_shaders[f->material_index()];

		if(n == 4)
			sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
		/*else
			sdmesh.add_face(vi[0], vi[1], vi[2]);*/
	}

	/* finalize subd mesh */
	sdmesh.link_boundary();

	/* subdivide */
	DiagSplit dsplit;
	dsplit.camera = NULL;
	dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");

	sdmesh.tessellate(&dsplit, false, mesh, used_shaders[0], true);
}

/* Sync */

Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool holdout, bool object_updated)
{
	/* test if we can instance or if the object is modified */
	BL::ID b_ob_data = b_ob.data();
	BL::ID key = (object_is_modified(b_ob) || holdout)? b_ob: b_ob_data;

	/* find shader indices */
	vector<uint> used_shaders;

	BL::Object::material_slots_iterator slot;
	for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
		BL::Material material_override = render_layer.material_override;

		if(holdout)
			find_shader(PointerRNA_NULL, used_shaders, scene->default_holdout);
		else if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			find_shader(slot->material(), used_shaders, scene->default_surface);
	}

	if(used_shaders.size() == 0) {
		if(holdout)
			used_shaders.push_back(scene->default_holdout);
		else
			used_shaders.push_back(scene->default_surface);
	}

	/* test if we need to sync */
	Mesh *mesh;

	if(!mesh_map.sync(&mesh, key)) {
		/* if transform was applied to mesh, need full update */
		if(object_updated && mesh->transform_applied);
		/* test if shaders changed, these can be object level so mesh
		   does not get tagged for recalc */
		else if(mesh->used_shaders != used_shaders);
		else {
			/* even if not tagged for recalc, we may need to sync anyway
			 * because the shader needs different mesh attributes */
			bool attribute_recalc = false;

			foreach(uint shader, mesh->used_shaders)
				if(scene->shaders[shader]->need_update_attributes)
					attribute_recalc = true;

			if(!attribute_recalc)
				return mesh;
		}
	}

	/* ensure we only sync instanced meshes once */
	if(mesh_synced.find(mesh) != mesh_synced.end())
		return mesh;

	mesh_synced.insert(mesh);

	/* create derived mesh */
	BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
	PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");

	vector<Mesh::Triangle> oldtriangle = mesh->triangles;

	mesh->clear();
	mesh->used_shaders = used_shaders;
	mesh->name = ustring(b_ob_data.name().c_str());

	if(b_mesh) {
		if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
			create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
		else
			create_mesh(scene, mesh, b_mesh, used_shaders);

		/* free derived mesh */
		object_remove_mesh(b_data, b_mesh);
	}

	/* displacement method */
	if(cmesh.data) {
		int method = RNA_enum_get(&cmesh, "displacement_method");

		if(method == 0 || !experimental)
			mesh->displacement_method = Mesh::DISPLACE_BUMP;
		else if(method == 1)
			mesh->displacement_method = Mesh::DISPLACE_TRUE;
		else
			mesh->displacement_method = Mesh::DISPLACE_BOTH;
	}

	/* tag update */
	bool rebuild = false;

	if(oldtriangle.size() != mesh->triangles.size())
		rebuild = true;
	else if(oldtriangle.size()) {
		if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
			rebuild = true;
	}

	mesh->tag_update(scene, rebuild);

	return mesh;
}

CCL_NAMESPACE_END

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: lngmerge.cxx,v $
 *
 *  $Revision: 1.19 $
 *
 *  last change: $Author: pjunck $ $Date: 2004-11-02 16:05:02 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#include <tools/fsys.hxx>

// local includes
#include "lngmerge.hxx"
#include "utf8conv.hxx"
#include <iostream>
using namespace std;
//
// class LngParser
//
/*****************************************************************************/
LngParser::LngParser( const ByteString &rLngFile, BOOL bUTF8, BOOL bULFFormat , bool bQuiet_in )
/*****************************************************************************/
                : sSource( rLngFile ),
                nError( LNG_OK ),
                pLines( NULL ),
                bDBIsUTF8( bUTF8 ),
                bULF( bULFFormat ),
                bQuiet( bQuiet_in )
{
    pLines = new LngLineList( 100, 100 );
    DirEntry aEntry( String( sSource, RTL_TEXTENCODING_ASCII_US ));
    if ( aEntry.Exists()) {
        SvFileStream aStream( String( sSource, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_READ );
        if ( aStream.IsOpen()) {
            ByteString sLine;
            bool bFirstLine = true;
            while ( !aStream.IsEof()) {
                aStream.ReadLine( sLine );

                if( bFirstLine ){       // Always remove UTF8 BOM from the first line
                    Export::RemoveUTF8ByteOrderMarker( sLine );
                    bFirstLine = false;
                }

                pLines->Insert( new ByteString( sLine ), LIST_APPEND );
            }
        }
        else
            nError = LNG_COULD_NOT_OPEN;
    }
    else
        nError = LNG_FILE_NOTFOUND;
}

/*****************************************************************************/
LngParser::~LngParser()
/*****************************************************************************/
{
    for ( ULONG i = 0; i < pLines->Count(); i++ )
        delete pLines->GetObject( i );
    delete pLines;
}

/*****************************************************************************/
void LngParser::FillInFallbacks( ByteStringHashMap Text )
/*****************************************************************************/
{
    ByteString sCur;
    for( long int n = 0; n < aLanguages.size(); n++ ){
        sCur = aLanguages[ n ];

        if( !sCur.EqualsIgnoreCaseAscii("de") && !sCur.EqualsIgnoreCaseAscii("en-US") ){
        //if( !sCur.Equals(ByteString("de")) && !sCur.Equals(ByteString("en-US"))){
            ByteString sFallbackLang = Export::GetFallbackLanguage( sCur );
            if( sFallbackLang.Len() ){
                Text[ sCur ] = Text[ sFallbackLang ];
            }
        }
    }
}

/*****************************************************************************/
BOOL LngParser::CreateSDF(
    const ByteString &rSDFFile, const ByteString &rPrj,
    const ByteString &rRoot )
/*****************************************************************************/
{

    Export::InitLanguages( false );
    aLanguages = Export::GetLanguages();
    SvFileStream aSDFStream( String( rSDFFile, RTL_TEXTENCODING_ASCII_US ),
        STREAM_STD_WRITE | STREAM_TRUNC );
    if ( !aSDFStream.IsOpen()) {
        nError = SDF_COULD_NOT_OPEN;
    }
    aSDFStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
    nError = SDF_OK;
    DirEntry aEntry( String( sSource, RTL_TEXTENCODING_ASCII_US ));
    aEntry.ToAbs();
    String sFullEntry = aEntry.GetFull();
    aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US ));
    aEntry += DirEntry( rRoot );
    ByteString sPrjEntry( aEntry.GetFull(), gsl_getSystemTextEncoding());
    ByteString sActFileName(
        sFullEntry.Copy( sPrjEntry.Len() + 1 ), gsl_getSystemTextEncoding());
    sActFileName.SearchAndReplaceAll( "/", "\\" );

    ULONG nPos  = 0;
    BOOL bStart = true;
    ByteString sGroup;
      ByteStringHashMap Text;
    ByteString sID;
    ByteString sLine;

    while( nPos < pLines->Count() ){
        sLine = *pLines->GetObject( nPos++ );
        while( nPos < pLines->Count() && !isNextGroup( sGroup , sLine ) ){
            ReadLine( sLine , Text );
            sID = sGroup;
            sLine = *pLines->GetObject( nPos++ );
        };
        if( bStart ){
            bStart = false;
            sID = sGroup;
        }
        else {

            WriteSDF( aSDFStream , Text , rSDFFile , rPrj , rRoot , sActFileName , sID );
        }
    }
    aSDFStream.Close();
    return true;
}

 void LngParser::WriteSDF( SvFileStream &aSDFStream , ByteStringHashMap &rText_inout ,
     const ByteString &rSDFFile, const ByteString &rPrj , const ByteString &rRoot ,
     const ByteString &sActFileName , const ByteString &sID )
 {
    //BOOL bExport = (rText_inout[ ByteString("de") ].Len() > 0) && (rText_inout[ ByteString("en-US") ].Len() > 0);
    BOOL bExport = true;
    if ( bExport ) {
           ByteString sTimeStamp( Export::GetTimeStamp());
        ByteString sCur;
        FillInFallbacks( rText_inout );
        for( long int n = 0; n < aLanguages.size(); n++ ){
            sCur = aLanguages[ n ];
            ByteString sAct = rText_inout[ sCur ];
            if ( !sAct.Len() && sCur.Len() )
                sAct = rText_inout[ ByteString("de") ];

            //if( sCur.EqualsIgnoreCaseAscii("de") ){
            //    sAct = UTF8Converter::ConvertToUTF8( sAct, RTL_TEXTENCODING_MS_1252 );
            //}

            ByteString sOutput( rPrj ); sOutput += "\t";
            if ( rRoot.Len())
                sOutput += sActFileName;
            sOutput += "\t0\t";
            sOutput += "LngText\t";
            sOutput += sID; sOutput += "\t\t\t\t0\t";
            sOutput += sCur; sOutput += "\t";
            sOutput += sAct; sOutput += "\t\t\t\t";
            sOutput += sTimeStamp;
            //if( sCur.EqualsIgnoreCaseAscii("de") ){
            //    sOutput = UTF8Converter::ConvertToUTF8( sOutput , RTL_TEXTENCODING_MS_1252 );
            //}

            aSDFStream.WriteLine( sOutput );
        }
    }
 }
 bool LngParser::isNextGroup( ByteString &sGroup_out , ByteString &sLine_in ){
    sLine_in.EraseLeadingChars( ' ' );
    sLine_in.EraseTrailingChars( ' ' );
    if (( sLine_in.GetChar( 0 ) == '[' ) &&
            ( sLine_in.GetChar( sLine_in.Len() - 1 ) == ']' )){
        sGroup_out = sLine_in.GetToken( 1, '[' ).GetToken( 0, ']' );
        sGroup_out.EraseLeadingChars( ' ' );
        sGroup_out.EraseTrailingChars( ' ' );
        return true;
    }
    return false;
 }
 void LngParser::ReadLine( const ByteString &sLine_in , ByteStringHashMap &rText_inout){
    //printf("sLine -> '%s'\n",sLine_in.GetBuffer());
    ByteString sLang = sLine_in.GetToken( 0, '=' );
    sLang.EraseLeadingChars( ' ' );
    sLang.EraseTrailingChars( ' ' );
    ByteString sText = sLine_in.GetToken( 1, '\"' ).GetToken( 0, '\"' );
    if( sLang.Len() )
        rText_inout[ sLang ] = sText;
 }

/*****************************************************************************/
BOOL LngParser::Merge(
    const ByteString &rSDFFile, const ByteString &rDestinationFile )
/*****************************************************************************/
{
    Export::InitLanguages( true );
    SvFileStream aDestination(
        String( rDestinationFile, RTL_TEXTENCODING_ASCII_US ),
        STREAM_STD_WRITE | STREAM_TRUNC );
    if ( !aDestination.IsOpen()) {
        nError = LNG_COULD_NOT_OPEN;
    }
    nError = LNG_OK;
//    MergeDataFile( const ByteString &rFileName, const ByteString& rFile , BOOL bErrLog, CharSet aCharSet, BOOL bUTF8 );

    MergeDataFile aMergeDataFile( rSDFFile, sSource , FALSE, RTL_TEXTENCODING_MS_1252, bDBIsUTF8 );
    ByteString sTmp( Export::sLanguages );
    if( sTmp.ToUpperAscii().Equals("ALL") )
        Export::SetLanguages( aMergeDataFile.GetLanguages() );
    aLanguages = Export::GetLanguages();

    ULONG nPos = 0;
    BOOL bGroup = FALSE;
    ByteString sGroup;

    // seek to next group
    while ( nPos < pLines->Count() && !bGroup ) {
        ByteString sLine( *pLines->GetObject( nPos ));
        sLine.EraseLeadingChars( ' ' );
        sLine.EraseTrailingChars( ' ' );
        if (( sLine.GetChar( 0 ) == '[' ) &&
            ( sLine.GetChar( sLine.Len() - 1 ) == ']' ))
        {
            sGroup = sLine.GetToken( 1, '[' ).GetToken( 0, ']' );
            sGroup.EraseLeadingChars( ' ' );
            sGroup.EraseTrailingChars( ' ' );
            bGroup = TRUE;
        }
        nPos ++;
    }

    while ( nPos < pLines->Count()) {
        ByteStringHashMap Text;
        ByteString sID( sGroup );
        ULONG nLastLangPos = 0;

        ResData  *pResData = new ResData( "", sID );
        pResData->sResTyp = "LngText";
        PFormEntrys *pEntrys = aMergeDataFile.GetPFormEntrys( pResData );

        // read languages
        bGroup = FALSE;

        ByteString sLanguagesDone;

        while ( nPos < pLines->Count() && !bGroup ) {
            ByteString sLine( *pLines->GetObject( nPos ));
            sLine.EraseLeadingChars( ' ' );
            sLine.EraseTrailingChars( ' ' );
            if (( sLine.GetChar( 0 ) == '[' ) &&
                ( sLine.GetChar( sLine.Len() - 1 ) == ']' ))
            {
                sGroup = sLine.GetToken( 1, '[' ).GetToken( 0, ']' );
                sGroup.EraseLeadingChars( ' ' );
                sGroup.EraseTrailingChars( ' ' );
                bGroup = TRUE;
                nPos ++;
                sLanguagesDone = "";
            }
            else if ( sLine.GetTokenCount( '=' ) > 1 ) {
                ByteString sLang = sLine.GetToken( 0, '=' );
                sLang.EraseLeadingChars( ' ' );
                sLang.EraseTrailingChars( ' ' );

                ByteString sSearch( ";" );
                sSearch += sLang;
                sSearch += ";";

                if (( sLanguagesDone.Search( sSearch ) != STRING_NOTFOUND )) {
                    pLines->Remove( nPos );
                }
                if( bULF && pEntrys )
                {
                    // this is a valid text line
                    ByteString sText = sLine.GetToken( 1, '\"' ).GetToken( 0, '\"' );
                    USHORT nIndex;
                    if( sLang.Len() ){
                        ByteString sNewText;
                        pEntrys->GetText( sNewText, STRING_TYP_TEXT, sLang, TRUE );
                        //if ( bULF )
                        //  sNewText = UTF8Converter::ConvertToUTF8( sNewText, Export::GetCharSet( Export::LangId[ nIndex ] ));

                        if ( sNewText.Len()) {
                            ByteString *pLine = pLines->GetObject( nPos );

                            if( !sLang.EqualsIgnoreCaseAscii("de") && !sLang.EqualsIgnoreCaseAscii("en-US") ){
                                ByteString sText( sLang );
                                sText += " = \"";
                                sText += sNewText;
                                sText += "\"";
                                *pLine = sText;
                            }
                            Text[ sLang ] = sNewText;
                        }
                    }
                    nLastLangPos = nPos;
                    nPos ++;
                    sLanguagesDone += sSearch;
                }
                else {
                    nLastLangPos = nPos;
                    nPos ++;
                    sLanguagesDone += sSearch;
                }
            }
            else
                nPos++;
        }
        ByteString sCur;
        if ( nLastLangPos ) {
            for( long int n = 0; n < aLanguages.size(); n++ ){
                sCur = aLanguages[ n ];

                if( ( !sCur.EqualsIgnoreCaseAscii("de") && !sCur.EqualsIgnoreCaseAscii("en-US")) && !Text[ sCur ].Len() && pEntrys ){
                ByteString sNewText;
                    pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur, TRUE );
                    if (( sNewText.Len()) &&
                        !(( sCur.Equals("x-comment") ) && ( sNewText == "-" )))
                    {
                        ByteString sLine;
                        sLine += sCur;
                        sLine += " = \"";
                        sLine += sNewText;
                        sLine += "\"";

                        nLastLangPos++;
                        nPos++;

                        pLines->Insert( new ByteString( sLine ), nLastLangPos );
                    }
                }
            }
        }

        delete pResData;
    }

    for ( ULONG i = 0; i < pLines->Count(); i++ )
        aDestination.WriteLine( *pLines->GetObject( i ));

    aDestination.Close();
    return TRUE;
}
<commit_msg>INTEGRATION: CWS mmw02 (1.19.48); FILE MERGED 2005/06/06 11:18:08 ihi 1.19.48.2: #123272# migrationanalysis projects gets german translation via localize.sdf 2005/06/01 13:32:57 ihi 1.19.48.1: #123272# migrationanalysis projects gets german translation via localize.sdf<commit_after>/*************************************************************************
 *
 *  $RCSfile: lngmerge.cxx,v $
 *
 *  $Revision: 1.20 $
 *
 *  last change: $Author: hr $ $Date: 2005-06-06 16:25:16 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#include <tools/fsys.hxx>

// local includes
#include "lngmerge.hxx"
#include "utf8conv.hxx"
#include <iostream>
using namespace std;
//
// class LngParser
//
/*****************************************************************************/
LngParser::LngParser( const ByteString &rLngFile, BOOL bUTF8, BOOL bULFFormat , bool bQuiet_in )
/*****************************************************************************/
                : sSource( rLngFile ),
                nError( LNG_OK ),
                pLines( NULL ),
                bDBIsUTF8( bUTF8 ),
                bULF( bULFFormat ),
                bQuiet( bQuiet_in )
{
    pLines = new LngLineList( 100, 100 );
    DirEntry aEntry( String( sSource, RTL_TEXTENCODING_ASCII_US ));
    if ( aEntry.Exists()) {
        SvFileStream aStream( String( sSource, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_READ );
        if ( aStream.IsOpen()) {
            ByteString sLine;
            bool bFirstLine = true;
            while ( !aStream.IsEof()) {
                aStream.ReadLine( sLine );

                if( bFirstLine ){       // Always remove UTF8 BOM from the first line
                    Export::RemoveUTF8ByteOrderMarker( sLine );
                    bFirstLine = false;
                }

                pLines->Insert( new ByteString( sLine ), LIST_APPEND );
            }
        }
        else
            nError = LNG_COULD_NOT_OPEN;
    }
    else
        nError = LNG_FILE_NOTFOUND;
}

/*****************************************************************************/
LngParser::~LngParser()
/*****************************************************************************/
{
    for ( ULONG i = 0; i < pLines->Count(); i++ )
        delete pLines->GetObject( i );
    delete pLines;
}

/*****************************************************************************/
void LngParser::FillInFallbacks( ByteStringHashMap Text )
/*****************************************************************************/
{
    ByteString sCur;
    for( long int n = 0; n < aLanguages.size(); n++ ){
        sCur = aLanguages[ n ];

        if( !sCur.EqualsIgnoreCaseAscii("de") && !sCur.EqualsIgnoreCaseAscii("en-US") ){
        //if( !sCur.Equals(ByteString("de")) && !sCur.Equals(ByteString("en-US"))){
            ByteString sFallbackLang = Export::GetFallbackLanguage( sCur );
            if( sFallbackLang.Len() ){
                Text[ sCur ] = Text[ sFallbackLang ];
            }
        }
    }
}

/*****************************************************************************/
BOOL LngParser::CreateSDF(
    const ByteString &rSDFFile, const ByteString &rPrj,
    const ByteString &rRoot )
/*****************************************************************************/
{

    Export::InitLanguages( false );
    aLanguages = Export::GetLanguages();
    SvFileStream aSDFStream( String( rSDFFile, RTL_TEXTENCODING_ASCII_US ),
        STREAM_STD_WRITE | STREAM_TRUNC );
    if ( !aSDFStream.IsOpen()) {
        nError = SDF_COULD_NOT_OPEN;
    }
    aSDFStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
    nError = SDF_OK;
    DirEntry aEntry( String( sSource, RTL_TEXTENCODING_ASCII_US ));
    aEntry.ToAbs();
    String sFullEntry = aEntry.GetFull();
    aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US ));
    aEntry += DirEntry( rRoot );
    ByteString sPrjEntry( aEntry.GetFull(), gsl_getSystemTextEncoding());
    ByteString sActFileName(
        sFullEntry.Copy( sPrjEntry.Len() + 1 ), gsl_getSystemTextEncoding());
    sActFileName.SearchAndReplaceAll( "/", "\\" );

    ULONG nPos  = 0;
    BOOL bStart = true;
    ByteString sGroup;
      ByteStringHashMap Text;
    ByteString sID;
    ByteString sLine;

    while( nPos < pLines->Count() ){
        sLine = *pLines->GetObject( nPos++ );
        while( nPos < pLines->Count() && !isNextGroup( sGroup , sLine ) ){
            ReadLine( sLine , Text );
            sID = sGroup;
            sLine = *pLines->GetObject( nPos++ );
        };
        if( bStart ){
            bStart = false;
            sID = sGroup;
        }
        else {

            WriteSDF( aSDFStream , Text , rSDFFile , rPrj , rRoot , sActFileName , sID );
        }
    }
    aSDFStream.Close();
    return true;
}

 void LngParser::WriteSDF( SvFileStream &aSDFStream , ByteStringHashMap &rText_inout ,
     const ByteString &rSDFFile, const ByteString &rPrj , const ByteString &rRoot ,
     const ByteString &sActFileName , const ByteString &sID )
 {
    //BOOL bExport = (rText_inout[ ByteString("de") ].Len() > 0) && (rText_inout[ ByteString("en-US") ].Len() > 0);
    BOOL bExport = true;
    if ( bExport ) {
           ByteString sTimeStamp( Export::GetTimeStamp());
        ByteString sCur;
        FillInFallbacks( rText_inout );
        for( long int n = 0; n < aLanguages.size(); n++ ){
            sCur = aLanguages[ n ];
            ByteString sAct = rText_inout[ sCur ];
            if ( !sAct.Len() && sCur.Len() )
                sAct = rText_inout[ ByteString("en-US") ];

            //if( sCur.EqualsIgnoreCaseAscii("de") ){
            //    sAct = UTF8Converter::ConvertToUTF8( sAct, RTL_TEXTENCODING_MS_1252 );
            //}

            ByteString sOutput( rPrj ); sOutput += "\t";
            if ( rRoot.Len())
                sOutput += sActFileName;
            sOutput += "\t0\t";
            sOutput += "LngText\t";
            sOutput += sID; sOutput += "\t\t\t\t0\t";
            sOutput += sCur; sOutput += "\t";
            sOutput += sAct; sOutput += "\t\t\t\t";
            sOutput += sTimeStamp;
            //if( sCur.EqualsIgnoreCaseAscii("de") ){
            //    sOutput = UTF8Converter::ConvertToUTF8( sOutput , RTL_TEXTENCODING_MS_1252 );
            //}

            aSDFStream.WriteLine( sOutput );
        }
    }
 }
 bool LngParser::isNextGroup( ByteString &sGroup_out , ByteString &sLine_in ){
    sLine_in.EraseLeadingChars( ' ' );
    sLine_in.EraseTrailingChars( ' ' );
    if (( sLine_in.GetChar( 0 ) == '[' ) &&
            ( sLine_in.GetChar( sLine_in.Len() - 1 ) == ']' )){
        sGroup_out = sLine_in.GetToken( 1, '[' ).GetToken( 0, ']' );
        sGroup_out.EraseLeadingChars( ' ' );
        sGroup_out.EraseTrailingChars( ' ' );
        return true;
    }
    return false;
 }
 void LngParser::ReadLine( const ByteString &sLine_in , ByteStringHashMap &rText_inout){
    //printf("sLine -> '%s'\n",sLine_in.GetBuffer());
    ByteString sLang = sLine_in.GetToken( 0, '=' );
    sLang.EraseLeadingChars( ' ' );
    sLang.EraseTrailingChars( ' ' );
    ByteString sText = sLine_in.GetToken( 1, '\"' ).GetToken( 0, '\"' );
    if( sLang.Len() )
        rText_inout[ sLang ] = sText;
 }

/*****************************************************************************/
BOOL LngParser::Merge(
    const ByteString &rSDFFile, const ByteString &rDestinationFile , const ByteString& rPrj )
/*****************************************************************************/
{
    Export::InitLanguages( true );
    SvFileStream aDestination(
        String( rDestinationFile, RTL_TEXTENCODING_ASCII_US ),
        STREAM_STD_WRITE | STREAM_TRUNC );
    if ( !aDestination.IsOpen()) {
        nError = LNG_COULD_NOT_OPEN;
    }
    nError = LNG_OK;
//    MergeDataFile( const ByteString &rFileName, const ByteString& rFile , BOOL bErrLog, CharSet aCharSet, BOOL bUTF8 );

    MergeDataFile aMergeDataFile( rSDFFile, sSource , FALSE, RTL_TEXTENCODING_MS_1252, bDBIsUTF8 );
    ByteString sTmp( Export::sLanguages );
    if( sTmp.ToUpperAscii().Equals("ALL") )
        Export::SetLanguages( aMergeDataFile.GetLanguages() );
    aLanguages = Export::GetLanguages();

    ULONG nPos = 0;
    BOOL bGroup = FALSE;
    ByteString sGroup;

    // seek to next group
    while ( nPos < pLines->Count() && !bGroup ) {
        ByteString sLine( *pLines->GetObject( nPos ));
        sLine.EraseLeadingChars( ' ' );
        sLine.EraseTrailingChars( ' ' );
        if (( sLine.GetChar( 0 ) == '[' ) &&
            ( sLine.GetChar( sLine.Len() - 1 ) == ']' ))
        {
            sGroup = sLine.GetToken( 1, '[' ).GetToken( 0, ']' );
            sGroup.EraseLeadingChars( ' ' );
            sGroup.EraseTrailingChars( ' ' );
            bGroup = TRUE;
        }
        nPos ++;
    }

    while ( nPos < pLines->Count()) {
        ByteStringHashMap Text;
        ByteString sID( sGroup );
        ULONG nLastLangPos = 0;

        ResData  *pResData = new ResData( "", sID );
        pResData->sResTyp = "LngText";
        PFormEntrys *pEntrys = aMergeDataFile.GetPFormEntrys( pResData );

        // read languages
        bGroup = FALSE;

        ByteString sLanguagesDone;

        while ( nPos < pLines->Count() && !bGroup ) {
            ByteString sLine( *pLines->GetObject( nPos ));
            sLine.EraseLeadingChars( ' ' );
            sLine.EraseTrailingChars( ' ' );
            if (( sLine.GetChar( 0 ) == '[' ) &&
                ( sLine.GetChar( sLine.Len() - 1 ) == ']' ))
            {
                sGroup = sLine.GetToken( 1, '[' ).GetToken( 0, ']' );
                sGroup.EraseLeadingChars( ' ' );
                sGroup.EraseTrailingChars( ' ' );
                bGroup = TRUE;
                nPos ++;
                sLanguagesDone = "";
            }
            else if ( sLine.GetTokenCount( '=' ) > 1 ) {
                ByteString sLang = sLine.GetToken( 0, '=' );
                sLang.EraseLeadingChars( ' ' );
                sLang.EraseTrailingChars( ' ' );

                ByteString sSearch( ";" );
                sSearch += sLang;
                sSearch += ";";

                if (( sLanguagesDone.Search( sSearch ) != STRING_NOTFOUND )) {
                    pLines->Remove( nPos );
                }
                if( bULF && pEntrys )
                {
                    // this is a valid text line
                    ByteString sText = sLine.GetToken( 1, '\"' ).GetToken( 0, '\"' );
                    USHORT nIndex;
                    if( sLang.Len() ){
                        ByteString sNewText;
                        pEntrys->GetText( sNewText, STRING_TYP_TEXT, sLang, TRUE );
                        //if ( bULF )
                        //  sNewText = UTF8Converter::ConvertToUTF8( sNewText, Export::GetCharSet( Export::LangId[ nIndex ] ));

                        if ( sNewText.Len()) {
                            ByteString *pLine = pLines->GetObject( nPos );

                            if( !sLang.EqualsIgnoreCaseAscii("de") && !sLang.EqualsIgnoreCaseAscii("en-US") ){
                                ByteString sText( sLang );
                                sText += " = \"";
                                sText += sNewText;
                                sText += "\"";
                                *pLine = sText;
                            }
                            Text[ sLang ] = sNewText;
                        }
                    }
                    nLastLangPos = nPos;
                    nPos ++;
                    sLanguagesDone += sSearch;
                }
                else {
                    nLastLangPos = nPos;
                    nPos ++;
                    sLanguagesDone += sSearch;
                }
            }
            else
                nPos++;
        }
        ByteString sCur;
        if ( nLastLangPos ) {
            for( long int n = 0; n < aLanguages.size(); n++ ){
                sCur = aLanguages[ n ];

                if( ( !sCur.EqualsIgnoreCaseAscii("de") || ( sCur.EqualsIgnoreCaseAscii("de") && Export::isMergingGermanAllowed( rPrj ) ) )
                    &&!sCur.EqualsIgnoreCaseAscii("en-US") && !Text[ sCur ].Len() && pEntrys ){

                    ByteString sNewText;
                    pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur, TRUE );
                    if (( sNewText.Len()) &&
                        !(( sCur.Equals("x-comment") ) && ( sNewText == "-" )))
                    {
                        ByteString sLine;
                        sLine += sCur;
                        sLine += " = \"";
                        sLine += sNewText;
                        sLine += "\"";

                        nLastLangPos++;
                        nPos++;

                        pLines->Insert( new ByteString( sLine ), nLastLangPos );
                    }
                }
            }
        }

        delete pResData;
    }

    for ( ULONG i = 0; i < pLines->Count(); i++ )
        aDestination.WriteLine( *pLines->GetObject( i ));

    aDestination.Close();
    return TRUE;
}
<|endoftext|>