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

#include "SkPDFFormXObject.h"
#include "SkPDFGraphicState.h"
#include "SkPDFUtils.h"
#include "SkStream.h"
#include "SkTypes.h"

static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
    switch (mode) {
        case SkXfermode::kSrcOver_Mode:    return "Normal";
        case SkXfermode::kModulate_Mode:   return "Multiply";
        case SkXfermode::kScreen_Mode:     return "Screen";
        case SkXfermode::kOverlay_Mode:    return "Overlay";
        case SkXfermode::kDarken_Mode:     return "Darken";
        case SkXfermode::kLighten_Mode:    return "Lighten";
        case SkXfermode::kColorDodge_Mode: return "ColorDodge";
        case SkXfermode::kColorBurn_Mode:  return "ColorBurn";
        case SkXfermode::kHardLight_Mode:  return "HardLight";
        case SkXfermode::kSoftLight_Mode:  return "SoftLight";
        case SkXfermode::kDifference_Mode: return "Difference";
        case SkXfermode::kExclusion_Mode:  return "Exclusion";

        // These are handled in SkPDFDevice::setUpContentEntry.
        case SkXfermode::kClear_Mode:
        case SkXfermode::kSrc_Mode:
        case SkXfermode::kDst_Mode:
        case SkXfermode::kDstOver_Mode:
        case SkXfermode::kSrcIn_Mode:
        case SkXfermode::kDstIn_Mode:
        case SkXfermode::kSrcOut_Mode:
        case SkXfermode::kDstOut_Mode:
            return "Normal";

        // TODO(vandebo): Figure out if we can support more of these modes.
        case SkXfermode::kSrcATop_Mode:
        case SkXfermode::kDstATop_Mode:
        case SkXfermode::kXor_Mode:
        case SkXfermode::kPlus_Mode:
            return NULL;
    }
    return NULL;
}

SkPDFGraphicState::~SkPDFGraphicState() {
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
    if (!fSMask) {
        int index = Find(fPaint);
        SkASSERT(index >= 0);
        SkASSERT(CanonicalPaints()[index].fGraphicState == this);
        CanonicalPaints().removeShuffle(index);
    }
    fResources.unrefAll();
}

void SkPDFGraphicState::getResources(SkTDArray<SkPDFObject*>* resourceList) {
    GetResourcesHelper(&fResources, resourceList);
}

void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
                                   bool indirect) {
    populateDict();
    SkPDFDict::emitObject(stream, catalog, indirect);
}

// static
size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    populateDict();
    return SkPDFDict::getOutputSize(catalog, indirect);
}

// static
SkTDArray<SkPDFGraphicState::GSCanonicalEntry>&
SkPDFGraphicState::CanonicalPaints() {
    // This initialization is only thread safe with gcc.
    static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints;
    return gCanonicalPaints;
}

// static
SkBaseMutex& SkPDFGraphicState::CanonicalPaintsMutex() {
    // This initialization is only thread safe with gcc or when
    // POD-style mutex initialization is used.
    SK_DECLARE_STATIC_MUTEX(gCanonicalPaintsMutex);
    return gCanonicalPaintsMutex;
}

// static
SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(
        const SkPaint& paint) {
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
    int index = Find(paint);
    if (index >= 0) {
        CanonicalPaints()[index].fGraphicState->ref();
        return CanonicalPaints()[index].fGraphicState;
    }
    GSCanonicalEntry newEntry(new SkPDFGraphicState(paint));
    CanonicalPaints().push(newEntry);
    return newEntry.fGraphicState;
}

// static
SkPDFObject* SkPDFGraphicState::GetInvertFunction() {
    // This assumes that canonicalPaintsMutex is held.
    static SkPDFStream* invertFunction = NULL;
    if (!invertFunction) {
        // Acrobat crashes if we use a type 0 function, kpdf crashes if we use
        // a type 2 function, so we use a type 4 function.
        SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray);
        domainAndRange->reserve(2);
        domainAndRange->appendInt(0);
        domainAndRange->appendInt(1);

        static const char psInvert[] = "{1 exch sub}";
        SkAutoTUnref<SkMemoryStream> psInvertStream(
            new SkMemoryStream(&psInvert, strlen(psInvert), true));

        invertFunction = new SkPDFStream(psInvertStream.get());
        invertFunction->insertInt("FunctionType", 4);
        invertFunction->insert("Domain", domainAndRange.get());
        invertFunction->insert("Range", domainAndRange.get());
    }
    return invertFunction;
}

// static
SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState(
        SkPDFFormXObject* sMask, bool invert) {
    // The practical chances of using the same mask more than once are unlikely
    // enough that it's not worth canonicalizing.
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());

    SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask"));
    sMaskDict->insertName("S", "Alpha");
    sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref();

    SkPDFGraphicState* result = new SkPDFGraphicState;
    result->fPopulated = true;
    result->fSMask = true;
    result->insertName("Type", "ExtGState");
    result->insert("SMask", sMaskDict.get());
    result->fResources.push(sMask);
    sMask->ref();

    if (invert) {
        SkPDFObject* invertFunction = GetInvertFunction();
        result->fResources.push(invertFunction);
        invertFunction->ref();
        sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref();
    }

    return result;
}

// static
SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() {
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
    static SkPDFGraphicState* noSMaskGS = NULL;
    if (!noSMaskGS) {
        noSMaskGS = new SkPDFGraphicState;
        noSMaskGS->fPopulated = true;
        noSMaskGS->fSMask = true;
        noSMaskGS->insertName("Type", "ExtGState");
        noSMaskGS->insertName("SMask", "None");
    }
    noSMaskGS->ref();
    return noSMaskGS;
}

// static
int SkPDFGraphicState::Find(const SkPaint& paint) {
    GSCanonicalEntry search(&paint);
    return CanonicalPaints().find(search);
}

SkPDFGraphicState::SkPDFGraphicState()
    : fPopulated(false),
      fSMask(false) {
}

SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint)
    : fPaint(paint),
      fPopulated(false),
      fSMask(false) {
}

// populateDict and operator== have to stay in sync with each other.
void SkPDFGraphicState::populateDict() {
    if (!fPopulated) {
        fPopulated = true;
        insertName("Type", "ExtGState");

        SkAutoTUnref<SkPDFScalar> alpha(
            new SkPDFScalar(SkScalarDiv(fPaint.getAlpha(), 0xFF)));
        insert("CA", alpha.get());
        insert("ca", alpha.get());

        SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch);
        SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2);
        insertInt("LC", fPaint.getStrokeCap());

        SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch);
        SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2);
        insertInt("LJ", fPaint.getStrokeJoin());

        insertScalar("LW", fPaint.getStrokeWidth());
        insertScalar("ML", fPaint.getStrokeMiter());
        insert("SA", new SkPDFBool(true))->unref();  // Auto stroke adjustment.

        SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
        // If asMode fails, default to kSrcOver_Mode.
        if (fPaint.getXfermode())
            fPaint.getXfermode()->asMode(&xfermode);
        // If we don't support the mode, just use kSrcOver_Mode.
        if (xfermode < 0 || xfermode > SkXfermode::kLastMode ||
                blend_mode_from_xfermode(xfermode) == NULL) {
            xfermode = SkXfermode::kSrcOver_Mode;
            NOT_IMPLEMENTED("unsupported xfermode", false);
        }
        insertName("BM", blend_mode_from_xfermode(xfermode));
    }
}

// We're only interested in some fields of the SkPaint, so we have a custom
// operator== function.
bool SkPDFGraphicState::GSCanonicalEntry::operator==(
        const SkPDFGraphicState::GSCanonicalEntry& gs) const {
    const SkPaint* a = fPaint;
    const SkPaint* b = gs.fPaint;
    SkASSERT(a != NULL);
    SkASSERT(b != NULL);

    if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) ||
           a->getStrokeCap() != b->getStrokeCap() ||
           a->getStrokeJoin() != b->getStrokeJoin() ||
           a->getStrokeWidth() != b->getStrokeWidth() ||
           a->getStrokeMiter() != b->getStrokeMiter()) {
        return false;
    }

    SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode;
    SkXfermode* aXfermode = a->getXfermode();
    if (aXfermode) {
        aXfermode->asMode(&aXfermodeName);
    }
    if (aXfermodeName < 0 || aXfermodeName > SkXfermode::kLastMode ||
            blend_mode_from_xfermode(aXfermodeName) == NULL) {
        aXfermodeName = SkXfermode::kSrcOver_Mode;
    }
    const char* aXfermodeString = blend_mode_from_xfermode(aXfermodeName);
    SkASSERT(aXfermodeString != NULL);

    SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode;
    SkXfermode* bXfermode = b->getXfermode();
    if (bXfermode) {
        bXfermode->asMode(&bXfermodeName);
    }
    if (bXfermodeName < 0 || bXfermodeName > SkXfermode::kLastMode ||
            blend_mode_from_xfermode(bXfermodeName) == NULL) {
        bXfermodeName = SkXfermode::kSrcOver_Mode;
    }
    const char* bXfermodeString = blend_mode_from_xfermode(bXfermodeName);
    SkASSERT(bXfermodeString != NULL);

    return strcmp(aXfermodeString, bXfermodeString) == 0;
}
<commit_msg>add kMultiply_Mode to switch statement (fix warning)<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkPDFFormXObject.h"
#include "SkPDFGraphicState.h"
#include "SkPDFUtils.h"
#include "SkStream.h"
#include "SkTypes.h"

static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
    switch (mode) {
        case SkXfermode::kSrcOver_Mode:    return "Normal";
        case SkXfermode::kModulate_Mode:   return "Multiply";
        case SkXfermode::kScreen_Mode:     return "Screen";
        case SkXfermode::kOverlay_Mode:    return "Overlay";
        case SkXfermode::kDarken_Mode:     return "Darken";
        case SkXfermode::kLighten_Mode:    return "Lighten";
        case SkXfermode::kColorDodge_Mode: return "ColorDodge";
        case SkXfermode::kColorBurn_Mode:  return "ColorBurn";
        case SkXfermode::kHardLight_Mode:  return "HardLight";
        case SkXfermode::kSoftLight_Mode:  return "SoftLight";
        case SkXfermode::kDifference_Mode: return "Difference";
        case SkXfermode::kExclusion_Mode:  return "Exclusion";

        // These are handled in SkPDFDevice::setUpContentEntry.
        case SkXfermode::kClear_Mode:
        case SkXfermode::kSrc_Mode:
        case SkXfermode::kDst_Mode:
        case SkXfermode::kDstOver_Mode:
        case SkXfermode::kSrcIn_Mode:
        case SkXfermode::kDstIn_Mode:
        case SkXfermode::kSrcOut_Mode:
        case SkXfermode::kDstOut_Mode:
            return "Normal";

        // TODO(vandebo): Figure out if we can support more of these modes.
        case SkXfermode::kSrcATop_Mode:
        case SkXfermode::kDstATop_Mode:
        case SkXfermode::kXor_Mode:
        case SkXfermode::kPlus_Mode:
        case SkXfermode::kMultiply_Mode:
            return NULL;
    }
    return NULL;
}

SkPDFGraphicState::~SkPDFGraphicState() {
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
    if (!fSMask) {
        int index = Find(fPaint);
        SkASSERT(index >= 0);
        SkASSERT(CanonicalPaints()[index].fGraphicState == this);
        CanonicalPaints().removeShuffle(index);
    }
    fResources.unrefAll();
}

void SkPDFGraphicState::getResources(SkTDArray<SkPDFObject*>* resourceList) {
    GetResourcesHelper(&fResources, resourceList);
}

void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
                                   bool indirect) {
    populateDict();
    SkPDFDict::emitObject(stream, catalog, indirect);
}

// static
size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    populateDict();
    return SkPDFDict::getOutputSize(catalog, indirect);
}

// static
SkTDArray<SkPDFGraphicState::GSCanonicalEntry>&
SkPDFGraphicState::CanonicalPaints() {
    // This initialization is only thread safe with gcc.
    static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints;
    return gCanonicalPaints;
}

// static
SkBaseMutex& SkPDFGraphicState::CanonicalPaintsMutex() {
    // This initialization is only thread safe with gcc or when
    // POD-style mutex initialization is used.
    SK_DECLARE_STATIC_MUTEX(gCanonicalPaintsMutex);
    return gCanonicalPaintsMutex;
}

// static
SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(
        const SkPaint& paint) {
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
    int index = Find(paint);
    if (index >= 0) {
        CanonicalPaints()[index].fGraphicState->ref();
        return CanonicalPaints()[index].fGraphicState;
    }
    GSCanonicalEntry newEntry(new SkPDFGraphicState(paint));
    CanonicalPaints().push(newEntry);
    return newEntry.fGraphicState;
}

// static
SkPDFObject* SkPDFGraphicState::GetInvertFunction() {
    // This assumes that canonicalPaintsMutex is held.
    static SkPDFStream* invertFunction = NULL;
    if (!invertFunction) {
        // Acrobat crashes if we use a type 0 function, kpdf crashes if we use
        // a type 2 function, so we use a type 4 function.
        SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray);
        domainAndRange->reserve(2);
        domainAndRange->appendInt(0);
        domainAndRange->appendInt(1);

        static const char psInvert[] = "{1 exch sub}";
        SkAutoTUnref<SkMemoryStream> psInvertStream(
            new SkMemoryStream(&psInvert, strlen(psInvert), true));

        invertFunction = new SkPDFStream(psInvertStream.get());
        invertFunction->insertInt("FunctionType", 4);
        invertFunction->insert("Domain", domainAndRange.get());
        invertFunction->insert("Range", domainAndRange.get());
    }
    return invertFunction;
}

// static
SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState(
        SkPDFFormXObject* sMask, bool invert) {
    // The practical chances of using the same mask more than once are unlikely
    // enough that it's not worth canonicalizing.
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());

    SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask"));
    sMaskDict->insertName("S", "Alpha");
    sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref();

    SkPDFGraphicState* result = new SkPDFGraphicState;
    result->fPopulated = true;
    result->fSMask = true;
    result->insertName("Type", "ExtGState");
    result->insert("SMask", sMaskDict.get());
    result->fResources.push(sMask);
    sMask->ref();

    if (invert) {
        SkPDFObject* invertFunction = GetInvertFunction();
        result->fResources.push(invertFunction);
        invertFunction->ref();
        sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref();
    }

    return result;
}

// static
SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() {
    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
    static SkPDFGraphicState* noSMaskGS = NULL;
    if (!noSMaskGS) {
        noSMaskGS = new SkPDFGraphicState;
        noSMaskGS->fPopulated = true;
        noSMaskGS->fSMask = true;
        noSMaskGS->insertName("Type", "ExtGState");
        noSMaskGS->insertName("SMask", "None");
    }
    noSMaskGS->ref();
    return noSMaskGS;
}

// static
int SkPDFGraphicState::Find(const SkPaint& paint) {
    GSCanonicalEntry search(&paint);
    return CanonicalPaints().find(search);
}

SkPDFGraphicState::SkPDFGraphicState()
    : fPopulated(false),
      fSMask(false) {
}

SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint)
    : fPaint(paint),
      fPopulated(false),
      fSMask(false) {
}

// populateDict and operator== have to stay in sync with each other.
void SkPDFGraphicState::populateDict() {
    if (!fPopulated) {
        fPopulated = true;
        insertName("Type", "ExtGState");

        SkAutoTUnref<SkPDFScalar> alpha(
            new SkPDFScalar(SkScalarDiv(fPaint.getAlpha(), 0xFF)));
        insert("CA", alpha.get());
        insert("ca", alpha.get());

        SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch);
        SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2);
        insertInt("LC", fPaint.getStrokeCap());

        SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch);
        SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch);
        SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2);
        insertInt("LJ", fPaint.getStrokeJoin());

        insertScalar("LW", fPaint.getStrokeWidth());
        insertScalar("ML", fPaint.getStrokeMiter());
        insert("SA", new SkPDFBool(true))->unref();  // Auto stroke adjustment.

        SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
        // If asMode fails, default to kSrcOver_Mode.
        if (fPaint.getXfermode())
            fPaint.getXfermode()->asMode(&xfermode);
        // If we don't support the mode, just use kSrcOver_Mode.
        if (xfermode < 0 || xfermode > SkXfermode::kLastMode ||
                blend_mode_from_xfermode(xfermode) == NULL) {
            xfermode = SkXfermode::kSrcOver_Mode;
            NOT_IMPLEMENTED("unsupported xfermode", false);
        }
        insertName("BM", blend_mode_from_xfermode(xfermode));
    }
}

// We're only interested in some fields of the SkPaint, so we have a custom
// operator== function.
bool SkPDFGraphicState::GSCanonicalEntry::operator==(
        const SkPDFGraphicState::GSCanonicalEntry& gs) const {
    const SkPaint* a = fPaint;
    const SkPaint* b = gs.fPaint;
    SkASSERT(a != NULL);
    SkASSERT(b != NULL);

    if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) ||
           a->getStrokeCap() != b->getStrokeCap() ||
           a->getStrokeJoin() != b->getStrokeJoin() ||
           a->getStrokeWidth() != b->getStrokeWidth() ||
           a->getStrokeMiter() != b->getStrokeMiter()) {
        return false;
    }

    SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode;
    SkXfermode* aXfermode = a->getXfermode();
    if (aXfermode) {
        aXfermode->asMode(&aXfermodeName);
    }
    if (aXfermodeName < 0 || aXfermodeName > SkXfermode::kLastMode ||
            blend_mode_from_xfermode(aXfermodeName) == NULL) {
        aXfermodeName = SkXfermode::kSrcOver_Mode;
    }
    const char* aXfermodeString = blend_mode_from_xfermode(aXfermodeName);
    SkASSERT(aXfermodeString != NULL);

    SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode;
    SkXfermode* bXfermode = b->getXfermode();
    if (bXfermode) {
        bXfermode->asMode(&bXfermodeName);
    }
    if (bXfermodeName < 0 || bXfermodeName > SkXfermode::kLastMode ||
            blend_mode_from_xfermode(bXfermodeName) == NULL) {
        bXfermodeName = SkXfermode::kSrcOver_Mode;
    }
    const char* bXfermodeString = blend_mode_from_xfermode(bXfermodeName);
    SkASSERT(bXfermodeString != NULL);

    return strcmp(aXfermodeString, bXfermodeString) == 0;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CommandCd.h"

CommandCd::CommandCd()
{
}

CommandCd::~CommandCd()
{
}

bool CommandCd::ShouldRunThisCommand(ParsedCommand* Parsed)
{
	return (Parsed->Words->at(0) == "cd");
}

void CommandCd::Run(ParsedCommand* Parsed)
{
	if (Parsed->Words->size() < 2)
	{
		Console->WriteLine("Missing required argument.");
	}
	else
	{
		//If we need to go up a directory.
		if (Parsed->Words->at(1) == "..")
		{
			this->GotoParentDir();
			Console->WriteLine(FilePath);
			return;
		}

		//If we need to stay at the same one.
		if (Parsed->Words->at(1) == ".")
		{
			return;
		}

		//If we want to go deeper into a subdirectory.
		this->CdNormal(Parsed);

		Console->WriteLine(FilePath);
	}
}

string* CommandCd::GetName()
{
	return new string("CD");
}

string* CommandCd::GetHelp()
{
	return new string("Changes the directory we are working from, just like in CMD. Cd \"..\" goes up to the parent directory, while cd \".\" goes to the current directory.");
}

void CommandCd::GotoParentDir()
{
	bool Slashfound = false;

	register size_t i = FilePath->size();

	while (i != 0)
	{
		if (FilePath->at(i - 1) == '\\')
		{
			if (!Slashfound)
			{
				//Found the first slash
				Slashfound = true;
			}
			else
			{
				//Found the second slash, calculating how many characters to remove from the end of the path string.
				size_t pop = FilePath->size() - i;

				while (pop != 0)
				{
					FilePath->pop_back();
					--pop;
				}
				break;
			}
		}
		--i;
	}
}

void CommandCd::CdNormal(ParsedCommand* Parsed)
{
	string arg = *FilePath;
	register size_t i;
	register size_t length = Parsed->Words->size();

	for (i = 0; i < length; i++)
	{

		if (i != 0)
		{
			arg.append(Parsed->Words->at(i));
		}
	}

	if (Files->DoesDirectoryExist(&arg))
	{
		FilePath->append(Parsed->Words->at(1));
		FilePath->append("\\");
	}
	else
	{
		string invalid = "Invalid directory: ";
		invalid.append(arg);
		Console->WriteLine("Directory does not exist!");
		Console->WriteLine(&invalid);
	}
}
<commit_msg>TODO:<commit_after>#include "stdafx.h"
#include "CommandCd.h"

CommandCd::CommandCd()
{
}

CommandCd::~CommandCd()
{
}

bool CommandCd::ShouldRunThisCommand(ParsedCommand* Parsed)
{
	return (Parsed->Words->at(0) == "cd");
}

void CommandCd::Run(ParsedCommand* Parsed)
{
	//If there is a space in the filepath, we need to reparse the input directly.
	if (Parsed->Words->size() < 2)
	{
		Console->WriteLine("Missing required argument.");
	}
	else
	{
		//If we need to go up a directory.
		if (Parsed->Words->at(1) == "..")
		{
			this->GotoParentDir();
			Console->WriteLine(FilePath);
			return;
		}

		//If we need to stay at the same one.
		if (Parsed->Words->at(1) == ".")
		{
			return;
		}

		//If we want to go deeper into a subdirectory.
		this->CdNormal(Parsed);

		Console->WriteLine(FilePath);
	}
}

string* CommandCd::GetName()
{
	return new string("CD");
}

string* CommandCd::GetHelp()
{
	return new string("Changes the directory we are working from, just like in CMD. Cd \"..\" goes up to the parent directory, while cd \".\" goes to the current directory.");
}

void CommandCd::GotoParentDir()
{
	bool Slashfound = false;

	register size_t i = FilePath->size();

	while (i != 0)
	{
		if (FilePath->at(i - 1) == '\\')
		{
			if (!Slashfound)
			{
				//Found the first slash
				Slashfound = true;
			}
			else
			{
				//Found the second slash, calculating how many characters to remove from the end of the path string.
				size_t pop = FilePath->size() - i;

				while (pop != 0)
				{
					FilePath->pop_back();
					--pop;
				}
				break;
			}
		}
		--i;
	}
}

void CommandCd::CdNormal(ParsedCommand* Parsed)
{
	string arg = *FilePath;
	register size_t i;
	register size_t length = Parsed->Words->size();

	for (i = 0; i < length; i++)
	{

		if (i != 0)
		{
			arg.append(Parsed->Words->at(i));
		}
	}

	if (Files->DoesDirectoryExist(&arg))
	{
		FilePath->append(Parsed->Words->at(1));
		FilePath->append("\\");
	}
	else
	{
		string invalid = "Invalid directory: ";
		invalid.append(arg);
		Console->WriteLine("Directory does not exist!");
		Console->WriteLine(&invalid);
	}
}
<|endoftext|>


<commit_before>/* Tests a kernel with an infinite loop.

   Copyright (c) 2012 Pekka Jääskeläinen / Tampere University of Technology

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

// Enable OpenCL C++ exceptions
#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <unistd.h>

#define WORK_ITEMS 1

static char
kernelSourceCode[] =
"void test_arrays_float(global int* data, int const ndata)\n"
"{\n"
"  float s = 0.0f;\n"
"  for (int i=0; i<ndata; ++i) {\n"
"    s += as_float(data[i]);\n"
"  }\n"
"  printf(\"sum=%g\\n\", s);\n"
"  for (;;);\n"
"}\n"
"\n"
"kernel void test_kernel(global int *input, global int* output)\n"
"{\n"
"  test_arrays_float(input, 2);\n"
"}\n";

int
main(void)
{
    int output[2];
    int input[2];
    input[0] = 1;
    input[1] = 2;

    try {
        std::vector<cl::Platform> platformList;

        // Pick platform
        cl::Platform::get(&platformList);

        // Pick first platform
        cl_context_properties cprops[] = {
            CL_CONTEXT_PLATFORM, (cl_context_properties)(platformList[0])(), 0};
        cl::Context context(CL_DEVICE_TYPE_CPU, cprops);

        // Query the set of devices attched to the context
        std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();

        // Create and program from source
        cl::Program::Sources sources(1, std::make_pair(kernelSourceCode, 0));
        cl::Program program(context, sources);

        // Build program
        program.build(devices);

        // Create buffer for that uses the host ptr C
        cl::Buffer outBuffer = cl::Buffer(
            context,
            CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
            2 * sizeof(int),
            (void *) &output[0]);

        cl::Buffer inBuffer = cl::Buffer(
            context,
            CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
            2 * sizeof(int),
            (void *) &input[0]);

        // Create kernel object
        cl::Kernel kernel(program, "test_kernel");

        // Set kernel args
        kernel.setArg(0, 2*sizeof(int), &inBuffer);
        kernel.setArg(1, 2*sizeof(int), &outBuffer);

        // Create command queue
        cl::CommandQueue queue(context, devices[0], 0);

        // Do the work
        queue.enqueueNDRangeKernel(
            kernel,
            cl::NullRange,
            cl::NDRange(1),
            cl::NullRange);

        /* The call should return cleanly, the compiler should not crash. */

        /* Force exit of the process regardless of the running kernel thread
           by replacing the process with a dummy process. */
        execlp("true", NULL, NULL);
    }
    catch (cl::Error err) {
         std::cerr
             << "ERROR: "
             << err.what()
             << "("
             << err.err()
             << ")"
             << std::endl;

         return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
<commit_msg>Parameter arg0 must contain executable file name (can not be NULL).<commit_after>/* Tests a kernel with an infinite loop.

   Copyright (c) 2012 Pekka Jääskeläinen / Tampere University of Technology

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

// Enable OpenCL C++ exceptions
#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <unistd.h>

#define WORK_ITEMS 1

static char
kernelSourceCode[] =
"void test_arrays_float(global int* data, int const ndata)\n"
"{\n"
"  float s = 0.0f;\n"
"  for (int i=0; i<ndata; ++i) {\n"
"    s += as_float(data[i]);\n"
"  }\n"
"  printf(\"sum=%g\\n\", s);\n"
"  for (;;);\n"
"}\n"
"\n"
"kernel void test_kernel(global int *input, global int* output)\n"
"{\n"
"  test_arrays_float(input, 2);\n"
"}\n";

int
main(void)
{
    int output[2];
    int input[2];
    input[0] = 1;
    input[1] = 2;

    try {
        std::vector<cl::Platform> platformList;

        // Pick platform
        cl::Platform::get(&platformList);

        // Pick first platform
        cl_context_properties cprops[] = {
            CL_CONTEXT_PLATFORM, (cl_context_properties)(platformList[0])(), 0};
        cl::Context context(CL_DEVICE_TYPE_CPU, cprops);

        // Query the set of devices attched to the context
        std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();

        // Create and program from source
        cl::Program::Sources sources(1, std::make_pair(kernelSourceCode, 0));
        cl::Program program(context, sources);

        // Build program
        program.build(devices);

        // Create buffer for that uses the host ptr C
        cl::Buffer outBuffer = cl::Buffer(
            context,
            CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
            2 * sizeof(int),
            (void *) &output[0]);

        cl::Buffer inBuffer = cl::Buffer(
            context,
            CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR,
            2 * sizeof(int),
            (void *) &input[0]);

        // Create kernel object
        cl::Kernel kernel(program, "test_kernel");

        // Set kernel args
        kernel.setArg(0, 2*sizeof(int), &inBuffer);
        kernel.setArg(1, 2*sizeof(int), &outBuffer);

        // Create command queue
        cl::CommandQueue queue(context, devices[0], 0);

        // Do the work
        queue.enqueueNDRangeKernel(
            kernel,
            cl::NullRange,
            cl::NDRange(1),
            cl::NullRange);

        /* The call should return cleanly, the compiler should not crash. */

        /* Force exit of the process regardless of the running kernel thread
           by replacing the process with a dummy process. */
        execlp("true", "true", NULL);
    }
    catch (cl::Error err) {
         std::cerr
             << "ERROR: "
             << err.what()
             << "("
             << err.err()
             << ")"
             << std::endl;

         return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "graphics/gFont.h"
#include "graphics/gBitmap.h"
#include "math/mRect.h"
#include "console/console.h"
#include "string/unicode.h"
#include "platformX86UNIX/platformX86UNIX.h"
#include "platformX86UNIX/x86UNIXFont.h"

// Needed by createFont
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/extensions/Xrender.h>      // For XRenderColor

// Needed for getenv in createFont
#include <stdlib.h>

XftFont *loadFont(const char *name, S32 size, Display *display)
{
  XftFont *fontInfo = NULL;
  char* fontname = const_cast<char*>(name);
  if (dStrlen(fontname)==0)
    fontname = "arial";
  else if (stristr(const_cast<char*>(name), "arial") != NULL)
    fontname = "arial";
  else if (stristr(const_cast<char*>(name), "lucida console") != NULL)
    fontname = "lucida console";

  char* weight = "medium";
  char* slant = "roman"; // no slant

  if (stristr(const_cast<char*>(name), "bold") != NULL)
    weight = "bold";
  if (stristr(const_cast<char*>(name), "italic") != NULL)
    slant = "italic";

  int mSize = size - 2 - (int)((float)size * 0.1);
  char xfontName[512];
  // We specify a lower DPI to get 'correct' looking fonts, if we go with the
  // native DPI the fonts are to big and don't fit the widgets.
  dSprintf(xfontName, 512, "%s-%d:%s:slant=%s:dpi=76", fontname, mSize, weight, slant);

  // Lets see if Xft can get a font for us.
  char xftname[1024];
  fontInfo = XftFontOpenName(display, DefaultScreen(display), xfontName);
  // Cant find a suitabke font, default to a known font (6x10)
  if ( !fontInfo )
    {
  	dSprintf(xfontName, 512, "6x10-%d:%s:slant=%s:dpi=76", mSize, weight, slant);
      fontInfo = XftFontOpenName(display, DefaultScreen(display), xfontName);
    }
      XftNameUnparse(fontInfo->pattern, xftname, 1024);

#ifdef DEBUG
      Con::printf("Font '%s %d' mapped to '%s'\n", name, size, xftname);
#endif

  return fontInfo;
}

// XA: New class for the unix unicode font
PlatformFont *createPlatformFont(const char *name, U32 size, U32 charset /* = TGE_ANSI_CHARSET */)
{
  PlatformFont *retFont = new x86UNIXFont;

  if(retFont->create(name, size, charset))
    return retFont;

  delete retFont;
  return NULL;
}

x86UNIXFont::x86UNIXFont()
{}

x86UNIXFont::~x86UNIXFont()
{}

bool x86UNIXFont::create(const char *name, U32 size, U32 charset)
{
  Display *display = XOpenDisplay(getenv("DISPLAY"));
  if (display == NULL)
    AssertFatal(false, "createFont: cannot connect to X server");

  XftFont *font = loadFont(name, size, display);

  if (!font)
  {
    Con::errorf("Error: Could not load font -%s-", name);
    return false;
  }
  char xfontname[1024];
  XftNameUnparse(font->pattern, xfontname, 1024);
#ifdef DEBUG
  Con::printf("CreateFont: request for %s %d, using %s", name, size, xfontname);
#endif
  // store some info about the font
  baseline = font->ascent;
  height = font->height;
  mFontName = StringTable->insert(xfontname);
  XftFontClose (display, font);
  // DISPLAY
  XCloseDisplay(display);

  return true;
}

bool x86UNIXFont::isValidChar(const UTF16 str) const
{
  // 0x20  == 32
  // 0x100 == 256
  if( str < 0x20 || str > 0x100 )
    return false;

  return true;
}

bool x86UNIXFont::isValidChar(const UTF8 *str) const
{

  return isValidChar(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
}

PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF16 ch) const
{
  Display *display = XOpenDisplay(getenv("DISPLAY"));
  if (!display )
    AssertFatal(false, "createFont: cannot connect to X server");

  static PlatformFont::CharInfo c;
  dMemset(&c, 0, sizeof(c));
  c.bitmapIndex = 0;
  c.xOffset     = 0;
  c.yOffset     = 0;

  XftFont *fontInfo  = XftFontOpenName(display, DefaultScreen(display), mFontName);
  if (!fontInfo)
  {
    //Try a fall back font before crashing..
    fontInfo  = XftFontOpenName(display, DefaultScreen(display), "lucida console-10:dpi=76");
    if (!fontInfo)
    {
      AssertFatal(false, "createFont: cannot load font");
    }
  }

  int screen = DefaultScreen(display);
  // Create the pixmap to draw on.
  Drawable pixmap = XCreatePixmap(display,
				  DefaultRootWindow(display),
				  fontInfo->max_advance_width,
				  fontInfo->height,
				  DefaultDepth(display, screen));
  // And the Xft wrapper around it.
  XftDraw *draw = XftDrawCreate(display,
                                pixmap,
                                DefaultVisual(display, screen),
                                DefaultColormap(display, screen));
  // Allocate some colors, we don't use XftColorAllocValue here as that
  // Don't appear to function correctly (or I'm using it wrong) As we only do
  // this twice per new un cached font it isn't that big of a penalty. (Each
  // call to XftColorAllocName involves a round trip to the X Server)
  XftColor black, white;
  XftColorAllocName(display,
                    DefaultVisual(display, screen),
                    DefaultColormap(display, screen),
                    "black",
                    &black);
  // White
  XftColorAllocName(display,
                    DefaultVisual(display, screen),
                    DefaultColormap(display, screen),
                    "white",
                    &white);

  XGlyphInfo charinfo;
  XftTextExtents16(display, fontInfo, &ch, 1, &charinfo);
  c.height     = fontInfo->height;
  c.xOrigin    = 0;
  c.yOrigin    = fontInfo->ascent;
  c.xIncrement = charinfo.xOff;
  c.width      = charinfo.xOff;
  // kick out early if the character is undrawable
  if( c.width == 0 || c.height == 0)
    return c;

  // allocate a greyscale bitmap and clear it.
  int bitmapDataSize = c.width * c.height;
  c.bitmapData = new U8[bitmapDataSize];
  dMemset(c.bitmapData, 0, bitmapDataSize);

  XftDrawRect (draw, &black, 0, 0, fontInfo->max_advance_width, fontInfo->height);
  XftDrawString16 (draw, &white, fontInfo, 0, fontInfo->ascent, &ch, 1);
  // grab the pixmap image

  XImage *ximage = XGetImage(display, pixmap, 0, 0,
			     charinfo.xOff, fontInfo->height,
			     AllPlanes, XYPixmap);
  if (!ximage)
    AssertFatal(false, "cannot get x image");
  int x, y;

  // grab each pixel and store it in the scratchPad
  for(y = 0; y < fontInfo->height; y++)
  {
    for(x = 0; x < charinfo.xOff; x++)
      c.bitmapData[y * charinfo.xOff + x] = static_cast<U8>(XGetPixel(ximage, x, y));
  }
  XDestroyImage(ximage);

  XftColorFree(display, DefaultVisual(display, screen),
               DefaultColormap(display, screen), &black);
  XftColorFree(display, DefaultVisual(display, screen),
               DefaultColormap(display, screen), &white);
  XftDrawDestroy(draw);
  XFreePixmap(display, pixmap);
  XCloseDisplay(display);

  return c;
}

PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF8 *str) const
{
  return getCharInfo(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
}

<commit_msg>Remove unused platform font code.<commit_after>//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "graphics/gFont.h"
#include "graphics/gBitmap.h"
#include "math/mRect.h"
#include "console/console.h"
#include "string/unicode.h"
#include "platformX86UNIX/platformX86UNIX.h"
#include "platformX86UNIX/x86UNIXFont.h"

x86UNIXFont::x86UNIXFont()
{}

x86UNIXFont::~x86UNIXFont()
{}

bool x86UNIXFont::create(const char *name, U32 size, U32 charset)
{
  return false;
}

bool x86UNIXFont::isValidChar(const UTF16 str) const
{
  return true;
}

bool x86UNIXFont::isValidChar(const UTF8 *str) const
{
  return isValidChar(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
}

PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF16 ch) const
{
  static PlatformFont::CharInfo c;
  dMemset(&c, 0, sizeof(c));
  return c;
}

PlatformFont::CharInfo &x86UNIXFont::getCharInfo(const UTF8 *str) const
{
  return getCharInfo(oneUTF32toUTF16(oneUTF8toUTF32(str,NULL)));
}
<|endoftext|>


<commit_before>#include <silicium/async_process.hpp>
#include <silicium/observable/spawn_coroutine.hpp>
#include <silicium/observable/spawn_observable.hpp>
#include <silicium/observable/transform.hpp>
#include <silicium/observable/ref.hpp>
#include <silicium/observable/thread.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <silicium/std_threading.hpp>
#include <silicium/environment_variables.hpp>
#include <boost/test/unit_test.hpp>

#if SILICIUM_HAS_EXCEPTIONS
#	include <boost/filesystem/operations.hpp>
#endif

namespace
{
	struct process_output
	{
		int exit_code;
		std::string output, error;
	};

#if SILICIUM_HAS_EXPERIMENTAL_READ_FROM_ANONYMOUS_PIPE
	process_output run_process(
		Si::async_process_parameters parameters,
		std::vector<std::pair<Si::os_char const *, Si::os_char const *>> environment_variables,
		Si::environment_inheritance inheritance)
	{
		Si::pipe standard_input = Si::make_pipe().move_value();
		Si::pipe standard_output = Si::make_pipe().move_value();
		Si::pipe standard_error = Si::make_pipe().move_value();

		Si::async_process process =
			Si::launch_process(
				parameters,
				standard_input.read.handle,
				standard_output.write.handle,
				standard_error.write.handle,
				std::move(environment_variables),
				inheritance
			).move_value();
		standard_input.read.close();
		standard_output.write.close();
		standard_error.write.close();

		boost::asio::io_service io;

		process_output result;

		Si::experimental::read_from_anonymous_pipe(io, Si::make_container_sink(result.output), std::move(standard_output.read));
		Si::experimental::read_from_anonymous_pipe(io, Si::make_container_sink(result.error), std::move(standard_error.read));

		io.run();

		result.exit_code = process.wait_for_exit().get();
		return result;
	}
#endif
}

#if !defined(_WIN32) && SILICIUM_HAS_ABSOLUTE_PATH_OPERATIONS
BOOST_AUTO_TEST_CASE(async_process_unix_which)
{
	Si::async_process_parameters parameters;
	parameters.executable = *Si::absolute_path::create("/usr/bin/which");
	parameters.arguments.emplace_back("which");
	parameters.current_path = Si::get_current_working_directory();

	process_output result = run_process(parameters, {}, Si::environment_inheritance::inherit);

	BOOST_CHECK_EQUAL("/usr/bin/which\n", result.output);
	BOOST_CHECK_EQUAL("", result.error);
	BOOST_CHECK_EQUAL(0, result.exit_code);
}
#endif

#if defined(_WIN32) && SILICIUM_HAS_ABSOLUTE_PATH_OPERATIONS
BOOST_AUTO_TEST_CASE(async_process_win32_where)
{
	Si::async_process_parameters parameters;
	parameters.executable = *Si::absolute_path::create(L"C:\\Windows\\System32\\where.exe");
	parameters.current_path = Si::get_current_working_directory();

	process_output result = run_process(parameters, {}, Si::environment_inheritance::no_inherit);

	std::size_t const windows7whereHelpSize = 1830;
	BOOST_CHECK_EQUAL(windows7whereHelpSize, result.output.size());
	BOOST_CHECK_EQUAL("", result.error);
	BOOST_CHECK_EQUAL(2, result.exit_code);
}
#endif

namespace
{
	Si::absolute_path const arbitrary_root_dir = *Si::absolute_path::create(
#ifdef _WIN32
		L"C:\\"
#else
		"/"
#endif
	);
}

#if SILICIUM_HAS_ABSOLUTE_PATH_OPERATIONS
BOOST_AUTO_TEST_CASE(async_process_executable_not_found)
{
	Si::async_process_parameters parameters;
	parameters.executable = arbitrary_root_dir / "does-not-exist";
	parameters.current_path = Si::get_current_working_directory();

	BOOST_CHECK_EXCEPTION(run_process(parameters, {}, Si::environment_inheritance::no_inherit), boost::system::system_error, [](boost::system::system_error const &ex)
	{
		return ex.code() == boost::system::errc::no_such_file_or_directory;
	});
}
#endif

namespace
{
	void test_environment_variables(
		Si::environment_inheritance const tested_inheritance,
		std::vector<std::pair<Si::os_char const *, Si::os_char const *>> const additional_variables)
	{
		Si::async_process_parameters parameters;
		parameters.executable = *Si::absolute_path::create(
#ifdef _WIN32
			SILICIUM_SYSTEM_LITERAL("C:\\Windows\\System32\\cmd.exe")
#else
			"/usr/bin/env"
#endif
			);
		parameters.current_path = Si::get_current_working_directory();
#ifdef _WIN32
		parameters.arguments.emplace_back(SILICIUM_SYSTEM_LITERAL("/C"));
		parameters.arguments.emplace_back(SILICIUM_SYSTEM_LITERAL("set"));
#endif

		BOOST_REQUIRE(!Si::set_environment_variable(SILICIUM_SYSTEM_LITERAL("silicium_parent_key"), SILICIUM_SYSTEM_LITERAL("parent_value")));

		process_output const output = run_process(parameters, additional_variables, tested_inheritance);
		BOOST_CHECK_EQUAL(0, output.exit_code);

		for (auto const &variable : additional_variables)
		{
			BOOST_CHECK_NE(std::string::npos, output.output.find(Si::to_utf8_string(variable.first) + '=' + Si::to_utf8_string(variable.second)));
		}

		auto const parent_key_found = output.output.find("silicium_parent_key=parent_value");
		switch (tested_inheritance)
		{
		case Si::environment_inheritance::inherit:
			BOOST_CHECK_NE(std::string::npos, parent_key_found);
			break;

		case Si::environment_inheritance::no_inherit:
			BOOST_CHECK_EQUAL(std::string::npos, parent_key_found);
			break;
		}
	}
}

namespace
{
	std::vector<std::pair<Si::os_char const *, Si::os_char const *>> const additional_variables
	{
		{SILICIUM_SYSTEM_LITERAL("key"), SILICIUM_SYSTEM_LITERAL("value")}
	};
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_inherit_additional_vars)
{
	test_environment_variables(Si::environment_inheritance::inherit, additional_variables);
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_no_inherit_additional_vars)
{
	test_environment_variables(Si::environment_inheritance::no_inherit, additional_variables);
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_inherit)
{
	test_environment_variables(Si::environment_inheritance::inherit, {});
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_no_inherit)
{
	test_environment_variables(Si::environment_inheritance::no_inherit, {});
}

<commit_msg>compiles without exceptions on Ubuntu again<commit_after>#include <silicium/async_process.hpp>
#include <silicium/observable/spawn_coroutine.hpp>
#include <silicium/observable/spawn_observable.hpp>
#include <silicium/observable/transform.hpp>
#include <silicium/observable/ref.hpp>
#include <silicium/observable/thread.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <silicium/std_threading.hpp>
#include <silicium/environment_variables.hpp>
#include <boost/test/unit_test.hpp>

#if SILICIUM_HAS_EXCEPTIONS
#	include <boost/filesystem/operations.hpp>
#endif

namespace
{
	struct process_output
	{
		int exit_code;
		std::string output, error;
	};

#if SILICIUM_HAS_EXPERIMENTAL_READ_FROM_ANONYMOUS_PIPE
	process_output run_process(
		Si::async_process_parameters parameters,
		std::vector<std::pair<Si::os_char const *, Si::os_char const *>> environment_variables,
		Si::environment_inheritance inheritance)
	{
		Si::pipe standard_input = Si::make_pipe().move_value();
		Si::pipe standard_output = Si::make_pipe().move_value();
		Si::pipe standard_error = Si::make_pipe().move_value();

		Si::async_process process =
			Si::launch_process(
				parameters,
				standard_input.read.handle,
				standard_output.write.handle,
				standard_error.write.handle,
				std::move(environment_variables),
				inheritance
			).move_value();
		standard_input.read.close();
		standard_output.write.close();
		standard_error.write.close();

		boost::asio::io_service io;

		process_output result;

		Si::experimental::read_from_anonymous_pipe(io, Si::make_container_sink(result.output), std::move(standard_output.read));
		Si::experimental::read_from_anonymous_pipe(io, Si::make_container_sink(result.error), std::move(standard_error.read));

		io.run();

		result.exit_code = process.wait_for_exit().get();
		return result;
	}
#endif
}

#if !defined(_WIN32) && SILICIUM_HAS_ABSOLUTE_PATH_OPERATIONS
BOOST_AUTO_TEST_CASE(async_process_unix_which)
{
	Si::async_process_parameters parameters;
	parameters.executable = *Si::absolute_path::create("/usr/bin/which");
	parameters.arguments.emplace_back("which");
	parameters.current_path = Si::get_current_working_directory();

	process_output result = run_process(parameters, {}, Si::environment_inheritance::inherit);

	BOOST_CHECK_EQUAL("/usr/bin/which\n", result.output);
	BOOST_CHECK_EQUAL("", result.error);
	BOOST_CHECK_EQUAL(0, result.exit_code);
}
#endif

#if defined(_WIN32) && SILICIUM_HAS_ABSOLUTE_PATH_OPERATIONS
BOOST_AUTO_TEST_CASE(async_process_win32_where)
{
	Si::async_process_parameters parameters;
	parameters.executable = *Si::absolute_path::create(L"C:\\Windows\\System32\\where.exe");
	parameters.current_path = Si::get_current_working_directory();

	process_output result = run_process(parameters, {}, Si::environment_inheritance::no_inherit);

	std::size_t const windows7whereHelpSize = 1830;
	BOOST_CHECK_EQUAL(windows7whereHelpSize, result.output.size());
	BOOST_CHECK_EQUAL("", result.error);
	BOOST_CHECK_EQUAL(2, result.exit_code);
}
#endif

namespace
{
	Si::absolute_path const arbitrary_root_dir = *Si::absolute_path::create(
#ifdef _WIN32
		L"C:\\"
#else
		"/"
#endif
	);
}

#if SILICIUM_HAS_ABSOLUTE_PATH_OPERATIONS
BOOST_AUTO_TEST_CASE(async_process_executable_not_found)
{
	Si::async_process_parameters parameters;
	parameters.executable = arbitrary_root_dir / "does-not-exist";
	parameters.current_path = Si::get_current_working_directory();

	BOOST_CHECK_EXCEPTION(run_process(parameters, {}, Si::environment_inheritance::no_inherit), boost::system::system_error, [](boost::system::system_error const &ex)
	{
		return ex.code() == boost::system::errc::no_such_file_or_directory;
	});
}
#endif

#if SILICIUM_HAS_ABSOLUTE_PATH_OPERATIONS
namespace
{
	void test_environment_variables(
		Si::environment_inheritance const tested_inheritance,
		std::vector<std::pair<Si::os_char const *, Si::os_char const *>> const additional_variables)
	{
		Si::async_process_parameters parameters;
		parameters.executable = *Si::absolute_path::create(
#ifdef _WIN32
			SILICIUM_SYSTEM_LITERAL("C:\\Windows\\System32\\cmd.exe")
#else
			"/usr/bin/env"
#endif
			);
		parameters.current_path = Si::get_current_working_directory();
#ifdef _WIN32
		parameters.arguments.emplace_back(SILICIUM_SYSTEM_LITERAL("/C"));
		parameters.arguments.emplace_back(SILICIUM_SYSTEM_LITERAL("set"));
#endif

		BOOST_REQUIRE(!Si::set_environment_variable(SILICIUM_SYSTEM_LITERAL("silicium_parent_key"), SILICIUM_SYSTEM_LITERAL("parent_value")));

		process_output const output = run_process(parameters, additional_variables, tested_inheritance);
		BOOST_CHECK_EQUAL(0, output.exit_code);

		for (auto const &variable : additional_variables)
		{
			BOOST_CHECK_NE(std::string::npos, output.output.find(Si::to_utf8_string(variable.first) + '=' + Si::to_utf8_string(variable.second)));
		}

		auto const parent_key_found = output.output.find("silicium_parent_key=parent_value");
		switch (tested_inheritance)
		{
		case Si::environment_inheritance::inherit:
			BOOST_CHECK_NE(std::string::npos, parent_key_found);
			break;

		case Si::environment_inheritance::no_inherit:
			BOOST_CHECK_EQUAL(std::string::npos, parent_key_found);
			break;
		}
	}
}

namespace
{
	std::vector<std::pair<Si::os_char const *, Si::os_char const *>> const additional_variables
	{
		{SILICIUM_SYSTEM_LITERAL("key"), SILICIUM_SYSTEM_LITERAL("value")}
	};
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_inherit_additional_vars)
{
	test_environment_variables(Si::environment_inheritance::inherit, additional_variables);
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_no_inherit_additional_vars)
{
	test_environment_variables(Si::environment_inheritance::no_inherit, additional_variables);
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_inherit)
{
	test_environment_variables(Si::environment_inheritance::inherit, {});
}

BOOST_AUTO_TEST_CASE(async_process_environment_variables_no_inherit)
{
	test_environment_variables(Si::environment_inheritance::no_inherit, {});
}
#endif
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////

#ifndef MANAGED_TEXTURE_HPP
#define MANAGED_TEXTURE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include <SFML/Graphic/Texture.hpp>

#include <BaseResource.hpp>

namespace rm
{
    ////////////////////////////////////////////////////////////
    /// \brief An inherited resource class for SFML Texture types
    ///
    /// This class handles an SFML Texture resource type, with specific
    /// implementation for loading, unloading and reloading.
    ////////////////////////////////////////////////////////////

    class ManagedTexture
    {
    public:

        ////////////////////////////////////////////////////////////
        /// \brief Default Constructor
        ///
        /// Normally called by rm::ResourceFactory
        ////////////////////////////////////////////////////////////
        void ManagedTexture();

        ////////////////////////////////////////////////////////////
        /// \brief  Destructor
        ///
        /// Standard destructor
        ////////////////////////////////////////////////////////////
        void ~ManagedTexture();

        ////////////////////////////////////////////////////////////
        /// \brief Loads the SFML Texture resource
        ///
        /// Invoked when rm::ResourceManager::singleton::load() is called
        ////////////////////////////////////////////////////////////
        void load();

        ////////////////////////////////////////////////////////////
        /// \brief Unloads the SFML Texture resource,
        /// but doesn't remove the instance of this class from rm::ResourceManager
        ///
        /// Invoked when rm::ResourceManager::singleton::unload() is called
        ////////////////////////////////////////////////////////////
        void unload();

        ////////////////////////////////////////////////////////////
        /// \brief Force reloads the SFML Texture resource
        ///
        /// Invoked when rm::ResourceManager::singleton::reload() is called
        ////////////////////////////////////////////////////////////
        void reload();

        ////////////////////////////////////////////////////////////
        /// \brief Returns the resource type of this instance
        ////////////////////////////////////////////////////////////
        string& getResourceClassType();

        ///////////////////////////////////////////////////////////
        /// \brief Returns the size of memory
        ///
        /// Helper function so that memory allocation can be kept track of
        ////////////////////////////////////////////////////////////
        size_t getRamUse();

        ////////////////////////////////////////////////////////////
        /// \brief Returns a pointer to the actual Texture resource
        ////////////////////////////////////////////////////////////
        sf::Texture* getTexture();

    private:

        ////////////////////////////////////////////////////////////
        /// Member data
        ////////////////////////////////////////////////////////////
        const sf::Texture*    m_texture;    ///< Reference to the Texture resource
    };

} // namespace rm

#endif //MANAGED_TEXTURE_HPP

////////////////////////////////////////////////////////////
/// \class ManagedTexture
/// \ingroup
/// rm::ManagedTexture is the inherited class which handles loading and unloading of
/// SFML sf::Texture resources. rm::ManagedTexture implements rm::BaseResource.
///
/// Usage example:
/// \code
/// (rm::ManagedTexture) rm::ResourceManager::singleton::getResource("example_Texture")->getTexture()->play();
/// \endcode
////////////////////////////////////////////////////////////<commit_msg>Updated licence in ManagedTexture<commit_after>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#ifndef MANAGED_TEXTURE_HPP
#define MANAGED_TEXTURE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include <SFML/Graphic/Texture.hpp>

#include <BaseResource.hpp>

namespace rm
{
    ////////////////////////////////////////////////////////////
    /// \brief An inherited resource class for SFML Texture types
    ///
    /// This class handles an SFML Texture resource type, with specific
    /// implementation for loading, unloading and reloading.
    ////////////////////////////////////////////////////////////

    class ManagedTexture
    {
    public:

        ////////////////////////////////////////////////////////////
        /// \brief Default Constructor
        ///
        /// Normally called by rm::ResourceFactory
        ////////////////////////////////////////////////////////////
        void ManagedTexture();

        ////////////////////////////////////////////////////////////
        /// \brief  Destructor
        ///
        /// Standard destructor
        ////////////////////////////////////////////////////////////
        void ~ManagedTexture();

        ////////////////////////////////////////////////////////////
        /// \brief Loads the SFML Texture resource
        ///
        /// Invoked when rm::ResourceManager::singleton::load() is called
        ////////////////////////////////////////////////////////////
        void load();

        ////////////////////////////////////////////////////////////
        /// \brief Unloads the SFML Texture resource,
        /// but doesn't remove the instance of this class from rm::ResourceManager
        ///
        /// Invoked when rm::ResourceManager::singleton::unload() is called
        ////////////////////////////////////////////////////////////
        void unload();

        ////////////////////////////////////////////////////////////
        /// \brief Force reloads the SFML Texture resource
        ///
        /// Invoked when rm::ResourceManager::singleton::reload() is called
        ////////////////////////////////////////////////////////////
        void reload();

        ////////////////////////////////////////////////////////////
        /// \brief Returns the resource type of this instance
        ////////////////////////////////////////////////////////////
        string& getResourceClassType();

        ///////////////////////////////////////////////////////////
        /// \brief Returns the size of memory
        ///
        /// Helper function so that memory allocation can be kept track of
        ////////////////////////////////////////////////////////////
        size_t getRamUse();

        ////////////////////////////////////////////////////////////
        /// \brief Returns a pointer to the actual Texture resource
        ////////////////////////////////////////////////////////////
        sf::Texture* getTexture();

    private:

        ////////////////////////////////////////////////////////////
        /// Member data
        ////////////////////////////////////////////////////////////
        const sf::Texture*    m_texture;    ///< Reference to the Texture resource
    };

} // namespace rm

#endif //MANAGED_TEXTURE_HPP

////////////////////////////////////////////////////////////
/// \class ManagedTexture
/// \ingroup
/// rm::ManagedTexture is the inherited class which handles loading and unloading of
/// SFML sf::Texture resources. rm::ManagedTexture implements rm::BaseResource.
///
/// Usage example:
/// \code
/// (rm::ManagedTexture) rm::ResourceManager::singleton::getResource("example_Texture")->getTexture()->play();
/// \endcode
////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "call/version.h"

namespace webrtc {

// The timestamp is always in UTC.
const char* const kSourceTimestamp = "WebRTC source stamp 2020-12-27T04:03:22";

void LoadWebRTCVersionInRegister() {
  // Using volatile to instruct the compiler to not optimize `p` away even
  // if it looks unused.
  const char* volatile p = kSourceTimestamp;
  static_cast<void>(p);
}

}  // namespace webrtc
<commit_msg>Update WebRTC code version (2020-12-30T04:03:04).<commit_after>/*
 *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "call/version.h"

namespace webrtc {

// The timestamp is always in UTC.
const char* const kSourceTimestamp = "WebRTC source stamp 2020-12-30T04:03:04";

void LoadWebRTCVersionInRegister() {
  // Using volatile to instruct the compiler to not optimize `p` away even
  // if it looks unused.
  const char* volatile p = kSourceTimestamp;
  static_cast<void>(p);
}

}  // namespace webrtc
<|endoftext|>


<commit_before>#include "JsPlayer.h"

#include <string.h>

#include <node_buffer.h>

#include <nah/NodeHelpers.h>

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AsyncData
{
    virtual void process( JsPlayer* ) = 0;
};

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AppSinkEventData : public JsPlayer::AsyncData
{
    AppSinkEventData( GstAppSink* appSink, JsPlayer::AppSinkEvent event ) :
        appSink( appSink), event( event ) {}

    void process( JsPlayer* );

    GstAppSink* appSink;
    const JsPlayer::AppSinkEvent event;
};

void JsPlayer::AppSinkEventData::process( JsPlayer* player )
{
    switch( event ) {
     case JsPlayer::AppSinkEvent::NewPreroll:
        player->onNewPreroll( appSink );
        break;
     case JsPlayer::AppSinkEvent::NewSample:
        player->onNewSample( appSink );
        break;
     case JsPlayer::AppSinkEvent::Eos:
        player->onEos( appSink );
        break;
    }
}

///////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::Function> JsPlayer::_jsConstructor;
std::set<JsPlayer*> JsPlayer::_instances;

void JsPlayer::initJsApi( const v8::Handle<v8::Object>& exports )
{
    node::AtExit( [] ( void* ) { JsPlayer::closeAll(); } );

    gst_init( 0, 0 );

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<FunctionTemplate> constructorTemplate = FunctionTemplate::New( isolate, jsCreate );
    constructorTemplate->SetClassName( String::NewFromUtf8( isolate, "Player", v8::String::kInternalizedString ) );

    Local<ObjectTemplate> instanceTemplate = constructorTemplate->InstanceTemplate();
    instanceTemplate->SetInternalFieldCount( 1 );

    SET_METHOD( instanceTemplate, "parseLaunch", &JsPlayer::parseLaunch );
    SET_METHOD( instanceTemplate, "addAppSinkCallback", &JsPlayer::addAppSinkCallback );
    SET_METHOD( instanceTemplate, "setState", &JsPlayer::setState );

    Local<Function> constructor = constructorTemplate->GetFunction();
    _jsConstructor.Reset( isolate, constructor );

    exports->Set( String::NewFromUtf8( isolate, "createPlayer", v8::String::kInternalizedString ), constructor );
}

void JsPlayer::jsCreate( const v8::FunctionCallbackInfo<v8::Value>& args )
{
    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Object> thisObject = args.Holder();
    if( args.IsConstructCall() ) {
        JsPlayer* jsPlayer = new JsPlayer( thisObject );
        args.GetReturnValue().Set( jsPlayer->handle() );
    } else {
        Local<Value> argv[] = { args[0] };
        Local<Function> constructor =
            Local<Function>::New( isolate, _jsConstructor );
        args.GetReturnValue().Set( constructor->NewInstance( sizeof( argv ) / sizeof( argv[0] ), argv ) );
    }
}

void JsPlayer::closeAll()
{
    for( JsPlayer* p : _instances ) {
        p->close();
    }

    gst_deinit();
}

JsPlayer::JsPlayer( v8::Local<v8::Object>& thisObject ) :
    _pipeline( nullptr ), _firstSample( true )
{
    Wrap( thisObject );

    _instances.insert( this );

    uv_loop_t* loop = uv_default_loop();

    uv_async_init( loop, &_async,
        [] ( uv_async_t* handle ) {
            if( handle->data )
                reinterpret_cast<JsPlayer*>( handle->data )->handleAsync();
        }
    );
    _async.data = this;

}

JsPlayer::~JsPlayer()
{
    close();

    _instances.erase( this );
}

void JsPlayer::close()
{
    _async.data = nullptr;
    uv_close( reinterpret_cast<uv_handle_t*>( &_async ), 0 );
}

void JsPlayer::handleAsync()
{
    while( !_asyncData.empty() ) {
        std::deque<std::unique_ptr<AsyncData> > tmpData;
        _asyncDataGuard.lock();
        _asyncData.swap( tmpData );
        _asyncDataGuard.unlock();

        for( const auto& i: tmpData ) {
            i->process( this );
        }
    }
}

GstFlowReturn JsPlayer::onNewPrerollProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewPreroll ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

GstFlowReturn JsPlayer::onNewSampleProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_appSinks[appSink].waitingSample.clear();
    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewSample ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

void JsPlayer::onEosProxy( GstAppSink* appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, Eos ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );
}

void JsPlayer::callCallback( GstAppSink* appSink, JsPlayer::AppSinkEvent event,
                             std::initializer_list<v8::Local<v8::Value> > list )
{
    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it )
        return;

    if( it->second.callback.IsEmpty() )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Function> callbackFunc =
        Local<Function>::New( isolate, _appSinks[appSink].callback );

    std::vector<v8::Local<v8::Value> > argList;

    argList.push_back( Integer::New( isolate, event ) );
    argList.insert( argList.end(), list );
    callbackFunc->Call( handle(), static_cast<int>( argList.size() ), argList.data() );
}

void JsPlayer::onSetup( GstAppSink* appSink, const GstVideoInfo& videoInfo )
{
    if( !appSink )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    _firstSample = false;

    callCallback( appSink, Setup,
                  { String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                    Integer::New( isolate, videoInfo.width ),
                    Integer::New( isolate, videoInfo.height ),
                    Integer::New( isolate, videoInfo.finfo->format ) } );
}

void JsPlayer::onNewPreroll( GstAppSink* appSink )
{
    GstSample* sample = gst_app_sink_pull_preroll( appSink );

    onSample( appSink, sample, true );

    gst_sample_unref( sample );
}

void JsPlayer::onNewSample( GstAppSink* appSink )
{
    if( _appSinks[appSink].waitingSample.test_and_set() )
        return;

    GstSample* sample = gst_app_sink_pull_sample( appSink );

    _appSinks[appSink].waitingSample.test_and_set();

    onSample( appSink, sample, false );

    gst_sample_unref( sample );
}

void JsPlayer::onSample( GstAppSink* appSink, GstSample* sample, bool preroll )
{
    if( !sample )
        return;

    GstVideoInfo videoInfo;

    GstCaps* caps = gst_sample_get_caps( sample );
    if( !caps || !gst_video_info_from_caps( &videoInfo, caps ) )
        return;

    if( _firstSample )
        onSetup( appSink, videoInfo );

    GstBuffer* buffer = gst_sample_get_buffer( sample );

    if( !buffer )
        return;

    GstMapInfo mapInfo;
    if( gst_buffer_map( buffer, &mapInfo, GST_MAP_READ ) ) {
        using namespace v8;

        Isolate* isolate = Isolate::GetCurrent();
        HandleScope scope( isolate );

        v8::MaybeLocal<v8::Object> maybeFrame =
            node::Buffer::New( isolate, reinterpret_cast<char*>( mapInfo.data ), mapInfo.size,
                               [] ( char* data, void* hint ) {}, nullptr );

        Local<v8::Object> frame;
        if( maybeFrame.ToLocal( &frame ) ) {
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormatName", v8::String::kInternalizedString ),
                             String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormat", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.finfo->format ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            frame->ForceSet( String::NewFromUtf8( isolate, "width", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.width ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "height", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.height ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            Local<Array> planes = Array::New( isolate, videoInfo.finfo->n_planes );
            for( guint p = 0; p < videoInfo.finfo->n_planes; ++p ) {
                planes->Set( p, Integer::New( isolate, videoInfo.offset[p] ) );
            }

            frame->ForceSet( String::NewFromUtf8( isolate, "planes", v8::String::kInternalizedString ),
                             planes,
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            callCallback( appSink, ( preroll ? NewPreroll : NewSample ), { frame } );
        }

        gst_buffer_unmap( buffer, &mapInfo );
    }
}

void JsPlayer::onEos( GstAppSink* appSink )
{
    callCallback( appSink, Eos );
}

bool JsPlayer::parseLaunch( const std::string& pipelineDescription )
{
    if( _pipeline ) {
        _appSinks.clear();
        gst_object_unref( _pipeline );
        _pipeline = nullptr;
        _firstSample = true;
    }

    GError* error = nullptr;
    _pipeline = gst_parse_launch( pipelineDescription.c_str(), &error );

    return ( nullptr != _pipeline );
}

bool JsPlayer::addAppSinkCallback( const std::string& appSinkName, v8::Local<v8::Value> value )
{
    if( !_pipeline || appSinkName.empty() )
        return false;

    GstElement* sink = gst_bin_get_by_name( GST_BIN( _pipeline ), appSinkName.c_str() );
    if( !sink )
        return false;

    GstAppSink* appSink = GST_APP_SINK_CAST( sink );
    if( !appSink )
        return appSink;

    using namespace v8;

    Local<Function> callbackFunc = Local<Function>::Cast( value );
    if( callbackFunc.IsEmpty() )
        return false;

    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it ) {
        gst_app_sink_set_drop( appSink, true );
        gst_app_sink_set_max_buffers( appSink, 1 );
        GstAppSinkCallbacks callbacks = { onEosProxy, onNewPrerollProxy, onNewSampleProxy };
        gst_app_sink_set_callbacks( appSink, &callbacks, this, nullptr );
        it = _appSinks.emplace( appSink, AppSinkData() ).first;
    }

    AppSinkData& sinkData = it->second;
    sinkData.callback.Reset( Isolate::GetCurrent(), callbackFunc );
    sinkData.waitingSample.test_and_set();
}

void JsPlayer::setState( unsigned state )
{
    if( _pipeline )
        gst_element_set_state( _pipeline, static_cast<GstState>( state ) );
}
<commit_msg>allow create via `new Player`<commit_after>#include "JsPlayer.h"

#include <string.h>

#include <node_buffer.h>

#include <nah/NodeHelpers.h>

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AsyncData
{
    virtual void process( JsPlayer* ) = 0;
};

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AppSinkEventData : public JsPlayer::AsyncData
{
    AppSinkEventData( GstAppSink* appSink, JsPlayer::AppSinkEvent event ) :
        appSink( appSink), event( event ) {}

    void process( JsPlayer* );

    GstAppSink* appSink;
    const JsPlayer::AppSinkEvent event;
};

void JsPlayer::AppSinkEventData::process( JsPlayer* player )
{
    switch( event ) {
     case JsPlayer::AppSinkEvent::NewPreroll:
        player->onNewPreroll( appSink );
        break;
     case JsPlayer::AppSinkEvent::NewSample:
        player->onNewSample( appSink );
        break;
     case JsPlayer::AppSinkEvent::Eos:
        player->onEos( appSink );
        break;
    }
}

///////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::Function> JsPlayer::_jsConstructor;
std::set<JsPlayer*> JsPlayer::_instances;

void JsPlayer::initJsApi( const v8::Handle<v8::Object>& exports )
{
    node::AtExit( [] ( void* ) { JsPlayer::closeAll(); } );

    gst_init( 0, 0 );

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<FunctionTemplate> constructorTemplate = FunctionTemplate::New( isolate, jsCreate );
    constructorTemplate->SetClassName( String::NewFromUtf8( isolate, "Player", v8::String::kInternalizedString ) );

    Local<ObjectTemplate> instanceTemplate = constructorTemplate->InstanceTemplate();
    instanceTemplate->SetInternalFieldCount( 1 );

    SET_METHOD( instanceTemplate, "parseLaunch", &JsPlayer::parseLaunch );
    SET_METHOD( instanceTemplate, "addAppSinkCallback", &JsPlayer::addAppSinkCallback );
    SET_METHOD( instanceTemplate, "setState", &JsPlayer::setState );

    Local<Function> constructor = constructorTemplate->GetFunction();
    _jsConstructor.Reset( isolate, constructor );

    exports->Set( String::NewFromUtf8( isolate, "createPlayer", v8::String::kInternalizedString ), constructor );
    exports->Set( String::NewFromUtf8( isolate, "Player", v8::String::kInternalizedString ), constructor );
}

void JsPlayer::jsCreate( const v8::FunctionCallbackInfo<v8::Value>& args )
{
    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Object> thisObject = args.Holder();
    if( args.IsConstructCall() ) {
        JsPlayer* jsPlayer = new JsPlayer( thisObject );
        args.GetReturnValue().Set( jsPlayer->handle() );
    } else {
        Local<Value> argv[] = { args[0] };
        Local<Function> constructor =
            Local<Function>::New( isolate, _jsConstructor );
        args.GetReturnValue().Set( constructor->NewInstance( sizeof( argv ) / sizeof( argv[0] ), argv ) );
    }
}

void JsPlayer::closeAll()
{
    for( JsPlayer* p : _instances ) {
        p->close();
    }

    gst_deinit();
}

JsPlayer::JsPlayer( v8::Local<v8::Object>& thisObject ) :
    _pipeline( nullptr ), _firstSample( true )
{
    Wrap( thisObject );

    _instances.insert( this );

    uv_loop_t* loop = uv_default_loop();

    uv_async_init( loop, &_async,
        [] ( uv_async_t* handle ) {
            if( handle->data )
                reinterpret_cast<JsPlayer*>( handle->data )->handleAsync();
        }
    );
    _async.data = this;

}

JsPlayer::~JsPlayer()
{
    close();

    _instances.erase( this );
}

void JsPlayer::close()
{
    _async.data = nullptr;
    uv_close( reinterpret_cast<uv_handle_t*>( &_async ), 0 );
}

void JsPlayer::handleAsync()
{
    while( !_asyncData.empty() ) {
        std::deque<std::unique_ptr<AsyncData> > tmpData;
        _asyncDataGuard.lock();
        _asyncData.swap( tmpData );
        _asyncDataGuard.unlock();

        for( const auto& i: tmpData ) {
            i->process( this );
        }
    }
}

GstFlowReturn JsPlayer::onNewPrerollProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewPreroll ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

GstFlowReturn JsPlayer::onNewSampleProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_appSinks[appSink].waitingSample.clear();
    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewSample ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

void JsPlayer::onEosProxy( GstAppSink* appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, Eos ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );
}

void JsPlayer::callCallback( GstAppSink* appSink, JsPlayer::AppSinkEvent event,
                             std::initializer_list<v8::Local<v8::Value> > list )
{
    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it )
        return;

    if( it->second.callback.IsEmpty() )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Function> callbackFunc =
        Local<Function>::New( isolate, _appSinks[appSink].callback );

    std::vector<v8::Local<v8::Value> > argList;

    argList.push_back( Integer::New( isolate, event ) );
    argList.insert( argList.end(), list );
    callbackFunc->Call( handle(), static_cast<int>( argList.size() ), argList.data() );
}

void JsPlayer::onSetup( GstAppSink* appSink, const GstVideoInfo& videoInfo )
{
    if( !appSink )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    _firstSample = false;

    callCallback( appSink, Setup,
                  { String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                    Integer::New( isolate, videoInfo.width ),
                    Integer::New( isolate, videoInfo.height ),
                    Integer::New( isolate, videoInfo.finfo->format ) } );
}

void JsPlayer::onNewPreroll( GstAppSink* appSink )
{
    GstSample* sample = gst_app_sink_pull_preroll( appSink );

    onSample( appSink, sample, true );

    gst_sample_unref( sample );
}

void JsPlayer::onNewSample( GstAppSink* appSink )
{
    if( _appSinks[appSink].waitingSample.test_and_set() )
        return;

    GstSample* sample = gst_app_sink_pull_sample( appSink );

    _appSinks[appSink].waitingSample.test_and_set();

    onSample( appSink, sample, false );

    gst_sample_unref( sample );
}

void JsPlayer::onSample( GstAppSink* appSink, GstSample* sample, bool preroll )
{
    if( !sample )
        return;

    GstVideoInfo videoInfo;

    GstCaps* caps = gst_sample_get_caps( sample );
    if( !caps || !gst_video_info_from_caps( &videoInfo, caps ) )
        return;

    if( _firstSample )
        onSetup( appSink, videoInfo );

    GstBuffer* buffer = gst_sample_get_buffer( sample );

    if( !buffer )
        return;

    GstMapInfo mapInfo;
    if( gst_buffer_map( buffer, &mapInfo, GST_MAP_READ ) ) {
        using namespace v8;

        Isolate* isolate = Isolate::GetCurrent();
        HandleScope scope( isolate );

        v8::MaybeLocal<v8::Object> maybeFrame =
            node::Buffer::New( isolate, reinterpret_cast<char*>( mapInfo.data ), mapInfo.size,
                               [] ( char* data, void* hint ) {}, nullptr );

        Local<v8::Object> frame;
        if( maybeFrame.ToLocal( &frame ) ) {
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormatName", v8::String::kInternalizedString ),
                             String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormat", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.finfo->format ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            frame->ForceSet( String::NewFromUtf8( isolate, "width", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.width ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "height", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.height ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            Local<Array> planes = Array::New( isolate, videoInfo.finfo->n_planes );
            for( guint p = 0; p < videoInfo.finfo->n_planes; ++p ) {
                planes->Set( p, Integer::New( isolate, videoInfo.offset[p] ) );
            }

            frame->ForceSet( String::NewFromUtf8( isolate, "planes", v8::String::kInternalizedString ),
                             planes,
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            callCallback( appSink, ( preroll ? NewPreroll : NewSample ), { frame } );
        }

        gst_buffer_unmap( buffer, &mapInfo );
    }
}

void JsPlayer::onEos( GstAppSink* appSink )
{
    callCallback( appSink, Eos );
}

bool JsPlayer::parseLaunch( const std::string& pipelineDescription )
{
    if( _pipeline ) {
        _appSinks.clear();
        gst_object_unref( _pipeline );
        _pipeline = nullptr;
        _firstSample = true;
    }

    GError* error = nullptr;
    _pipeline = gst_parse_launch( pipelineDescription.c_str(), &error );

    return ( nullptr != _pipeline );
}

bool JsPlayer::addAppSinkCallback( const std::string& appSinkName, v8::Local<v8::Value> value )
{
    if( !_pipeline || appSinkName.empty() )
        return false;

    GstElement* sink = gst_bin_get_by_name( GST_BIN( _pipeline ), appSinkName.c_str() );
    if( !sink )
        return false;

    GstAppSink* appSink = GST_APP_SINK_CAST( sink );
    if( !appSink )
        return appSink;

    using namespace v8;

    Local<Function> callbackFunc = Local<Function>::Cast( value );
    if( callbackFunc.IsEmpty() )
        return false;

    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it ) {
        gst_app_sink_set_drop( appSink, true );
        gst_app_sink_set_max_buffers( appSink, 1 );
        GstAppSinkCallbacks callbacks = { onEosProxy, onNewPrerollProxy, onNewSampleProxy };
        gst_app_sink_set_callbacks( appSink, &callbacks, this, nullptr );
        it = _appSinks.emplace( appSink, AppSinkData() ).first;
    }

    AppSinkData& sinkData = it->second;
    sinkData.callback.Reset( Isolate::GetCurrent(), callbackFunc );
    sinkData.waitingSample.test_and_set();
}

void JsPlayer::setState( unsigned state )
{
    if( _pipeline )
        gst_element_set_state( _pipeline, static_cast<GstState>( state ) );
}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "OffscreenScene.h"

#include "SDLDisplayEngine.h"
#include "SceneNode.h"
#include "OGLTexture.h"

#include "../base/Exception.h"

#include <iostream>

using namespace boost;
using namespace std;

namespace avg {

OffscreenScene::OffscreenScene(Player * pPlayer, NodePtr pRootNode)
    : Scene(pPlayer, pRootNode)
{
    if (!pRootNode) {
        throw (Exception(AVG_ERR_XML_PARSE,
                "Root node of a scene tree needs to be a <scene> node."));
    }
    if (pRootNode->getID() == "") {
        throw (Exception(AVG_ERR_XML_PARSE,
                "Root node of a scene tree needs to have an id."));
    }
}

OffscreenScene::~OffscreenScene()
{
    glDeleteTextures(1, &m_TexID);
}

void OffscreenScene::initPlayback(DisplayEngine* pDisplayEngine,
        AudioEngine* pAudioEngine, TestHelper* pTestHelper)
{
    Scene::initPlayback(pDisplayEngine, pAudioEngine, pTestHelper);
    glGenTextures(1, &m_TexID);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "OffscreenScene::initPlayback: glGenTextures()");
    glBindTexture(GL_TEXTURE_2D, m_TexID);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "OffscreenScene::initPlayback: glBindTexture()");
    IntPoint size = getSize();
    // Mipmaps needed for FBO support on nVidia cards (!?)
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, size.x);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0,
            GL_RGBA, GL_UNSIGNED_BYTE, 0);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "OffscreenScene::initPlayback: glTexImage2D()");

    unsigned multiSampleSamples = dynamic_cast<SDLDisplayEngine*>(pDisplayEngine)
            ->getOGLOptions().m_MultiSampleSamples;
    m_pFBO = FBOPtr(new FBO(size, R8G8B8X8, m_TexID, multiSampleSamples));
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}

void OffscreenScene::render()
{
    m_pFBO->activate();
    getDisplayEngine()->render(getRootNode(), true);
    m_pFBO->deactivate();
    m_pFBO->copyToDestTexture();
/*
    OGLTexturePtr pTex(new OGLTexture(getSize(), B8G8R8X8,
            MaterialInfo(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true),
            getDisplayEngine(), PBO));
    pTex->setTexID(m_TexID);
    BitmapPtr pBmp = pTex->readbackBmp();
    pBmp->save(getID()+".png");
*/
}

std::string OffscreenScene::getID() const
{
    return getRootNode()->getID();
}

bool OffscreenScene::isRunning() const
{
    return (m_pFBO != FBOPtr());
}

unsigned OffscreenScene::getTexID() const
{
    return m_pFBO->getTexture();
}

}
<commit_msg>Temporarily removed offscreen mipmap support because not all graphics cards support it.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "OffscreenScene.h"

#include "SDLDisplayEngine.h"
#include "SceneNode.h"
#include "OGLTexture.h"

#include "../base/Exception.h"

#include <iostream>

using namespace boost;
using namespace std;

namespace avg {

OffscreenScene::OffscreenScene(Player * pPlayer, NodePtr pRootNode)
    : Scene(pPlayer, pRootNode)
{
    if (!pRootNode) {
        throw (Exception(AVG_ERR_XML_PARSE,
                "Root node of a scene tree needs to be a <scene> node."));
    }
    if (pRootNode->getID() == "") {
        throw (Exception(AVG_ERR_XML_PARSE,
                "Root node of a scene tree needs to have an id."));
    }
}

OffscreenScene::~OffscreenScene()
{
    glDeleteTextures(1, &m_TexID);
}

void OffscreenScene::initPlayback(DisplayEngine* pDisplayEngine,
        AudioEngine* pAudioEngine, TestHelper* pTestHelper)
{
    Scene::initPlayback(pDisplayEngine, pAudioEngine, pTestHelper);
    glGenTextures(1, &m_TexID);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "OffscreenScene::initPlayback: glGenTextures()");
    glBindTexture(GL_TEXTURE_2D, m_TexID);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "OffscreenScene::initPlayback: glBindTexture()");
    IntPoint size = getSize();
//    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, size.x);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.x, size.y, 0,
            GL_RGBA, GL_UNSIGNED_BYTE, 0);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "OffscreenScene::initPlayback: glTexImage2D()");

    unsigned multiSampleSamples = dynamic_cast<SDLDisplayEngine*>(pDisplayEngine)
            ->getOGLOptions().m_MultiSampleSamples;
    m_pFBO = FBOPtr(new FBO(size, R8G8B8X8, m_TexID, multiSampleSamples));
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}

void OffscreenScene::render()
{
    m_pFBO->activate();
    getDisplayEngine()->render(getRootNode(), true);
    m_pFBO->deactivate();
    m_pFBO->copyToDestTexture();
/*
    OGLTexturePtr pTex(new OGLTexture(getSize(), B8G8R8X8,
            MaterialInfo(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true),
            getDisplayEngine(), PBO));
    pTex->setTexID(m_TexID);
    BitmapPtr pBmp = pTex->readbackBmp();
    pBmp->save(getID()+".png");
*/
}

std::string OffscreenScene::getID() const
{
    return getRootNode()->getID();
}

bool OffscreenScene::isRunning() const
{
    return (m_pFBO != FBOPtr());
}

unsigned OffscreenScene::getTexID() const
{
    return m_pFBO->getTexture();
}

}
<|endoftext|>