<commit_before>/*
 * jcom.snapshot
 * External for Jamoma: capture, recall, transform, and manipulate global snapshots
 * By Timothy Place, Copyright 2009
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "Jamoma.h"

class SnapshotParameterValue {
public:
    TTFloat64   value;
    ObjectPtr   parameter;

    SnapshotParameterValue(TTFloat64& f, ObjectPtr o):
        value(f),
        parameter(o)
    {;}

};

// A vector of 64-bit floats used to represent a given snapshot
typedef vector<SnapshotParameterValue>  Snapshot;
typedef Snapshot::iterator              SnapshotIter;
typedef Snapshot*                       SnapshotPtr;

// A vector (or collection) of snapshots
typedef vector<SnapshotPtr>             SnapshotCollection;
typedef SnapshotCollection::iterator    SnapshotCollectionIter;
typedef SnapshotCollection*             SnapshotCollectionPtr;

// Data Structure for this object
typedef struct {
    Object                  ob;
    TTTreePtr               tree;
    SnapshotCollectionPtr   snapshots;
    SymbolPtr               excludes[128];  // list of parameter and container names to exclude from snapshots
    TTInt32                 excludeSize;
} TTModSnapshot;
typedef TTModSnapshot* TTModSnapshotPtr;

// Prototypes
TTPtr       TTModSnapshotNew    (SymbolPtr name, AtomCount argc, AtomPtr argv);
void        TTModSnapshotFree   (TTModSnapshotPtr self);
MaxErr      TTModSnapshotNotify (TTModSnapshotPtr self, SymbolPtr s, SymbolPtr msg, void *sender, void *data);
void        TTModSnapshotAssist (TTModSnapshotPtr self, void *b, long m, long a, char *s);
void        TTModSnapshotDump   (TTModSnapshotPtr self);
void        TTModSnapshotStore  (TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv);
void        TTModSnapshotRecall (TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv);

// Shared
static ClassPtr sMaxClass;

// Class Definition
int JAMOMA_EXPORT_MAXOBJ main(void)
{
    ClassPtr c = class_new("jcom.snapshot",
                           (method)TTModSnapshotNew,
                           (method)TTModSnapshotFree,
                            sizeof(TTModSnapshot),
                            NULL, A_GIMME, 0);

    jamoma_init();
    common_symbols_init();

    class_addmethod(c, (method)TTModSnapshotNotify,     "notify",       A_CANT, 0);
    class_addmethod(c, (method)TTModSnapshotAssist,     "assist",       A_CANT, 0);
    class_addmethod(c, (method)TTModSnapshotDump,       "dump",         0);
    class_addmethod(c, (method)TTModSnapshotStore,      "store",        A_GIMME, 0);
    class_addmethod(c, (method)TTModSnapshotRecall,     "recall",       A_GIMME, 0);

    CLASS_ATTR_SYM_VARSIZE(c,   "excludes", 0,  TTModSnapshot,  excludes, excludeSize, 128);

    class_register(_sym_box, c);
    sMaxClass = c;
    return 0;
}

#if 0
#pragma mark -
#pragma mark Life Cycle
#endif 0

TTPtr TTModSnapshotNew(SymbolPtr name, AtomCount argc, AtomPtr argv)
{
    TTModSnapshotPtr self = (TTModSnapshotPtr)object_alloc(sMaxClass);

    if (self) {
        TTUInt32 i=0;

        self->snapshots = new SnapshotCollection;
        self->tree = jamoma_tree_init();

        self->excludes[i++] = gensym("ch");
        self->excludes[i++] = gensym("view");
        self->excludes[i++] = gensym("documentation");
        self->excludeSize = i;

        attr_args_process(self, argc, argv);
    }
    return self;
}

void TTModSnapshotFree(TTModSnapshotPtr self)
{
    // TODO: leaking memory! -- free of the actuall snapshots held by the pointers!
    delete self->snapshots;
}

#if 0
#pragma mark -
#pragma mark Methods
#endif 0

MaxErr TTModSnapshotNotify(TTModSnapshotPtr self, SymbolPtr s, SymbolPtr msg, TTPtr sender, TTPtr data)
{
    object_post(SELF, "notification : %s", msg->s_name);
    return MAX_ERR_NONE;
}

void TTModSnapshotAssist(TTModSnapshotPtr self, void* b, long msg, long arg, char* dst)
{
    if (msg == ASSIST_INLET) {  // inlet
        if (arg == 0)
            strcpy(dst, "inlet");
    }
    else {                      // outlet
        if (arg == 0)
            strcpy(dst, "outlet");
    }
}

void TTModSnapshotDump(TTModSnapshotPtr self)
{
    jamoma_tree_dump(); // dump all the address of the tree in the Max window
}

void TTModSnapshotStore(TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv)
{
    TTNodePtr   rootNode = self->tree->getRoot();
    TTValue     moduleNodes;
    TTUInt32    numModules;
    TTListPtr   returnedChildren = NULL;
    TTErr       err;
    SnapshotPtr snapshot = NULL;
    TTUInt32    snapshotIndex = 0;

    // snapshot numbers are 1-based for the outside world
    if (argc && argv)
        snapshotIndex = atom_getlong(argv) - 1;
    if (snapshotIndex < 0)
        snapshotIndex = 0;

    if (snapshotIndex >= self->snapshots->size()) {
        if (snapshotIndex >= self->snapshots->capacity()) {
            self->snapshots->reserve(snapshotIndex+1);
        }
        self->snapshots->resize(snapshotIndex+1);
    }
    else {
        snapshot = self->snapshots->at(snapshotIndex);
        delete snapshot;
        snapshot = NULL;
    }
    snapshot = new Snapshot;

    err = rootNode->getChildren(TT("*"), TT("*"), &returnedChildren);

    returnedChildren->assignToValue(moduleNodes);
    numModules = moduleNodes.getSize();
    for (TTUInt32 i=0; i<numModules; i++) {
        TTNodePtr   module = NULL;
        TTSymbolPtr type;

        moduleNodes.get(i, (TTPtr*)(&module));
        if (module) {
            type = module->getType();
            if (type == TT("hub")) {
                TTValue     parameterNodes;
                TTUInt32    numParameters;

                post("  Module: %s", module->getName()->getCString());
                err = module->getChildren(TT("*"), TT("*"), &returnedChildren);
                returnedChildren->assignToValue(parameterNodes);
                numParameters = parameterNodes.getSize();
                for (TTUInt32 i=0; i<numParameters; i++) {
                    TTNodePtr   parameter = NULL;
                    TTSymbolPtr childType;

                    parameterNodes.get(i, (TTPtr*)(&parameter));
                    if (parameter) {
                        bool exclude = false;
                        // first check for the name in the excludes list
                        for (TTInt32 e=0; e < self->excludeSize; e++) {
                            TTSymbolPtr s1 = parameter->getName();
                            TTSymbolPtr s2 = TT(self->excludes[e]->s_name);

                            if (s1 == s2) {
                                exclude = true;
                                break;
                            }
                        }
                        if (exclude)
                            continue;

                        // then make sure it is actually a parameter
                        childType = parameter->getType();
                        if (childType == TT("subscribe_parameter")) {   // FIXME: this name sucks for the type.
                            ObjectPtr maxObject = (ObjectPtr)parameter->getObject();
                            SymbolPtr maxType = object_attr_getsym(maxObject, SymbolGen("type"));

                            // we're ignoring non-int, non-float params for the time being
                            if (maxType == SymbolGen("decimal") || maxType == SymbolGen("integer")) {
                                TTFloat64               value = object_attr_getfloat(maxObject, SymbolGen("value"));
                                SnapshotParameterValue  spv(value, maxObject);

                                snapshot->push_back(spv);
                                post("    parameter: %s -- value: %lf", parameter->getName()->getCString(), value);
                            }
                        }
                        // FIXME: the code below sucks big-time -- need to redo as a recursive function
                        else if (childType == TT("container")) {
							TTValue     containerNodes;
							TTUInt32    numParameters2;
							TTListPtr	containerChildren = NULL;

							post("  Container: %s", parameter->getName()->getCString());
							err = parameter->getChildren(TT("*"), TT("*"), &containerChildren);
							containerChildren->assignToValue(containerNodes);
							numParameters2 = containerNodes.getSize();
							for (TTUInt32 i=0; i<numParameters2; i++) {
								TTNodePtr   parameter2 = NULL;
								TTSymbolPtr childType2;

								containerNodes.get(i, (TTPtr*)(&parameter2));
								if (parameter2) {
									bool exclude = false;
									// first check for the name in the excludes list
									for (TTInt32 e=0; e < self->excludeSize; e++) {
										TTSymbolPtr s1 = parameter2->getName();
										TTSymbolPtr s2 = TT(self->excludes[e]->s_name);

										if (s1 == s2) {
											exclude = true;
											break;
										}
									}
									if (exclude)
										continue;

									// then make sure it is actually a parameter
									childType2 = parameter2->getType();
									if (childType2 == TT("subscribe_parameter")) {   // FIXME: this name sucks for the type.
										ObjectPtr maxObject = (ObjectPtr)parameter2->getObject();
										SymbolPtr maxType = object_attr_getsym(maxObject, SymbolGen("type"));

										// we're ignoring non-int, non-float params for the time being
										if (maxType == SymbolGen("decimal") || maxType == SymbolGen("integer")) {
											TTFloat64               value = object_attr_getfloat(maxObject, SymbolGen("value"));
											SnapshotParameterValue  spv(value, maxObject);

											snapshot->push_back(spv);
											post("    parameter: %s -- value: %lf", parameter2->getName()->getCString(), value);
										}
									}
								}
        }
                        }
                    }
                }
            }
        }
    }
    (*self->snapshots)[snapshotIndex] = snapshot;
}

void TTModSnapshotRecallOne(const SnapshotParameterValue& spv)
{
    object_method(spv.parameter, _sym_float, spv.value);
}

void TTModSnapshotRecall(TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv)
{
    if (!argc || !argv)
        return;

    // straight recall
    if (argc == 1) {
        SnapshotPtr snapshot;
        TTUInt32    snapshotIndex = atom_getlong(argv) - 1;

        if (snapshotIndex < 0)
            snapshotIndex = 0;

        if (snapshotIndex >= self->snapshots->size()) {
            object_error(SELF, "preset recall out of range");
            return;
        }
        snapshot = (*self->snapshots)[snapshotIndex];
        for_each((*snapshot).begin(), (*snapshot).end(), TTModSnapshotRecallOne);
    }

    // interpolate between any two
    else if (argc == 3) {
        SnapshotPtr snapshotA;
        SnapshotPtr snapshotB;
        TTUInt32    snapshotIndexA = atom_getlong(argv+0) - 1;
        TTUInt32    snapshotIndexB = atom_getlong(argv+1) - 1;
        TTUInt32    snapshotSizeA = atom_getlong(argv+0);
        TTUInt32    snapshotSizeB = atom_getlong(argv+1);
        TTFloat32   position = atom_getfloat(argv+2);

        if (snapshotIndexA < 0)
            snapshotIndexA = 0;
        if (snapshotIndexB < 0)
            snapshotIndexB = 0;

        if (snapshotIndexA >= self->snapshots->size() ||
            snapshotIndexB >= self->snapshots->size())
        {
            object_error(SELF, "preset recall out of range");
            return;
        }

        snapshotA = (*self->snapshots)[snapshotIndexA];
        snapshotB = (*self->snapshots)[snapshotIndexB];
        snapshotSizeA = snapshotA->size();
        snapshotSizeB = snapshotB->size();

        if (snapshotSizeA != snapshotSizeB) {
            object_error(SELF, "preset recall -- cannot interpolate between snapshots of unequal size");
            return;
        }

        for (TTUInt32 i=0; i<snapshotSizeA; i++) {
            if ( (*snapshotA)[i].parameter == (*snapshotB)[i].parameter ) {
                TTFloat32 f = ((*snapshotA)[i].value * (1.0 - position)) + ((*snapshotB)[i].value * (position));
                object_method((*snapshotA)[i].parameter, _sym_float, f);
            }
        }
    }

    // wieghted interpolation
    else if (argc > 3) {
        TTUInt32    size;
        TTUInt32    ac = argc;
        bool        boundsCheckFailed = false;
        SnapshotPtr snapshot;
        Snapshot    interpolatedResult;
        TTFloat32   weight;

        // check bounds
        if (ac > self->snapshots->size()) {
            object_error(SELF, "recall can not interpolate -- not enough snapshots for provided weights");
            return;
        }

        snapshot = (*self->snapshots)[0];
        if (!snapshot) {
            object_error(SELF, "recall can not interpolate -- bogus initial snapshot");
            return;
        }

        size = snapshot->size();
        for (int i=1; i<argc; i++) {
            if (!(*self->snapshots)[i] || (*self->snapshots)[i]->size() != size) {
                boundsCheckFailed = true;
                break;
            }
        }
        if (boundsCheckFailed) {
            object_error(SELF, "recall can not interpolate -- snapshots are of unequal size, or there is a missing snapshot in the sequence");
            return;
        }

        interpolatedResult.reserve(size);
        for (int i=0; i<argc; i++) {
            snapshot = (*self->snapshots)[i];
            weight = atom_getfloat(argv+i);
            if (i==0) {
                interpolatedResult.insert(interpolatedResult.begin(), snapshot->begin(), snapshot->end());
                // TODO: There must be a better way than this nested loop using some variant for for_each() or something...
                for (TTUInt32 j=0; j<size; j++) {
                    interpolatedResult[j].value *= weight;
                }
            }
            else {
                // TODO: There must be a better way than this nested loop using some variant for for_each() or something...
                for (TTUInt32 j=0; j<size; j++) {
                    interpolatedResult[j].value += ((*snapshot)[j].value * weight);
                }
            }
        }
       for_each(interpolatedResult.begin(), interpolatedResult.end(), TTModSnapshotRecallOne);
    }
}

<commit_msg>jcom.snapshot: fix for crash when a preset is recalled that was never actually stored.<commit_after>/*
 * jcom.snapshot
 * External for Jamoma: capture, recall, transform, and manipulate global snapshots
 * By Timothy Place, Copyright 2009
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "Jamoma.h"

class SnapshotParameterValue {
public:
    TTFloat64   value;
    ObjectPtr   parameter;

    SnapshotParameterValue(TTFloat64& f, ObjectPtr o):
        value(f),
        parameter(o)
    {;}

};

// A vector of 64-bit floats used to represent a given snapshot
typedef vector<SnapshotParameterValue>  Snapshot;
typedef Snapshot::iterator              SnapshotIter;
typedef Snapshot*                       SnapshotPtr;

// A vector (or collection) of snapshots
typedef vector<SnapshotPtr>             SnapshotCollection;
typedef SnapshotCollection::iterator    SnapshotCollectionIter;
typedef SnapshotCollection*             SnapshotCollectionPtr;

// Data Structure for this object
typedef struct {
    Object                  ob;
    TTTreePtr               tree;
    SnapshotCollectionPtr   snapshots;
    SymbolPtr               excludes[128];  // list of parameter and container names to exclude from snapshots
    TTInt32                 excludeSize;
} TTModSnapshot;
typedef TTModSnapshot* TTModSnapshotPtr;

// Prototypes
TTPtr       TTModSnapshotNew    (SymbolPtr name, AtomCount argc, AtomPtr argv);
void        TTModSnapshotFree   (TTModSnapshotPtr self);
MaxErr      TTModSnapshotNotify (TTModSnapshotPtr self, SymbolPtr s, SymbolPtr msg, void *sender, void *data);
void        TTModSnapshotAssist (TTModSnapshotPtr self, void *b, long m, long a, char *s);
void        TTModSnapshotDump   (TTModSnapshotPtr self);
void        TTModSnapshotStore  (TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv);
void        TTModSnapshotRecall (TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv);

// Shared
static ClassPtr sMaxClass;

// Class Definition
int JAMOMA_EXPORT_MAXOBJ main(void)
{
    ClassPtr c = class_new("jcom.snapshot",
                           (method)TTModSnapshotNew,
                           (method)TTModSnapshotFree,
                            sizeof(TTModSnapshot),
                            NULL, A_GIMME, 0);

    jamoma_init();
    common_symbols_init();

    class_addmethod(c, (method)TTModSnapshotNotify,     "notify",       A_CANT, 0);
    class_addmethod(c, (method)TTModSnapshotAssist,     "assist",       A_CANT, 0);
    class_addmethod(c, (method)TTModSnapshotDump,       "dump",         0);
    class_addmethod(c, (method)TTModSnapshotStore,      "store",        A_GIMME, 0);
    class_addmethod(c, (method)TTModSnapshotRecall,     "recall",       A_GIMME, 0);

    CLASS_ATTR_SYM_VARSIZE(c,   "excludes", 0,  TTModSnapshot,  excludes, excludeSize, 128);

    class_register(_sym_box, c);
    sMaxClass = c;
    return 0;
}

#if 0
#pragma mark -
#pragma mark Life Cycle
#endif 0

TTPtr TTModSnapshotNew(SymbolPtr name, AtomCount argc, AtomPtr argv)
{
    TTModSnapshotPtr self = (TTModSnapshotPtr)object_alloc(sMaxClass);

    if (self) {
        TTUInt32 i=0;

        self->snapshots = new SnapshotCollection;
        self->tree = jamoma_tree_init();

        self->excludes[i++] = gensym("ch");
        self->excludes[i++] = gensym("view");
        self->excludes[i++] = gensym("documentation");
        self->excludeSize = i;

        attr_args_process(self, argc, argv);
    }
    return self;
}

void TTModSnapshotFree(TTModSnapshotPtr self)
{
    // TODO: leaking memory! -- free of the actuall snapshots held by the pointers!
    delete self->snapshots;
}

#if 0
#pragma mark -
#pragma mark Methods
#endif 0

MaxErr TTModSnapshotNotify(TTModSnapshotPtr self, SymbolPtr s, SymbolPtr msg, TTPtr sender, TTPtr data)
{
    object_post(SELF, "notification : %s", msg->s_name);
    return MAX_ERR_NONE;
}

void TTModSnapshotAssist(TTModSnapshotPtr self, void* b, long msg, long arg, char* dst)
{
    if (msg == ASSIST_INLET) {  // inlet
        if (arg == 0)
            strcpy(dst, "inlet");
    }
    else {                      // outlet
        if (arg == 0)
            strcpy(dst, "outlet");
    }
}

void TTModSnapshotDump(TTModSnapshotPtr self)
{
    jamoma_tree_dump(); // dump all the address of the tree in the Max window
}

void TTModSnapshotStore(TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv)
{
    TTNodePtr   rootNode = self->tree->getRoot();
    TTValue     moduleNodes;
    TTUInt32    numModules;
    TTListPtr   returnedChildren = NULL;
    TTErr       err;
    SnapshotPtr snapshot = NULL;
    TTUInt32    snapshotIndex = 0;

    // snapshot numbers are 1-based for the outside world
    if (argc && argv)
        snapshotIndex = atom_getlong(argv) - 1;
    if (snapshotIndex < 0)
        snapshotIndex = 0;

    if (snapshotIndex >= self->snapshots->size()) {
        if (snapshotIndex >= self->snapshots->capacity()) {
            self->snapshots->reserve(snapshotIndex+1);
        }
        self->snapshots->resize(snapshotIndex+1);
    }
    else {
        snapshot = self->snapshots->at(snapshotIndex);
        delete snapshot;
        snapshot = NULL;
    }
    snapshot = new Snapshot;

    err = rootNode->getChildren(TT("*"), TT("*"), &returnedChildren);

    returnedChildren->assignToValue(moduleNodes);
    numModules = moduleNodes.getSize();
    for (TTUInt32 i=0; i<numModules; i++) {
        TTNodePtr   module = NULL;
        TTSymbolPtr type;

        moduleNodes.get(i, (TTPtr*)(&module));
        if (module) {
            type = module->getType();
            if (type == TT("hub")) {
                TTValue     parameterNodes;
                TTUInt32    numParameters;

                post("  Module: %s", module->getName()->getCString());
                err = module->getChildren(TT("*"), TT("*"), &returnedChildren);
                returnedChildren->assignToValue(parameterNodes);
                numParameters = parameterNodes.getSize();
                for (TTUInt32 i=0; i<numParameters; i++) {
                    TTNodePtr   parameter = NULL;
                    TTSymbolPtr childType;

                    parameterNodes.get(i, (TTPtr*)(&parameter));
                    if (parameter) {
                        bool exclude = false;
                        // first check for the name in the excludes list
                        for (TTInt32 e=0; e < self->excludeSize; e++) {
                            TTSymbolPtr s1 = parameter->getName();
                            TTSymbolPtr s2 = TT(self->excludes[e]->s_name);

                            if (s1 == s2) {
                                exclude = true;
                                break;
                            }
                        }
                        if (exclude)
                            continue;

                        // then make sure it is actually a parameter
                        childType = parameter->getType();
                        if (childType == TT("subscribe_parameter")) {   // FIXME: this name sucks for the type.
                            ObjectPtr maxObject = (ObjectPtr)parameter->getObject();
                            SymbolPtr maxType = object_attr_getsym(maxObject, SymbolGen("type"));

                            // we're ignoring non-int, non-float params for the time being
                            if (maxType == SymbolGen("decimal") || maxType == SymbolGen("integer")) {
                                TTFloat64               value = object_attr_getfloat(maxObject, SymbolGen("value"));
                                SnapshotParameterValue  spv(value, maxObject);

                                snapshot->push_back(spv);
                                post("    parameter: %s -- value: %lf", parameter->getName()->getCString(), value);
                            }
                        }
                        // FIXME: the code below sucks big-time -- need to redo as a recursive function
                        else if (childType == TT("container")) {
							TTValue     containerNodes;
							TTUInt32    numParameters2;
							TTListPtr	containerChildren = NULL;

							post("  Container: %s", parameter->getName()->getCString());
							err = parameter->getChildren(TT("*"), TT("*"), &containerChildren);
							containerChildren->assignToValue(containerNodes);
							numParameters2 = containerNodes.getSize();
							for (TTUInt32 i=0; i<numParameters2; i++) {
								TTNodePtr   parameter2 = NULL;
								TTSymbolPtr childType2;

								containerNodes.get(i, (TTPtr*)(&parameter2));
								if (parameter2) {
									bool exclude = false;
									// first check for the name in the excludes list
									for (TTInt32 e=0; e < self->excludeSize; e++) {
										TTSymbolPtr s1 = parameter2->getName();
										TTSymbolPtr s2 = TT(self->excludes[e]->s_name);

										if (s1 == s2) {
											exclude = true;
											break;
										}
									}
									if (exclude)
										continue;

									// then make sure it is actually a parameter
									childType2 = parameter2->getType();
									if (childType2 == TT("subscribe_parameter")) {   // FIXME: this name sucks for the type.
										ObjectPtr maxObject = (ObjectPtr)parameter2->getObject();
										SymbolPtr maxType = object_attr_getsym(maxObject, SymbolGen("type"));

										// we're ignoring non-int, non-float params for the time being
										if (maxType == SymbolGen("decimal") || maxType == SymbolGen("integer")) {
											TTFloat64               value = object_attr_getfloat(maxObject, SymbolGen("value"));
											SnapshotParameterValue  spv(value, maxObject);

											snapshot->push_back(spv);
											post("    parameter: %s -- value: %lf", parameter2->getName()->getCString(), value);
										}
									}
								}
        }
                        }
                    }
                }
            }
        }
    }
    (*self->snapshots)[snapshotIndex] = snapshot;
}

void TTModSnapshotRecallOne(const SnapshotParameterValue& spv)
{
    object_method(spv.parameter, _sym_float, spv.value);
}

void TTModSnapshotRecall(TTModSnapshotPtr self, SymbolPtr s, AtomCount argc, AtomPtr argv)
{
    if (!argc || !argv)
        return;

    // straight recall
    if (argc == 1) {
        SnapshotPtr snapshot;
        TTUInt32    snapshotIndex = atom_getlong(argv) - 1;

        if (snapshotIndex < 0)
            snapshotIndex = 0;

        if (snapshotIndex >= self->snapshots->size()) {
            object_error(SELF, "preset recall out of range");
            return;
        }
        snapshot = (*self->snapshots)[snapshotIndex];
		if (snapshot)
        	for_each((*snapshot).begin(), (*snapshot).end(), TTModSnapshotRecallOne);
		else
			object_error(SELF, "invalid preset recall requested");
    }

    // interpolate between any two
    else if (argc == 3) {
        SnapshotPtr snapshotA;
        SnapshotPtr snapshotB;
        TTUInt32    snapshotIndexA = atom_getlong(argv+0) - 1;
        TTUInt32    snapshotIndexB = atom_getlong(argv+1) - 1;
        TTUInt32    snapshotSizeA = atom_getlong(argv+0);
        TTUInt32    snapshotSizeB = atom_getlong(argv+1);
        TTFloat32   position = atom_getfloat(argv+2);

        if (snapshotIndexA < 0)
            snapshotIndexA = 0;
        if (snapshotIndexB < 0)
            snapshotIndexB = 0;

        if (snapshotIndexA >= self->snapshots->size() ||
            snapshotIndexB >= self->snapshots->size())
        {
            object_error(SELF, "preset recall out of range");
            return;
        }

        snapshotA = (*self->snapshots)[snapshotIndexA];
        snapshotB = (*self->snapshots)[snapshotIndexB];
        snapshotSizeA = snapshotA->size();
        snapshotSizeB = snapshotB->size();

        if (snapshotSizeA != snapshotSizeB) {
            object_error(SELF, "preset recall -- cannot interpolate between snapshots of unequal size");
            return;
        }

        for (TTUInt32 i=0; i<snapshotSizeA; i++) {
            if ( (*snapshotA)[i].parameter == (*snapshotB)[i].parameter ) {
                TTFloat32 f = ((*snapshotA)[i].value * (1.0 - position)) + ((*snapshotB)[i].value * (position));
                object_method((*snapshotA)[i].parameter, _sym_float, f);
            }
        }
    }

    // wieghted interpolation
    else if (argc > 3) {
        TTUInt32    size;
        TTUInt32    ac = argc;
        bool        boundsCheckFailed = false;
        SnapshotPtr snapshot;
        Snapshot    interpolatedResult;
        TTFloat32   weight;

        // check bounds
        if (ac > self->snapshots->size()) {
            object_error(SELF, "recall can not interpolate -- not enough snapshots for provided weights");
            return;
        }

        snapshot = (*self->snapshots)[0];
        if (!snapshot) {
            object_error(SELF, "recall can not interpolate -- bogus initial snapshot");
            return;
        }

        size = snapshot->size();
        for (int i=1; i<argc; i++) {
            if (!(*self->snapshots)[i] || (*self->snapshots)[i]->size() != size) {
                boundsCheckFailed = true;
                break;
            }
        }
        if (boundsCheckFailed) {
            object_error(SELF, "recall can not interpolate -- snapshots are of unequal size, or there is a missing snapshot in the sequence");
            return;
        }

        interpolatedResult.reserve(size);
        for (int i=0; i<argc; i++) {
            snapshot = (*self->snapshots)[i];
            weight = atom_getfloat(argv+i);
            if (i==0) {
                interpolatedResult.insert(interpolatedResult.begin(), snapshot->begin(), snapshot->end());
                // TODO: There must be a better way than this nested loop using some variant for for_each() or something...
                for (TTUInt32 j=0; j<size; j++) {
                    interpolatedResult[j].value *= weight;
                }
            }
            else {
                // TODO: There must be a better way than this nested loop using some variant for for_each() or something...
                for (TTUInt32 j=0; j<size; j++) {
                    interpolatedResult[j].value += ((*snapshot)[j].value * weight);
                }
            }
        }
       for_each(interpolatedResult.begin(), interpolatedResult.end(), TTModSnapshotRecallOne);
    }
}

<|endoftext|>


<commit_before>/*
 *  caosVM_agent.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on Tue Jun 01 2004.
 *  Copyright (c) 2004 Alyssa Milburn. All rights reserved.
 *
 *  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.
 *
 */

#include "caosVM.h"
#include "openc2e.h"
#include "Agent.h"
#include "AgentRef.h"
#include "World.h"
#include <iostream>
using std::cerr;

/**
 ELAS (command) elas (integer)
 %status maybe

 Sets the elasticity (in other words, bounciness) of the TARG agent.
*/
void caosVM::c_ELAS() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_INTEGER(elas)

	valid_agent(targ);
	targ->elas = elas;
}

/***
 ELAS (integer)
 %status maybe

 Returns the elasticity of the TARG agent.
*/
void caosVM::v_ELAS() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setInt(targ->elas);
}

/**
 MVTO (command) x (float) y (float)
 %status maybe

 Places the TARG agent at the given x/y position in the world (using the upper left hand corner of the agent).
*/
void caosVM::c_MVTO() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)
	valid_agent(targ);
	targ->moveTo(x, y);
}

/**
 MVBY (command) x (float) y (float)
 %status maybe

 Changes the TARG agent's position by the given relative distances.
*/
void caosVM::c_MVBY() {
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ);
	targ->moveTo(targ->x + x, targ->y + y);
}

/**
 VELX (variable)
 %status maybe

 Returns the current horizontal velocity, in pixels/tick, of the TARG agent.
*/
void caosVM::v_VELX() {
	VM_VERIFY_SIZE(0)
	valid_agent(targ);
	vm->valueStack.push_back(&targ->velx);
}

/**
 VELY (variable)
 %status maybe

 Returns the current vertical velocity, in pixels/tick, of the TARG agent.
*/
void caosVM::v_VELY() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	vm->valueStack.push_back(&targ->vely);
}

/**
 OBST (float) direction (integer)
 %status maybe

 Returns the distance from the TARG agent to the nearest wall that it might collide with in the given direction.
 (except right now it just gives the direction to the nearest wall at world edge - fuzzie)
*/
void caosVM::v_OBST() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_INTEGER(direction) caos_assert(direction >= 0); caos_assert(direction <= 3);

	/*
	 * TODO: CL's docs say to return "a very large number" if distance is greater than rnge - if (!collided)?
	 * also, this code is untested :) - fuzzie
	 */

	valid_agent(targ);

	Point src = targ->boundingBoxPoint(direction);
	Point dest = src;

	switch (direction) {
		case 0: // left
			dest.x -= targ->range; break;
		case 1: // right
			dest.x += targ->range; break;
		case 2: // top
			dest.y -= targ->range; break;
		case 3: // bottom
			dest.y += targ->range; break;
	}

	Room *ourRoom = world.map.roomAt(src.x, src.y);
	if (!ourRoom) {
		// TODO: is this correct behaviour?
		result.setFloat(0.0f);
		return;
	}

	unsigned int dummy1; Line dummy2; Point point;
	bool collided = world.map.collideLineWithRoomSystem(src, dest, ourRoom, point, dummy2, dummy1, targ->perm);

	switch (direction) {
		case 0: result.setFloat(src.x - point.x); break;
		case 1: result.setFloat(point.x - src.x); break;
		case 2: result.setFloat(src.y - point.y); break;
		case 3: result.setFloat(point.y - src.y); break;
	}
}

/**
 TMVT (integer) x (float) y (float)
 %status maybe

 Returns 1 if the TARG agent could move to (x, y) and still be in room system, or 0 if otherwise.
*/
void caosVM::v_TMVT() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ);

	if (targ->validInRoomSystem(Point(x, y), targ->getWidth(), targ->getHeight(), targ->perm))
		result.setInt(1);
	else
		result.setInt(0);
}

/**
 TMVF (integer) x (float) y (float)
 %status stub

 Returns 1 if the TARG Creature could move foot to (x, y) and still be in room system, or 0 if otherwise.
*/
void caosVM::v_TMVF() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ);
	result.setInt(1); // TODO: don't hardcode
}

/**
 ACCG (command) accel (float)
 %status maybe

 Sets the TARG agent's free-fall acceleration, in pixels/tick squared.
*/
void caosVM::c_ACCG() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_FLOAT(accel)

	valid_agent(targ);
	targ->accg = accel;
}

/**
 ACCG (float)
 %status maybe

 Returns the TARG agent's free-fall acceleration, in pixels/tick squared.
*/
void caosVM::v_ACCG() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setFloat(targ->accg);
}

/**
 AERO (command) aero (float)
 %status maybe

 Sets the aerodynamics of the TARG agent to the given float value.
*/
void caosVM::c_AERO() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_FLOAT(aero)

	valid_agent(targ);
	targ->aero = aero;
}

/**
 AERO (float)
 %status maybe

 Returns the aerodynamics of the TARG agent.
*/
void caosVM::v_AERO() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setFloat(targ->aero);
}

/**
 RELX (float) first (agent) second (agent)
 %status maybe

 Returns the relative horizontal distance between the centers of the two given agents.
*/
void caosVM::v_RELX() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_VALIDAGENT(second)
	VM_PARAM_VALIDAGENT(first)

	float one = first->x + (first->getWidth() / 2.0);
	float two = second->x + (second->getWidth() / 2.0);

	result.setFloat(two - one);
}

/**
 RELY (float) first (agent) second (agent)
 %status maybe

 Returns the relative vertical distance between the centers of the two given agents.
*/
void caosVM::v_RELY() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_VALIDAGENT(second)
	VM_PARAM_VALIDAGENT(first)

	float one = first->y + (first->getHeight() / 2.0);
	float two = second->y + (second->getHeight() / 2.0);

	result.setFloat(two - one);
}

/**
 VELO (command) xvel (float) yvel (float)
 %status maybe

 Sets the horizontal and vertical velocity of the TARG agent, in pixels/tick.
*/
void caosVM::c_VELO() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(vely)
	VM_PARAM_FLOAT(velx)

	valid_agent(targ);
	targ->velx.reset();
	targ->velx.setFloat(velx);
	targ->vely.reset();
	targ->vely.setFloat(vely);
}

/**
 MVSF (command) x (float) y (float)
 %status maybe

 Move the target agent to an area inside the room system at about (x, y).
 This allows 'safe' moves.
*/
void caosVM::c_MVSF() {
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)
	valid_agent(targ);

	// TODO: this is a silly hack, to cater for simplest case (where we just need to nudge the agent up a bit)
	unsigned int tries = 0;
	while (tries < 150) {
		if (targ->validInRoomSystem(Point(x, y - tries), targ->getWidth(), targ->getHeight(), targ->perm)) {
			targ->moveTo(x, y - tries);
			return;
		}
		tries++;
	}

	// TODO: temp hack to shut scripts up
	targ->kill();
	if (owner) owner->kill();
	throw creaturesException("MVSF failed to find a safe place");
}

/**
 FRIC (float)
 %status maybe

 Returns the TARG agent's coefficient of friction as a percentage.
*/
void caosVM::v_FRIC() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setFloat(targ->friction);
}

/**
 FRIC (command) friction (integer)
 %status maybe

 Sets the TARG agent's coefficient of friction, or the percentage of motion that will be lost as it slides on a
 surface.
*/
void caosVM::c_FRIC() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_INTEGER(friction) caos_assert(friction >= 0); caos_assert(friction <= 100);

	valid_agent(targ);
	targ->friction = friction;
}

/**
 FALL (integer)
 %status maybe

 Returns 1 if the TARG agent is moving due to gravity, or 0 if otherwise.
*/
void caosVM::v_FALL() {
	VM_VERIFY_SIZE(0)
	valid_agent(targ);

	// XXX: this probably isn't quite correct, but it's close enough for now.
	if (targ->falling)
		result.setInt(1);
	else
		result.setInt(0);
}

/**
 MOVS (integer)
 %status stub

 Returns an integer representing the motion status of the TARG agent.  0 is autonomous, 1 is moving by mouse, 2 is
 floating, 3 is inside a vehicle, and 4 is being carried.
*/
void caosVM::v_MOVS() {
	valid_agent(targ);

	result.setInt(0); // TODO
}

/**
 FLTO (command) x (float) y (float)
 %status maybe

 Sets the TARG agent to float its top-left corner (x, y) away from the top-left corner of the FREL agent.
*/
void caosVM::c_FLTO() {
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ)
	targ->floatTo(x, y);
}

/**
 FREL (command) agent (agent)
 %status maybe

 Sets the agent the TARG agent floats relative to. You must set the 'floatable' attribute for this to work.
 The default is NULL, which means the target agent floats relative to the main camera.
*/
void caosVM::c_FREL() {
	VM_PARAM_AGENT(agent)

	valid_agent(targ)
	targ->floatTo(agent);
}

/**
 FLTX (float)
 %status maybe

 Returns the x value of the TARG agent's floating vector.
*/
void caosVM::v_FLTX() {
	valid_agent(targ);

	if (targ->floatingagent)
		result.setFloat(targ->floatingagent->x - targ->x);
	else
		result.setFloat(world.camera.getX() - targ->x);
}

/**
 FLTY (float)
 %status maybe

 Returns the y value of the TARG agent's floating vector.
*/
void caosVM::v_FLTY() {
	valid_agent(targ);

	if (targ->floatingagent)
		result.setFloat(targ->floatingagent->x - targ->x);
	else
		result.setFloat(world.camera.getX() - targ->x);
}

/* vim: set noet: */
<commit_msg>add more hacky behaviour to MVSF, plus a better exception message<commit_after>/*
 *  caosVM_agent.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on Tue Jun 01 2004.
 *  Copyright (c) 2004 Alyssa Milburn. All rights reserved.
 *
 *  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.
 *
 */

#include "caosVM.h"
#include "openc2e.h"
#include "Agent.h"
#include "AgentRef.h"
#include "World.h"
#include <iostream>
#include <boost/format.hpp>
using std::cerr;

/**
 ELAS (command) elas (integer)
 %status maybe

 Sets the elasticity (in other words, bounciness) of the TARG agent.
*/
void caosVM::c_ELAS() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_INTEGER(elas)

	valid_agent(targ);
	targ->elas = elas;
}

/***
 ELAS (integer)
 %status maybe

 Returns the elasticity of the TARG agent.
*/
void caosVM::v_ELAS() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setInt(targ->elas);
}

/**
 MVTO (command) x (float) y (float)
 %status maybe

 Places the TARG agent at the given x/y position in the world (using the upper left hand corner of the agent).
*/
void caosVM::c_MVTO() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)
	valid_agent(targ);
	targ->moveTo(x, y);
}

/**
 MVBY (command) x (float) y (float)
 %status maybe

 Changes the TARG agent's position by the given relative distances.
*/
void caosVM::c_MVBY() {
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ);
	targ->moveTo(targ->x + x, targ->y + y);
}

/**
 VELX (variable)
 %status maybe

 Returns the current horizontal velocity, in pixels/tick, of the TARG agent.
*/
void caosVM::v_VELX() {
	VM_VERIFY_SIZE(0)
	valid_agent(targ);
	vm->valueStack.push_back(&targ->velx);
}

/**
 VELY (variable)
 %status maybe

 Returns the current vertical velocity, in pixels/tick, of the TARG agent.
*/
void caosVM::v_VELY() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	vm->valueStack.push_back(&targ->vely);
}

/**
 OBST (float) direction (integer)
 %status maybe

 Returns the distance from the TARG agent to the nearest wall that it might collide with in the given direction.
 (except right now it just gives the direction to the nearest wall at world edge - fuzzie)
*/
void caosVM::v_OBST() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_INTEGER(direction) caos_assert(direction >= 0); caos_assert(direction <= 3);

	/*
	 * TODO: CL's docs say to return "a very large number" if distance is greater than rnge - if (!collided)?
	 * also, this code is untested :) - fuzzie
	 */

	valid_agent(targ);

	Point src = targ->boundingBoxPoint(direction);
	Point dest = src;

	switch (direction) {
		case 0: // left
			dest.x -= targ->range; break;
		case 1: // right
			dest.x += targ->range; break;
		case 2: // top
			dest.y -= targ->range; break;
		case 3: // bottom
			dest.y += targ->range; break;
	}

	Room *ourRoom = world.map.roomAt(src.x, src.y);
	if (!ourRoom) {
		// TODO: is this correct behaviour?
		result.setFloat(0.0f);
		return;
	}

	unsigned int dummy1; Line dummy2; Point point;
	bool collided = world.map.collideLineWithRoomSystem(src, dest, ourRoom, point, dummy2, dummy1, targ->perm);

	switch (direction) {
		case 0: result.setFloat(src.x - point.x); break;
		case 1: result.setFloat(point.x - src.x); break;
		case 2: result.setFloat(src.y - point.y); break;
		case 3: result.setFloat(point.y - src.y); break;
	}
}

/**
 TMVT (integer) x (float) y (float)
 %status maybe

 Returns 1 if the TARG agent could move to (x, y) and still be in room system, or 0 if otherwise.
*/
void caosVM::v_TMVT() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ);

	if (targ->validInRoomSystem(Point(x, y), targ->getWidth(), targ->getHeight(), targ->perm))
		result.setInt(1);
	else
		result.setInt(0);
}

/**
 TMVF (integer) x (float) y (float)
 %status stub

 Returns 1 if the TARG Creature could move foot to (x, y) and still be in room system, or 0 if otherwise.
*/
void caosVM::v_TMVF() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ);
	result.setInt(1); // TODO: don't hardcode
}

/**
 ACCG (command) accel (float)
 %status maybe

 Sets the TARG agent's free-fall acceleration, in pixels/tick squared.
*/
void caosVM::c_ACCG() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_FLOAT(accel)

	valid_agent(targ);
	targ->accg = accel;
}

/**
 ACCG (float)
 %status maybe

 Returns the TARG agent's free-fall acceleration, in pixels/tick squared.
*/
void caosVM::v_ACCG() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setFloat(targ->accg);
}

/**
 AERO (command) aero (float)
 %status maybe

 Sets the aerodynamics of the TARG agent to the given float value.
*/
void caosVM::c_AERO() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_FLOAT(aero)

	valid_agent(targ);
	targ->aero = aero;
}

/**
 AERO (float)
 %status maybe

 Returns the aerodynamics of the TARG agent.
*/
void caosVM::v_AERO() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setFloat(targ->aero);
}

/**
 RELX (float) first (agent) second (agent)
 %status maybe

 Returns the relative horizontal distance between the centers of the two given agents.
*/
void caosVM::v_RELX() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_VALIDAGENT(second)
	VM_PARAM_VALIDAGENT(first)

	float one = first->x + (first->getWidth() / 2.0);
	float two = second->x + (second->getWidth() / 2.0);

	result.setFloat(two - one);
}

/**
 RELY (float) first (agent) second (agent)
 %status maybe

 Returns the relative vertical distance between the centers of the two given agents.
*/
void caosVM::v_RELY() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_VALIDAGENT(second)
	VM_PARAM_VALIDAGENT(first)

	float one = first->y + (first->getHeight() / 2.0);
	float two = second->y + (second->getHeight() / 2.0);

	result.setFloat(two - one);
}

/**
 VELO (command) xvel (float) yvel (float)
 %status maybe

 Sets the horizontal and vertical velocity of the TARG agent, in pixels/tick.
*/
void caosVM::c_VELO() {
	VM_VERIFY_SIZE(2)
	VM_PARAM_FLOAT(vely)
	VM_PARAM_FLOAT(velx)

	valid_agent(targ);
	targ->velx.reset();
	targ->velx.setFloat(velx);
	targ->vely.reset();
	targ->vely.setFloat(vely);
}

/**
 MVSF (command) x (float) y (float)
 %status maybe

 Move the target agent to an area inside the room system at about (x, y).
 This allows 'safe' moves.
*/
void caosVM::c_MVSF() {
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)
	valid_agent(targ);

	// TODO: this is a silly hack, to cater for simplest case (where we just need to nudge the agent up a bit)
	unsigned int tries = 0;
	while (tries < 150) {
		if (targ->validInRoomSystem(Point(x, y - tries), targ->getWidth(), targ->getHeight(), targ->perm)) {
			targ->moveTo(x, y - tries);
			return;
		}
		tries++;
	}

	// second hacky attempt, move from side to side (+/- 50) and up a little
	for (unsigned int xadjust = 0; xadjust < 50; xadjust++) {
		for (unsigned int yadjust = 0; yadjust < 50; yadjust++) {
			if (targ->validInRoomSystem(Point(x - xadjust, y - yadjust), targ->getWidth(), targ->getHeight(), targ->perm))
				targ->moveTo(x - xadjust, y - yadjust);
			else if (targ->validInRoomSystem(Point(x + xadjust, y - yadjust), targ->getWidth(), targ->getHeight(), targ->perm))
				targ->moveTo(x + xadjust, y - yadjust);
			else
				continue;
			return;
		}
	}

	throw creaturesException(boost::str(boost::format("MVSF failed to find a safe place around (%d, %d)") % x % y));
}

/**
 FRIC (float)
 %status maybe

 Returns the TARG agent's coefficient of friction as a percentage.
*/
void caosVM::v_FRIC() {
	VM_VERIFY_SIZE(0)

	valid_agent(targ);
	result.setFloat(targ->friction);
}

/**
 FRIC (command) friction (integer)
 %status maybe

 Sets the TARG agent's coefficient of friction, or the percentage of motion that will be lost as it slides on a
 surface.
*/
void caosVM::c_FRIC() {
	VM_VERIFY_SIZE(1)
	VM_PARAM_INTEGER(friction) caos_assert(friction >= 0); caos_assert(friction <= 100);

	valid_agent(targ);
	targ->friction = friction;
}

/**
 FALL (integer)
 %status maybe

 Returns 1 if the TARG agent is moving due to gravity, or 0 if otherwise.
*/
void caosVM::v_FALL() {
	VM_VERIFY_SIZE(0)
	valid_agent(targ);

	// XXX: this probably isn't quite correct, but it's close enough for now.
	if (targ->falling)
		result.setInt(1);
	else
		result.setInt(0);
}

/**
 MOVS (integer)
 %status stub

 Returns an integer representing the motion status of the TARG agent.  0 is autonomous, 1 is moving by mouse, 2 is
 floating, 3 is inside a vehicle, and 4 is being carried.
*/
void caosVM::v_MOVS() {
	valid_agent(targ);

	result.setInt(0); // TODO
}

/**
 FLTO (command) x (float) y (float)
 %status maybe

 Sets the TARG agent to float its top-left corner (x, y) away from the top-left corner of the FREL agent.
*/
void caosVM::c_FLTO() {
	VM_PARAM_FLOAT(y)
	VM_PARAM_FLOAT(x)

	valid_agent(targ)
	targ->floatTo(x, y);
}

/**
 FREL (command) agent (agent)
 %status maybe

 Sets the agent the TARG agent floats relative to. You must set the 'floatable' attribute for this to work.
 The default is NULL, which means the target agent floats relative to the main camera.
*/
void caosVM::c_FREL() {
	VM_PARAM_AGENT(agent)

	valid_agent(targ)
	targ->floatTo(agent);
}

/**
 FLTX (float)
 %status maybe

 Returns the x value of the TARG agent's floating vector.
*/
void caosVM::v_FLTX() {
	valid_agent(targ);

	if (targ->floatingagent)
		result.setFloat(targ->floatingagent->x - targ->x);
	else
		result.setFloat(world.camera.getX() - targ->x);
}

/**
 FLTY (float)
 %status maybe

 Returns the y value of the TARG agent's floating vector.
*/
void caosVM::v_FLTY() {
	valid_agent(targ);

	if (targ->floatingagent)
		result.setFloat(targ->floatingagent->x - targ->x);
	else
		result.setFloat(world.camera.getX() - targ->x);
}

/* vim: set noet: */
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2012-2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// \file
/// Render Tests for the OsgShader class.

#include "SurgSim/Framework/ApplicationData.h"
#include "SurgSim/Framework/BasicSceneElement.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Framework/Scene.h"
#include "SurgSim/Framework/SceneElement.h"
#include "SurgSim/Graphics/OsgAxesRepresentation.h"
#include "SurgSim/Graphics/OsgCamera.h"
#include "SurgSim/Graphics/OsgLight.h"
#include "SurgSim/Graphics/OsgManager.h"
#include "SurgSim/Graphics/OsgMaterial.h"
#include "SurgSim/Graphics/OsgShader.h"
#include "SurgSim/Graphics/OsgSphereRepresentation.h"
#include "SurgSim/Graphics/OsgUniform.h"
#include "SurgSim/Graphics/OsgViewElement.h"
#include "SurgSim/Graphics/RenderTests/RenderTest.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"

#include <boost/filesystem.hpp>

#include <gtest/gtest.h>

#include <random>

using SurgSim::Framework::Runtime;
using SurgSim::Framework::Scene;
using SurgSim::Framework::SceneElement;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::RigidTransform3d;
using SurgSim::Math::Vector3d;
using SurgSim::Math::makeRigidTransform;

namespace SurgSim
{

namespace Graphics
{

std::shared_ptr<Shader> loadExampleShader(const SurgSim::Framework::ApplicationData& data)
{
	std::shared_ptr<Shader> shader = std::make_shared<OsgShader>();

	std::string vertexShaderPath = data.findFile("OsgShaderRenderTests/shader.vert");
	std::string geometryShaderPath = data.findFile("OsgShaderRenderTests/shader.geom");
	std::string fragmentShaderPath = data.findFile("OsgShaderRenderTests/shader.frag");

	EXPECT_NE("", vertexShaderPath) << "Could not find vertex shader!";
	EXPECT_NE("", geometryShaderPath) << "Could not find geometry shader!";
	EXPECT_NE("", fragmentShaderPath) << "Could not find fragment shader!";

	shader->loadVertexShaderSource(vertexShaderPath);
	shader->loadGeometryShaderSource(geometryShaderPath);
	shader->loadFragmentShaderSource(fragmentShaderPath);

	return shader;
}

std::shared_ptr<Material> loadMaterial(const SurgSim::Framework::ApplicationData& data,
									   const std::string& shaderName)
{
	SCOPED_TRACE("Load Material");

	auto shader = std::make_shared<SurgSim::Graphics::OsgShader>();

	std::string filename;
	EXPECT_TRUE(data.tryFindFile(shaderName + ".vert", &filename));
	shader->loadVertexShaderSource(filename);

	EXPECT_TRUE(data.tryFindFile(shaderName + ".frag", &filename));
	shader->loadFragmentShaderSource(filename);

	auto material = std::make_shared<SurgSim::Graphics::OsgMaterial>();
	material->setShader(shader);

	return material;
}

std::shared_ptr<Material> createShinyMaterial(const SurgSim::Framework::ApplicationData& data)
{
	auto material = loadMaterial(data, "Shaders/material");
	std::shared_ptr<SurgSim::Graphics::UniformBase>
	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("diffuseColor");
	material->addUniform(uniform);

	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("specularColor");
	material->addUniform(uniform);

	uniform = std::make_shared<OsgUniform<float>>("shininess");
	material->addUniform(uniform);

	return material;
}

struct OsgShaderRenderTests : public RenderTest
{

};

/// Pops up a window with a sphere colored by its normals and its mirror along the x-axis is also drawn using the
/// geometry shader
TEST_F(OsgShaderRenderTests, SphereShaderTest)
{
	/// Add the sphere representation to the view element, no need to make another scene element
	std::shared_ptr<SphereRepresentation> sphereRepresentation =
		std::make_shared<OsgSphereRepresentation>("sphere representation");
	sphereRepresentation->setRadius(0.25);
	sphereRepresentation->setLocalPose(makeRigidTransform(Quaterniond::Identity(), Vector3d(0.25, 0.0, -1.0)));

	/// Add a shader to the sphere
	std::shared_ptr<OsgMaterial> material = std::make_shared<OsgMaterial>();
	std::shared_ptr<Shader> shader = loadExampleShader(*applicationData);

	material->setShader(shader);
	sphereRepresentation->setMaterial(material);

	viewElement->addComponent(sphereRepresentation);

	/// Run the thread
	runtime->start();
	boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
	runtime->stop();

}

TEST_F(OsgShaderRenderTests, ShinyShaderTest)
{
	/// Add the sphere representation to the view element, no need to make another scene element
	auto sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Sphere");
	std::shared_ptr<SphereRepresentation> sphereRepresentation =
		std::make_shared<OsgSphereRepresentation>("sphere representation");
	sphereRepresentation->setRadius(0.25);

	auto material = createShinyMaterial(*runtime->getApplicationData());
	material->setValue("diffuseColor", SurgSim::Math::Vector4f(0.8, 0.8, 0.1, 1.0));
	material->setValue("specularColor", SurgSim::Math::Vector4f(1.0, 1.0, 0.4, 1.0));
	material->setValue("shininess", 64.0f);
	sphereRepresentation->setMaterial(material);
	sceneElement->addComponent(sphereRepresentation);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	scene->addSceneElement(sceneElement);

	sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Light");
	auto light = std::make_shared<SurgSim::Graphics::OsgLight>("Light");
	light->setDiffuseColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setSpecularColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setLightGroupReference(SurgSim::Graphics::Representation::DefaultGroupName);
	sceneElement->addComponent(light);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	sceneElement->setPose(makeRigidTransform(Quaterniond::Identity(), Vector3d(-2.0, -2.0, -4.0)));

	scene->addSceneElement(sceneElement);

	viewElement->setPose(
		makeRigidTransform(Vector3d(0.0, 0.0, -2.0), Vector3d(0.0, 0.0, 0.0), Vector3d(0.0, 1.0, 0.0)));
	viewElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));

	/// Run the thread
	runtime->start();
	boost::this_thread::sleep(boost::posix_time::milliseconds(500));
	runtime->stop();

}

TEST_F(OsgShaderRenderTests, TexturedShinyShaderTest)
{
	/// Add the sphere representation to the view element, no need to make another scene element
	auto sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Sphere");
	std::shared_ptr<SphereRepresentation> sphereRepresentation =
		std::make_shared<OsgSphereRepresentation>("sphere representation");
	sphereRepresentation->setRadius(0.25);

	viewElement->getCamera()->setAmbientColor(SurgSim::Math::Vector4d(0.2, 0.2, 0.2, 1.0));

	auto material = loadMaterial(*runtime->getApplicationData(), "Shaders/ds_mapping_material");
	std::shared_ptr<SurgSim::Graphics::UniformBase>
	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("diffuseColor");
	material->addUniform(uniform);
	material->setValue("diffuseColor", SurgSim::Math::Vector4f(1.0, 1.0, 1.0, 1.0));

	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("specularColor");
	material->addUniform(uniform);
	material->setValue("specularColor", SurgSim::Math::Vector4f(1.0, 1.0, 1.0, 1.0));

	uniform = std::make_shared<OsgUniform<float>>("shininess");
	material->addUniform(uniform);
	material->setValue("shininess", 32.0f);

	std::string filename;
	EXPECT_TRUE(runtime->getApplicationData()->tryFindFile("Data/Textures/CheckerBoard.png", &filename));
	auto texture = std::make_shared<SurgSim::Graphics::OsgTexture2d>();
	texture->loadImage(filename);
	auto diffuseMapUniform =
		std::make_shared<OsgTextureUniform<OsgTexture2d>>("diffuseMap");
	diffuseMapUniform->set(texture);
	material->addUniform(diffuseMapUniform);

	material->setValue("diffuseColor", SurgSim::Math::Vector4f(0.8, 0.8, 0.1, 1.0));
	material->setValue("specularColor", SurgSim::Math::Vector4f(1.0, 1.0, 0.4, 1.0));
	material->setValue("shininess", 1.0f);
	sphereRepresentation->setMaterial(material);
	sceneElement->addComponent(sphereRepresentation);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	scene->addSceneElement(sceneElement);

	sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Light");
	auto light = std::make_shared<SurgSim::Graphics::OsgLight>("Light");
	light->setDiffuseColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setSpecularColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setLightGroupReference(SurgSim::Graphics::Representation::DefaultGroupName);
	sceneElement->addComponent(light);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	sceneElement->setPose(makeRigidTransform(Quaterniond::Identity(), Vector3d(-2.0, -2.0, -4.0)));

	sphereRepresentation = std::make_shared<OsgSphereRepresentation>("debug");
	sphereRepresentation->setRadius(0.01);
	sceneElement->addComponent(sphereRepresentation);

	scene->addSceneElement(sceneElement);

	//viewElement->enableManipulator(true);

	viewElement->setPose(makeRigidTransform(Vector3d(0.0, 0.0, -2.0),
											Vector3d(0.0, 0.0, 0.0),
											Vector3d(0.0, 1.0, 0.0)));
	viewElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));

	/// Run the thread
	// 	runtime->start();
	// 	boost::this_thread::sleep(boost::posix_time::milliseconds(10000));
	// 	runtime->stop();
	runtime->execute();

}

};  // namespace Graphics

};  // namespace SurgSim
<commit_msg>Use common load material function in ShaderRenderTest<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2012-2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// \file
/// Render Tests for the OsgShader class.

#include "SurgSim/Framework/ApplicationData.h"
#include "SurgSim/Framework/BasicSceneElement.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Framework/Scene.h"
#include "SurgSim/Framework/SceneElement.h"
#include "SurgSim/Graphics/OsgAxesRepresentation.h"
#include "SurgSim/Graphics/OsgCamera.h"
#include "SurgSim/Graphics/OsgLight.h"
#include "SurgSim/Graphics/OsgManager.h"
#include "SurgSim/Graphics/OsgMaterial.h"
#include "SurgSim/Graphics/OsgShader.h"
#include "SurgSim/Graphics/OsgSphereRepresentation.h"
#include "SurgSim/Graphics/OsgUniform.h"
#include "SurgSim/Graphics/OsgViewElement.h"
#include "SurgSim/Graphics/RenderTests/RenderTest.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"

#include <boost/filesystem.hpp>

#include <gtest/gtest.h>

#include <random>

using SurgSim::Framework::Runtime;
using SurgSim::Framework::Scene;
using SurgSim::Framework::SceneElement;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::RigidTransform3d;
using SurgSim::Math::Vector3d;
using SurgSim::Math::makeRigidTransform;

namespace SurgSim
{

namespace Graphics
{

std::shared_ptr<Shader> loadExampleShader(const SurgSim::Framework::ApplicationData& data)
{
	std::shared_ptr<Shader> shader = std::make_shared<OsgShader>();

	std::string vertexShaderPath = data.findFile("OsgShaderRenderTests/shader.vert");
	std::string geometryShaderPath = data.findFile("OsgShaderRenderTests/shader.geom");
	std::string fragmentShaderPath = data.findFile("OsgShaderRenderTests/shader.frag");

	EXPECT_NE("", vertexShaderPath) << "Could not find vertex shader!";
	EXPECT_NE("", geometryShaderPath) << "Could not find geometry shader!";
	EXPECT_NE("", fragmentShaderPath) << "Could not find fragment shader!";

	shader->loadVertexShaderSource(vertexShaderPath);
	shader->loadGeometryShaderSource(geometryShaderPath);
	shader->loadFragmentShaderSource(fragmentShaderPath);

	return shader;
}

std::shared_ptr<Material> createShinyMaterial(const SurgSim::Framework::ApplicationData& data)
{
	auto material = createMaterialWithShaders(data, "Shaders/material");
	std::shared_ptr<SurgSim::Graphics::UniformBase>
	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("diffuseColor");
	material->addUniform(uniform);

	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("specularColor");
	material->addUniform(uniform);

	uniform = std::make_shared<OsgUniform<float>>("shininess");
	material->addUniform(uniform);

	return material;
}

struct OsgShaderRenderTests : public RenderTest
{

};

/// Pops up a window with a sphere colored by its normals and its mirror along the x-axis is also drawn using the
/// geometry shader
TEST_F(OsgShaderRenderTests, SphereShaderTest)
{
	/// Add the sphere representation to the view element, no need to make another scene element
	std::shared_ptr<SphereRepresentation> sphereRepresentation =
		std::make_shared<OsgSphereRepresentation>("sphere representation");
	sphereRepresentation->setRadius(0.25);
	sphereRepresentation->setLocalPose(makeRigidTransform(Quaterniond::Identity(), Vector3d(0.25, 0.0, -1.0)));

	/// Add a shader to the sphere
	std::shared_ptr<OsgMaterial> material = std::make_shared<OsgMaterial>();
	std::shared_ptr<Shader> shader = loadExampleShader(*applicationData);

	material->setShader(shader);
	sphereRepresentation->setMaterial(material);

	viewElement->addComponent(sphereRepresentation);

	/// Run the thread
	runtime->start();
	boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
	runtime->stop();

}

TEST_F(OsgShaderRenderTests, ShinyShaderTest)
{
	/// Add the sphere representation to the view element, no need to make another scene element
	auto sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Sphere");
	std::shared_ptr<SphereRepresentation> sphereRepresentation =
		std::make_shared<OsgSphereRepresentation>("sphere representation");
	sphereRepresentation->setRadius(0.25);

	auto material = createShinyMaterial(*runtime->getApplicationData());
	material->setValue("diffuseColor", SurgSim::Math::Vector4f(0.8, 0.8, 0.1, 1.0));
	material->setValue("specularColor", SurgSim::Math::Vector4f(1.0, 1.0, 0.4, 1.0));
	material->setValue("shininess", 64.0f);
	sphereRepresentation->setMaterial(material);
	sceneElement->addComponent(sphereRepresentation);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	scene->addSceneElement(sceneElement);

	sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Light");
	auto light = std::make_shared<SurgSim::Graphics::OsgLight>("Light");
	light->setDiffuseColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setSpecularColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setLightGroupReference(SurgSim::Graphics::Representation::DefaultGroupName);
	sceneElement->addComponent(light);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	sceneElement->setPose(makeRigidTransform(Quaterniond::Identity(), Vector3d(-2.0, -2.0, -4.0)));

	scene->addSceneElement(sceneElement);

	viewElement->setPose(
		makeRigidTransform(Vector3d(0.0, 0.0, -2.0), Vector3d(0.0, 0.0, 0.0), Vector3d(0.0, 1.0, 0.0)));
	viewElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));

	/// Run the thread
	runtime->start();
	boost::this_thread::sleep(boost::posix_time::milliseconds(500));
	runtime->stop();

}

TEST_F(OsgShaderRenderTests, TexturedShinyShaderTest)
{
	/// Add the sphere representation to the view element, no need to make another scene element
	auto sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Sphere");
	std::shared_ptr<SphereRepresentation> sphereRepresentation =
		std::make_shared<OsgSphereRepresentation>("sphere representation");
	sphereRepresentation->setRadius(0.25);

	viewElement->getCamera()->setAmbientColor(SurgSim::Math::Vector4d(0.2, 0.2, 0.2, 1.0));

	auto material = createMaterialWithShaders(*runtime->getApplicationData(), "Shaders/ds_mapping_material");
	std::shared_ptr<SurgSim::Graphics::UniformBase>
	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("diffuseColor");
	material->addUniform(uniform);
	material->setValue("diffuseColor", SurgSim::Math::Vector4f(1.0, 1.0, 1.0, 1.0));

	uniform = std::make_shared<OsgUniform<SurgSim::Math::Vector4f>>("specularColor");
	material->addUniform(uniform);
	material->setValue("specularColor", SurgSim::Math::Vector4f(1.0, 1.0, 1.0, 1.0));

	uniform = std::make_shared<OsgUniform<float>>("shininess");
	material->addUniform(uniform);
	material->setValue("shininess", 32.0f);

	std::string filename;
	EXPECT_TRUE(runtime->getApplicationData()->tryFindFile("Data/Textures/CheckerBoard.png", &filename));
	auto texture = std::make_shared<SurgSim::Graphics::OsgTexture2d>();
	texture->loadImage(filename);
	auto diffuseMapUniform =
		std::make_shared<OsgTextureUniform<OsgTexture2d>>("diffuseMap");
	diffuseMapUniform->set(texture);
	material->addUniform(diffuseMapUniform);

	material->setValue("diffuseColor", SurgSim::Math::Vector4f(0.8, 0.8, 0.1, 1.0));
	material->setValue("specularColor", SurgSim::Math::Vector4f(1.0, 1.0, 0.4, 1.0));
	material->setValue("shininess", 1.0f);
	sphereRepresentation->setMaterial(material);
	sceneElement->addComponent(sphereRepresentation);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	scene->addSceneElement(sceneElement);

	sceneElement = std::make_shared<SurgSim::Framework::BasicSceneElement>("Light");
	auto light = std::make_shared<SurgSim::Graphics::OsgLight>("Light");
	light->setDiffuseColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setSpecularColor(SurgSim::Math::Vector4d(0.8, 0.8, 0.8, 1.0));
	light->setLightGroupReference(SurgSim::Graphics::Representation::DefaultGroupName);
	sceneElement->addComponent(light);
	sceneElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));
	sceneElement->setPose(makeRigidTransform(Quaterniond::Identity(), Vector3d(-2.0, -2.0, -4.0)));

	sphereRepresentation = std::make_shared<OsgSphereRepresentation>("debug");
	sphereRepresentation->setRadius(0.01);
	sceneElement->addComponent(sphereRepresentation);

	scene->addSceneElement(sceneElement);

	//viewElement->enableManipulator(true);

	viewElement->setPose(makeRigidTransform(Vector3d(0.0, 0.0, -2.0),
											Vector3d(0.0, 0.0, 0.0),
											Vector3d(0.0, 1.0, 0.0)));
	viewElement->addComponent(std::make_shared<SurgSim::Graphics::OsgAxesRepresentation>("axes"));

	/// Run the thread
	// 	runtime->start();
	// 	boost::this_thread::sleep(boost::posix_time::milliseconds(10000));
	// 	runtime->stop();
	runtime->execute();

}

};  // namespace Graphics

};  // namespace SurgSim
<|endoftext|>


<commit_before>#include "TeslaCoilModuleControllerSystem.h"
#include "ShipModule.h"
#include "TeslaCoilModule.h"
#include "ShipModulesTrackerSystem.h"
#include "Transform.h"
#include "PhysicsBody.h"
#include "PhysicsSystem.h"
#include <PhysicsController.h>
#include <TcpClient.h>
#include "NetworkSynced.h"
#include <RandomUtil.h>
#include "TeslaHitPacket.h"
#include <TcpServer.h>
#include <algorithm>

TeslaCoilModuleControllerSystem::TeslaCoilModuleControllerSystem(TcpServer* p_server)
	: EntitySystem(SystemType::TeslaCoilModuleControllerSystem, 5,
	ComponentType::TeslaCoilModule, ComponentType::ShipModule, ComponentType::Transform,
	ComponentType::PhysicsBody, ComponentType::NetworkSynced)
{
	m_server = p_server;
}

void TeslaCoilModuleControllerSystem::processEntities( const vector<Entity*>& p_entities )
{
	float dt = m_world->getDelta();
	for(unsigned int i=0; i<p_entities.size(); i++)
	{
		ShipModule* module = static_cast<ShipModule*>(p_entities[i]->getComponent(
			ComponentType::ShipModule));
		if(module->isOwned())
		{
			TeslaCoilModule* teslaCoil = static_cast<TeslaCoilModule*>(
				p_entities[i]->getComponent(ComponentType::TeslaCoilModule));
			teslaCoil->cooldown -= dt;
			if(teslaCoil->cooldown <= 0.0f && module->getActive())
			{
				teslaCoil->cooldown = teslaCoil->cooldownTime;
				Transform* teslaTransform = static_cast<Transform*>(p_entities[i]->
					getComponent(ComponentType::Transform));
				NetworkSynced* teslaNetsync = static_cast<NetworkSynced*>(p_entities[i]->
					getComponent(ComponentType::NetworkSynced));
				ShipModule* teslaShipModule = static_cast<ShipModule*>(p_entities[i]->
					getComponent(ComponentType::ShipModule));
				fireTeslaCoil(p_entities[i], teslaCoil, teslaTransform, teslaNetsync,
					teslaShipModule);
			}
		}
	}
}

void TeslaCoilModuleControllerSystem::fireTeslaCoil(Entity* p_teslaEntity,
	TeslaCoilModule* p_teslaModule, Transform* p_teslaTransform,
	NetworkSynced* p_teslaNetsync, ShipModule* p_teslaShipModule)
{
	vector<int> entitiesHit;
	ShipModulesTrackerSystem* moduleTracker = static_cast<
		ShipModulesTrackerSystem*>(m_world->getSystem(
		SystemType::ShipModulesTrackerSystem));
	AglVector3 teslaPosition = p_teslaTransform->getTranslation();
	for(unsigned int otherModuleIndex=0;
		otherModuleIndex<moduleTracker->getActiveEntities().size();
		otherModuleIndex++)
	{
		Entity* otherModule = moduleTracker->getActiveEntities()[otherModuleIndex];
		AglVector3 otherModulePosition = static_cast<Transform*>(otherModule->getComponent(
			ComponentType::Transform))->getTranslation();
		AglVector3 distanceVector = otherModulePosition - teslaPosition;
		if(distanceVector.lengthSquared() < p_teslaModule->range * p_teslaModule->range)
		{
			PhysicsBody* body = static_cast<PhysicsBody*>(
				otherModule->getComponent(ComponentType::PhysicsBody));
			ShipModule* otherShipModule = static_cast<ShipModule*>(
				otherModule->getComponent(ComponentType::ShipModule));
			float distance = distanceVector.length();
			float hitChance = calculateHitChance(distance, p_teslaModule->optimalRange,
				p_teslaModule->range);
			if(RandomUtil::randomSingle() <= hitChance)
			{
				if(otherShipModule->m_parentEntity != p_teslaShipModule->m_parentEntity)
				{
					otherShipModule->addDamageThisTick(hitChance * p_teslaModule->damage,
						p_teslaNetsync->getNetworkOwner());
					entitiesHit.push_back(otherModule->getIndex());
				}
			}
		}//if
	}//for: otherModuleIndex
	if(!entitiesHit.empty())
	{
		//struct lengthCompare
		//{
		//	EntityWorld* world;
		//	AglVector3 sourcePosition;
		//	lengthCompare(EntityWorld* p_world, AglVector3 p_sourcePosition)
		//	{
		//		world = p_world;
		//		sourcePosition = p_sourcePosition;
		//	}
		//	bool operator() (int i, int j)
		//	{
		//	}
		//} myLengthCompare(m_world, static_cast<Transform*>(p_teslaEntity->getComponent(
		//	ComponentType::Transform))->getTranslation());
		unsigned int i=0;
		TeslaHitPacket hitPacket;
		hitPacket.identitySource = p_teslaEntity->getIndex();
		while(i < (unsigned int)hitPacket.NUM_TESLA_HITS_MAX && i < entitiesHit.size())
		{
			hitPacket.identitiesHit[i] = entitiesHit[i];
			i++;
		}
		hitPacket.numberOfHits = static_cast<unsigned char>(i);
		m_server->broadcastPacket(hitPacket.pack());
	}
}

float TeslaCoilModuleControllerSystem::calculateHitChance(float p_distance,
	float p_optimalRange, float p_range)
{
	float hitChance = 1.0f;
	if(p_distance > p_optimalRange)
	{
		hitChance = 1.0f - (p_distance - p_optimalRange) /
			(p_range - p_optimalRange);
	}
	return hitChance;
}<commit_msg>Made so that Tesla coil fires on the 10 closest target modules (if there are 10 or more within range).<commit_after>#include "TeslaCoilModuleControllerSystem.h"
#include "ShipModule.h"
#include "TeslaCoilModule.h"
#include "ShipModulesTrackerSystem.h"
#include "Transform.h"
#include "PhysicsBody.h"
#include "PhysicsSystem.h"
#include <PhysicsController.h>
#include <TcpClient.h>
#include "NetworkSynced.h"
#include <RandomUtil.h>
#include "TeslaHitPacket.h"
#include <TcpServer.h>
#include <algorithm>

TeslaCoilModuleControllerSystem::TeslaCoilModuleControllerSystem(TcpServer* p_server)
	: EntitySystem(SystemType::TeslaCoilModuleControllerSystem, 5,
	ComponentType::TeslaCoilModule, ComponentType::ShipModule, ComponentType::Transform,
	ComponentType::PhysicsBody, ComponentType::NetworkSynced)
{
	m_server = p_server;
}

void TeslaCoilModuleControllerSystem::processEntities( const vector<Entity*>& p_entities )
{
	float dt = m_world->getDelta();
	for(unsigned int i=0; i<p_entities.size(); i++)
	{
		ShipModule* module = static_cast<ShipModule*>(p_entities[i]->getComponent(
			ComponentType::ShipModule));
		if(module->isOwned())
		{
			TeslaCoilModule* teslaCoil = static_cast<TeslaCoilModule*>(
				p_entities[i]->getComponent(ComponentType::TeslaCoilModule));
			teslaCoil->cooldown -= dt;
			if(teslaCoil->cooldown <= 0.0f && module->getActive())
			{
				teslaCoil->cooldown = teslaCoil->cooldownTime;
				Transform* teslaTransform = static_cast<Transform*>(p_entities[i]->
					getComponent(ComponentType::Transform));
				NetworkSynced* teslaNetsync = static_cast<NetworkSynced*>(p_entities[i]->
					getComponent(ComponentType::NetworkSynced));
				ShipModule* teslaShipModule = static_cast<ShipModule*>(p_entities[i]->
					getComponent(ComponentType::ShipModule));
				fireTeslaCoil(p_entities[i], teslaCoil, teslaTransform, teslaNetsync,
					teslaShipModule);
			}
		}
	}
}

void TeslaCoilModuleControllerSystem::fireTeslaCoil(Entity* p_teslaEntity,
	TeslaCoilModule* p_teslaModule, Transform* p_teslaTransform,
	NetworkSynced* p_teslaNetsync, ShipModule* p_teslaShipModule)
{
	vector<int> entitiesHit;
	ShipModulesTrackerSystem* moduleTracker = static_cast<
		ShipModulesTrackerSystem*>(m_world->getSystem(
		SystemType::ShipModulesTrackerSystem));
	AglVector3 teslaPosition = p_teslaTransform->getTranslation();
	for(unsigned int otherModuleIndex=0;
		otherModuleIndex<moduleTracker->getActiveEntities().size();
		otherModuleIndex++)
	{
		Entity* otherModule = moduleTracker->getActiveEntities()[otherModuleIndex];
		AglVector3 otherModulePosition = static_cast<Transform*>(otherModule->getComponent(
			ComponentType::Transform))->getTranslation();
		AglVector3 distanceVector = otherModulePosition - teslaPosition;
		if(distanceVector.lengthSquared() < p_teslaModule->range * p_teslaModule->range)
		{
			PhysicsBody* body = static_cast<PhysicsBody*>(
				otherModule->getComponent(ComponentType::PhysicsBody));
			ShipModule* otherShipModule = static_cast<ShipModule*>(
				otherModule->getComponent(ComponentType::ShipModule));
			float distance = distanceVector.length();
			float hitChance = calculateHitChance(distance, p_teslaModule->optimalRange,
				p_teslaModule->range);
			if(RandomUtil::randomSingle() <= hitChance)
			{
				if(otherShipModule->m_parentEntity != p_teslaShipModule->m_parentEntity)
				{
					otherShipModule->addDamageThisTick(hitChance * p_teslaModule->damage,
						p_teslaNetsync->getNetworkOwner());
					entitiesHit.push_back(otherModule->getIndex());
				}
			}
		}//if
	}//for: otherModuleIndex
	if(!entitiesHit.empty())
	{
		// Compare functor
		struct LengthCompare
		{
			EntityWorld* world;
			AglVector3 sourcePosition;
			LengthCompare(EntityWorld* p_world, AglVector3 p_sourcePosition)
			{
				world = p_world;
				sourcePosition = p_sourcePosition;
			}
			bool operator() (int p_firstIndex, int p_secondIndex)
			{
				AglVector3 firstPosition = static_cast<Transform*>(
					world->getComponentManager()->getComponent(p_firstIndex,
					ComponentType::Transform))->getTranslation();
				AglVector3 secondPosition = static_cast<Transform*>(
					world->getComponentManager()->getComponent(p_secondIndex,
					ComponentType::Transform))->getTranslation();
				float firstLengthSquared = (firstPosition - sourcePosition).lengthSquared();
				float secondLengthSquared = (secondPosition - sourcePosition).lengthSquared();
				return firstLengthSquared < secondLengthSquared;
			}
		} myLengthCompare(m_world, static_cast<Transform*>(p_teslaEntity->getComponent(
			ComponentType::Transform))->getTranslation());

		std::sort(entitiesHit.begin(), entitiesHit.begin() + entitiesHit.size(), myLengthCompare);
		unsigned int i=0;
		TeslaHitPacket hitPacket;
		hitPacket.identitySource = p_teslaEntity->getIndex();
		while(i < (unsigned int)hitPacket.NUM_TESLA_HITS_MAX && i < entitiesHit.size())
		{
			hitPacket.identitiesHit[i] = entitiesHit[i];
			i++;
		}
		hitPacket.numberOfHits = static_cast<unsigned char>(i);
		m_server->broadcastPacket(hitPacket.pack());
	}
}

float TeslaCoilModuleControllerSystem::calculateHitChance(float p_distance,
	float p_optimalRange, float p_range)
{
	float hitChance = 1.0f;
	if(p_distance > p_optimalRange)
	{
		hitChance = 1.0f - (p_distance - p_optimalRange) /
			(p_range - p_optimalRange);
	}
	return hitChance;
}<|endoftext|>


<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#ifndef    AL_MESSAGING_SLEEP_HXX_
# define   AL_MESSAGING_SLEEP_HXX_

#ifdef _WIN32
#  define sleep(x) Sleep(x * 1000)
#else
#  include <unistd.h>
#endif

#endif    /* !AL_MESSAGING_SLEEP_HXX_ */
<commit_msg>Fixed sleep<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010 Aldebaran Robotics
*/

#ifndef    AL_MESSAGING_SLEEP_HXX_
# define   AL_MESSAGING_SLEEP_HXX_

#ifdef _WIN32
#  include <winsock2.h>
#  define sleep(x) Sleep(x * 1000)
#else
#  include <unistd.h>
#endif

#endif    /* !AL_MESSAGING_SLEEP_HXX_ */
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include "otbDotProductImageFilter.h"
#include "otbProjectiveProjectionImageFilter.h"
#include "otbMatrixImageFilter.h"
#include "otbVectorImageToMatrixImageFilter.h"
#include "otbStreamingStatisticsImageFilter.h"
#include "otbStreamingStatisticsVectorImageFilter.h"

const unsigned int Dimension = 2;
typedef double PixelType;
typedef double PrecisionType;

typedef otb::Image<PixelType, Dimension> ImageType;
typedef otb::VectorImage<PixelType, Dimension> VectorImageType;
typedef otb::ImageFileReader<VectorImageType> ReaderType;
typedef otb::ProjectiveProjectionImageFilter<VectorImageType, VectorImageType, PrecisionType> ProjectiveProjectionImageFilterType;
typedef otb::DotProductImageFilter<VectorImageType, ImageType> DotProductImageFilterType;
typedef otb::MatrixImageFilter<VectorImageType, VectorImageType> MatrixImageFilterType;
typedef otb::VectorImageToMatrixImageFilter<VectorImageType> VectorImageToMatrixImageFilterType;
typedef otb::ImageFileWriter<VectorImageType> WriterType;
typedef otb::StreamingStatisticsVectorImageFilter<VectorImageType> StreamingStatisticsVectorImageFilterType;
typedef otb::StreamingStatisticsImageFilter<ImageType> StreamingStatisticsImageFilterType;

typedef StreamingStatisticsVectorImageFilterType::MatrixType MatrixType;

int otbProjectiveProjectionNew(int argc, char * argv[])
{
  ProjectiveProjectionImageFilterType::Pointer filter = ProjectiveProjectionImageFilterType::New();
  std::cout << filter << std::endl;
  return EXIT_SUCCESS;
}

int otbProjectiveProjectionTestHighSNR(int argc, char * argv[])
{
  const char * inputImage = argv[1];
  const unsigned int nbEndmembers = atoi(argv[2]);
  const char * outputImage = argv[3];

  ReaderType::Pointer readerImage = ReaderType::New();
  readerImage->SetFileName(inputImage);

  std::cout << "Computing image stats" << std::endl;
  StreamingStatisticsVectorImageFilterType::Pointer statsInput = \
      StreamingStatisticsVectorImageFilterType::New();

  statsInput->SetInput(readerImage->GetOutput());
  statsInput->Update();

  std::cout << "Computing SVD of correlation matrix" << std::endl;
  // Take the correlation matrix
  vnl_matrix<PrecisionType> R = statsInput->GetCorrelation().GetVnlMatrix();

  // Apply SVD
  vnl_svd<PrecisionType>    svd(R);
  vnl_matrix<PrecisionType> U = svd.U();
  vnl_matrix<PrecisionType> Ud = U.get_n_columns(0, nbEndmembers).transpose();

  std::cout << "Apply dimensionnality reduction" << std::endl;
  // Xd = Ud.'*M;
  MatrixImageFilterType::Pointer mulUd = MatrixImageFilterType::New();
  mulUd->SetInput(readerImage->GetOutput());
  mulUd->SetMatrix(Ud);
  mulUd->UpdateOutputInformation();

  VectorImageType::Pointer Xd = mulUd->GetOutput();

  // Compute mean(Xd)
  std::cout << "Compute mean(Xd)" << std::endl;
  StreamingStatisticsVectorImageFilterType::Pointer statsXd = \
      StreamingStatisticsVectorImageFilterType::New();
  statsXd->SetInput(Xd);
  statsXd->Update();
  VectorImageType::PixelType Xdmean = statsXd->GetMean();

  // Compute Xd ./ repmat( sum( Xd .* repmat(u, [1 N]) ) , [d 1]);
  // -> divides each pixel component by the dot product <Xd(i, j), mean(Xd)>
  std::cout << "Compute projective projection" << std::endl;
  ProjectiveProjectionImageFilterType::Pointer proj = ProjectiveProjectionImageFilterType::New();
  proj->SetInput(Xd);
  proj->SetProjectionDirection(Xdmean);

  std::cout << "Write output" << std::endl;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(outputImage);
  writer->SetInput(proj->GetOutput());
  writer->Update();

  return EXIT_SUCCESS;
}
<commit_msg>ENH: fix ProjectiveProjection test<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include "otbDotProductImageFilter.h"
#include "otbProjectiveProjectionImageFilter.h"
#include "otbMatrixImageFilter.h"
#include "otbVectorImageToMatrixImageFilter.h"
#include "otbStreamingStatisticsImageFilter.h"
#include "otbStreamingStatisticsVectorImageFilter.h"

const unsigned int Dimension = 2;
typedef double PixelType;
typedef double PrecisionType;

typedef otb::Image<PixelType, Dimension> ImageType;
typedef otb::VectorImage<PixelType, Dimension> VectorImageType;
typedef otb::ImageFileReader<VectorImageType> ReaderType;
typedef otb::ProjectiveProjectionImageFilter<VectorImageType, VectorImageType, PrecisionType> ProjectiveProjectionImageFilterType;
typedef otb::DotProductImageFilter<VectorImageType, ImageType> DotProductImageFilterType;
typedef otb::MatrixImageFilter<VectorImageType, VectorImageType> MatrixImageFilterType;
typedef otb::VectorImageToMatrixImageFilter<VectorImageType> VectorImageToMatrixImageFilterType;
typedef otb::ImageFileWriter<VectorImageType> WriterType;
typedef otb::StreamingStatisticsVectorImageFilter<VectorImageType> StreamingStatisticsVectorImageFilterType;
typedef otb::StreamingStatisticsImageFilter<ImageType> StreamingStatisticsImageFilterType;

typedef StreamingStatisticsVectorImageFilterType::MatrixType MatrixType;

int otbProjectiveProjectionNew(int argc, char * argv[])
{
  ProjectiveProjectionImageFilterType::Pointer filter = ProjectiveProjectionImageFilterType::New();
  std::cout << filter << std::endl;
  return EXIT_SUCCESS;
}

int otbProjectiveProjectionTestHighSNR(int argc, char * argv[])
{
  const char * inputImage = argv[1];
  const unsigned int nbEndmembers = atoi(argv[2]);
  const char * outputImage = argv[3];

  ReaderType::Pointer readerImage = ReaderType::New();
  readerImage->SetFileName(inputImage);

  std::cout << "Computing image stats" << std::endl;
  StreamingStatisticsVectorImageFilterType::Pointer statsInput = \
      StreamingStatisticsVectorImageFilterType::New();

  statsInput->SetInput(readerImage->GetOutput());
  statsInput->Update();

  std::cout << "Computing SVD of correlation matrix" << std::endl;
  // Take the correlation matrix
  vnl_matrix<PrecisionType> R = statsInput->GetCorrelation().GetVnlMatrix();

  // Apply SVD
  vnl_svd<PrecisionType>    svd(R);
  vnl_matrix<PrecisionType> U = svd.U();
  vnl_matrix<PrecisionType> Ud = U.get_n_columns(0, nbEndmembers).transpose();

  std::cout << "Apply dimensionnality reduction" << std::endl;
  // Xd = Ud.'*M;
  MatrixImageFilterType::Pointer mulUd = MatrixImageFilterType::New();
  mulUd->SetInput(readerImage->GetOutput());
  mulUd->SetMatrix(Ud);
  mulUd->MatrixByVectorOn();
  mulUd->UpdateOutputInformation();

  VectorImageType::Pointer Xd = mulUd->GetOutput();

  // Compute mean(Xd)
  std::cout << "Compute mean(Xd)" << std::endl;
  StreamingStatisticsVectorImageFilterType::Pointer statsXd = \
      StreamingStatisticsVectorImageFilterType::New();
  statsXd->SetInput(Xd);
  statsXd->Update();
  VectorImageType::PixelType Xdmean = statsXd->GetMean();

  // Compute Xd ./ repmat( sum( Xd .* repmat(u, [1 N]) ) , [d 1]);
  // -> divides each pixel component by the dot product <Xd(i, j), mean(Xd)>
  std::cout << "Compute projective projection" << std::endl;
  ProjectiveProjectionImageFilterType::Pointer proj = ProjectiveProjectionImageFilterType::New();
  proj->SetInput(Xd);
  proj->SetProjectionDirection(Xdmean);

  std::cout << "Write output" << std::endl;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(outputImage);
  writer->SetInput(proj->GetOutput());
  writer->Update();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

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 <htl_stdinc.hpp>

#include <inttypes.h>
#include <stdlib.h>

#include <string>
#include <sstream>
using namespace std;

#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_rtmp_play.hpp>
#include <htl_app_rtmp_publish.hpp>

#include <htl_app_rtmp_load.hpp>

StRtmpTask::StRtmpTask(){
}

StRtmpTask::~StRtmpTask(){
}

int StRtmpTask::Initialize(string http_url, double startup, double delay, double error, int count){
    int ret = ERROR_SUCCESS;

    if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
        return ret;
    }

    return ret;
}

Uri* StRtmpTask::GetUri(){
    return &url;
}

int StRtmpTask::ProcessTask(){
    int ret = ERROR_SUCCESS;

    Trace("start to process RTMP play task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
        GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);

    StRtmpPlayClient client;

    // if count is zero, infinity loop.
    for(int i = 0; count == 0 || i < count; i++){
        statistic->OnTaskStart(GetId(), url.GetUrl());

        if((ret = client.Dump(&url)) != ERROR_SUCCESS){
            statistic->OnTaskError(GetId(), 0);

            Error("rtmp client dump url failed. ret=%d", ret);
            st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
            continue;
        }

        int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
        Trace("[RTMP] %s dump success, sleep %dms", url.GetUrl(), sleep_ms);
        st_usleep(sleep_ms * 1000);

        statistic->OnTaskEnd(GetId(), 0);
    }

    return ret;
}

StRtmpTaskFast::StRtmpTaskFast(){
}

StRtmpTaskFast::~StRtmpTaskFast(){
}

int StRtmpTaskFast::Initialize(string http_url, double startup, double delay, double error, int count){
    int ret = ERROR_SUCCESS;

    if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
        return ret;
    }

    return ret;
}

Uri* StRtmpTaskFast::GetUri(){
    return &url;
}

int StRtmpTaskFast::ProcessTask(){
    int ret = ERROR_SUCCESS;

    Trace("start to process RTMP play fast task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
        GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);

    StRtmpPlayClient client;

    // if count is zero, infinity loop.
    for(int i = 0; count == 0 || i < count; i++){
        statistic->OnTaskStart(GetId(), url.GetUrl());

        if((ret = client.Dump(&url)) != ERROR_SUCCESS){
            statistic->OnTaskError(GetId(), 0);

            Error("rtmp client dump url failed. ret=%d", ret);
            st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
            continue;
        }

        int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
        Trace("[RTMP] %s dump success, sleep %dms", url.GetUrl(), sleep_ms);
        st_usleep(sleep_ms * 1000);

        statistic->OnTaskEnd(GetId(), 0);
    }

    return ret;
}

StRtmpPublishTask::StRtmpPublishTask(){
}

StRtmpPublishTask::~StRtmpPublishTask(){
}

int StRtmpPublishTask::Initialize(string input, string http_url, double startup, double delay, double error, int count){
    int ret = ERROR_SUCCESS;

    input_flv_file = input;

    if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
        return ret;
    }

    return ret;
}

Uri* StRtmpPublishTask::GetUri(){
    return &url;
}

int StRtmpPublishTask::ProcessTask(){
    int ret = ERROR_SUCCESS;

    Trace("start to process RTMP publish task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
        GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);

    StRtmpPublishClient client;

    // if count is zero, infinity loop.
    for(int i = 0; count == 0 || i < count; i++){
        statistic->OnTaskStart(GetId(), url.GetUrl());

        if((ret = client.Publish(input_flv_file, &url)) != ERROR_SUCCESS){
            statistic->OnTaskError(GetId(), 0);

            Error("rtmp client publish url failed. ret=%d", ret);
            st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
            continue;
        }

        int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
        Trace("[RTMP] %s publish success, sleep %dms", url.GetUrl(), sleep_ms);
        st_usleep(sleep_ms * 1000);

        statistic->OnTaskEnd(GetId(), 0);
    }

    return ret;
}

<commit_msg>use fast rtmp client.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

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 <htl_stdinc.hpp>

#include <inttypes.h>
#include <stdlib.h>

#include <string>
#include <sstream>
using namespace std;

#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_rtmp_play.hpp>
#include <htl_app_rtmp_publish.hpp>

#include <htl_app_rtmp_load.hpp>

StRtmpTask::StRtmpTask(){
}

StRtmpTask::~StRtmpTask(){
}

int StRtmpTask::Initialize(string http_url, double startup, double delay, double error, int count){
    int ret = ERROR_SUCCESS;

    if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
        return ret;
    }

    return ret;
}

Uri* StRtmpTask::GetUri(){
    return &url;
}

int StRtmpTask::ProcessTask(){
    int ret = ERROR_SUCCESS;

    Trace("start to process RTMP play task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
        GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);

    StRtmpPlayClient client;

    // if count is zero, infinity loop.
    for(int i = 0; count == 0 || i < count; i++){
        statistic->OnTaskStart(GetId(), url.GetUrl());

        if((ret = client.Dump(&url)) != ERROR_SUCCESS){
            statistic->OnTaskError(GetId(), 0);

            Error("rtmp client dump url failed. ret=%d", ret);
            st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
            continue;
        }

        int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
        Trace("[RTMP] %s dump success, sleep %dms", url.GetUrl(), sleep_ms);
        st_usleep(sleep_ms * 1000);

        statistic->OnTaskEnd(GetId(), 0);
    }

    return ret;
}

StRtmpTaskFast::StRtmpTaskFast(){
}

StRtmpTaskFast::~StRtmpTaskFast(){
}

int StRtmpTaskFast::Initialize(string http_url, double startup, double delay, double error, int count){
    int ret = ERROR_SUCCESS;

    if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
        return ret;
    }

    return ret;
}

Uri* StRtmpTaskFast::GetUri(){
    return &url;
}

int StRtmpTaskFast::ProcessTask(){
    int ret = ERROR_SUCCESS;

    Trace("start to process RTMP play fast task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
        GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);

    StRtmpPlayClientFast client;

    // if count is zero, infinity loop.
    for(int i = 0; count == 0 || i < count; i++){
        statistic->OnTaskStart(GetId(), url.GetUrl());

        if((ret = client.Dump(&url)) != ERROR_SUCCESS){
            statistic->OnTaskError(GetId(), 0);

            Error("rtmp client dump url failed. ret=%d", ret);
            st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
            continue;
        }

        int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
        Trace("[RTMP] %s dump success, sleep %dms", url.GetUrl(), sleep_ms);
        st_usleep(sleep_ms * 1000);

        statistic->OnTaskEnd(GetId(), 0);
    }

    return ret;
}

StRtmpPublishTask::StRtmpPublishTask(){
}

StRtmpPublishTask::~StRtmpPublishTask(){
}

int StRtmpPublishTask::Initialize(string input, string http_url, double startup, double delay, double error, int count){
    int ret = ERROR_SUCCESS;

    input_flv_file = input;

    if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
        return ret;
    }

    return ret;
}

Uri* StRtmpPublishTask::GetUri(){
    return &url;
}

int StRtmpPublishTask::ProcessTask(){
    int ret = ERROR_SUCCESS;

    Trace("start to process RTMP publish task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
        GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);

    StRtmpPublishClient client;

    // if count is zero, infinity loop.
    for(int i = 0; count == 0 || i < count; i++){
        statistic->OnTaskStart(GetId(), url.GetUrl());

        if((ret = client.Publish(input_flv_file, &url)) != ERROR_SUCCESS){
            statistic->OnTaskError(GetId(), 0);

            Error("rtmp client publish url failed. ret=%d", ret);
            st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
            continue;
        }

        int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
        Trace("[RTMP] %s publish success, sleep %dms", url.GetUrl(), sleep_ms);
        st_usleep(sleep_ms * 1000);

        statistic->OnTaskEnd(GetId(), 0);
    }

    return ret;
}

<|endoftext|>