<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/predecoder.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "sim/host.hh"

namespace X86ISA
{
    void Predecoder::process()
    {
        //This function drives the predecoder state machine.

        //Some sanity checks. You shouldn't try to process more bytes if
        //there aren't any, and you shouldn't overwrite an already
        //predecoder ExtMachInst.
        assert(!outOfBytes);
        assert(!emiIsReady);

        //While there's still something to do...
        while(!emiIsReady && !outOfBytes)
        {
            uint8_t nextByte = getNextByte();
            switch(state)
            {
              case PrefixState:
                state = doPrefixState(nextByte);
                break;
              case OpcodeState:
                state = doOpcodeState(nextByte);
                break;
              case ModRMState:
                state = doModRMState(nextByte);
                break;
              case SIBState:
                state = doSIBState(nextByte);
                break;
              case DisplacementState:
                state = doDisplacementState();
                break;
              case ImmediateState:
                state = doImmediateState();
                break;
              case ErrorState:
                panic("Went to the error state in the predecoder.\n");
              default:
                panic("Unrecognized state! %d\n", state);
            }
        }
    }

    //Either get a prefix and record it in the ExtMachInst, or send the
    //state machine on to get the opcode(s).
    Predecoder::State Predecoder::doPrefixState(uint8_t nextByte)
    {
        uint8_t prefix = Prefixes[nextByte];
        State nextState = PrefixState;
        if(prefix)
            consumeByte();
        switch(prefix)
        {
            //Operand size override prefixes
          case OperandSizeOverride:
            DPRINTF(Predecoder, "Found operand size override prefix.\n");
            break;
          case AddressSizeOverride:
            DPRINTF(Predecoder, "Found address size override prefix.\n");
            break;
            //Segment override prefixes
          case CSOverride:
            DPRINTF(Predecoder, "Found cs segment override.\n");
            break;
          case DSOverride:
            DPRINTF(Predecoder, "Found ds segment override.\n");
            break;
          case ESOverride:
            DPRINTF(Predecoder, "Found es segment override.\n");
            break;
          case FSOverride:
            DPRINTF(Predecoder, "Found fs segment override.\n");
            break;
          case GSOverride:
            DPRINTF(Predecoder, "Found gs segment override.\n");
            break;
          case SSOverride:
            DPRINTF(Predecoder, "Found ss segment override.\n");
            break;
          case Lock:
            DPRINTF(Predecoder, "Found lock prefix.\n");
            break;
          case Rep:
            DPRINTF(Predecoder, "Found rep prefix.\n");
            break;
          case Repne:
            DPRINTF(Predecoder, "Found repne prefix.\n");
            break;
          case RexPrefix:
            DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
            emi.rex = nextByte;
            break;
          case 0:
            emi.opcode.num = 0;
            nextState = OpcodeState;
            break;
          default:
            panic("Unrecognized prefix %#x\n", nextByte);
        }
        return nextState;
    }

    //Load all the opcodes (currently up to 2) and then figure out
    //what immediate and/or ModRM is needed.
    Predecoder::State Predecoder::doOpcodeState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.opcode.num++;
        //We can't handle 3+ byte opcodes right now
        assert(emi.opcode.num < 3);
        consumeByte();
        if(emi.opcode.num == 1 && nextByte == 0x0f)
        {
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found two byte opcode.\n");
            emi.opcode.prefixA = nextByte;
        }
        else if(emi.opcode.num == 2 &&
                (nextByte == 0x0f ||
                 (nextByte & 0xf8) == 0x38))
        {
            panic("Three byte opcodes aren't yet supported!\n");
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found three byte opcode.\n");
            emi.opcode.prefixB = nextByte;
        }
        else
        {
            DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
            emi.opcode.op = nextByte;

            //Prepare for any immediate/displacement we might need
            immediateCollected = 0;
            emi.immediate = 0;
            displacementCollected = 0;
            emi.displacement = 0;

            //Figure out how big of an immediate we'll retreive based
            //on the opcode.
            int immType = ImmediateType[
                emi.opcode.num - 1][nextByte];
            if(0) //16 bit mode
                immediateSize = ImmediateTypeToSize[0][immType];
            else if(!(emi.rex & 0x4)) //32 bit mode
                immediateSize = ImmediateTypeToSize[1][immType];
            else //64 bit mode
                immediateSize = ImmediateTypeToSize[2][immType];

            //Determine what to expect next
            if (UsesModRM[emi.opcode.num - 1][nextByte]) {
                nextState = ModRMState;
            } else if(immediateSize) {
                nextState = ImmediateState;
            } else {
                emiIsReady = true;
                nextState = PrefixState;
            }
        }
        return nextState;
    }

    //Get the ModRM byte and determine what displacement, if any, there is.
    //Also determine whether or not to get the SIB byte, displacement, or
    //immediate next.
    Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.modRM = nextByte;
        DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
        if (0) {//FIXME in 16 bit mode
            //figure out 16 bit displacement size
            if(nextByte & 0xC7 == 0x06 ||
                    nextByte & 0xC0 == 0x80)
                displacementSize = 2;
            else if(nextByte & 0xC0 == 0x40)
                displacementSize = 1;
            else
                displacementSize = 0;
        } else {
            //figure out 32/64 bit displacement size
            if(nextByte & 0xC7 == 0x05 ||
                    nextByte & 0xC0 == 0x80)
                displacementSize = 4;
            else if(nextByte & 0xC0 == 0x40)
                displacementSize = 2;
            else
                displacementSize = 0;
        }
        //If there's an SIB, get that next.
        //There is no SIB in 16 bit mode.
        if(nextByte & 0x7 == 4 &&
                nextByte & 0xC0 != 0xC0) {
                // && in 32/64 bit mode)
            nextState = SIBState;
        } else if(displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = PrefixState;
        }
        //The ModRM byte is consumed no matter what
        consumeByte();
        return nextState;
    }

    //Get the SIB byte. We don't do anything with it at this point, other
    //than storing it in the ExtMachInst. Determine if we need to get a
    //displacement or immediate next.
    Predecoder::State Predecoder::doSIBState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.sib = nextByte;
        DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
        consumeByte();
        if(displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = PrefixState;
        }
        return nextState;
    }

    //Gather up the displacement, or at least as much of it
    //as we can get.
    Predecoder::State Predecoder::doDisplacementState()
    {
        State nextState = ErrorState;

        getImmediate(displacementCollected,
                emi.displacement,
                displacementSize);

        DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
                displacementSize, displacementCollected);

        if(displacementSize == displacementCollected) {
            //Sign extend the displacement
            switch(displacementSize)
            {
              case 1:
                emi.displacement = sext<8>(emi.displacement);
                break;
              case 2:
                emi.displacement = sext<16>(emi.displacement);
                break;
              case 4:
                emi.displacement = sext<32>(emi.displacement);
                break;
              default:
                panic("Undefined displacement size!\n");
            }
            DPRINTF(Predecoder, "Collected displacement %#x.\n",
                    emi.displacement);
            if(immediateSize) {
                nextState = ImmediateState;
            } else {
                emiIsReady = true;
                nextState = PrefixState;
            }
        }
        else
            nextState = DisplacementState;
        return nextState;
    }

    //Gather up the immediate, or at least as much of it
    //as we can get
    Predecoder::State Predecoder::doImmediateState()
    {
        State nextState = ErrorState;

        getImmediate(immediateCollected,
                emi.immediate,
                immediateSize);

        DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n",
                immediateSize, immediateCollected);

        if(immediateSize == immediateCollected)
        {
            DPRINTF(Predecoder, "Collected immediate %#x.\n",
                    emi.immediate);
            emiIsReady = true;
            nextState = PrefixState;
        }
        else
            nextState = ImmediateState;
        return nextState;
    }
}
<commit_msg>Zero out ModRM if the byte isn't there, and fix some displacement size stuff.<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "arch/x86/predecoder.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "sim/host.hh"

namespace X86ISA
{
    void Predecoder::process()
    {
        //This function drives the predecoder state machine.

        //Some sanity checks. You shouldn't try to process more bytes if
        //there aren't any, and you shouldn't overwrite an already
        //predecoder ExtMachInst.
        assert(!outOfBytes);
        assert(!emiIsReady);

        //While there's still something to do...
        while(!emiIsReady && !outOfBytes)
        {
            uint8_t nextByte = getNextByte();
            switch(state)
            {
              case PrefixState:
                state = doPrefixState(nextByte);
                break;
              case OpcodeState:
                state = doOpcodeState(nextByte);
                break;
              case ModRMState:
                state = doModRMState(nextByte);
                break;
              case SIBState:
                state = doSIBState(nextByte);
                break;
              case DisplacementState:
                state = doDisplacementState();
                break;
              case ImmediateState:
                state = doImmediateState();
                break;
              case ErrorState:
                panic("Went to the error state in the predecoder.\n");
              default:
                panic("Unrecognized state! %d\n", state);
            }
        }
    }

    //Either get a prefix and record it in the ExtMachInst, or send the
    //state machine on to get the opcode(s).
    Predecoder::State Predecoder::doPrefixState(uint8_t nextByte)
    {
        uint8_t prefix = Prefixes[nextByte];
        State nextState = PrefixState;
        if(prefix)
            consumeByte();
        switch(prefix)
        {
            //Operand size override prefixes
          case OperandSizeOverride:
            DPRINTF(Predecoder, "Found operand size override prefix.\n");
            break;
          case AddressSizeOverride:
            DPRINTF(Predecoder, "Found address size override prefix.\n");
            break;
            //Segment override prefixes
          case CSOverride:
            DPRINTF(Predecoder, "Found cs segment override.\n");
            break;
          case DSOverride:
            DPRINTF(Predecoder, "Found ds segment override.\n");
            break;
          case ESOverride:
            DPRINTF(Predecoder, "Found es segment override.\n");
            break;
          case FSOverride:
            DPRINTF(Predecoder, "Found fs segment override.\n");
            break;
          case GSOverride:
            DPRINTF(Predecoder, "Found gs segment override.\n");
            break;
          case SSOverride:
            DPRINTF(Predecoder, "Found ss segment override.\n");
            break;
          case Lock:
            DPRINTF(Predecoder, "Found lock prefix.\n");
            break;
          case Rep:
            DPRINTF(Predecoder, "Found rep prefix.\n");
            break;
          case Repne:
            DPRINTF(Predecoder, "Found repne prefix.\n");
            break;
          case RexPrefix:
            DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
            emi.rex = nextByte;
            break;
          case 0:
            emi.opcode.num = 0;
            nextState = OpcodeState;
            break;
          default:
            panic("Unrecognized prefix %#x\n", nextByte);
        }
        return nextState;
    }

    //Load all the opcodes (currently up to 2) and then figure out
    //what immediate and/or ModRM is needed.
    Predecoder::State Predecoder::doOpcodeState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.opcode.num++;
        //We can't handle 3+ byte opcodes right now
        assert(emi.opcode.num < 3);
        consumeByte();
        if(emi.opcode.num == 1 && nextByte == 0x0f)
        {
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found two byte opcode.\n");
            emi.opcode.prefixA = nextByte;
        }
        else if(emi.opcode.num == 2 &&
                (nextByte == 0x0f ||
                 (nextByte & 0xf8) == 0x38))
        {
            panic("Three byte opcodes aren't yet supported!\n");
            nextState = OpcodeState;
            DPRINTF(Predecoder, "Found three byte opcode.\n");
            emi.opcode.prefixB = nextByte;
        }
        else
        {
            DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
            emi.opcode.op = nextByte;

            //Prepare for any immediate/displacement we might need
            immediateCollected = 0;
            emi.immediate = 0;
            displacementCollected = 0;
            emi.displacement = 0;

            //Figure out how big of an immediate we'll retreive based
            //on the opcode.
            int immType = ImmediateType[
                emi.opcode.num - 1][nextByte];
            if(0) //16 bit mode
                immediateSize = ImmediateTypeToSize[0][immType];
            else if(!(emi.rex & 0x4)) //32 bit mode
                immediateSize = ImmediateTypeToSize[1][immType];
            else //64 bit mode
                immediateSize = ImmediateTypeToSize[2][immType];

            //Determine what to expect next
            if (UsesModRM[emi.opcode.num - 1][nextByte]) {
                nextState = ModRMState;
            } else {
                //If there's no modRM byte, set it to 0 so we can detect
                //that later.
                emi.modRM = 0;
                if(immediateSize) {
                    nextState = ImmediateState;
                } else {
                    emiIsReady = true;
                    nextState = PrefixState;
                }
            }
        }
        return nextState;
    }

    //Get the ModRM byte and determine what displacement, if any, there is.
    //Also determine whether or not to get the SIB byte, displacement, or
    //immediate next.
    Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.modRM = nextByte;
        DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
        if (0) {//FIXME in 16 bit mode
            //figure out 16 bit displacement size
            if(nextByte & 0xC7 == 0x06 ||
                    nextByte & 0xC0 == 0x80)
                displacementSize = 2;
            else if(nextByte & 0xC0 == 0x40)
                displacementSize = 1;
            else
                displacementSize = 0;
        } else {
            //figure out 32/64 bit displacement size
            if(nextByte & 0xC6 == 0x04 ||
                    nextByte & 0xC0 == 0x80)
                displacementSize = 4;
            else if(nextByte & 0xC0 == 0x40)
                displacementSize = 1;
            else
                displacementSize = 0;
        }
        //If there's an SIB, get that next.
        //There is no SIB in 16 bit mode.
        if(nextByte & 0x7 == 4 &&
                nextByte & 0xC0 != 0xC0) {
                // && in 32/64 bit mode)
            nextState = SIBState;
        } else if(displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = PrefixState;
        }
        //The ModRM byte is consumed no matter what
        consumeByte();
        return nextState;
    }

    //Get the SIB byte. We don't do anything with it at this point, other
    //than storing it in the ExtMachInst. Determine if we need to get a
    //displacement or immediate next.
    Predecoder::State Predecoder::doSIBState(uint8_t nextByte)
    {
        State nextState = ErrorState;
        emi.sib = nextByte;
        DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
        consumeByte();
        if(displacementSize) {
            nextState = DisplacementState;
        } else if(immediateSize) {
            nextState = ImmediateState;
        } else {
            emiIsReady = true;
            nextState = PrefixState;
        }
        return nextState;
    }

    //Gather up the displacement, or at least as much of it
    //as we can get.
    Predecoder::State Predecoder::doDisplacementState()
    {
        State nextState = ErrorState;

        getImmediate(displacementCollected,
                emi.displacement,
                displacementSize);

        DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
                displacementSize, displacementCollected);

        if(displacementSize == displacementCollected) {
            //Sign extend the displacement
            switch(displacementSize)
            {
              case 1:
                emi.displacement = sext<8>(emi.displacement);
                break;
              case 2:
                emi.displacement = sext<16>(emi.displacement);
                break;
              case 4:
                emi.displacement = sext<32>(emi.displacement);
                break;
              default:
                panic("Undefined displacement size!\n");
            }
            DPRINTF(Predecoder, "Collected displacement %#x.\n",
                    emi.displacement);
            if(immediateSize) {
                nextState = ImmediateState;
            } else {
                emiIsReady = true;
                nextState = PrefixState;
            }
        }
        else
            nextState = DisplacementState;
        return nextState;
    }

    //Gather up the immediate, or at least as much of it
    //as we can get
    Predecoder::State Predecoder::doImmediateState()
    {
        State nextState = ErrorState;

        getImmediate(immediateCollected,
                emi.immediate,
                immediateSize);

        DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n",
                immediateSize, immediateCollected);

        if(immediateSize == immediateCollected)
        {
            DPRINTF(Predecoder, "Collected immediate %#x.\n",
                    emi.immediate);
            emiIsReady = true;
            nextState = PrefixState;
        }
        else
            nextState = ImmediateState;
        return nextState;
    }
}
<|endoftext|>


<commit_before>#ifdef USE_MEM_CHECK
#include <mcheck.h>
#endif

#include <osg/Group>
#include <osg/Notify>

#include <osgDB/Registry>
#include <osgDB/ReadFile>

#include <osgProducer/Viewer>

#include <osg/Quat>

#if defined (WIN32) && !defined(__CYGWIN__)
#include <winsock.h>
#endif

#include "receiver.h"
#include "broadcaster.h"

typedef unsigned char * BytePtr;
template <class T>
inline void swapBytes(  T &s )
{
    if( sizeof( T ) == 1 ) return;

    T d = s;
    BytePtr sptr = (BytePtr)&s;
    BytePtr dptr = &(((BytePtr)&d)[sizeof(T)-1]);

    for( unsigned int i = 0; i < sizeof(T); i++ )
        *(sptr++) = *(dptr--);
}

class PackedEvent
{
    public:
        PackedEvent():
            _eventType(osgProducer::EventAdapter::NONE),
            _key(0),
            _button(0),
            _Xmin(0),_Xmax(0),
            _Ymin(0),_Ymax(0),
            _mx(0),
            _my(0),
            _buttonMask(0),
            _modKeyMask(0),
            _time(0.0) {}

        void set(const osgProducer::EventAdapter& event)
        {
            _eventType = event._eventType;
            _key = event._key;
            _button = event._button;
            _Xmin = event._Xmin;
            _Xmax = event._Xmax;
            _Ymin = event._Ymin;
            _Ymax = event._Ymax;
            _mx = event._mx;
            _my = event._my;
            _buttonMask = event._buttonMask;
            _modKeyMask = event._modKeyMask;
            _time = event._time;
        }

        void get(osgProducer::EventAdapter& event)
        {
            event._eventType = _eventType;
            event._key = _key;
            event._button = _button;
            event._Xmin = _Xmin;
            event._Xmax = _Xmax;
            event._Ymin = _Ymin;
            event._Ymax = _Ymax;
            event._mx = _mx;
            event._my = _my;
            event._buttonMask = _buttonMask;
            event._modKeyMask = _modKeyMask;
            event._time = _time;
        }

        void swapBytes()
        {
        }

    protected:

        osgProducer::EventAdapter::EventType _eventType;
        int _key;
        int _button;
        float _Xmin,_Xmax;
        float _Ymin,_Ymax;
        float _mx;
        float _my;
        unsigned int _buttonMask;
        unsigned int _modKeyMask;
        double _time;
};

const unsigned int MAX_NUM_EVENTS = 10;

class CameraPacket {
    public:

        CameraPacket():_masterKilled(false)
        {
            _byte_order = 0x12345678;
        }

        void setPacket(const osg::Matrix& matrix,const osg::FrameStamp* frameStamp)
        {
            _matrix = matrix;
            if (frameStamp)
            {
                _frameStamp    = *frameStamp;
            }
        }

        void getModelView(osg::Matrix& matrix,float angle_offset=0.0f)
        {

            matrix = _matrix * osg::Matrix::rotate(osg::DegreesToRadians(angle_offset),0.0f,1.0f,0.0f);
        }

        void readEventQueue(osgProducer::Viewer& viewer);

        void writeEventQueue(osgProducer::Viewer& viewer);

        void checkByteOrder( void )
        {
            if( _byte_order == 0x78563412 )  // We're backwards
            {
                swapBytes( _byte_order );
                swapBytes( _masterKilled );
                for( int i = 0; i < 16; i++ )
                swapBytes( _matrix.ptr()[i] );

                    // umm.. we should byte swap _frameStamp too...

                for(unsigned int ei=0; ei<_numEvents; ++ei)
                {
                    _events[ei].swapBytes();
                }
            }
        }

        void setMasterKilled(const bool flag) { _masterKilled = flag; }
        const bool getMasterKilled() const { return _masterKilled; }

        unsigned int    _byte_order;
        bool            _masterKilled;
        osg::Matrix     _matrix;

        // note don't use a ref_ptr as used elsewhere for FrameStamp
        // since we don't want to copy the pointer - but the memory.
        // FrameStamp doesn't have a private destructor to allow
        // us to do this, even though its a reference counted object.
        osg::FrameStamp  _frameStamp;

        unsigned int _numEvents;
        PackedEvent  _events[MAX_NUM_EVENTS];

};

void CameraPacket::readEventQueue(osgProducer::Viewer& viewer)
{
    osgProducer::KeyboardMouseCallback::EventQueue queue;
    viewer.getKeyboardMouseCallback()->copyEventQueue(queue);

    _numEvents = 0;
    for(osgProducer::KeyboardMouseCallback::EventQueue::iterator itr =queue.begin();
        itr != queue.end() && _numEvents<MAX_NUM_EVENTS;
        ++itr, ++_numEvents)
    {
        osgProducer::EventAdapter* event = itr->get();
        _events[_numEvents].set(*event);
    }
    osg::notify(osg::INFO)<<"written events = "<<_numEvents<<std::endl;
}

void CameraPacket::writeEventQueue(osgProducer::Viewer& viewer)
{
    osg::notify(osg::INFO)<<"recieved events = "<<_numEvents<<std::endl;

    // copy the packed events to osgProducer style events.
    osgProducer::KeyboardMouseCallback::EventQueue queue;
    for(unsigned int ei=0; ei<_numEvents; ++ei)
    {
        osgProducer::EventAdapter* event = new osgProducer::EventAdapter;
        _events[ei].get(*event);
        queue.push_back(event);
    }

    // pass them to the viewer.
    viewer.getKeyboardMouseCallback()->appendEventQueue(queue);
}

enum ViewerMode
{
    STAND_ALONE,
    SLAVE,
    MASTER
};

int main( int argc, char **argv )
{
    osg::notify(osg::INFO)<<"FrameStamp "<<sizeof(osg::FrameStamp)<<std::endl;
    osg::notify(osg::INFO)<<"osg::Matrix "<<sizeof(osg::Matrix)<<std::endl;
    osg::notify(osg::INFO)<<"PackedEvent "<<sizeof(PackedEvent)<<std::endl;

    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates how to approach implementation of clustering. Note, cluster support will soon be encompassed in Producer itself.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
    arguments.getApplicationUsage()->addCommandLineOption("-m","Set viewer to MASTER mode, sending view via packets.");
    arguments.getApplicationUsage()->addCommandLineOption("-s","Set viewer to SLAVE mode, reciving view via packets.");
    arguments.getApplicationUsage()->addCommandLineOption("-n <int>","Socket number to transmit packets");
    arguments.getApplicationUsage()->addCommandLineOption("-f <float>","Field of view of camera");
    arguments.getApplicationUsage()->addCommandLineOption("-o <float>","Offset angle of camera");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // read up the osgcluster specific arguments.
    ViewerMode viewerMode = STAND_ALONE;
    while (arguments.read("-m")) viewerMode = MASTER;
    while (arguments.read("-s")) viewerMode = SLAVE;

    int socketNumber=8100;
    while (arguments.read("-n",socketNumber)) ;

    float camera_fov=-1.0f;
    while (arguments.read("-f",camera_fov))
    {
    }

    float camera_offset=45.0f;
    while (arguments.read("-o",camera_offset)) ;

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    if (arguments.argc()<=1)
    {
        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
        return 1;
    }

    // load model.
    osg::ref_ptr<osg::Node> rootnode = osgDB::readNodeFiles(arguments);

    // set the scene to render
    viewer.setSceneData(rootnode.get());

    // create the windows and run the threads.
    viewer.realize();

    // set up the lens after realize as the Producer lens is not set up properly before this.... will need to inveestigate this at a later date.
    if (camera_fov>0.0f)
    {
        float aspectRatio = tan( osg::DegreesToRadians(viewer.getLensVerticalFov()*0.5)) / tan(osg::DegreesToRadians(viewer.getLensHorizontalFov()*0.5));
        float new_fovy = osg::RadiansToDegrees(atan( aspectRatio * tan( osg::DegreesToRadians(camera_fov*0.5))))*2.0f;
        std::cout << "setting lens perspective : original "<<viewer.getLensHorizontalFov()<<"  "<<viewer.getLensVerticalFov()<<std::endl;
        viewer.setLensPerspective(camera_fov,new_fovy,1.0f,1000.0f);
        std::cout << "setting lens perspective : new "<<viewer.getLensHorizontalFov()<<"  "<<viewer.getLensVerticalFov()<<std::endl;
    }

    CameraPacket *cp = new CameraPacket;
    // objects for managing the broadcasting and recieving of camera packets.
    Broadcaster     bc;
    Receiver        rc;

    bc.setPort(static_cast<short int>(socketNumber));
    rc.setPort(static_cast<short int>(socketNumber));

    bool masterKilled = false;

    while( !viewer.done() && !masterKilled )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        osg::Timer_t startTick = osg::Timer::instance()->tick();

        // special handling for working as a cluster.
        switch (viewerMode)
        {
        case(MASTER):
            {

                // take camera zero as the guide.
                osg::Matrix modelview(viewer.getCameraConfig()->getCamera(0)->getViewMatrix());

                cp->setPacket(modelview,viewer.getFrameStamp());

                cp->readEventQueue(viewer);

                bc.setBuffer(cp, sizeof( CameraPacket ));

                std::cout << "bc.sync()"<<sizeof( CameraPacket )<<std::endl;

                bc.sync();

            }
            break;
        case(SLAVE):
            {

                rc.setBuffer(cp, sizeof( CameraPacket ));

                osg::notify(osg::INFO) << "rc.sync()"<<sizeof( CameraPacket )<<std::endl;

                rc.sync();

                cp->checkByteOrder();

                cp->writeEventQueue(viewer);

                if (cp->getMasterKilled())
                {
                    std::cout << "Received master killed."<<std::endl;
                    // break out of while (!done) loop since we've now want to shut down.
                    masterKilled = true;
                }
            }
            break;
        default:
            // no need to anything here, just a normal interactive viewer.
            break;
        }

        osg::Timer_t endTick = osg::Timer::instance()->tick();

        osg::notify(osg::INFO)<<"Time to do cluster sync "<<osg::Timer::instance()->delta_m(startTick,endTick)<<std::endl;

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        if (viewerMode==SLAVE)
        {
            osg::Matrix modelview;
            cp->getModelView(modelview,camera_offset);

            viewer.setView(modelview);
        }

        // fire off the cull and draw traversals of the scene.
        if(!masterKilled)
            viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    // if we are master clean up by telling all slaves that we're going down.
    if (viewerMode==MASTER)
    {
        // need to broadcast my death.
        cp->setPacket(osg::Matrix::identity(),viewer.getFrameStamp());
        cp->setMasterKilled(true);

        bc.setBuffer(cp, sizeof( CameraPacket ));
        bc.sync();

        std::cout << "Broadcasting death."<<std::endl;

    }

    return 0;
}
<commit_msg>Implement a scratch pad for writing and read data to, to solve issue between running a master and slave on a mix of 32bit and 64bit.<commit_after>#ifdef USE_MEM_CHECK
#include <mcheck.h>
#endif

#include <osg/Group>
#include <osg/Notify>

#include <osgDB/Registry>
#include <osgDB/ReadFile>

#include <osgProducer/Viewer>

#include <osg/Quat>

#if defined (WIN32) && !defined(__CYGWIN__)
#include <winsock.h>
#endif

#include "receiver.h"
#include "broadcaster.h"

const unsigned int MAX_NUM_EVENTS = 10;
const unsigned int SWAP_BYTES_COMPARE = 0x12345678;
class CameraPacket {
    public:

        CameraPacket():_masterKilled(false)
        {
            _byte_order = SWAP_BYTES_COMPARE;
        }

        void setPacket(const osg::Matrix& matrix,const osg::FrameStamp* frameStamp)
        {
            _matrix = matrix;
            if (frameStamp)
            {
                _frameStamp    = *frameStamp;
            }
        }

        void getModelView(osg::Matrix& matrix,float angle_offset=0.0f)
        {

            matrix = _matrix * osg::Matrix::rotate(osg::DegreesToRadians(angle_offset),0.0f,1.0f,0.0f);
        }

        void readEventQueue(osgProducer::Viewer& viewer);

        void writeEventQueue(osgProducer::Viewer& viewer);

        void setMasterKilled(const bool flag) { _masterKilled = flag; }
        const bool getMasterKilled() const { return _masterKilled; }

        unsigned int    _byte_order;
        bool            _masterKilled;
        osg::Matrix     _matrix;

        // note don't use a ref_ptr as used elsewhere for FrameStamp
        // since we don't want to copy the pointer - but the memory.
        // FrameStamp doesn't have a private destructor to allow
        // us to do this, even though its a reference counted object.
        osg::FrameStamp  _frameStamp;

        osgProducer::KeyboardMouseCallback::EventQueue _events;

};

class DataConverter
{
    public:

        DataConverter(unsigned int numBytes):
            _startPtr(0),
            _endPtr(0),
            _swapBytes(false),
            _currentPtr(0)
        {
            _currentPtr = _startPtr = new char[numBytes];
            _endPtr = _startPtr+numBytes;
            _numBytes = numBytes;
        }

        char* _startPtr;
        char* _endPtr;
        unsigned int _numBytes;
        bool _swapBytes;

        char* _currentPtr;

        inline void write1(char* ptr)
        {
            if (_currentPtr+1>=_endPtr) return;

            *(_currentPtr++) = *(ptr);
        }

        inline void read1(char* ptr)
        {
            if (_currentPtr+1>=_endPtr) return;

            *(ptr) = *(_currentPtr++);
        }

        inline void write2(char* ptr)
        {
            if (_currentPtr+2>=_endPtr) return;

            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr);
        }

        inline void read2(char* ptr)
        {
            if (_currentPtr+2>=_endPtr) return;

            if (_swapBytes)
            {
                *(ptr+1) = *(_currentPtr++);
                *(ptr) = *(_currentPtr++);
            }
            else
            {
                *(ptr++) = *(_currentPtr++);
                *(ptr) = *(_currentPtr++);
            }
        }

        inline void write4(char* ptr)
        {
            if (_currentPtr+4>=_endPtr) return;

            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr);
        }

        inline void read4(char* ptr)
        {
            if (_currentPtr+4>=_endPtr) return;

            if (_swapBytes)
            {
                *(ptr+3) = *(_currentPtr++);
                *(ptr+2) = *(_currentPtr++);
                *(ptr+1) = *(_currentPtr++);
                *(ptr) = *(_currentPtr++);
            }
            else
            {
                *(ptr++) = *(_currentPtr++);
                *(ptr++) = *(_currentPtr++);
                *(ptr++) = *(_currentPtr++);
                *(ptr) = *(_currentPtr++);
            }
        }

        inline void write8(char* ptr)
        {
            if (_currentPtr+8>=_endPtr) return;

            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr++);

            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr++);
            *(_currentPtr++) = *(ptr);
        }

        inline void read8(char* ptr)
        {
            char* endPtr = _currentPtr+8;
            if (endPtr>=_endPtr) return;

            if (_swapBytes)
            {
                *(ptr+7) = *(_currentPtr++);
                *(ptr+6) = *(_currentPtr++);
                *(ptr+5) = *(_currentPtr++);
                *(ptr+4) = *(_currentPtr++);

                *(ptr+3) = *(_currentPtr++);
                *(ptr+2) = *(_currentPtr++);
                *(ptr+1) = *(_currentPtr++);
                *(ptr) = *(_currentPtr++);
            }
            else
            {
                *(ptr++) = *(_currentPtr++);
                *(ptr++) = *(_currentPtr++);
                *(ptr++) = *(_currentPtr++);
                *(ptr++) = *(_currentPtr++);

                *(ptr++) = *(_currentPtr++);
                *(ptr++) = *(_currentPtr++);
                *(ptr++) = *(_currentPtr++);
                *(ptr) = *(_currentPtr++);
            }
        }

        inline void writeChar(char c)               { write1(&c); }
        inline void writeUChar(unsigned char c)     { write1((char*)&c); }
        inline void writeShort(short c)             { write2((char*)&c); }
        inline void writeUShort(unsigned short c)   { write2((char*)&c); }
        inline void writeInt(int c)                 { write4((char*)&c); }
        inline void writeUInt(unsigned int c)       { write4((char*)&c); }
        inline void writeFloat(float c)             { write4((char*)&c); }
        inline void writeDouble(double c)           { write8((char*)&c); }

        inline char readChar() { char c; read1(&c); return c; }
        inline unsigned char readUChar() { unsigned char c; read1((char*)&c); return c; }
        inline short readShort() { short c; read2((char*)&c); return c; }
        inline unsigned short readUShort() { unsigned short c; read2((char*)&c); return c; }
        inline int readInt() { int c; read4((char*)&c); return c; }
        inline unsigned int readUInt() { unsigned int c; read4((char*)&c); return c; }
        inline float readFloat() { float c; read4((char*)&c); return c; }
        inline double readDouble() { double c; read8((char*)&c); return c; }

        void write(const osg::FrameStamp& fs)
        {
            writeUInt(fs.getFrameNumber());
            return writeDouble(fs.getReferenceTime());
        }

        void read(osg::FrameStamp& fs)
        {
            fs.setFrameNumber(readUInt());
            fs.setReferenceTime(readDouble());
        }

        void write(const osg::Matrix& matrix)
        {
            writeDouble(matrix(0,0));
            writeDouble(matrix(0,1));
            writeDouble(matrix(0,2));
            writeDouble(matrix(0,3));

            writeDouble(matrix(1,0));
            writeDouble(matrix(1,1));
            writeDouble(matrix(1,2));
            writeDouble(matrix(1,3));

            writeDouble(matrix(2,0));
            writeDouble(matrix(2,1));
            writeDouble(matrix(2,2));
            writeDouble(matrix(2,3));

            writeDouble(matrix(3,0));
            writeDouble(matrix(3,1));
            writeDouble(matrix(3,2));
            writeDouble(matrix(3,3));
        }

        void read(osg::Matrix& matrix)
        {
            matrix(0,0) = readDouble();
            matrix(0,1) = readDouble();
            matrix(0,2) = readDouble();
            matrix(0,3) = readDouble();

            matrix(1,0) = readDouble();
            matrix(1,1) = readDouble();
            matrix(1,2) = readDouble();
            matrix(1,3) = readDouble();

            matrix(2,0) = readDouble();
            matrix(2,1) = readDouble();
            matrix(2,2) = readDouble();
            matrix(2,3) = readDouble();

            matrix(3,0) = readDouble();
            matrix(3,1) = readDouble();
            matrix(3,2) = readDouble();
            matrix(3,3) = readDouble();
        }

        void write(const osgProducer::EventAdapter& event)
        {
            writeUInt(event._eventType);
            writeUInt(event._key);
            writeUInt(event._button);
            writeFloat(event._Xmin);
            writeFloat(event._Xmax);
            writeFloat(event._Ymin);
            writeFloat(event._Ymax);
            writeFloat(event._mx);
            writeFloat(event._my);
            writeUInt(event._buttonMask);
            writeUInt(event._modKeyMask);
            writeDouble(event._time);
        }

        void read(osgProducer::EventAdapter& event)
        {
            event._eventType = (osgGA::GUIEventAdapter::EventType)readUInt();
            event._key = readUInt();
            event._button = readUInt();
            event._Xmin = readFloat();
            event._Xmax = readFloat();
            event._Ymin = readFloat();
            event._Ymax = readFloat();
            event._mx = readFloat();
            event._my = readFloat();
            event._buttonMask = readUInt();
            event._modKeyMask = readUInt();
            event._time = readDouble();
        }

        void write(CameraPacket& cameraPacket)
        {
            writeUInt(cameraPacket._byte_order);

            writeUInt(cameraPacket._masterKilled);

            write(cameraPacket._matrix);
            write(cameraPacket._frameStamp);

            writeUInt(cameraPacket._events.size());
            for(unsigned int i=0;i<cameraPacket._events.size();++i)
            {
                write(*(cameraPacket._events[i]));
            }
        }

        void read(CameraPacket& cameraPacket)
        {
            cameraPacket._byte_order = readUInt();
            if (cameraPacket._byte_order != SWAP_BYTES_COMPARE) _swapBytes = !_swapBytes;

            cameraPacket._masterKilled = readUInt();

            read(cameraPacket._matrix);
            read(cameraPacket._frameStamp);

            cameraPacket._events.clear();
            unsigned int numEvents = readUInt();
            for(unsigned int i=0;i<numEvents;++i)
            {
                osgProducer::EventAdapter* event = new osgProducer::EventAdapter;
                read(*(event));
                cameraPacket._events.push_back(event);
            }
        }
};

void CameraPacket::readEventQueue(osgProducer::Viewer& viewer)
{
    viewer.getKeyboardMouseCallback()->copyEventQueue(_events);

    osg::notify(osg::INFO)<<"written events = "<<_events.size()<<std::endl;
}

void CameraPacket::writeEventQueue(osgProducer::Viewer& viewer)
{
    osg::notify(osg::INFO)<<"recieved events = "<<_events.size()<<std::endl;

    // copy the events to osgProducer style events.
    viewer.getKeyboardMouseCallback()->appendEventQueue(_events);
}

enum ViewerMode
{
    STAND_ALONE,
    SLAVE,
    MASTER
};

int main( int argc, char **argv )
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates how to approach implementation of clustering. Note, cluster support will soon be encompassed in Producer itself.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
    arguments.getApplicationUsage()->addCommandLineOption("-m","Set viewer to MASTER mode, sending view via packets.");
    arguments.getApplicationUsage()->addCommandLineOption("-s","Set viewer to SLAVE mode, reciving view via packets.");
    arguments.getApplicationUsage()->addCommandLineOption("-n <int>","Socket number to transmit packets");
    arguments.getApplicationUsage()->addCommandLineOption("-f <float>","Field of view of camera");
    arguments.getApplicationUsage()->addCommandLineOption("-o <float>","Offset angle of camera");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // read up the osgcluster specific arguments.
    ViewerMode viewerMode = STAND_ALONE;
    while (arguments.read("-m")) viewerMode = MASTER;
    while (arguments.read("-s")) viewerMode = SLAVE;

    int socketNumber=8100;
    while (arguments.read("-n",socketNumber)) ;

    float camera_fov=-1.0f;
    while (arguments.read("-f",camera_fov))
    {
    }

    float camera_offset=45.0f;
    while (arguments.read("-o",camera_offset)) ;

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    if (arguments.argc()<=1)
    {
        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
        return 1;
    }

    // load model.
    osg::ref_ptr<osg::Node> rootnode = osgDB::readNodeFiles(arguments);

    // set the scene to render
    viewer.setSceneData(rootnode.get());

    // create the windows and run the threads.
    viewer.realize();

    // set up the lens after realize as the Producer lens is not set up properly before this.... will need to inveestigate this at a later date.
    if (camera_fov>0.0f)
    {
        float aspectRatio = tan( osg::DegreesToRadians(viewer.getLensVerticalFov()*0.5)) / tan(osg::DegreesToRadians(viewer.getLensHorizontalFov()*0.5));
        float new_fovy = osg::RadiansToDegrees(atan( aspectRatio * tan( osg::DegreesToRadians(camera_fov*0.5))))*2.0f;
        std::cout << "setting lens perspective : original "<<viewer.getLensHorizontalFov()<<"  "<<viewer.getLensVerticalFov()<<std::endl;
        viewer.setLensPerspective(camera_fov,new_fovy,1.0f,1000.0f);
        std::cout << "setting lens perspective : new "<<viewer.getLensHorizontalFov()<<"  "<<viewer.getLensVerticalFov()<<std::endl;
    }

    CameraPacket *cp = new CameraPacket;

    // objects for managing the broadcasting and recieving of camera packets.
    Broadcaster     bc;
    Receiver        rc;

    bc.setPort(static_cast<short int>(socketNumber));
    rc.setPort(static_cast<short int>(socketNumber));

    bool masterKilled = false;

    DataConverter scratchPad(1024);

    while( !viewer.done() && !masterKilled )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        osg::Timer_t startTick = osg::Timer::instance()->tick();

        // special handling for working as a cluster.
        switch (viewerMode)
        {
        case(MASTER):
            {

                // take camera zero as the guide.
                osg::Matrix modelview(viewer.getCameraConfig()->getCamera(0)->getViewMatrix());

                cp->setPacket(modelview,viewer.getFrameStamp());

                cp->readEventQueue(viewer);

                scratchPad.write(*cp);

                bc.setBuffer(scratchPad._startPtr, scratchPad._numBytes);

                std::cout << "bc.sync()"<<scratchPad._numBytes<<std::endl;

                bc.sync();

            }
            break;
        case(SLAVE):
            {

                rc.setBuffer(scratchPad._startPtr, scratchPad._numBytes);

                osg::notify(osg::INFO) << "rc.sync()"<<scratchPad._numBytes<<std::endl;

                rc.sync();

                scratchPad.read(*cp);

                cp->writeEventQueue(viewer);

                if (cp->getMasterKilled())
                {
                    std::cout << "Received master killed."<<std::endl;
                    // break out of while (!done) loop since we've now want to shut down.
                    masterKilled = true;
                }
            }
            break;
        default:
            // no need to anything here, just a normal interactive viewer.
            break;
        }

        osg::Timer_t endTick = osg::Timer::instance()->tick();

        osg::notify(osg::INFO)<<"Time to do cluster sync "<<osg::Timer::instance()->delta_m(startTick,endTick)<<std::endl;

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        if (viewerMode==SLAVE)
        {
            osg::Matrix modelview;
            cp->getModelView(modelview,camera_offset);

            viewer.setView(modelview);
        }

        // fire off the cull and draw traversals of the scene.
        if(!masterKilled)
            viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    // if we are master clean up by telling all slaves that we're going down.
    if (viewerMode==MASTER)
    {
        // need to broadcast my death.
        cp->setPacket(osg::Matrix::identity(),viewer.getFrameStamp());
        cp->setMasterKilled(true);

        bc.setBuffer(cp, sizeof( CameraPacket ));
        bc.sync();

        std::cout << "Broadcasting death."<<std::endl;

    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2020 ANON authors, see AUTHORS file.

 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 "sync_teflon_app.h"
#include "log.h"
#include "sproc_mgr.h"
#include "nlohmann/json.hpp"
#include <sys/stat.h>
#include <aws/core/Aws.h>
#include <aws/core/utils/Outcome.h>
#include <aws/dynamodb/DynamoDBClient.h>
#include <aws/dynamodb/model/QueryRequest.h>

using namespace nlohmann;
using namespace Aws::DynamoDB::Model;

namespace
{

struct tef_app
{
  tef_app(const Aws::String &id,
          const Aws::Vector<Aws::String> &filesv,
          Aws::Map<Aws::String, const std::shared_ptr<AttributeValue>> &fids)
      : id(id)
  {
    for (auto &f : filesv)
    {
      files[fids[f]->GetS()] = f;
    }
  }

  Aws::String id;
  std::map<Aws::String, Aws::String> files;
};

void exe_cmd(const std::string &str)
{
  std::string cmd = "bash -c '" + str + "'";
  auto f = popen(cmd.c_str(), "r");
  if (f)
  {
    auto exit_code = pclose(f);
    if (exit_code != 0)
      anon_throw(std::runtime_error, "command: " << str << " exited non-zero: " << error_string(exit_code));
  }
  else
  {
    anon_throw(std::runtime_error, "popen failed: " << errno_string());
  }
}

void create_empty_directory(const ec2_info &ec2i, const Aws::String &id)
{
  auto dir = ec2i.root_dir;
  if (id.size() != 0)
  {
    dir += "/";
    dir += id.c_str();
  }
  std::ostringstream oss;
  oss << "rm -rf " << dir << " && mkdir " << dir;
  exe_cmd(oss.str());
}

void remove_directory(const ec2_info &ec2i, const Aws::String &id)
{
  auto dir = ec2i.root_dir;
  if (id.size() != 0)
  {
    dir += "/";
    dir += id.c_str();
  }
  std::ostringstream oss;
  oss << "rm -rf " << id;
  exe_cmd(oss.str());
}

bool validate_user_data_string(const json& ud, const char* key)
{
  if (ud.find(key) == ud.end() || !ud[key].is_string()) {
    anon_log_error("no " << key << " in user data");
    return false;
  }
  return true;
}

bool validate_all_user_data_strings(const json& ud)
{
  return validate_user_data_string(ud, "artifacts_ddb_table_name")
    && validate_user_data_string(ud, "artifacts_ddb_table_region")
    && validate_user_data_string(ud, "artifacts_ddb_table_primary_key")
    && validate_user_data_string(ud, "artifacts_s3_bucket")
    && validate_user_data_string(ud, "artifacts_s3_key");
}

std::shared_ptr<tef_app> curr_app;

} // namespace

teflon_state sync_teflon_app(const ec2_info &ec2i)
{
  auto &ud = ec2i.user_data_js;
  if (!validate_all_user_data_strings(ud))
    return teflon_server_failed;

  Aws::Client::ClientConfiguration ddb_config;
  std::string region = ud["artifacts_ddb_table_region"];
  ddb_config.region = region.c_str();
  Aws::DynamoDB::DynamoDBClient ddbc(ddb_config);

  if (!curr_app)
    create_empty_directory(ec2i, "");

  std::string table_name = ud["artifacts_ddb_table_name"];
  std::string p_key_name = ud["artifacts_ddb_table_primary_key_name"];
  std::string p_key_value = ud["artifacts_ddb_table_primary_key_value"];
  std::string s_key_name = ud["artifacts_ddb_table_secondary_key_name"];
  std::string s_key_value = ud["artifacts_ddb_table_secondary_key_value"];

  QueryRequest  q_req;
  q_req.WithTableName(table_name)
    .WithKeyConditionExpression("#P = :p AND #S = :s")
    .WithScanIndexForward(false)
    .AddExpressionAttributeNames("#P", p_key_name)
    .AddExpressionAttributeValues(":p", AttributeValue(p_key_value))
    .AddExpressionAttributeNames("#S", s_key_name)
    .AddExpressionAttributeValues(":s", AttributeValue(s_key_value));

  auto outcome = ddbc.Query(q_req);
  if (!outcome.IsSuccess())
    anon_throw(std::runtime_error, "Query failed: " << outcome.GetError());
  auto &result = outcome.GetResult();
  auto &items = result.GetItems();
  if (items.size() == 0)
    anon_throw(std::runtime_error, "no item for " << p_key_value << "/" << s_key_value << " in ddb table " << table_name);
  auto &cur_def = items[0];
  auto end = cur_def.end();

  auto uid_it = cur_def.find("uid");
  if (uid_it == end)
    anon_throw(std::runtime_error, "item missing \"uid\" entry");

  auto uid = uid_it->second.GetS();
  if (curr_app && uid == curr_app->id)
  {
    anon_log("current server definition matches running server, no-op");
    return teflon_server_still_running;
  }

  auto files_it = cur_def.find("files");
  auto exe_it = cur_def.find("entry");
  auto ids_it = cur_def.find("fids");
  if (files_it == end || exe_it == end || ids_it == end)
    anon_throw(std::runtime_error, "current_server record missing required \"files\", \"entry\", and/or \"fids\" field(s)");

  auto files_needed = files_it->second.GetSS();
  auto file_to_execute = exe_it->second.GetS();
  auto ids = ids_it->second.GetM();

  std::string bucket = ud["artifacts_s3_bucket"];
  std::string key = ud["artifacts_s3_key"];

  std::ostringstream files_cmd;
  for (const auto &f : files_needed)
  {
    if (ids.find(f) == ids.end())
      anon_throw(std::runtime_error, "file: \"" << f << "\" missing in fids");
    if (curr_app && curr_app->files.find(f) != curr_app->files.end())
    {
      // f matches a file we have already downloaded, so just hard link it
      // to the new directory
      auto existing_file = curr_app->files[f];
      files_cmd << "ln " << ec2i.root_dir << "/" << curr_app->id << "/" << curr_app->files[f]
                << " " << ec2i.root_dir << "/" << uid << "/" << f << " || exit 1 &\n";
    }
    else
    {
      // does not match an existing file, so download it from s3
      files_cmd << "aws s3 cp s3://" << bucket << "/" << key
                << "/" << ids[f]->GetS() << "/" << f << " "
                << ec2i.root_dir << "/" << uid << "/" << f << " --quiet || exit 1 &\n";
    }
  }
  create_empty_directory(ec2i, uid);
  files_cmd << "wait < <(jobs -p)\n";
  exe_cmd(files_cmd.str());

  std::ostringstream ef;
  ef << ec2i.root_dir << "/" << uid << "/" << file_to_execute;
  auto efs = ef.str();
  chmod(efs.c_str(), ACCESSPERMS);

  try
  {
    auto new_app = std::make_shared<tef_app>(uid, files_needed, ids);
    start_server(efs.c_str(), false /*do_tls*/, std::vector<std::string>());
    if (curr_app)
      remove_directory(ec2i, curr_app->id);
    curr_app = new_app;
  }
  catch (const std::exception &exc)
  {
    anon_log_error("start_server failed: " << exc.what());
    remove_directory(ec2i, uid);
    return teflon_server_failed;
  }
  catch (...)
  {
    anon_log_error("start_server");
    remove_directory(ec2i, uid);
    return teflon_server_failed;
  }

  return teflon_server_running;
}
<commit_msg>bug fix<commit_after>/*
 Copyright (c) 2020 ANON authors, see AUTHORS file.

 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 "sync_teflon_app.h"
#include "log.h"
#include "sproc_mgr.h"
#include "nlohmann/json.hpp"
#include <sys/stat.h>
#include <aws/core/Aws.h>
#include <aws/core/utils/Outcome.h>
#include <aws/dynamodb/DynamoDBClient.h>
#include <aws/dynamodb/model/QueryRequest.h>

using namespace nlohmann;
using namespace Aws::DynamoDB::Model;

namespace
{

struct tef_app
{
  tef_app(const Aws::String &id,
          const Aws::Vector<Aws::String> &filesv,
          Aws::Map<Aws::String, const std::shared_ptr<AttributeValue>> &fids)
      : id(id)
  {
    for (auto &f : filesv)
    {
      files[fids[f]->GetS()] = f;
    }
  }

  Aws::String id;
  std::map<Aws::String, Aws::String> files;
};

void exe_cmd(const std::string &str)
{
  std::string cmd = "bash -c '" + str + "'";
  auto f = popen(cmd.c_str(), "r");
  if (f)
  {
    auto exit_code = pclose(f);
    if (exit_code != 0)
      anon_throw(std::runtime_error, "command: " << str << " exited non-zero: " << error_string(exit_code));
  }
  else
  {
    anon_throw(std::runtime_error, "popen failed: " << errno_string());
  }
}

void create_empty_directory(const ec2_info &ec2i, const Aws::String &id)
{
  auto dir = ec2i.root_dir;
  if (id.size() != 0)
  {
    dir += "/";
    dir += id.c_str();
  }
  std::ostringstream oss;
  oss << "rm -rf " << dir << " && mkdir " << dir;
  exe_cmd(oss.str());
}

void remove_directory(const ec2_info &ec2i, const Aws::String &id)
{
  auto dir = ec2i.root_dir;
  if (id.size() != 0)
  {
    dir += "/";
    dir += id.c_str();
  }
  std::ostringstream oss;
  oss << "rm -rf " << id;
  exe_cmd(oss.str());
}

bool validate_user_data_string(const json& ud, const char* key)
{
  if (ud.find(key) == ud.end() || !ud[key].is_string()) {
    anon_log_error("no " << key << " in user data");
    return false;
  }
  return true;
}

bool validate_all_user_data_strings(const json& ud)
{
  return validate_user_data_string(ud, "artifacts_ddb_table_region")
    && validate_user_data_string(ud, "artifacts_ddb_table_name")
    && validate_user_data_string(ud, "artifacts_ddb_table_primary_key_name")
    && validate_user_data_string(ud, "artifacts_ddb_table_primary_key_value")
    && validate_user_data_string(ud, "artifacts_ddb_table_secondary_key_name")
    && validate_user_data_string(ud, "artifacts_ddb_table_secondary_key_value")
    && validate_user_data_string(ud, "artifacts_s3_bucket")
    && validate_user_data_string(ud, "artifacts_s3_key");
}

std::shared_ptr<tef_app> curr_app;

} // namespace

teflon_state sync_teflon_app(const ec2_info &ec2i)
{
  auto &ud = ec2i.user_data_js;
  if (!validate_all_user_data_strings(ud))
    return teflon_server_failed;

  Aws::Client::ClientConfiguration ddb_config;
  std::string region = ud["artifacts_ddb_table_region"];
  ddb_config.region = region.c_str();
  Aws::DynamoDB::DynamoDBClient ddbc(ddb_config);

  if (!curr_app)
    create_empty_directory(ec2i, "");

  std::string table_name = ud["artifacts_ddb_table_name"];
  std::string p_key_name = ud["artifacts_ddb_table_primary_key_name"];
  std::string p_key_value = ud["artifacts_ddb_table_primary_key_value"];
  std::string s_key_name = ud["artifacts_ddb_table_secondary_key_name"];
  std::string s_key_value = ud["artifacts_ddb_table_secondary_key_value"];

  QueryRequest  q_req;
  q_req.WithTableName(table_name)
    .WithKeyConditionExpression("#P = :p AND #S = :s")
    .WithScanIndexForward(false)
    .AddExpressionAttributeNames("#P", p_key_name)
    .AddExpressionAttributeValues(":p", AttributeValue(p_key_value))
    .AddExpressionAttributeNames("#S", s_key_name)
    .AddExpressionAttributeValues(":s", AttributeValue(s_key_value));

  auto outcome = ddbc.Query(q_req);
  if (!outcome.IsSuccess())
    anon_throw(std::runtime_error, "Query failed: " << outcome.GetError());
  auto &result = outcome.GetResult();
  auto &items = result.GetItems();
  if (items.size() == 0)
    anon_throw(std::runtime_error, "no item for " << p_key_value << "/" << s_key_value << " in ddb table " << table_name);
  auto &cur_def = items[0];
  auto end = cur_def.end();

  auto uid_it = cur_def.find("uid");
  if (uid_it == end)
    anon_throw(std::runtime_error, "item missing \"uid\" entry");

  auto uid = uid_it->second.GetS();
  if (curr_app && uid == curr_app->id)
  {
    anon_log("current server definition matches running server, no-op");
    return teflon_server_still_running;
  }

  auto files_it = cur_def.find("files");
  auto exe_it = cur_def.find("entry");
  auto ids_it = cur_def.find("fids");
  if (files_it == end || exe_it == end || ids_it == end)
    anon_throw(std::runtime_error, "current_server record missing required \"files\", \"entry\", and/or \"fids\" field(s)");

  auto files_needed = files_it->second.GetSS();
  auto file_to_execute = exe_it->second.GetS();
  auto ids = ids_it->second.GetM();

  std::string bucket = ud["artifacts_s3_bucket"];
  std::string key = ud["artifacts_s3_key"];

  std::ostringstream files_cmd;
  for (const auto &f : files_needed)
  {
    if (ids.find(f) == ids.end())
      anon_throw(std::runtime_error, "file: \"" << f << "\" missing in fids");
    if (curr_app && curr_app->files.find(f) != curr_app->files.end())
    {
      // f matches a file we have already downloaded, so just hard link it
      // to the new directory
      auto existing_file = curr_app->files[f];
      files_cmd << "ln " << ec2i.root_dir << "/" << curr_app->id << "/" << curr_app->files[f]
                << " " << ec2i.root_dir << "/" << uid << "/" << f << " || exit 1 &\n";
    }
    else
    {
      // does not match an existing file, so download it from s3
      files_cmd << "aws s3 cp s3://" << bucket << "/" << key
                << "/" << ids[f]->GetS() << "/" << f << " "
                << ec2i.root_dir << "/" << uid << "/" << f << " --quiet || exit 1 &\n";
    }
  }
  create_empty_directory(ec2i, uid);
  files_cmd << "wait < <(jobs -p)\n";
  exe_cmd(files_cmd.str());

  std::ostringstream ef;
  ef << ec2i.root_dir << "/" << uid << "/" << file_to_execute;
  auto efs = ef.str();
  chmod(efs.c_str(), ACCESSPERMS);

  try
  {
    auto new_app = std::make_shared<tef_app>(uid, files_needed, ids);
    start_server(efs.c_str(), false /*do_tls*/, std::vector<std::string>());
    if (curr_app)
      remove_directory(ec2i, curr_app->id);
    curr_app = new_app;
  }
  catch (const std::exception &exc)
  {
    anon_log_error("start_server failed: " << exc.what());
    remove_directory(ec2i, uid);
    return teflon_server_failed;
  }
  catch (...)
  {
    anon_log_error("start_server");
    remove_directory(ec2i, uid);
    return teflon_server_failed;
  }

  return teflon_server_running;
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>
    Copyright © 2015 Jonathan Hale <squareys@googlemail.com>

    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 <Corrade/PluginManager/PluginManager.h>

#include <Magnum/Audio/AbstractImporter.h>
#include <Magnum/Audio/Buffer.h>
#include <Magnum/Audio/Context.h>
#include <Magnum/Audio/Renderer.h>
#include <Magnum/Audio/Source.h>
#include <Magnum/Buffer.h>
#include <Magnum/DefaultFramebuffer.h>
#include <Magnum/Math/Range.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Renderer.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/Trade/ImageData.h>

#include "configure.h"
#include "TexturedDrawable2D.h"
#include "Types.h"

namespace Magnum {namespace Examples {

class AudioExample: public Platform::Application {
    public:
        explicit AudioExample(const Arguments& arguments);

    private:
        void drawEvent() override;
        void mousePressEvent(MouseEvent& event) override;
        void mouseMoveEvent(MouseMoveEvent& event) override;
        void updateSourceTranslation(const Vector2i& mousePos);

        Buffer _vertexBuffer;
        Mesh _mesh;
        Shaders::Flat2D _shader;

        /* Scene objects */
        Scene2D _scene;
        SceneGraph::Camera2D _camera;
        Object2D _sourceTopObject;
        Object2D _sourceFrontObject;

        /* Drawable groups, separated per viewport */
        SceneGraph::DrawableGroup2D _drawablesFront;
        SceneGraph::DrawableGroup2D _drawablesTop;

        /* Drawables */
        std::unique_ptr<TexturedDrawable2D> _listenerFront;
        std::unique_ptr<TexturedDrawable2D> _listenerTop;
        std::unique_ptr<TexturedDrawable2D> _sourceFront;
        std::unique_ptr<TexturedDrawable2D> _sourceTop;

        /* Textures */
        Texture2D _textureListenerTop;
        Texture2D _textureListenerFront;
        Texture2D _textureSource;

        /* Viewports ranges */
        Range2Di _leftViewport;
        Range2Di _rightViewport;

        /* Audio related members */
        Audio::Context _context;
        Audio::Buffer _testBuffer;
        Audio::Source _source;
        Corrade::Containers::Array<char> _bufferData;
};

AudioExample::AudioExample(const Arguments& arguments):
    Platform::Application{arguments, Configuration{}.setTitle("Magnum Audio Example")},
    _shader(Shaders::Flat2D::Flag::Textured),
    _scene(),
    _camera(_scene),
    _sourceTopObject(&_scene),
    _sourceFrontObject(&_scene),
    _leftViewport(),
    _rightViewport(),
    _context(), /* Create the audio context. Without this, sound will not be initialized. */
    _testBuffer(),
    _source()
{
    /* Create a 2D plane for rendering all the sprites. */
    _vertexBuffer.setData(MeshTools::interleave(std::vector<Vector2>{
                 {1.0f, -1.0f},
                 {1.0f, 1.0f},
                 {-1.0f, -1.0f},
                 {-1.0f, 1.0f}
             }, std::vector<Vector2>{
                 {1.0f, 0.0f},
                 {1.0f, 1.0f},
                 {0.0f, 0.0f},
                 {0.0f, 1.0f}
             }), BufferUsage::StaticDraw);

    _mesh.setPrimitive(MeshPrimitive::TriangleStrip)
        .setCount(4)
        .addVertexBuffer(_vertexBuffer, 0, Shaders::Flat2D::Position{}, Shaders::Flat2D::TextureCoordinates{});

    /* Prepare viewports for top view (on the right) and front view (on the left) */
    const Vector2i halfViewport = defaultFramebuffer.viewport().size()*Vector2::xScale(0.5f);

    _leftViewport = Range2Di::fromSize({}, halfViewport);
    _rightViewport = Range2Di::fromSize({halfViewport.x(), 0}, halfViewport);

    /* Setup camera to scale down pixel measure to -1.0;1.0 on x and y according to aspect ratio for both viewports */
    _camera.setProjectionMatrix(Matrix3::projection({1.0f, 1.f/Vector2{halfViewport}.aspectRatio()}));

    /* Load TGA importer plugin */
    PluginManager::Manager<Trade::AbstractImporter> imageManager{MAGNUM_PLUGINS_IMPORTER_DIR};
    PluginManager::Manager<Audio::AbstractImporter> audioManager{MAGNUM_PLUGINS_AUDIOIMPORTER_DIR};

    if(!(imageManager.load("TgaImporter") & PluginManager::LoadState::Loaded))
        std::exit(1);
    std::unique_ptr<Trade::AbstractImporter> importer = imageManager.instance("TgaImporter");

    if(!(audioManager.load("WavAudioImporter") & PluginManager::LoadState::Loaded))
        std::exit(1);
    std::unique_ptr<Audio::AbstractImporter> wavImporter = audioManager.instance("WavAudioImporter");

    /* Load the textures from compiled resources */
    const Utility::Resource rs{"audio-data"};
    if(!importer->openData(rs.getRaw("source.tga")))
        std::exit(2);

    std::optional<Trade::ImageData2D> image = importer->image2D(0);
    CORRADE_INTERNAL_ASSERT(image);
    _textureSource.setWrapping(Sampler::Wrapping::ClampToEdge)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setMinificationFilter(Sampler::Filter::Linear)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    if(!importer->openData(rs.getRaw("listener_top.tga")))
        std::exit(2);

    image = importer->image2D(0);
    CORRADE_INTERNAL_ASSERT(image);
    _textureListenerTop.setWrapping(Sampler::Wrapping::ClampToEdge)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setMinificationFilter(Sampler::Filter::Linear)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    if(!importer->openData(rs.getRaw("listener_front.tga")))
        std::exit(2);

   image = importer->image2D(0);
    CORRADE_INTERNAL_ASSERT(image);
    _textureListenerFront.setWrapping(Sampler::Wrapping::ClampToEdge)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setMinificationFilter(Sampler::Filter::Linear)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    /* Load wav file */
    if(!wavImporter->openData(rs.getRaw("test.wav")))
        std::exit(2);

    _bufferData = wavImporter->data(); /* Get the data from importer */
    /* Add the sample data to the buffer */
    _testBuffer.setData(wavImporter->format(), _bufferData, wavImporter->frequency());

    /* Make our sound source play the buffer again and again... */
    _source.setBuffer(&_testBuffer);
    _source.setLooping(true);

    _source.play();

    /* Create and add drawables to scene */
    _listenerFront.reset(new TexturedDrawable2D(_mesh, _shader, _textureListenerFront, _scene, _drawablesFront));
    _listenerTop.reset(new TexturedDrawable2D(_mesh, _shader, _textureListenerTop, _scene, _drawablesTop));
    _sourceFront.reset(new TexturedDrawable2D(_mesh, _shader, _textureSource, _sourceFrontObject, _drawablesFront));
    _sourceTop.reset(new TexturedDrawable2D(_mesh, _shader, _textureSource, _sourceTopObject, _drawablesTop));

    /* We do not need depth test, drawing order is fine. */
    Renderer::disable(Renderer::Feature::DepthTest);

    /* Enable blending for alpha channel in textures. */
    Renderer::enable(Renderer::Feature::Blending);
    Renderer::setBlendFunction(Renderer::BlendFunction::SourceAlpha, Renderer::BlendFunction::OneMinusSourceAlpha);

    Renderer::setClearColor({0.6, 0.6, 0.6, 1.0});

    /* setup image scaling since the plane is currently larger than the screen. */
    _sourceFront->scale({0.1, 0.1});
    _sourceTop->scale({0.1, 0.1});
    _listenerFront->scale({0.1, 0.1});
    _listenerTop->scale({0.1, 0.05});

    /* initial positioning of sound source */
    _sourceTopObject.translate({0.5, 0.3});
    _sourceFrontObject.translate({0.5, 0.3});

    /* set initial sound source position to match the visualization */
    _source.setPosition(Vector3i{5, 3, 3});
}

void AudioExample::updateSourceTranslation(const Vector2i& mousePos) {
    const Vector2 normalized = Vector2{mousePos}/Vector2{_leftViewport.size()} - Vector2{0.5f};
    const Vector2 position = normalized*Vector2::yScale(-1.0f)*_camera.projectionSize();

    Vector2 newTop = {position.x(), _sourceTopObject.transformation().translation().y()};
    Vector2 newFront = {position.x(), _sourceFrontObject.transformation().translation().y()};

    if (normalized.x() > 0.5f) {
        /* clicked on the right viewport/"top view" */
        newTop.y() = position.y();

        newFront.x() -= 1.0f;
        newTop.x() -= 1.0f;
    } else {
        /* clicked on the left viewport/"front view" */
        newFront.y() = position.y();
    }

    _sourceTopObject.setTransformation(Matrix3::translation(newTop));
    _sourceFrontObject.setTransformation(Matrix3::translation(newFront));

    /* Update sound source position to new input */
    _source.setPosition(Vector3i{Int(newTop.x()*10), Int(newFront.y()*10), Int(newTop.y()*10)});
}

void AudioExample::drawEvent() {
    defaultFramebuffer.clear(FramebufferClear::Color);

    defaultFramebuffer.setViewport(_leftViewport);
    _camera.draw(_drawablesFront);

    defaultFramebuffer.setViewport(_rightViewport);
    _camera.draw(_drawablesTop);

    swapBuffers();
}

void AudioExample::mousePressEvent(MouseEvent& event) {
    if(event.button() != MouseEvent::Button::Left) return;

    updateSourceTranslation(event.position());

    event.setAccepted();
    redraw();
}

void AudioExample::mouseMoveEvent(MouseMoveEvent& event) {
    if(!(event.buttons() & MouseMoveEvent::Button::Left)) return;

    updateSourceTranslation(event.position());

    event.setAccepted();
    redraw();
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::AudioExample)
<commit_msg>audio: Remove custom clear color<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>
    Copyright © 2015 Jonathan Hale <squareys@googlemail.com>

    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 <Corrade/PluginManager/PluginManager.h>

#include <Magnum/Audio/AbstractImporter.h>
#include <Magnum/Audio/Buffer.h>
#include <Magnum/Audio/Context.h>
#include <Magnum/Audio/Renderer.h>
#include <Magnum/Audio/Source.h>
#include <Magnum/Buffer.h>
#include <Magnum/DefaultFramebuffer.h>
#include <Magnum/Math/Range.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Renderer.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/SceneGraph/Object.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/Trade/ImageData.h>

#include "configure.h"
#include "TexturedDrawable2D.h"
#include "Types.h"

namespace Magnum {namespace Examples {

class AudioExample: public Platform::Application {
    public:
        explicit AudioExample(const Arguments& arguments);

    private:
        void drawEvent() override;
        void mousePressEvent(MouseEvent& event) override;
        void mouseMoveEvent(MouseMoveEvent& event) override;
        void updateSourceTranslation(const Vector2i& mousePos);

        Buffer _vertexBuffer;
        Mesh _mesh;
        Shaders::Flat2D _shader;

        /* Scene objects */
        Scene2D _scene;
        SceneGraph::Camera2D _camera;
        Object2D _sourceTopObject;
        Object2D _sourceFrontObject;

        /* Drawable groups, separated per viewport */
        SceneGraph::DrawableGroup2D _drawablesFront;
        SceneGraph::DrawableGroup2D _drawablesTop;

        /* Drawables */
        std::unique_ptr<TexturedDrawable2D> _listenerFront;
        std::unique_ptr<TexturedDrawable2D> _listenerTop;
        std::unique_ptr<TexturedDrawable2D> _sourceFront;
        std::unique_ptr<TexturedDrawable2D> _sourceTop;

        /* Textures */
        Texture2D _textureListenerTop;
        Texture2D _textureListenerFront;
        Texture2D _textureSource;

        /* Viewports ranges */
        Range2Di _leftViewport;
        Range2Di _rightViewport;

        /* Audio related members */
        Audio::Context _context;
        Audio::Buffer _testBuffer;
        Audio::Source _source;
        Corrade::Containers::Array<char> _bufferData;
};

AudioExample::AudioExample(const Arguments& arguments):
    Platform::Application{arguments, Configuration{}.setTitle("Magnum Audio Example")},
    _shader(Shaders::Flat2D::Flag::Textured),
    _scene(),
    _camera(_scene),
    _sourceTopObject(&_scene),
    _sourceFrontObject(&_scene),
    _leftViewport(),
    _rightViewport(),
    _context(), /* Create the audio context. Without this, sound will not be initialized. */
    _testBuffer(),
    _source()
{
    /* Create a 2D plane for rendering all the sprites. */
    _vertexBuffer.setData(MeshTools::interleave(std::vector<Vector2>{
                 {1.0f, -1.0f},
                 {1.0f, 1.0f},
                 {-1.0f, -1.0f},
                 {-1.0f, 1.0f}
             }, std::vector<Vector2>{
                 {1.0f, 0.0f},
                 {1.0f, 1.0f},
                 {0.0f, 0.0f},
                 {0.0f, 1.0f}
             }), BufferUsage::StaticDraw);

    _mesh.setPrimitive(MeshPrimitive::TriangleStrip)
        .setCount(4)
        .addVertexBuffer(_vertexBuffer, 0, Shaders::Flat2D::Position{}, Shaders::Flat2D::TextureCoordinates{});

    /* Prepare viewports for top view (on the right) and front view (on the left) */
    const Vector2i halfViewport = defaultFramebuffer.viewport().size()*Vector2::xScale(0.5f);

    _leftViewport = Range2Di::fromSize({}, halfViewport);
    _rightViewport = Range2Di::fromSize({halfViewport.x(), 0}, halfViewport);

    /* Setup camera to scale down pixel measure to -1.0;1.0 on x and y according to aspect ratio for both viewports */
    _camera.setProjectionMatrix(Matrix3::projection({1.0f, 1.f/Vector2{halfViewport}.aspectRatio()}));

    /* Load TGA importer plugin */
    PluginManager::Manager<Trade::AbstractImporter> imageManager{MAGNUM_PLUGINS_IMPORTER_DIR};
    PluginManager::Manager<Audio::AbstractImporter> audioManager{MAGNUM_PLUGINS_AUDIOIMPORTER_DIR};

    if(!(imageManager.load("TgaImporter") & PluginManager::LoadState::Loaded))
        std::exit(1);
    std::unique_ptr<Trade::AbstractImporter> importer = imageManager.instance("TgaImporter");

    if(!(audioManager.load("WavAudioImporter") & PluginManager::LoadState::Loaded))
        std::exit(1);
    std::unique_ptr<Audio::AbstractImporter> wavImporter = audioManager.instance("WavAudioImporter");

    /* Load the textures from compiled resources */
    const Utility::Resource rs{"audio-data"};
    if(!importer->openData(rs.getRaw("source.tga")))
        std::exit(2);

    std::optional<Trade::ImageData2D> image = importer->image2D(0);
    CORRADE_INTERNAL_ASSERT(image);
    _textureSource.setWrapping(Sampler::Wrapping::ClampToEdge)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setMinificationFilter(Sampler::Filter::Linear)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    if(!importer->openData(rs.getRaw("listener_top.tga")))
        std::exit(2);

    image = importer->image2D(0);
    CORRADE_INTERNAL_ASSERT(image);
    _textureListenerTop.setWrapping(Sampler::Wrapping::ClampToEdge)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setMinificationFilter(Sampler::Filter::Linear)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    if(!importer->openData(rs.getRaw("listener_front.tga")))
        std::exit(2);

   image = importer->image2D(0);
    CORRADE_INTERNAL_ASSERT(image);
    _textureListenerFront.setWrapping(Sampler::Wrapping::ClampToEdge)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setMinificationFilter(Sampler::Filter::Linear)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    /* Load wav file */
    if(!wavImporter->openData(rs.getRaw("test.wav")))
        std::exit(2);

    _bufferData = wavImporter->data(); /* Get the data from importer */
    /* Add the sample data to the buffer */
    _testBuffer.setData(wavImporter->format(), _bufferData, wavImporter->frequency());

    /* Make our sound source play the buffer again and again... */
    _source.setBuffer(&_testBuffer);
    _source.setLooping(true);

    _source.play();

    /* Create and add drawables to scene */
    _listenerFront.reset(new TexturedDrawable2D(_mesh, _shader, _textureListenerFront, _scene, _drawablesFront));
    _listenerTop.reset(new TexturedDrawable2D(_mesh, _shader, _textureListenerTop, _scene, _drawablesTop));
    _sourceFront.reset(new TexturedDrawable2D(_mesh, _shader, _textureSource, _sourceFrontObject, _drawablesFront));
    _sourceTop.reset(new TexturedDrawable2D(_mesh, _shader, _textureSource, _sourceTopObject, _drawablesTop));

    /* We do not need depth test, drawing order is fine. */
    Renderer::disable(Renderer::Feature::DepthTest);

    /* Enable blending for alpha channel in textures. */
    Renderer::enable(Renderer::Feature::Blending);
    Renderer::setBlendFunction(Renderer::BlendFunction::SourceAlpha, Renderer::BlendFunction::OneMinusSourceAlpha);

    /* setup image scaling since the plane is currently larger than the screen. */
    _sourceFront->scale({0.1, 0.1});
    _sourceTop->scale({0.1, 0.1});
    _listenerFront->scale({0.1, 0.1});
    _listenerTop->scale({0.1, 0.05});

    /* initial positioning of sound source */
    _sourceTopObject.translate({0.5, 0.3});
    _sourceFrontObject.translate({0.5, 0.3});

    /* set initial sound source position to match the visualization */
    _source.setPosition(Vector3i{5, 3, 3});
}

void AudioExample::updateSourceTranslation(const Vector2i& mousePos) {
    const Vector2 normalized = Vector2{mousePos}/Vector2{_leftViewport.size()} - Vector2{0.5f};
    const Vector2 position = normalized*Vector2::yScale(-1.0f)*_camera.projectionSize();

    Vector2 newTop = {position.x(), _sourceTopObject.transformation().translation().y()};
    Vector2 newFront = {position.x(), _sourceFrontObject.transformation().translation().y()};

    if (normalized.x() > 0.5f) {
        /* clicked on the right viewport/"top view" */
        newTop.y() = position.y();

        newFront.x() -= 1.0f;
        newTop.x() -= 1.0f;
    } else {
        /* clicked on the left viewport/"front view" */
        newFront.y() = position.y();
    }

    _sourceTopObject.setTransformation(Matrix3::translation(newTop));
    _sourceFrontObject.setTransformation(Matrix3::translation(newFront));

    /* Update sound source position to new input */
    _source.setPosition(Vector3i{Int(newTop.x()*10), Int(newFront.y()*10), Int(newTop.y()*10)});
}

void AudioExample::drawEvent() {
    defaultFramebuffer.clear(FramebufferClear::Color);

    defaultFramebuffer.setViewport(_leftViewport);
    _camera.draw(_drawablesFront);

    defaultFramebuffer.setViewport(_rightViewport);
    _camera.draw(_drawablesTop);

    swapBuffers();
}

void AudioExample::mousePressEvent(MouseEvent& event) {
    if(event.button() != MouseEvent::Button::Left) return;

    updateSourceTranslation(event.position());

    event.setAccepted();
    redraw();
}

void AudioExample::mouseMoveEvent(MouseMoveEvent& event) {
    if(!(event.buttons() & MouseMoveEvent::Button::Left)) return;

    updateSourceTranslation(event.position());

    event.setAccepted();
    redraw();
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::AudioExample)
<|endoftext|>