<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrStrokeInfo.h"
#include "GrTestUtils.h"
#include "SkMatrix.h"
#include "SkPathEffect.h"
#include "SkPath.h"
#include "SkRRect.h"

#ifdef GR_TEST_UTILS

static const SkMatrix& test_matrix(SkRandom* random, bool includePerspective) {
    static SkMatrix gMatrices[5];
    static const int kPerspectiveCount = 1;
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        gMatrices[0].reset();
        gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
        gMatrices[2].setRotate(SkIntToScalar(17));
        gMatrices[3].setRotate(SkIntToScalar(185));
        gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
        gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf);

        // Perspective matrices
        gMatrices[4].setRotate(SkIntToScalar(215));
        gMatrices[4].set(SkMatrix::kMPersp0, 0.00013f);
        gMatrices[4].set(SkMatrix::kMPersp1, -0.000039f);
    }

    uint32_t count = static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices));
    if (includePerspective) {
        return gMatrices[random->nextULessThan(count)];
    } else {
        return gMatrices[random->nextULessThan(count - kPerspectiveCount)];
    }
}

namespace GrTest {
const SkMatrix& TestMatrix(SkRandom* random) { return test_matrix(random, true); }

const SkMatrix& TestMatrixPreservesRightAngles(SkRandom* random) {
    static SkMatrix gMatrices[5];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // identity
        gMatrices[0].reset();
        // translation
        gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
        // scale
        gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
        // scale + translation
        gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
        gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
        // orthogonal basis vectors
        gMatrices[4].reset();
        gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
        gMatrices[4].setRotate(47);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) {
            SkASSERT(gMatrices[i].preservesRightAngles());
        }
    }
    return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))];
}

const SkMatrix& TestMatrixRectStaysRect(SkRandom* random) {
    static SkMatrix gMatrices[6];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // identity
        gMatrices[0].reset();
        // translation
        gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
        // scale
        gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
        // scale + translation
        gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
        gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
        // reflection
        gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
        // 90 degress rotation
        gMatrices[5].setRotate(90);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) {
            SkASSERT(gMatrices[i].rectStaysRect());
        }
    }
    return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))];
}

const SkMatrix& TestMatrixInvertible(SkRandom* random) { return test_matrix(random, false); }

const SkRect& TestRect(SkRandom* random) {
    static SkRect gRects[7];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        gRects[0] = SkRect::MakeWH(1.f, 1.f);
        gRects[1] = SkRect::MakeWH(1.0f, 256.0f);
        gRects[2] = SkRect::MakeWH(256.0f, 1.0f);
        gRects[4] = SkRect::MakeLargest();
        gRects[5] = SkRect::MakeLTRB(-65535.0f, -65535.0f, 65535.0f, 65535.0f);
        gRects[6] = SkRect::MakeLTRB(-10.0f, -10.0f, 10.0f, 10.0f);
    }
    return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))];
}

// Just some simple rects for code which expects its input very sanitized
const SkRect& TestSquare(SkRandom* random) {
    static SkRect gRects[2];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        gRects[0] = SkRect::MakeWH(128.f, 128.f);
        gRects[1] = SkRect::MakeWH(256.0f, 256.0f);
    }
    return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))];
}

const SkRRect& TestRRectSimple(SkRandom* random) {
    static SkRRect gRRect[2];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        SkRect rectangle = SkRect::MakeWH(10.f, 20.f);
        // true round rect with circular corners
        gRRect[0].setRectXY(rectangle, 1.f, 1.f);
        // true round rect with elliptical corners
        gRRect[1].setRectXY(rectangle, 2.0f, 1.0f);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gRRect); i++) {
            SkASSERT(gRRect[i].isSimple());
        }
    }
    return gRRect[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRRect)))];
}

const SkPath& TestPath(SkRandom* random) {
    static SkPath gPath[7];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // line
        gPath[0].moveTo(0.f, 0.f);
        gPath[0].lineTo(10.f, 10.f);
        // quad
        gPath[1].moveTo(0.f, 0.f);
        gPath[1].quadTo(10.f, 10.f, 20.f, 20.f);
        // conic
        gPath[2].moveTo(0.f, 0.f);
        gPath[2].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
        // cubic
        gPath[3].moveTo(0.f, 0.f);
        gPath[3].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
        // all three
        gPath[4].moveTo(0.f, 0.f);
        gPath[4].lineTo(10.f, 10.f);
        gPath[4].quadTo(10.f, 10.f, 20.f, 20.f);
        gPath[4].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
        gPath[4].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
        // convex
        gPath[5].moveTo(0.0f, 0.0f);
        gPath[5].lineTo(10.0f, 0.0f);
        gPath[5].lineTo(10.0f, 10.0f);
        gPath[5].lineTo(0.0f, 10.0f);
        gPath[5].close();
        // concave
        gPath[6].moveTo(0.0f, 0.0f);
        gPath[6].lineTo(5.0f, 5.0f);
        gPath[6].lineTo(10.0f, 0.0f);
        gPath[6].lineTo(10.0f, 10.0f);
        gPath[6].lineTo(0.0f, 10.0f);
        gPath[6].close();
    }

    return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
}

const SkPath& TestPathConvex(SkRandom* random) {
    static SkPath gPath[3];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // narrow rect
        gPath[0].moveTo(-1.5f, -50.0f);
        gPath[0].lineTo(-1.5f, -50.0f);
        gPath[0].lineTo( 1.5f, -50.0f);
        gPath[0].lineTo( 1.5f,  50.0f);
        gPath[0].lineTo(-1.5f,  50.0f);
        // degenerate
        gPath[1].moveTo(-0.025f, -0.025f);
        gPath[1].lineTo(-0.025f, -0.025f);
        gPath[1].lineTo( 0.025f, -0.025f);
        gPath[1].lineTo( 0.025f,  0.025f);
        gPath[1].lineTo(-0.025f,  0.025f);
        // clipped triangle
        gPath[2].moveTo(-10.0f, -50.0f);
        gPath[2].lineTo(-10.0f, -50.0f);
        gPath[2].lineTo( 10.0f, -50.0f);
        gPath[2].lineTo( 50.0f,  31.0f);
        gPath[2].lineTo( 40.0f,  50.0f);
        gPath[2].lineTo(-40.0f,  50.0f);
        gPath[2].lineTo(-50.0f,  31.0f);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gPath); i++) {
            SkASSERT(SkPath::kConvex_Convexity == gPath[i].getConvexity());
        }
    }

    return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
}

static void randomize_stroke_rec(SkStrokeRec* rec, SkRandom* random) {
    bool strokeAndFill = random->nextBool();
    SkScalar strokeWidth = random->nextBool() ? 0.f : 1.f;
    rec->setStrokeStyle(strokeWidth, strokeAndFill);

    SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount));
    SkPaint::Join join = SkPaint::Join(random->nextULessThan(SkPaint::kJoinCount));
    SkScalar miterLimit = random->nextRangeScalar(1.f, 5.f);
    rec->setStrokeParams(cap, join, miterLimit);
}

SkStrokeRec TestStrokeRec(SkRandom* random) {
    SkStrokeRec::InitStyle style =
            SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
    SkStrokeRec rec(style);
    randomize_stroke_rec(&rec, random);
    return rec;
}

GrStrokeInfo TestStrokeInfo(SkRandom* random) {
    SkStrokeRec::InitStyle style =
            SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
    GrStrokeInfo strokeInfo(style);
    randomize_stroke_rec(&strokeInfo, random);
    SkPathEffect::DashInfo dashInfo;
    dashInfo.fCount = random->nextRangeU(1, 50) * 2;
    SkAutoTDeleteArray<SkScalar> intervals(SkNEW_ARRAY(SkScalar, dashInfo.fCount));
    dashInfo.fIntervals = intervals.get();
    SkScalar sum = 0;
    for (int i = 0; i < dashInfo.fCount; i++) {
    #if defined(SK_BUILD_FOR_IOS)
        SkDebugf("&dashInfo.fIntervals[%d] = %p\n", i, &dashInfo.fIntervals[i]);
    #endif
        dashInfo.fIntervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
                                                         SkDoubleToScalar(10.0));
        sum += dashInfo.fIntervals[i];
    }
    dashInfo.fPhase = random->nextRangeScalar(0, sum);
    strokeInfo.setDashInfo(dashInfo);
    return strokeInfo;
}

};

#endif
<commit_msg>This iOS crash makes little sense to me.  Add some debugging.<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrStrokeInfo.h"
#include "GrTestUtils.h"
#include "SkMatrix.h"
#include "SkPathEffect.h"
#include "SkPath.h"
#include "SkRRect.h"

#ifdef GR_TEST_UTILS

static const SkMatrix& test_matrix(SkRandom* random, bool includePerspective) {
    static SkMatrix gMatrices[5];
    static const int kPerspectiveCount = 1;
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        gMatrices[0].reset();
        gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
        gMatrices[2].setRotate(SkIntToScalar(17));
        gMatrices[3].setRotate(SkIntToScalar(185));
        gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
        gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf);

        // Perspective matrices
        gMatrices[4].setRotate(SkIntToScalar(215));
        gMatrices[4].set(SkMatrix::kMPersp0, 0.00013f);
        gMatrices[4].set(SkMatrix::kMPersp1, -0.000039f);
    }

    uint32_t count = static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices));
    if (includePerspective) {
        return gMatrices[random->nextULessThan(count)];
    } else {
        return gMatrices[random->nextULessThan(count - kPerspectiveCount)];
    }
}

namespace GrTest {
const SkMatrix& TestMatrix(SkRandom* random) { return test_matrix(random, true); }

const SkMatrix& TestMatrixPreservesRightAngles(SkRandom* random) {
    static SkMatrix gMatrices[5];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // identity
        gMatrices[0].reset();
        // translation
        gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
        // scale
        gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
        // scale + translation
        gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
        gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
        // orthogonal basis vectors
        gMatrices[4].reset();
        gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
        gMatrices[4].setRotate(47);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) {
            SkASSERT(gMatrices[i].preservesRightAngles());
        }
    }
    return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))];
}

const SkMatrix& TestMatrixRectStaysRect(SkRandom* random) {
    static SkMatrix gMatrices[6];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // identity
        gMatrices[0].reset();
        // translation
        gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
        // scale
        gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
        // scale + translation
        gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
        gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
        // reflection
        gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
        // 90 degress rotation
        gMatrices[5].setRotate(90);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) {
            SkASSERT(gMatrices[i].rectStaysRect());
        }
    }
    return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))];
}

const SkMatrix& TestMatrixInvertible(SkRandom* random) { return test_matrix(random, false); }

const SkRect& TestRect(SkRandom* random) {
    static SkRect gRects[7];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        gRects[0] = SkRect::MakeWH(1.f, 1.f);
        gRects[1] = SkRect::MakeWH(1.0f, 256.0f);
        gRects[2] = SkRect::MakeWH(256.0f, 1.0f);
        gRects[4] = SkRect::MakeLargest();
        gRects[5] = SkRect::MakeLTRB(-65535.0f, -65535.0f, 65535.0f, 65535.0f);
        gRects[6] = SkRect::MakeLTRB(-10.0f, -10.0f, 10.0f, 10.0f);
    }
    return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))];
}

// Just some simple rects for code which expects its input very sanitized
const SkRect& TestSquare(SkRandom* random) {
    static SkRect gRects[2];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        gRects[0] = SkRect::MakeWH(128.f, 128.f);
        gRects[1] = SkRect::MakeWH(256.0f, 256.0f);
    }
    return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))];
}

const SkRRect& TestRRectSimple(SkRandom* random) {
    static SkRRect gRRect[2];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        SkRect rectangle = SkRect::MakeWH(10.f, 20.f);
        // true round rect with circular corners
        gRRect[0].setRectXY(rectangle, 1.f, 1.f);
        // true round rect with elliptical corners
        gRRect[1].setRectXY(rectangle, 2.0f, 1.0f);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gRRect); i++) {
            SkASSERT(gRRect[i].isSimple());
        }
    }
    return gRRect[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRRect)))];
}

const SkPath& TestPath(SkRandom* random) {
    static SkPath gPath[7];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // line
        gPath[0].moveTo(0.f, 0.f);
        gPath[0].lineTo(10.f, 10.f);
        // quad
        gPath[1].moveTo(0.f, 0.f);
        gPath[1].quadTo(10.f, 10.f, 20.f, 20.f);
        // conic
        gPath[2].moveTo(0.f, 0.f);
        gPath[2].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
        // cubic
        gPath[3].moveTo(0.f, 0.f);
        gPath[3].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
        // all three
        gPath[4].moveTo(0.f, 0.f);
        gPath[4].lineTo(10.f, 10.f);
        gPath[4].quadTo(10.f, 10.f, 20.f, 20.f);
        gPath[4].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
        gPath[4].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
        // convex
        gPath[5].moveTo(0.0f, 0.0f);
        gPath[5].lineTo(10.0f, 0.0f);
        gPath[5].lineTo(10.0f, 10.0f);
        gPath[5].lineTo(0.0f, 10.0f);
        gPath[5].close();
        // concave
        gPath[6].moveTo(0.0f, 0.0f);
        gPath[6].lineTo(5.0f, 5.0f);
        gPath[6].lineTo(10.0f, 0.0f);
        gPath[6].lineTo(10.0f, 10.0f);
        gPath[6].lineTo(0.0f, 10.0f);
        gPath[6].close();
    }

    return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
}

const SkPath& TestPathConvex(SkRandom* random) {
    static SkPath gPath[3];
    static bool gOnce;
    if (!gOnce) {
        gOnce = true;
        // narrow rect
        gPath[0].moveTo(-1.5f, -50.0f);
        gPath[0].lineTo(-1.5f, -50.0f);
        gPath[0].lineTo( 1.5f, -50.0f);
        gPath[0].lineTo( 1.5f,  50.0f);
        gPath[0].lineTo(-1.5f,  50.0f);
        // degenerate
        gPath[1].moveTo(-0.025f, -0.025f);
        gPath[1].lineTo(-0.025f, -0.025f);
        gPath[1].lineTo( 0.025f, -0.025f);
        gPath[1].lineTo( 0.025f,  0.025f);
        gPath[1].lineTo(-0.025f,  0.025f);
        // clipped triangle
        gPath[2].moveTo(-10.0f, -50.0f);
        gPath[2].lineTo(-10.0f, -50.0f);
        gPath[2].lineTo( 10.0f, -50.0f);
        gPath[2].lineTo( 50.0f,  31.0f);
        gPath[2].lineTo( 40.0f,  50.0f);
        gPath[2].lineTo(-40.0f,  50.0f);
        gPath[2].lineTo(-50.0f,  31.0f);

        for (size_t i = 0; i < SK_ARRAY_COUNT(gPath); i++) {
            SkASSERT(SkPath::kConvex_Convexity == gPath[i].getConvexity());
        }
    }

    return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
}

static void randomize_stroke_rec(SkStrokeRec* rec, SkRandom* random) {
    bool strokeAndFill = random->nextBool();
    SkScalar strokeWidth = random->nextBool() ? 0.f : 1.f;
    rec->setStrokeStyle(strokeWidth, strokeAndFill);

    SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount));
    SkPaint::Join join = SkPaint::Join(random->nextULessThan(SkPaint::kJoinCount));
    SkScalar miterLimit = random->nextRangeScalar(1.f, 5.f);
    rec->setStrokeParams(cap, join, miterLimit);
}

SkStrokeRec TestStrokeRec(SkRandom* random) {
    SkStrokeRec::InitStyle style =
            SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
    SkStrokeRec rec(style);
    randomize_stroke_rec(&rec, random);
    return rec;
}

GrStrokeInfo TestStrokeInfo(SkRandom* random) {
    SkStrokeRec::InitStyle style =
            SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
    GrStrokeInfo strokeInfo(style);
    randomize_stroke_rec(&strokeInfo, random);
    SkPathEffect::DashInfo dashInfo;
    dashInfo.fCount = random->nextRangeU(1, 50) * 2;
    SkAutoTMalloc<SkScalar> intervals(dashInfo.fCount);
    dashInfo.fIntervals = intervals.get();
    SkScalar sum = 0;
    for (int i = 0; i < dashInfo.fCount; i++) {
    #if defined(SK_BUILD_FOR_IOS)
        SkDebugf("&dashInfo.fIntervals[%d] = %p\n", i, &dashInfo.fIntervals[i]);
    #endif
        dashInfo.fIntervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
                                                         SkDoubleToScalar(10.0));
        sum += dashInfo.fIntervals[i];
    }
    dashInfo.fPhase = random->nextRangeScalar(0, sum);
    strokeInfo.setDashInfo(dashInfo);
    return strokeInfo;
}

};

#endif
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qcontactmanager.h"
#include "qcontactmanager_p.h"
#include "qcontactmanagerengine.h"
#include "qcontactmanagerenginefactory.h"
#include "qcontactmanagerenginev2wrapper_p.h"

#include "qcontact_p.h"

#include "qcontactaction.h"
#include "qcontactactiondescriptor.h"
#ifdef QT_SIMULATOR
#include "qcontactsimulatorbackend_p.h"
#endif

#include <QSharedData>
#include <QtPlugin>
#include <QPluginLoader>
#include <QWeakPointer>

#include <QDebug>
#include <QDir>
#include <QFile>

#include <QApplication>

#if defined(Q_OS_SYMBIAN)
# include <f32file.h>
#endif

#include "qcontactmemorybackend_p.h"
#include "qcontactinvalidbackend_p.h"
#include "qmobilitypluginsearch.h"

QTM_BEGIN_NAMESPACE

/* Shared QContactManager stuff here, default engine stuff below */
QHash<QString, QContactManagerEngineFactory*> QContactManagerData::m_engines;
QSet<QContactManager*> QContactManagerData::m_aliveEngines;
QList<QContactActionManagerPlugin*> QContactManagerData::m_actionManagers;

bool QContactManagerData::m_discoveredStatic;
QStringList QContactManagerData::m_pluginPaths;

static void qContactsCleanEngines()
{
    // This is complicated by needing to remove any engines before we unload factories
    // guard pointers as one engine could be parent of another manager and cause doubledelete
    QList<QWeakPointer<QContactManager> > aliveManagers;
    foreach(QContactManager* manager, QContactManagerData::m_aliveEngines) {
        aliveManagers << QWeakPointer<QContactManager>(manager);
    }

    foreach(QWeakPointer<QContactManager> manager, aliveManagers) {
        if (not manager) {
            // deleting engine of one manager, could cause deleting next manager in list (aggregation case)
            continue;
        }
        // We don't delete the managers here, we just kill their engines
        // and replace it with an invalid engine (for safety :/)
        QContactManagerData* d = QContactManagerData::managerData(manager.data());

        delete d->m_engine;
        d->m_engine = new QContactInvalidEngine();
    }

    QList<QContactManagerEngineFactory*> factories = QContactManagerData::m_engines.values();

    for (int i=0; i < factories.count(); i++) {
        delete factories.at(i);
    }
    QContactManagerData::m_engines.clear();
    QContactManagerData::m_actionManagers.clear();
    QContactManagerData::m_aliveEngines.clear();
}

static int parameterValue(const QMap<QString, QString>& parameters, const char* key, int defaultValue)
{
    if (parameters.contains(QString::fromAscii(key))) {
        bool ok;
        int version = parameters.value(QString::fromAscii(key)).toInt(&ok);

        if (ok)
            return version;
    }
    return defaultValue;
}

void QContactManagerData::createEngine(const QString& managerName, const QMap<QString, QString>& parameters)
{
    m_engine = 0;

    QString builtManagerName = managerName.isEmpty() ? QContactManager::availableManagers().value(0) : managerName;
    if (builtManagerName == QLatin1String("memory")) {
        QContactManagerEngine* engine = QContactMemoryEngine::createMemoryEngine(parameters);
        m_engine = new QContactManagerEngineV2Wrapper(engine);
        m_signalSource = engine;
#ifdef QT_SIMULATOR
    } else if (builtManagerName == QLatin1String("simulator")) {
        QContactManagerEngine* engine = QContactSimulatorEngine::createSimulatorEngine(parameters);
        m_engine = new QContactManagerEngineV2Wrapper(engine);
        m_signalSource = engine;
#endif
    } else {
        int implementationVersion = parameterValue(parameters, QTCONTACTS_IMPLEMENTATION_VERSION_NAME, -1);

        bool found = false;
        bool loadedDynamic = false;

        /* First check static factories */
        loadStaticFactories();

        /* See if we got a fast hit */
        QList<QContactManagerEngineFactory*> factories = m_engines.values(builtManagerName);
        m_lastError = QContactManager::NoError;

        while(!found) {
            foreach (QContactManagerEngineFactory* f, factories) {
                QList<int> versions = f->supportedImplementationVersions();
                if (implementationVersion == -1 ||//no given implementation version required
                        versions.isEmpty() || //the manager engine factory does not report any version
                        versions.contains(implementationVersion)) {
                    QContactManagerEngine* engine = f->engine(parameters, &m_lastError);
                    // if it's a V2, use it
                    m_engine = qobject_cast<QContactManagerEngineV2*>(engine);
                    if (!m_engine && engine) {
                        // Nope, v1, so wrap it
                        m_engine = new QContactManagerEngineV2Wrapper(engine);
                        m_signalSource = engine;
                    } else {
                        m_signalSource = m_engine; // use the v2 engine directly
                    }
                    found = true;
                    break;
                }
            }

            // Break if found or if this is the second time through
            if (loadedDynamic || found)
                break;

            // otherwise load dynamic factories and reloop
            loadFactories();
            factories = m_engines.values(builtManagerName);
            loadedDynamic = true;
        }

        // XXX remove this
        // the engine factory could lie to us, so check the real implementation version
        if (m_engine && (implementationVersion != -1 && m_engine->managerVersion() != implementationVersion)) {
            m_lastError = QContactManager::VersionMismatchError;
            m_signalSource = m_engine = 0;
        }

        if (!m_engine) {
            if (m_lastError == QContactManager::NoError)
                m_lastError = QContactManager::DoesNotExistError;
            m_signalSource = m_engine = new QContactInvalidEngine();
        }
    }
}

void QContactManagerData::loadStaticFactories()
{
    if (!m_discoveredStatic) {
#if !defined QT_NO_DEBUG
        const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0;
#endif

        m_discoveredStatic = true;

        /* Clean stuff up at the end */
        qAddPostRoutine(qContactsCleanEngines);

        /* Loop over all the static plugins */
        QObjectList staticPlugins = QPluginLoader::staticInstances();
        for (int i=0; i < staticPlugins.count(); i++ ){
            QContactManagerEngineFactory *f = qobject_cast<QContactManagerEngineFactory*>(staticPlugins.at(i));
            if (f) {
                QString name = f->managerName();
#if !defined QT_NO_DEBUG
                if (showDebug)
                    qDebug() << "Static: found an engine plugin" << f << "with name" << name;
#endif
                if (name != QLatin1String("memory") && name != QLatin1String("invalid") && !name.isEmpty()) {
                    // we also need to ensure that we haven't already loaded this factory.
                    if (m_engines.keys().contains(name)) {
                        qWarning() << "Static contacts plugin" << name << "has the same name as a currently loaded plugin; ignored";
                    } else {
                        m_engines.insertMulti(name, f);
                    }
                } else {
                    qWarning() << "Static contacts plugin with reserved name" << name << "ignored";
                }
            }
        }
    }
}

/* Plugin loader */
void QContactManagerData::loadFactories()
{
#if !defined QT_NO_DEBUG
    const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0;
#endif

    // Always do this..
    loadStaticFactories();

    // But only load dynamic plugins when the paths change
    QStringList paths = QCoreApplication::libraryPaths();
#ifdef QTM_PLUGIN_PATH
    paths << QLatin1String(QTM_PLUGIN_PATH);
#endif

    if (paths != m_pluginPaths) {
        m_pluginPaths = paths;

        QStringList plugins = mobilityPlugins(QLatin1String("contacts"));

        /* Now discover the dynamic plugins */
        for (int i=0; i < plugins.count(); i++) {
            QPluginLoader qpl(plugins.at(i));

#if !defined QT_NO_DEBUG
            if (showDebug)
                qDebug() << "Loading plugin" << plugins.at(i);
#endif

            QContactManagerEngineFactory *f = qobject_cast<QContactManagerEngineFactory*>(qpl.instance());
            QContactActionManagerPlugin *m = qobject_cast<QContactActionManagerPlugin*>(qpl.instance());

            if (f) {
                QString name = f->managerName();
#if !defined QT_NO_DEBUG
                if (showDebug)
                    qDebug() << "Dynamic: found a contact engine plugin" << f << "with name" << name;
#endif
                if (name != QLatin1String("memory") && name != QLatin1String("invalid") && !name.isEmpty()) {
                    // we also need to ensure that we haven't already loaded this factory.
                    if (m_engines.keys().contains(name)) {
                        qWarning() << "Contacts plugin" << plugins.at(i) << "has the same name as currently loaded plugin" << name << "; ignored";
                    } else {
                        m_engines.insertMulti(name, f);
                    }
                } else {
                    qWarning() << "Contacts plugin" << plugins.at(i) << "with reserved name" << name << "ignored";
                }
            }

            if (m) {
                m_actionManagers.append(m);
            }

            /* Debugging */
#if !defined QT_NO_DEBUG
            if (showDebug && !f && !m) {
                qDebug() << "Unknown plugin:" << qpl.errorString();
                if (qpl.instance()) {
                    qDebug() << "[qobject:" << qpl.instance() << "]";
                }
            }
#endif
        }

        QStringList engineNames;
        foreach (QContactManagerEngineFactory* f, m_engines.values()) {
            QStringList versions;
            foreach (int v, f->supportedImplementationVersions()) {
                versions << QString::fromAscii("%1").arg(v);
            }
            engineNames << QString::fromAscii("%1[%2]").arg(f->managerName()).arg(versions.join(QString::fromAscii(",")));
        }
#if !defined QT_NO_DEBUG
        if (showDebug) {
            qDebug() << "Found engines:" << engineNames;
            qDebug() << "Found action engines:" << m_actionManagers;
        }
#endif
    }
}

// Observer stuff

void QContactManagerData::registerObserver(QContactManager* manager, QContactObserver* observer)
{
    if (!manager)
        return;

    QContactManagerData* d = QContactManagerData::get(manager);

    d->m_observerForContact.insert(observer->contactLocalId(), observer);

    // If this is the first observer, connect to the engine too
    if (d->m_observerForContact.size() == 1) {
        // This takes advantage of the manager connectNotify code
        QObject::connect(manager, SIGNAL(contactsChanged(QList<QContactLocalId>)),
                manager, SLOT(_q_contactsUpdated(QList<QContactLocalId>)));
        QObject::connect(manager, SIGNAL(contactsRemoved(QList<QContactLocalId>)),
                manager, SLOT(_q_contactsDeleted(QList<QContactLocalId>)));
    }
}

void QContactManagerData::unregisterObserver(QContactManager* manager, QContactObserver* observer)
{
    Q_ASSERT(manager);

    QContactManagerData* d = QContactManagerData::get(manager);

    QContactLocalId key = d->m_observerForContact.key(observer);
    if (key != 0) {
        d->m_observerForContact.remove(key, observer);

        // If there are now no more observers, disconnect from the engine
        if (d->m_observerForContact.size() == 0) {
            // This takes advantage of the manager disconnectNotify code
            QObject::disconnect(manager, SIGNAL(contactsChanged(QList<QContactLocalId>)),
                    manager, SLOT(_q_contactsUpdated(QList<QContactLocalId>)));
            QObject::disconnect(manager, SIGNAL(contactsRemoved(QList<QContactLocalId>)),
                    manager, SLOT(_q_contactsDeleted(QList<QContactLocalId>)));
        }
    }
}

void QContactManagerData::_q_contactsUpdated(const QList<QContactLocalId>& ids)
{
    foreach (QContactLocalId id, ids) {
        QList<QContactObserver*> observers = m_observerForContact.values(id);
        foreach (QContactObserver* observer, observers) {
            QMetaObject::invokeMethod(observer, "contactChanged");
        }
    }
}

void QContactManagerData::_q_contactsDeleted(const QList<QContactLocalId>& ids)
{
    foreach (QContactLocalId id, ids) {
        QList<QContactObserver*> observers = m_observerForContact.values(id);
        foreach (QContactObserver* observer, observers) {
            QMetaObject::invokeMethod(observer, "contactRemoved");
        }
    }
}

// trampolines for private classes
QContactManagerData* QContactManagerData::get(const QContactManager* manager)
{
    return manager->d;
}

QContactManagerEngineV2* QContactManagerData::engine(const QContactManager* manager)
{
    if (manager)
        return manager->d->m_engine;
    return 0;
}

QTM_END_NAMESPACE

<commit_msg>Style update: not -> !<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qcontactmanager.h"
#include "qcontactmanager_p.h"
#include "qcontactmanagerengine.h"
#include "qcontactmanagerenginefactory.h"
#include "qcontactmanagerenginev2wrapper_p.h"

#include "qcontact_p.h"

#include "qcontactaction.h"
#include "qcontactactiondescriptor.h"
#ifdef QT_SIMULATOR
#include "qcontactsimulatorbackend_p.h"
#endif

#include <QSharedData>
#include <QtPlugin>
#include <QPluginLoader>
#include <QWeakPointer>

#include <QDebug>
#include <QDir>
#include <QFile>

#include <QApplication>

#if defined(Q_OS_SYMBIAN)
# include <f32file.h>
#endif

#include "qcontactmemorybackend_p.h"
#include "qcontactinvalidbackend_p.h"
#include "qmobilitypluginsearch.h"

QTM_BEGIN_NAMESPACE

/* Shared QContactManager stuff here, default engine stuff below */
QHash<QString, QContactManagerEngineFactory*> QContactManagerData::m_engines;
QSet<QContactManager*> QContactManagerData::m_aliveEngines;
QList<QContactActionManagerPlugin*> QContactManagerData::m_actionManagers;

bool QContactManagerData::m_discoveredStatic;
QStringList QContactManagerData::m_pluginPaths;

static void qContactsCleanEngines()
{
    // This is complicated by needing to remove any engines before we unload factories
    // guard pointers as one engine could be parent of another manager and cause doubledelete
    QList<QWeakPointer<QContactManager> > aliveManagers;
    foreach(QContactManager* manager, QContactManagerData::m_aliveEngines) {
        aliveManagers << QWeakPointer<QContactManager>(manager);
    }

    foreach(QWeakPointer<QContactManager> manager, aliveManagers) {
        if (!manager) {
            // deleting engine of one manager, could cause deleting next manager in list (aggregation case)
            continue;
        }
        // We don't delete the managers here, we just kill their engines
        // and replace it with an invalid engine (for safety :/)
        QContactManagerData* d = QContactManagerData::managerData(manager.data());

        delete d->m_engine;
        d->m_engine = new QContactInvalidEngine();
    }

    QList<QContactManagerEngineFactory*> factories = QContactManagerData::m_engines.values();

    for (int i=0; i < factories.count(); i++) {
        delete factories.at(i);
    }
    QContactManagerData::m_engines.clear();
    QContactManagerData::m_actionManagers.clear();
    QContactManagerData::m_aliveEngines.clear();
}

static int parameterValue(const QMap<QString, QString>& parameters, const char* key, int defaultValue)
{
    if (parameters.contains(QString::fromAscii(key))) {
        bool ok;
        int version = parameters.value(QString::fromAscii(key)).toInt(&ok);

        if (ok)
            return version;
    }
    return defaultValue;
}

void QContactManagerData::createEngine(const QString& managerName, const QMap<QString, QString>& parameters)
{
    m_engine = 0;

    QString builtManagerName = managerName.isEmpty() ? QContactManager::availableManagers().value(0) : managerName;
    if (builtManagerName == QLatin1String("memory")) {
        QContactManagerEngine* engine = QContactMemoryEngine::createMemoryEngine(parameters);
        m_engine = new QContactManagerEngineV2Wrapper(engine);
        m_signalSource = engine;
#ifdef QT_SIMULATOR
    } else if (builtManagerName == QLatin1String("simulator")) {
        QContactManagerEngine* engine = QContactSimulatorEngine::createSimulatorEngine(parameters);
        m_engine = new QContactManagerEngineV2Wrapper(engine);
        m_signalSource = engine;
#endif
    } else {
        int implementationVersion = parameterValue(parameters, QTCONTACTS_IMPLEMENTATION_VERSION_NAME, -1);

        bool found = false;
        bool loadedDynamic = false;

        /* First check static factories */
        loadStaticFactories();

        /* See if we got a fast hit */
        QList<QContactManagerEngineFactory*> factories = m_engines.values(builtManagerName);
        m_lastError = QContactManager::NoError;

        while(!found) {
            foreach (QContactManagerEngineFactory* f, factories) {
                QList<int> versions = f->supportedImplementationVersions();
                if (implementationVersion == -1 ||//no given implementation version required
                        versions.isEmpty() || //the manager engine factory does not report any version
                        versions.contains(implementationVersion)) {
                    QContactManagerEngine* engine = f->engine(parameters, &m_lastError);
                    // if it's a V2, use it
                    m_engine = qobject_cast<QContactManagerEngineV2*>(engine);
                    if (!m_engine && engine) {
                        // Nope, v1, so wrap it
                        m_engine = new QContactManagerEngineV2Wrapper(engine);
                        m_signalSource = engine;
                    } else {
                        m_signalSource = m_engine; // use the v2 engine directly
                    }
                    found = true;
                    break;
                }
            }

            // Break if found or if this is the second time through
            if (loadedDynamic || found)
                break;

            // otherwise load dynamic factories and reloop
            loadFactories();
            factories = m_engines.values(builtManagerName);
            loadedDynamic = true;
        }

        // XXX remove this
        // the engine factory could lie to us, so check the real implementation version
        if (m_engine && (implementationVersion != -1 && m_engine->managerVersion() != implementationVersion)) {
            m_lastError = QContactManager::VersionMismatchError;
            m_signalSource = m_engine = 0;
        }

        if (!m_engine) {
            if (m_lastError == QContactManager::NoError)
                m_lastError = QContactManager::DoesNotExistError;
            m_signalSource = m_engine = new QContactInvalidEngine();
        }
    }
}

void QContactManagerData::loadStaticFactories()
{
    if (!m_discoveredStatic) {
#if !defined QT_NO_DEBUG
        const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0;
#endif

        m_discoveredStatic = true;

        /* Clean stuff up at the end */
        qAddPostRoutine(qContactsCleanEngines);

        /* Loop over all the static plugins */
        QObjectList staticPlugins = QPluginLoader::staticInstances();
        for (int i=0; i < staticPlugins.count(); i++ ){
            QContactManagerEngineFactory *f = qobject_cast<QContactManagerEngineFactory*>(staticPlugins.at(i));
            if (f) {
                QString name = f->managerName();
#if !defined QT_NO_DEBUG
                if (showDebug)
                    qDebug() << "Static: found an engine plugin" << f << "with name" << name;
#endif
                if (name != QLatin1String("memory") && name != QLatin1String("invalid") && !name.isEmpty()) {
                    // we also need to ensure that we haven't already loaded this factory.
                    if (m_engines.keys().contains(name)) {
                        qWarning() << "Static contacts plugin" << name << "has the same name as a currently loaded plugin; ignored";
                    } else {
                        m_engines.insertMulti(name, f);
                    }
                } else {
                    qWarning() << "Static contacts plugin with reserved name" << name << "ignored";
                }
            }
        }
    }
}

/* Plugin loader */
void QContactManagerData::loadFactories()
{
#if !defined QT_NO_DEBUG
    const bool showDebug = qgetenv("QT_DEBUG_PLUGINS").toInt() > 0;
#endif

    // Always do this..
    loadStaticFactories();

    // But only load dynamic plugins when the paths change
    QStringList paths = QCoreApplication::libraryPaths();
#ifdef QTM_PLUGIN_PATH
    paths << QLatin1String(QTM_PLUGIN_PATH);
#endif

    if (paths != m_pluginPaths) {
        m_pluginPaths = paths;

        QStringList plugins = mobilityPlugins(QLatin1String("contacts"));

        /* Now discover the dynamic plugins */
        for (int i=0; i < plugins.count(); i++) {
            QPluginLoader qpl(plugins.at(i));

#if !defined QT_NO_DEBUG
            if (showDebug)
                qDebug() << "Loading plugin" << plugins.at(i);
#endif

            QContactManagerEngineFactory *f = qobject_cast<QContactManagerEngineFactory*>(qpl.instance());
            QContactActionManagerPlugin *m = qobject_cast<QContactActionManagerPlugin*>(qpl.instance());

            if (f) {
                QString name = f->managerName();
#if !defined QT_NO_DEBUG
                if (showDebug)
                    qDebug() << "Dynamic: found a contact engine plugin" << f << "with name" << name;
#endif
                if (name != QLatin1String("memory") && name != QLatin1String("invalid") && !name.isEmpty()) {
                    // we also need to ensure that we haven't already loaded this factory.
                    if (m_engines.keys().contains(name)) {
                        qWarning() << "Contacts plugin" << plugins.at(i) << "has the same name as currently loaded plugin" << name << "; ignored";
                    } else {
                        m_engines.insertMulti(name, f);
                    }
                } else {
                    qWarning() << "Contacts plugin" << plugins.at(i) << "with reserved name" << name << "ignored";
                }
            }

            if (m) {
                m_actionManagers.append(m);
            }

            /* Debugging */
#if !defined QT_NO_DEBUG
            if (showDebug && !f && !m) {
                qDebug() << "Unknown plugin:" << qpl.errorString();
                if (qpl.instance()) {
                    qDebug() << "[qobject:" << qpl.instance() << "]";
                }
            }
#endif
        }

        QStringList engineNames;
        foreach (QContactManagerEngineFactory* f, m_engines.values()) {
            QStringList versions;
            foreach (int v, f->supportedImplementationVersions()) {
                versions << QString::fromAscii("%1").arg(v);
            }
            engineNames << QString::fromAscii("%1[%2]").arg(f->managerName()).arg(versions.join(QString::fromAscii(",")));
        }
#if !defined QT_NO_DEBUG
        if (showDebug) {
            qDebug() << "Found engines:" << engineNames;
            qDebug() << "Found action engines:" << m_actionManagers;
        }
#endif
    }
}

// Observer stuff

void QContactManagerData::registerObserver(QContactManager* manager, QContactObserver* observer)
{
    if (!manager)
        return;

    QContactManagerData* d = QContactManagerData::get(manager);

    d->m_observerForContact.insert(observer->contactLocalId(), observer);

    // If this is the first observer, connect to the engine too
    if (d->m_observerForContact.size() == 1) {
        // This takes advantage of the manager connectNotify code
        QObject::connect(manager, SIGNAL(contactsChanged(QList<QContactLocalId>)),
                manager, SLOT(_q_contactsUpdated(QList<QContactLocalId>)));
        QObject::connect(manager, SIGNAL(contactsRemoved(QList<QContactLocalId>)),
                manager, SLOT(_q_contactsDeleted(QList<QContactLocalId>)));
    }
}

void QContactManagerData::unregisterObserver(QContactManager* manager, QContactObserver* observer)
{
    Q_ASSERT(manager);

    QContactManagerData* d = QContactManagerData::get(manager);

    QContactLocalId key = d->m_observerForContact.key(observer);
    if (key != 0) {
        d->m_observerForContact.remove(key, observer);

        // If there are now no more observers, disconnect from the engine
        if (d->m_observerForContact.size() == 0) {
            // This takes advantage of the manager disconnectNotify code
            QObject::disconnect(manager, SIGNAL(contactsChanged(QList<QContactLocalId>)),
                    manager, SLOT(_q_contactsUpdated(QList<QContactLocalId>)));
            QObject::disconnect(manager, SIGNAL(contactsRemoved(QList<QContactLocalId>)),
                    manager, SLOT(_q_contactsDeleted(QList<QContactLocalId>)));
        }
    }
}

void QContactManagerData::_q_contactsUpdated(const QList<QContactLocalId>& ids)
{
    foreach (QContactLocalId id, ids) {
        QList<QContactObserver*> observers = m_observerForContact.values(id);
        foreach (QContactObserver* observer, observers) {
            QMetaObject::invokeMethod(observer, "contactChanged");
        }
    }
}

void QContactManagerData::_q_contactsDeleted(const QList<QContactLocalId>& ids)
{
    foreach (QContactLocalId id, ids) {
        QList<QContactObserver*> observers = m_observerForContact.values(id);
        foreach (QContactObserver* observer, observers) {
            QMetaObject::invokeMethod(observer, "contactRemoved");
        }
    }
}

// trampolines for private classes
QContactManagerData* QContactManagerData::get(const QContactManager* manager)
{
    return manager->d;
}

QContactManagerEngineV2* QContactManagerData::engine(const QContactManager* manager)
{
    if (manager)
        return manager->d->m_engine;
    return 0;
}

QTM_END_NAMESPACE

<|endoftext|>


<commit_before>#include "hsApp.h"

//--------------------------------------------------------------
void hsApp::setup()
{
	//ofBackground(34, 34, 34);
	ofSetVerticalSync(true);

	widthi = 512;
	widthf = 512.f;

	mesh.setMode(OF_PRIMITIVE_POINTS);

	for(int y = 0; y < widthi; y++ )
	{
		for(int x = 0; x < widthi; x++ )
		{
			ofFloatColor color(x/widthf,y/widthf,1.f,1.f);
			mesh.addColor(color);
			ofVec3f pos(x-widthf/2.f, y-widthf/2.f, 0);
			mesh.addVertex(pos);
		}
	}

	ofEnableDepthTest();
	glEnable(GL_POINT_SMOOTH); // use circular points instead of square points
	glPointSize(1); // make the points bigger

	// 2 output channels,
	// 0 input channels
	// 22050 samples per second
	// 512 samples per buffer
	// 4 num buffers (latency)

	int bufferSize		= 512;
	sampleRate 			= 44100;
	phase1				= 0;
	phase2				= 0;
	phase3				= 0;
	phaseAdder 			= 0.0f;
	volume				= 0.1f;
	bNoise 				= false;

	voice1.assign(bufferSize, 0.0);
	voice2.assign(bufferSize, 0.0);
	voice3.assign(bufferSize, 0.0);

	frequency = targetFrequency = 0;
	numerator1 = numerator2 = 2;
	denominator1 = denominator2 = 3;
	rotator = 0;

	//soundStream.listDevices();

	//if you want to set the device id to be different than the default
	//soundStream.setDeviceID(1); 	//note some devices are input only and some are output only

	soundStream.setup(this, 2, 0, sampleRate, bufferSize, 4);

	ofSetFrameRate(60);
}

//--------------------------------------------------------------
void hsApp::update()
{
}

//--------------------------------------------------------------
void hsApp::draw()
{
	ofBackgroundGradient(ofColor::gray, ofColor::black, OF_GRADIENT_CIRCULAR);

	int W = (ofGetWidth()-64.f)/2.f;
	int H = 100;

	vector<ofVec3f>& verts = mesh.getVertices();
	vector<ofFloatColor>& color = mesh.getColors();

	for(unsigned int i = 0; i < verts.size(); i++)
	{
		int j = ofMap(i, 0, verts.size(), 0, widthf);

		verts[i].x = voice1[j] * widthf * 2.f;
		verts[i].y = voice2[j] * widthf * 2.f;
		verts[i].z = voice3[j] * widthf * 2.f;

		color[i].r = 1.f - voice1[j];
		color[i].g = 1.f - voice2[j];
		color[i].b = 1.f - voice3[j];
	}

	cam.begin();
	ofTranslate(W/2, 0);
	ofRotateY(rotator);
	rotator += 0.1f;
	mesh.draw();
	cam.end();

	//

	ofSetColor(225);
	ofDrawBitmapString("AUDIO OUTPUT EXAMPLE", 32, 32);
	ofDrawBitmapString("press 'z' to unpause the audio, press 'x' to pause the audio", 32, 92);
	ofDrawBitmapString("press 'q/w' to to modify first numerator, press 'a/s' to modify first denominator", 32, 92+12);
	ofDrawBitmapString("press 'i/o' to to modify second numerator, press 'k/l' to modify second denominator", 32, 92+24);

	ofNoFill();

	// draw voice 1
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 150, 0);

	ofSetColor(225);
	ofDrawBitmapString("Voice 1", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice1.size(); i++)
	{
		float x =  ofMap(i, 0, voice1.size(), 0, W, true);
		ofVertex(x, 50 -voice1[i]*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	// draw voice 2
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 250, 0);

	ofSetColor(225);
	ofDrawBitmapString("Voice 2", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice2.size(); i++)
	{
		float x =  ofMap(i, 0, voice2.size(), 0, W, true);
		ofVertex(x, 50 -voice2[i]*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	// draw voice 3
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 350, 0);

	ofSetColor(225);
	ofDrawBitmapString("Voice 3", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice3.size(); i++)
	{
		float x =  ofMap(i, 0, voice3.size(), 0, W, true);
		ofVertex(x, 50 -voice3[i]*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	// draw output
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 450, 0);

	ofSetColor(225);
	ofDrawBitmapString("Output", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice3.size(); i++)
	{
		float x =  ofMap(i, 0, voice3.size(), 0, W, true);
		ofVertex(x, 50 -(voice1[i]+voice2[i]+voice3[i])*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	ofSetColor(225);
	string reportString = "volume: ("+ofToString(volume, 2)+") modify with -/+ keys\npan: ("+ofToString(pan, 2)+") modify with mouse x\nsynthesis: ";
	if( !bNoise )
	{
		reportString += "sine wave (" + ofToString(frequency, 2) + " > " + ofToString(targetFrequency, 2) + "hz) modify with mouse y";
	}
	else
	{
		reportString += "noise";
	}
	reportString += "\nratios = " + ofToString(numerator1) + ":" + ofToString(denominator1) + ", " + ofToString(numerator2) + ":" + ofToString(denominator2);
	ofDrawBitmapString(reportString, 32, 579);

}

//--------------------------------------------------------------
void hsApp::keyPressed  (int key)
{
	if (key == '-' || key == '_' )
	{
		volume -= 0.05;
		volume = MAX(volume, 0);
	}
	else if (key == '+' || key == '=' )
	{
		volume += 0.05;
		volume = MIN(volume, 1);
	}

	if( key == 'z' )
	{
		soundStream.start();
	}

	if( key == 'x' )
	{
		soundStream.stop();
	}

	if( key == 'q' )
	{
		numerator1--;
		if( numerator1 < 1 ) numerator1 = 1;
	}

	if( key == 'w' )
	{
		numerator1++;
	}

	if( key == 'a' )
	{
		denominator1--;
		if( denominator1 < 1 ) denominator1 = 1;
	}

	if( key == 's' )
	{
		denominator1++;
	}

	if( key == 'i' )
	{
		numerator2--;
		if( numerator2 < 1 ) numerator2 = 1;
	}

	if( key == 'o' )
	{
		numerator2++;
	}

	if( key == 'k' )
	{
		denominator2--;
		if( denominator2 < 1 ) denominator2 = 1;
	}

	if( key == 'l' )
	{
		denominator2++;
	}

}

//--------------------------------------------------------------
void hsApp::keyReleased  (int key)
{
}

//--------------------------------------------------------------
void hsApp::mouseMoved(int x, int y )
{
	int width = ofGetWidth();
	pan = (float)x / (float)width;
	float height = (float)ofGetHeight();
	targetFrequency = 27.f * (height-y);
}

//--------------------------------------------------------------
void hsApp::mouseDragged(int x, int y, int button)
{
	int width = ofGetWidth();
	pan = (float)x / (float)width;
}

//--------------------------------------------------------------
void hsApp::mousePressed(int x, int y, int button)
{
	//bNoise = true;
}

//--------------------------------------------------------------
void hsApp::mouseReleased(int x, int y, int button)
{
	//bNoise = false;
}

//--------------------------------------------------------------
void hsApp::windowResized(int w, int h)
{
}

//--------------------------------------------------------------
void hsApp::audioOut(float * output, int bufferSize, int nChannels)
{
	while (phase1 > TWO_PI)
	{
		phase1 -= TWO_PI;
	}
	while (phase2 > TWO_PI)
	{
		phase2 -= TWO_PI;
	}
	while (phase3 > TWO_PI)
	{
		phase3 -= TWO_PI;
	}

	if ( bNoise == true)
	{
		// ---------------------- noise --------------
		for (int i = 0; i < bufferSize; i++)
		{
			voice1[i] = ofRandom(0, 1) * volume;
			voice2[i] = ofRandom(0, 1) * volume;
			voice3[i] = ofRandom(0, 1) * volume;

			output[i*nChannels] = output[i*nChannels + 1] = voice1[i] + voice2[i] + voice3[i];
		}
	}
	else
	{
		frequency = 0.98f * frequency + 0.02f * targetFrequency;
		phaseAdder = (frequency / (float) sampleRate) * TWO_PI;

		for (int i = 0; i < bufferSize; i++)
		{
			phase1 += phaseAdder;
			phase2 += phaseAdder*float(numerator1)/float(denominator1);
			phase3 += (phaseAdder*float(numerator1)/float(denominator1))*float(numerator2)/float(denominator2);

			float sample1 = sin(phase1);
			float sample2 = sin(phase2);
			float sample3 = sin(phase3);

			voice1[i] = sample1 * volume;
			voice2[i] = sample2 * volume;
			voice3[i] = sample3 * volume;

			output[i*nChannels] = output[i*nChannels + 1] = voice1[i] + voice2[i] + voice3[i];
		}
	}

}

//--------------------------------------------------------------
void hsApp::gotMessage(ofMessage msg)
{
}

//--------------------------------------------------------------
void hsApp::dragEvent(ofDragInfo dragInfo)
{
}
<commit_msg>some massaging of sizing<commit_after>#include "hsApp.h"

//--------------------------------------------------------------
void hsApp::setup()
{
	//ofBackground(34, 34, 34);
	ofSetVerticalSync(true);

	widthi = 512;
	widthf = widthi;

	mesh.setMode(OF_PRIMITIVE_POINTS);

	for(int y = 0; y < widthi; y++ )
	{
		for(int x = 0; x < widthi; x++ )
		{
			ofFloatColor color(x/widthf,y/widthf,1.f,1.f);
			mesh.addColor(color);
			ofVec3f pos(x-widthf/2.f, y-widthf/2.f, 0);
			mesh.addVertex(pos);
		}
	}

	ofEnableDepthTest();
	glEnable(GL_POINT_SMOOTH); // use circular points instead of square points
	glPointSize(1); // make the points bigger

	// 2 output channels,
	// 0 input channels
	// 22050 samples per second
	// 512 samples per buffer
	// 4 num buffers (latency)

	int bufferSize		= 512;
	sampleRate 			= 44100;
	phase1				= 0;
	phase2				= 0;
	phase3				= 0;
	phaseAdder 			= 0.0f;
	volume				= 0.1f;
	bNoise 				= false;

	voice1.assign(bufferSize, 0.0);
	voice2.assign(bufferSize, 0.0);
	voice3.assign(bufferSize, 0.0);

	frequency = targetFrequency = 0;
	numerator1 = numerator2 = 2;
	denominator1 = denominator2 = 3;
	rotator = 0;

	//soundStream.listDevices();

	//if you want to set the device id to be different than the default
	//soundStream.setDeviceID(1); 	//note some devices are input only and some are output only

	soundStream.setup(this, 2, 0, sampleRate, bufferSize, 4);

	ofSetFrameRate(60);
}

//--------------------------------------------------------------
void hsApp::update()
{
}

//--------------------------------------------------------------
void hsApp::draw()
{
	ofBackgroundGradient(ofColor::gray, ofColor::black, OF_GRADIENT_CIRCULAR);

	int W = (ofGetWidth()-64.f)/2.f;
	int H = 100;

	vector<ofVec3f>& verts = mesh.getVertices();
	vector<ofFloatColor>& color = mesh.getColors();

	for(unsigned int i = 0; i < verts.size(); i++)
	{
		int j = ofMap(i, 0, verts.size(), 0, widthf);

		verts[i].x = voice1[j] * W;
		verts[i].y = voice2[j] * W;
		verts[i].z = voice3[j] * W;

		color[i].r = 1.f - voice1[j];
		color[i].g = 1.f - voice2[j];
		color[i].b = 1.f - voice3[j];
	}

	cam.begin();
	ofTranslate(W/2, 0);
	ofRotateY(rotator);
	rotator += 0.1f;
	mesh.draw();
	cam.end();

	//

	ofSetColor(225);
	ofDrawBitmapString("AUDIO OUTPUT EXAMPLE", 32, 32);
	ofDrawBitmapString("press 'z' to unpause the audio, press 'x' to pause the audio", 32, 92);
	ofDrawBitmapString("press 'q/w' to to modify first numerator, press 'a/s' to modify first denominator", 32, 92+12);
	ofDrawBitmapString("press 'i/o' to to modify second numerator, press 'k/l' to modify second denominator", 32, 92+24);

	ofNoFill();

	// draw voice 1
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 150, 0);

	ofSetColor(225);
	ofDrawBitmapString("Voice 1", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice1.size(); i++)
	{
		float x =  ofMap(i, 0, voice1.size(), 0, W, true);
		ofVertex(x, 50 -voice1[i]*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	// draw voice 2
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 250, 0);

	ofSetColor(225);
	ofDrawBitmapString("Voice 2", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice2.size(); i++)
	{
		float x =  ofMap(i, 0, voice2.size(), 0, W, true);
		ofVertex(x, 50 -voice2[i]*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	// draw voice 3
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 350, 0);

	ofSetColor(225);
	ofDrawBitmapString("Voice 3", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice3.size(); i++)
	{
		float x =  ofMap(i, 0, voice3.size(), 0, W, true);
		ofVertex(x, 50 -voice3[i]*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	// draw output
	ofPushStyle();
	ofPushMatrix();
	ofTranslate(32, 450, 0);

	ofSetColor(225);
	ofDrawBitmapString("Output", 4, 18);

	ofSetLineWidth(1);
	ofRect(0, 0, W, 100);

	ofSetColor(245, 58, 135);
	ofSetLineWidth(1);

	ofBeginShape();
	for (unsigned int i = 0; i < voice3.size(); i++)
	{
		float x =  ofMap(i, 0, voice3.size(), 0, W, true);
		ofVertex(x, 50 -(voice1[i]+voice2[i]+voice3[i])*80.0f);
	}
	ofEndShape(false);

	ofPopMatrix();
	ofPopStyle();

	ofSetColor(225);
	string reportString = "volume: ("+ofToString(volume, 2)+") modify with -/+ keys";//\npan: ("+ofToString(pan, 2)+") modify with mouse x\nsynthesis: ";
	if( !bNoise )
	{
		reportString += "sine wave (" + ofToString(frequency, 2) + " > " + ofToString(targetFrequency, 2) + "hz) modify with mouse y";
	}
	else
	{
		reportString += "noise";
	}
	reportString += "\nratios = " + ofToString(numerator1) + ":" + ofToString(denominator1) + ", " + ofToString(numerator2) + ":" + ofToString(denominator2);
	ofDrawBitmapString(reportString, 32, 579);

}

//--------------------------------------------------------------
void hsApp::keyPressed  (int key)
{
	if (key == '-' || key == '_' )
	{
		volume -= 0.05;
		volume = MAX(volume, 0);
	}
	else if (key == '+' || key == '=' )
	{
		volume += 0.05;
		volume = MIN(volume, 1);
	}

	if( key == 'z' )
	{
		soundStream.start();
	}

	if( key == 'x' )
	{
		soundStream.stop();
	}

	if( key == 'q' )
	{
		numerator1--;
		if( numerator1 < 1 ) numerator1 = 1;
	}

	if( key == 'w' )
	{
		numerator1++;
	}

	if( key == 'a' )
	{
		denominator1--;
		if( denominator1 < 1 ) denominator1 = 1;
	}

	if( key == 's' )
	{
		denominator1++;
	}

	if( key == 'i' )
	{
		numerator2--;
		if( numerator2 < 1 ) numerator2 = 1;
	}

	if( key == 'o' )
	{
		numerator2++;
	}

	if( key == 'k' )
	{
		denominator2--;
		if( denominator2 < 1 ) denominator2 = 1;
	}

	if( key == 'l' )
	{
		denominator2++;
	}

}

//--------------------------------------------------------------
void hsApp::keyReleased  (int key)
{
}

//--------------------------------------------------------------
void hsApp::mouseMoved(int x, int y )
{
	int width = ofGetWidth();
	pan = (float)x / (float)width;
	float height = (float)ofGetHeight();
	targetFrequency = 27.f * (height-y);
}

//--------------------------------------------------------------
void hsApp::mouseDragged(int x, int y, int button)
{
	int width = ofGetWidth();
	pan = (float)x / (float)width;
}

//--------------------------------------------------------------
void hsApp::mousePressed(int x, int y, int button)
{
	//bNoise = true;
}

//--------------------------------------------------------------
void hsApp::mouseReleased(int x, int y, int button)
{
	//bNoise = false;
}

//--------------------------------------------------------------
void hsApp::windowResized(int w, int h)
{
}

//--------------------------------------------------------------
void hsApp::audioOut(float * output, int bufferSize, int nChannels)
{
	while (phase1 > TWO_PI)
	{
		phase1 -= TWO_PI;
	}
	while (phase2 > TWO_PI)
	{
		phase2 -= TWO_PI;
	}
	while (phase3 > TWO_PI)
	{
		phase3 -= TWO_PI;
	}

	if ( bNoise == true)
	{
		// ---------------------- noise --------------
		for (int i = 0; i < bufferSize; i++)
		{
			voice1[i] = ofRandom(0, 1) * volume;
			voice2[i] = ofRandom(0, 1) * volume;
			voice3[i] = ofRandom(0, 1) * volume;

			output[i*nChannels] = output[i*nChannels + 1] = voice1[i] + voice2[i] + voice3[i];
		}
	}
	else
	{
		frequency = 0.98f * frequency + 0.02f * targetFrequency;
		phaseAdder = (frequency / (float) sampleRate) * TWO_PI;

		for (int i = 0; i < bufferSize; i++)
		{
			phase1 += phaseAdder;
			phase2 += phaseAdder*float(numerator1)/float(denominator1);
			phase3 += (phaseAdder*float(numerator1)/float(denominator1))*float(numerator2)/float(denominator2);

			float sample1 = sin(phase1);
			float sample2 = sin(phase2);
			float sample3 = sin(phase3);

			voice1[i] = sample1 * volume;
			voice2[i] = sample2 * volume;
			voice3[i] = sample3 * volume;

			output[i*nChannels] = output[i*nChannels + 1] = voice1[i] + voice2[i] + voice3[i];
		}
	}

}

//--------------------------------------------------------------
void hsApp::gotMessage(ofMessage msg)
{
}

//--------------------------------------------------------------
void hsApp::dragEvent(ofDragInfo dragInfo)
{
}
<|endoftext|>


<commit_before>#include "sprite_batch.hpp"

namespace mo {
namespace renderer {

	using namespace renderer;

	bool talkative = false;

	// layout description for vertices
	Vertex_layout layout {
		Vertex_layout::Mode::triangles,
		vertex("position",  &Sprite_batch::SpriteVertex::pos),
		vertex("uv",        &Sprite_batch::SpriteVertex::uv)
	};

	Sprite_batch::Sprite_batch(asset::Asset_manager& asset_manager) : _object(layout, create_buffer(_vertices, true)){
		_shader.attach_shader(asset_manager.load<Shader>("vert_shader:sprite_batch"_aid))
			   .attach_shader(asset_manager.load<Shader>("frag_shader:sprite_batch"_aid))
		       .bind_all_attribute_locations(layout)
		       .build();
	}

	void Sprite_batch::draw(const Camera& cam, const Sprite& sprite) noexcept {

		float x = sprite.position.x.value(), y = sprite.position.y.value();
		glm::vec4 uv = glm::vec4(sprite.uv);

		// Rotation Matrix to be applied to coords of the Sprite
		glm::mat4 rotMat = glm::translate(glm::vec3(x + 0.5f, y + 0.5f, 0.f)) *
				glm::rotate(sprite.rotation -1.5707f, glm::vec3(0.f, 0.f, 1.f)) * glm::translate(-glm::vec3(x + 0.5f, y + 0.5f, 0.f));

//		std::cout << "Entity with Sprite Component at: " << x << "/" << y << std::endl;
//		std::cout << "Name of attached texture: " << sprite.texture.str() << std::endl;
//		std::cout << "rotation is: " << sprite.rotation << std::endl;

		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x, y, 0.0f, 1.0f), {uv.x, uv.w}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x, y+1.f, 0.0f, 1.0f), {uv.x, uv.y}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x+1.f, y+1.f, 0.0f, 1.0f), {uv.z, uv.y}, &sprite.texture));

		//_vertices.push_back({{x, y}, {uv.x, uv.w}, {sprite.texture}});
		//_vertices.push_back({{x, y+1.f}, {uv.x, uv.y}, {sprite.texture}});
		//_vertices.push_back({{x+1.f, y+1.f}, {uv.z, uv.y}, {sprite.texture}});

		if(talkative){
			// DEBUG CODE TO CHECK GIVEN UV DATA AND POS OF FIRST TRIANGLE
			std::cout << "x / y -> " << x << "/" << y << std::endl;
			std::cout << "ux / uy -> " << uv.x << "/" << uv.w << std::endl;
			std::cout << "x / y -> " << x << "/" << y+1 << std::endl;
			std::cout << "ux / uy -> " << uv.x << "/" << uv.y << std::endl;
			std::cout << "x / y -> " << x+1 << "/" << y+1 << std::endl;
			std::cout << "ux / uy -> " << uv.z << "/" << uv.y << std::endl;
		}

		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x+1.f, y+1.f, 0.0f, 1.0f), {uv.z, uv.y}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x, y, 0.0f, 1.0f), {uv.x, uv.w}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x+1.f, y, 0.0f, 1.0f), {uv.z, uv.w}, &sprite.texture));

		//_vertices.push_back({{x+1.f, y+1.f}, {uv.z, uv.y}, {sprite.texture}});
		//_vertices.push_back({{x, y}, {uv.x, uv.w}, {sprite.texture}});
		//_vertices.push_back({{x+1.f, y}, {uv.z, uv.w}, {sprite.texture}});

	}

	void Sprite_batch::drawAll(const Camera& cam) noexcept {

		glm::mat4 MVP = cam.vp();
		_shader.bind()
			   .set_uniform("MVP", MVP)
			   .set_uniform("myTextureSampler", 0);

		std::vector<unsigned int> iterPos;

		// Sorting the vertices by used texture
		// so that blocks of vertices are bound together
		// where the textures match each other -> less switching in texture binding
		std::stable_sort(_vertices.begin(), _vertices.end());

		// Mark positions, where the texture references differ from the one before
		const Texture* curTex = _vertices.at(0).tex;
		for(unsigned int i = 0; i < _vertices.size(); i++){
			if(curTex != _vertices.at(i).tex){
				iterPos.push_back(i);
				curTex = _vertices.at(i).tex;
				//std::cout << "Other tex than before at pos: " << i << std::endl;
			}
		}

		// Draw the vertices and bind the corresponding right texture
		unsigned int begin = 0;
		unsigned int end = iterPos.at(0);
		for(unsigned int i = 0; i <= iterPos.size(); i++){
			_object.buffer().set<SpriteVertex>(_vertices.begin() + begin, _vertices.begin() + end);
			_vertices.at(begin).tex->bind();
			_object.draw();
			//std::cout << "Begin: " << begin << " & End: " << end << std::endl << std::endl;
			begin = (i < iterPos.size()) ? iterPos.at(i) : iterPos.at(i-1);
			end = (i+1 < iterPos.size()) ? iterPos.at(i+1) : _vertices.size();
		}

		// TODO: nullptr check

		_vertices.clear();

	}

}
}
<commit_msg>bugfix<commit_after>#include "sprite_batch.hpp"

namespace mo {
namespace renderer {

	using namespace renderer;

	bool talkative = false;

	// layout description for vertices
	Vertex_layout layout {
		Vertex_layout::Mode::triangles,
		vertex("position",  &Sprite_batch::SpriteVertex::pos),
		vertex("uv",        &Sprite_batch::SpriteVertex::uv)
	};

	Sprite_batch::Sprite_batch(asset::Asset_manager& asset_manager) : _object(layout, create_buffer(_vertices, true)){
		_shader.attach_shader(asset_manager.load<Shader>("vert_shader:sprite_batch"_aid))
			   .attach_shader(asset_manager.load<Shader>("frag_shader:sprite_batch"_aid))
		       .bind_all_attribute_locations(layout)
		       .build();
	}

	void Sprite_batch::draw(const Camera& cam, const Sprite& sprite) noexcept {

		float x = sprite.position.x.value(), y = sprite.position.y.value();
		glm::vec4 uv = glm::vec4(sprite.uv);

		// Rotation Matrix to be applied to coords of the Sprite
		glm::mat4 rotMat = glm::translate(glm::vec3(x + 0.5f, y + 0.5f, 0.f)) *
				glm::rotate(sprite.rotation -1.5707f, glm::vec3(0.f, 0.f, 1.f)) * glm::translate(-glm::vec3(x + 0.5f, y + 0.5f, 0.f));

//		std::cout << "Entity with Sprite Component at: " << x << "/" << y << std::endl;
//		std::cout << "Name of attached texture: " << sprite.texture.str() << std::endl;
//		std::cout << "rotation is: " << sprite.rotation << std::endl;

		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x, y, 0.0f, 1.0f), {uv.x, uv.w}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x, y+1.f, 0.0f, 1.0f), {uv.x, uv.y}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x+1.f, y+1.f, 0.0f, 1.0f), {uv.z, uv.y}, &sprite.texture));

		//_vertices.push_back({{x, y}, {uv.x, uv.w}, {sprite.texture}});
		//_vertices.push_back({{x, y+1.f}, {uv.x, uv.y}, {sprite.texture}});
		//_vertices.push_back({{x+1.f, y+1.f}, {uv.z, uv.y}, {sprite.texture}});

		if(talkative){
			// DEBUG CODE TO CHECK GIVEN UV DATA AND POS OF FIRST TRIANGLE
			std::cout << "x / y -> " << x << "/" << y << std::endl;
			std::cout << "ux / uy -> " << uv.x << "/" << uv.w << std::endl;
			std::cout << "x / y -> " << x << "/" << y+1 << std::endl;
			std::cout << "ux / uy -> " << uv.x << "/" << uv.y << std::endl;
			std::cout << "x / y -> " << x+1 << "/" << y+1 << std::endl;
			std::cout << "ux / uy -> " << uv.z << "/" << uv.y << std::endl;
		}

		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x+1.f, y+1.f, 0.0f, 1.0f), {uv.z, uv.y}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x, y, 0.0f, 1.0f), {uv.x, uv.w}, &sprite.texture));
		_vertices.push_back(SpriteVertex(rotMat * glm::vec4(x+1.f, y, 0.0f, 1.0f), {uv.z, uv.w}, &sprite.texture));

		//_vertices.push_back({{x+1.f, y+1.f}, {uv.z, uv.y}, {sprite.texture}});
		//_vertices.push_back({{x, y}, {uv.x, uv.w}, {sprite.texture}});
		//_vertices.push_back({{x+1.f, y}, {uv.z, uv.w}, {sprite.texture}});

	}

	void Sprite_batch::drawAll(const Camera& cam) noexcept {

		glm::mat4 MVP = cam.vp();
		_shader.bind()
			   .set_uniform("MVP", MVP)
			   .set_uniform("myTextureSampler", 0);

		std::vector<unsigned int> iterPos;

		// Sorting the vertices by used texture
		// so that blocks of vertices are bound together
		// where the textures match each other -> less switching in texture binding
		std::stable_sort(_vertices.begin(), _vertices.end());

		// Mark positions, where the texture references differ from the one before
		const Texture* curTex = _vertices.at(0).tex;
		for(unsigned int i = 0; i < _vertices.size(); i++){
			if(curTex != _vertices.at(i).tex){
				iterPos.push_back(i);
				curTex = _vertices.at(i).tex;
				//std::cout << "Other tex than before at pos: " << i << std::endl;
			}
		}

		// Draw the vertices and bind the corresponding right texture
		unsigned int begin = 0;
		unsigned int end = (iterPos.size() > 0) ? iterPos.at(0) : _vertices.size();
		_object.buffer().set<SpriteVertex>(_vertices.begin() + begin, _vertices.begin() + end);
		_vertices.at(begin).tex->bind();
		_object.draw();

		for(unsigned int i = 0; i < iterPos.size(); i++){
			begin = (i < iterPos.size()) ? iterPos.at(i) : iterPos.at(i-1);
			end = (i+1 < iterPos.size()) ? iterPos.at(i+1) : _vertices.size();
			_object.buffer().set<SpriteVertex>(_vertices.begin() + begin, _vertices.begin() + end);
			_vertices.at(begin).tex->bind();
			_object.draw();
			//std::cout << "Begin: " << begin << " & End: " << end << std::endl << std::endl;
		}

		// TODO: nullptr check

		_vertices.clear();

	}

}
}
<|endoftext|>