<commit_before>//===- lib/MC/MCMachOStreamer.cpp - Mach-O Object Output ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCStreamer.h"

#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {

class MCMachOStreamer : public MCStreamer {
  /// SymbolFlags - We store the value for the 'desc' symbol field in the lowest
  /// 16 bits of the implementation defined flags.
  enum SymbolFlags { // See <mach-o/nlist.h>.
    SF_DescFlagsMask                        = 0xFFFF,

    // Reference type flags.
    SF_ReferenceTypeMask                    = 0x0007,
    SF_ReferenceTypeUndefinedNonLazy        = 0x0000,
    SF_ReferenceTypeUndefinedLazy           = 0x0001,
    SF_ReferenceTypeDefined                 = 0x0002,
    SF_ReferenceTypePrivateDefined          = 0x0003,
    SF_ReferenceTypePrivateUndefinedNonLazy = 0x0004,
    SF_ReferenceTypePrivateUndefinedLazy    = 0x0005,

    // Other 'desc' flags.
    SF_NoDeadStrip                          = 0x0020,
    SF_WeakReference                        = 0x0040,
    SF_WeakDefinition                       = 0x0080
  };

private:
  MCAssembler Assembler;
  MCCodeEmitter *Emitter;
  MCSectionData *CurSectionData;
  DenseMap<const MCSection*, MCSectionData*> SectionMap;
  DenseMap<const MCSymbol*, MCSymbolData*> SymbolMap;

private:
  MCFragment *getCurrentFragment() const {
    assert(CurSectionData && "No current section!");

    if (!CurSectionData->empty())
      return &CurSectionData->getFragmentList().back();

    return 0;
  }

  MCSectionData &getSectionData(const MCSection &Section) {
    MCSectionData *&Entry = SectionMap[&Section];

    if (!Entry)
      Entry = new MCSectionData(Section, &Assembler);

    return *Entry;
  }

  MCSymbolData &getSymbolData(const MCSymbol &Symbol) {
    MCSymbolData *&Entry = SymbolMap[&Symbol];

    if (!Entry)
      Entry = new MCSymbolData(Symbol, 0, 0, &Assembler);

    return *Entry;
  }

public:
  MCMachOStreamer(MCContext &Context, raw_ostream &_OS, MCCodeEmitter *_Emitter)
    : MCStreamer(Context), Assembler(Context, _OS), Emitter(_Emitter),
      CurSectionData(0) {}
  ~MCMachOStreamer() {}

  const MCExpr *AddValueSymbols(const MCExpr *Value) {
    switch (Value->getKind()) {
    case MCExpr::Target: assert(0 && "Can't handle target exprs yet!");
    case MCExpr::Constant:
      break;

    case MCExpr::Binary: {
      const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
      AddValueSymbols(BE->getLHS());
      AddValueSymbols(BE->getRHS());
      break;
    }

    case MCExpr::SymbolRef:
      getSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol());
      break;

    case MCExpr::Unary:
      AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr());
      break;
    }

    return Value;
  }

  /// @name MCStreamer Interface
  /// @{

  virtual void SwitchSection(const MCSection *Section);
  virtual void EmitLabel(MCSymbol *Symbol);
  virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
  virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
  virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
  virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
  virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                unsigned ByteAlignment);
  virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
                            unsigned Size = 0, unsigned ByteAlignment = 0);
  virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
  virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
  virtual void EmitGPRel32Value(const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
                                    unsigned ValueSize = 1,
                                    unsigned MaxBytesToEmit = 0);
  virtual void EmitValueToOffset(const MCExpr *Offset,
                                 unsigned char Value = 0);

  virtual void EmitFileDirective(StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitFileDirective not implemented\n";
  }
  virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitDwarfFileDirective not implemented\n";
  }

  virtual void EmitInstruction(const MCInst &Inst);
  virtual void Finish();

  /// @}
};

} // end anonymous namespace.

void MCMachOStreamer::SwitchSection(const MCSection *Section) {
  assert(Section && "Cannot switch to a null section!");

  // If already in this section, then this is a noop.
  if (Section == CurSection) return;

  CurSection = Section;
  CurSectionData = &getSectionData(*Section);
}

void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  // FIXME: We should also use offsets into Fill fragments.
  MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!F)
    F = new MCDataFragment(CurSectionData);

  MCSymbolData &SD = getSymbolData(*Symbol);
  assert(!SD.getFragment() && "Unexpected fragment on symbol data!");
  SD.setFragment(F);
  SD.setOffset(F->getContents().size());

  // This causes the reference type and weak reference flags to be cleared.
  SD.setFlags(SD.getFlags() & ~(SF_WeakReference | SF_ReferenceTypeMask));

  Symbol->setSection(*CurSection);
}

void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
  switch (Flag) {
  case MCAF_SubsectionsViaSymbols:
    Assembler.setSubsectionsViaSymbols(true);
    return;
  }

  assert(0 && "invalid assembler flag!");
}

void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
  // Only absolute symbols can be redefined.
  assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
         "Cannot define a symbol twice!");

  // FIXME: Lift context changes into super class.
  // FIXME: Set associated section.
  Symbol->setValue(Value);
}

void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
                                          MCSymbolAttr Attribute) {
  // Indirect symbols are handled differently, to match how 'as' handles
  // them. This makes writing matching .o files easier.
  if (Attribute == MCSA_IndirectSymbol) {
    // Note that we intentionally cannot use the symbol data here; this is
    // important for matching the string table that 'as' generates.
    IndirectSymbolData ISD;
    ISD.Symbol = Symbol;
    ISD.SectionData = CurSectionData;
    Assembler.getIndirectSymbols().push_back(ISD);
    return;
  }

  // Adding a symbol attribute always introduces the symbol, note that an
  // important side effect of calling getSymbolData here is to register the
  // symbol with the assembler.
  MCSymbolData &SD = getSymbolData(*Symbol);

  // The implementation of symbol attributes is designed to match 'as', but it
  // leaves much to desired. It doesn't really make sense to arbitrarily add and
  // remove flags, but 'as' allows this (in particular, see .desc).
  //
  // In the future it might be worth trying to make these operations more well
  // defined.
  switch (Attribute) {
  case MCSA_Invalid:
  case MCSA_ELF_TypeFunction:
  case MCSA_ELF_TypeIndFunction:
  case MCSA_ELF_TypeObject:
  case MCSA_ELF_TypeTLS:
  case MCSA_ELF_TypeCommon:
  case MCSA_ELF_TypeNoType:
  case MCSA_IndirectSymbol:
  case MCSA_Hidden:
  case MCSA_Internal:
  case MCSA_Protected:
  case MCSA_Weak:
  case MCSA_Local:
    assert(0 && "Invalid symbol attribute for Mach-O!");
    break;

  case MCSA_Global:
    SD.setExternal(true);
    break;

  case MCSA_LazyReference:
    // FIXME: This requires -dynamic.
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_ReferenceTypeUndefinedLazy);
    break;

    // Since .reference sets the no dead strip bit, it is equivalent to
    // .no_dead_strip in practice.
  case MCSA_Reference:
  case MCSA_NoDeadStrip:
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    break;

  case MCSA_PrivateExtern:
    SD.setExternal(true);
    SD.setPrivateExtern(true);
    break;

  case MCSA_WeakReference:
    // FIXME: This requires -dynamic.
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_WeakReference);
    break;

  case MCSA_WeakDefinition:
    // FIXME: 'as' enforces that this is defined and global. The manual claims
    // it has to be in a coalesced section, but this isn't enforced.
    SD.setFlags(SD.getFlags() | SF_WeakDefinition);
    break;
  }
}

void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
  // Encode the 'desc' value into the lowest implementation defined bits.
  assert(DescValue == (DescValue & SF_DescFlagsMask) &&
         "Invalid .desc value!");
  getSymbolData(*Symbol).setFlags(DescValue & SF_DescFlagsMask);
}

void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                       unsigned ByteAlignment) {
  // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself.
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = getSymbolData(*Symbol);
  SD.setExternal(true);
  SD.setCommon(Size, ByteAlignment);
}

void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
                                   unsigned Size, unsigned ByteAlignment) {
  MCSectionData &SectData = getSectionData(*Section);

  // The symbol may not be present, which only creates the section.
  if (!Symbol)
    return;

  // FIXME: Assert that this section has the zerofill type.

  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = getSymbolData(*Symbol);

  MCFragment *F = new MCZeroFillFragment(Size, ByteAlignment, &SectData);
  SD.setFragment(F);

  Symbol->setSection(*Section);

  // Update the maximum alignment on the zero fill section if necessary.
  if (ByteAlignment > SectData.getAlignment())
    SectData.setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
  MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!DF)
    DF = new MCDataFragment(CurSectionData);
  DF->getContents().append(Data.begin(), Data.end());
}

void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size,
                                unsigned AddrSpace) {
  new MCFillFragment(*AddValueSymbols(Value), Size, 1, CurSectionData);
}

void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
                                           int64_t Value, unsigned ValueSize,
                                           unsigned MaxBytesToEmit) {
  if (MaxBytesToEmit == 0)
    MaxBytesToEmit = ByteAlignment;
  new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
                      CurSectionData);

  // Update the maximum alignment on the current section if necessary.
  if (ByteAlignment > CurSectionData->getAlignment())
    CurSectionData->setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset,
                                        unsigned char Value) {
  new MCOrgFragment(*Offset, Value, CurSectionData);
}

void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
  // Scan for values.
  for (unsigned i = 0; i != Inst.getNumOperands(); ++i)
    if (Inst.getOperand(i).isExpr())
      AddValueSymbols(Inst.getOperand(i).getExpr());

  if (!Emitter)
    llvm_unreachable("no code emitter available!");

  CurSectionData->setHasInstructions(true);

  // FIXME: Relocations!
  SmallVector<MCFixup, 4> Fixups;
  SmallString<256> Code;
  raw_svector_ostream VecOS(Code);
  Emitter->EncodeInstruction(Inst, VecOS, Fixups);
  EmitBytes(VecOS.str(), 0);
}

void MCMachOStreamer::Finish() {
  Assembler.Finish();
}

MCStreamer *llvm::createMachOStreamer(MCContext &Context, raw_ostream &OS,
                                      MCCodeEmitter *CE) {
  return new MCMachOStreamer(Context, OS, CE);
}
<commit_msg>MC/Mach-O: Implement EmitValue using data fragments + fixups instead of fill fragment.<commit_after>//===- lib/MC/MCMachOStreamer.cpp - Mach-O Object Output ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCStreamer.h"

#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {

class MCMachOStreamer : public MCStreamer {
  /// SymbolFlags - We store the value for the 'desc' symbol field in the lowest
  /// 16 bits of the implementation defined flags.
  enum SymbolFlags { // See <mach-o/nlist.h>.
    SF_DescFlagsMask                        = 0xFFFF,

    // Reference type flags.
    SF_ReferenceTypeMask                    = 0x0007,
    SF_ReferenceTypeUndefinedNonLazy        = 0x0000,
    SF_ReferenceTypeUndefinedLazy           = 0x0001,
    SF_ReferenceTypeDefined                 = 0x0002,
    SF_ReferenceTypePrivateDefined          = 0x0003,
    SF_ReferenceTypePrivateUndefinedNonLazy = 0x0004,
    SF_ReferenceTypePrivateUndefinedLazy    = 0x0005,

    // Other 'desc' flags.
    SF_NoDeadStrip                          = 0x0020,
    SF_WeakReference                        = 0x0040,
    SF_WeakDefinition                       = 0x0080
  };

private:
  MCAssembler Assembler;
  MCCodeEmitter *Emitter;
  MCSectionData *CurSectionData;
  DenseMap<const MCSection*, MCSectionData*> SectionMap;
  DenseMap<const MCSymbol*, MCSymbolData*> SymbolMap;

private:
  MCFragment *getCurrentFragment() const {
    assert(CurSectionData && "No current section!");

    if (!CurSectionData->empty())
      return &CurSectionData->getFragmentList().back();

    return 0;
  }

  MCSectionData &getSectionData(const MCSection &Section) {
    MCSectionData *&Entry = SectionMap[&Section];

    if (!Entry)
      Entry = new MCSectionData(Section, &Assembler);

    return *Entry;
  }

  MCSymbolData &getSymbolData(const MCSymbol &Symbol) {
    MCSymbolData *&Entry = SymbolMap[&Symbol];

    if (!Entry)
      Entry = new MCSymbolData(Symbol, 0, 0, &Assembler);

    return *Entry;
  }

public:
  MCMachOStreamer(MCContext &Context, raw_ostream &_OS, MCCodeEmitter *_Emitter)
    : MCStreamer(Context), Assembler(Context, _OS), Emitter(_Emitter),
      CurSectionData(0) {}
  ~MCMachOStreamer() {}

  const MCExpr *AddValueSymbols(const MCExpr *Value) {
    switch (Value->getKind()) {
    case MCExpr::Target: assert(0 && "Can't handle target exprs yet!");
    case MCExpr::Constant:
      break;

    case MCExpr::Binary: {
      const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
      AddValueSymbols(BE->getLHS());
      AddValueSymbols(BE->getRHS());
      break;
    }

    case MCExpr::SymbolRef:
      getSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol());
      break;

    case MCExpr::Unary:
      AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr());
      break;
    }

    return Value;
  }

  /// @name MCStreamer Interface
  /// @{

  virtual void SwitchSection(const MCSection *Section);
  virtual void EmitLabel(MCSymbol *Symbol);
  virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
  virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
  virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
  virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
  virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                unsigned ByteAlignment);
  virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
                            unsigned Size = 0, unsigned ByteAlignment = 0);
  virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
  virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
  virtual void EmitGPRel32Value(const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
                                    unsigned ValueSize = 1,
                                    unsigned MaxBytesToEmit = 0);
  virtual void EmitValueToOffset(const MCExpr *Offset,
                                 unsigned char Value = 0);

  virtual void EmitFileDirective(StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitFileDirective not implemented\n";
  }
  virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitDwarfFileDirective not implemented\n";
  }

  virtual void EmitInstruction(const MCInst &Inst);
  virtual void Finish();

  /// @}
};

} // end anonymous namespace.

void MCMachOStreamer::SwitchSection(const MCSection *Section) {
  assert(Section && "Cannot switch to a null section!");

  // If already in this section, then this is a noop.
  if (Section == CurSection) return;

  CurSection = Section;
  CurSectionData = &getSectionData(*Section);
}

void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  // FIXME: We should also use offsets into Fill fragments.
  MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!F)
    F = new MCDataFragment(CurSectionData);

  MCSymbolData &SD = getSymbolData(*Symbol);
  assert(!SD.getFragment() && "Unexpected fragment on symbol data!");
  SD.setFragment(F);
  SD.setOffset(F->getContents().size());

  // This causes the reference type and weak reference flags to be cleared.
  SD.setFlags(SD.getFlags() & ~(SF_WeakReference | SF_ReferenceTypeMask));

  Symbol->setSection(*CurSection);
}

void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
  switch (Flag) {
  case MCAF_SubsectionsViaSymbols:
    Assembler.setSubsectionsViaSymbols(true);
    return;
  }

  assert(0 && "invalid assembler flag!");
}

void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
  // Only absolute symbols can be redefined.
  assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
         "Cannot define a symbol twice!");

  // FIXME: Lift context changes into super class.
  // FIXME: Set associated section.
  Symbol->setValue(Value);
}

void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
                                          MCSymbolAttr Attribute) {
  // Indirect symbols are handled differently, to match how 'as' handles
  // them. This makes writing matching .o files easier.
  if (Attribute == MCSA_IndirectSymbol) {
    // Note that we intentionally cannot use the symbol data here; this is
    // important for matching the string table that 'as' generates.
    IndirectSymbolData ISD;
    ISD.Symbol = Symbol;
    ISD.SectionData = CurSectionData;
    Assembler.getIndirectSymbols().push_back(ISD);
    return;
  }

  // Adding a symbol attribute always introduces the symbol, note that an
  // important side effect of calling getSymbolData here is to register the
  // symbol with the assembler.
  MCSymbolData &SD = getSymbolData(*Symbol);

  // The implementation of symbol attributes is designed to match 'as', but it
  // leaves much to desired. It doesn't really make sense to arbitrarily add and
  // remove flags, but 'as' allows this (in particular, see .desc).
  //
  // In the future it might be worth trying to make these operations more well
  // defined.
  switch (Attribute) {
  case MCSA_Invalid:
  case MCSA_ELF_TypeFunction:
  case MCSA_ELF_TypeIndFunction:
  case MCSA_ELF_TypeObject:
  case MCSA_ELF_TypeTLS:
  case MCSA_ELF_TypeCommon:
  case MCSA_ELF_TypeNoType:
  case MCSA_IndirectSymbol:
  case MCSA_Hidden:
  case MCSA_Internal:
  case MCSA_Protected:
  case MCSA_Weak:
  case MCSA_Local:
    assert(0 && "Invalid symbol attribute for Mach-O!");
    break;

  case MCSA_Global:
    SD.setExternal(true);
    break;

  case MCSA_LazyReference:
    // FIXME: This requires -dynamic.
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_ReferenceTypeUndefinedLazy);
    break;

    // Since .reference sets the no dead strip bit, it is equivalent to
    // .no_dead_strip in practice.
  case MCSA_Reference:
  case MCSA_NoDeadStrip:
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    break;

  case MCSA_PrivateExtern:
    SD.setExternal(true);
    SD.setPrivateExtern(true);
    break;

  case MCSA_WeakReference:
    // FIXME: This requires -dynamic.
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_WeakReference);
    break;

  case MCSA_WeakDefinition:
    // FIXME: 'as' enforces that this is defined and global. The manual claims
    // it has to be in a coalesced section, but this isn't enforced.
    SD.setFlags(SD.getFlags() | SF_WeakDefinition);
    break;
  }
}

void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
  // Encode the 'desc' value into the lowest implementation defined bits.
  assert(DescValue == (DescValue & SF_DescFlagsMask) &&
         "Invalid .desc value!");
  getSymbolData(*Symbol).setFlags(DescValue & SF_DescFlagsMask);
}

void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                       unsigned ByteAlignment) {
  // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself.
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = getSymbolData(*Symbol);
  SD.setExternal(true);
  SD.setCommon(Size, ByteAlignment);
}

void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
                                   unsigned Size, unsigned ByteAlignment) {
  MCSectionData &SectData = getSectionData(*Section);

  // The symbol may not be present, which only creates the section.
  if (!Symbol)
    return;

  // FIXME: Assert that this section has the zerofill type.

  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = getSymbolData(*Symbol);

  MCFragment *F = new MCZeroFillFragment(Size, ByteAlignment, &SectData);
  SD.setFragment(F);

  Symbol->setSection(*Section);

  // Update the maximum alignment on the zero fill section if necessary.
  if (ByteAlignment > SectData.getAlignment())
    SectData.setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
  MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!DF)
    DF = new MCDataFragment(CurSectionData);
  DF->getContents().append(Data.begin(), Data.end());
}

void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size,
                                unsigned AddrSpace) {
  // Assume the front-end will have evaluate things absolute expressions, so
  // just create data + fixup.
  MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!DF)
    DF = new MCDataFragment(CurSectionData);

  // Avoid fixups when possible.
  int64_t AbsValue;
  if (Value->EvaluateAsAbsolute(AbsValue)) {
    // FIXME: Endianness assumption.
    for (unsigned i = 0; i != Size; ++i)
      DF->getContents().push_back(uint8_t(AbsValue >> (i * 8)));
  } else {
    DF->getFixups().push_back(MCAsmFixup(DF->getContents().size(),
                                         *AddValueSymbols(Value), Size));
    DF->getContents().resize(DF->getContents().size() + Size, 0);
  }
}

void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
                                           int64_t Value, unsigned ValueSize,
                                           unsigned MaxBytesToEmit) {
  if (MaxBytesToEmit == 0)
    MaxBytesToEmit = ByteAlignment;
  new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
                      CurSectionData);

  // Update the maximum alignment on the current section if necessary.
  if (ByteAlignment > CurSectionData->getAlignment())
    CurSectionData->setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset,
                                        unsigned char Value) {
  new MCOrgFragment(*Offset, Value, CurSectionData);
}

void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
  // Scan for values.
  for (unsigned i = 0; i != Inst.getNumOperands(); ++i)
    if (Inst.getOperand(i).isExpr())
      AddValueSymbols(Inst.getOperand(i).getExpr());

  if (!Emitter)
    llvm_unreachable("no code emitter available!");

  CurSectionData->setHasInstructions(true);

  // FIXME: Relocations!
  SmallVector<MCFixup, 4> Fixups;
  SmallString<256> Code;
  raw_svector_ostream VecOS(Code);
  Emitter->EncodeInstruction(Inst, VecOS, Fixups);
  EmitBytes(VecOS.str(), 0);
}

void MCMachOStreamer::Finish() {
  Assembler.Finish();
}

MCStreamer *llvm::createMachOStreamer(MCContext &Context, raw_ostream &OS,
                                      MCCodeEmitter *CE) {
  return new MCMachOStreamer(Context, OS, CE);
}
<|endoftext|>


<commit_before>// $Id: selectable.C,v 1.4 2000/01/07 21:57:54 oliver Exp $

#include <BALL/CONCEPT/selectable.h>
#include <BALL/CONCEPT/persistenceManager.h>

using namespace std;

namespace BALL
{

	Selectable::Selectable()
		:	selected_(BALL_SELECTABLE_DEFAULT_SELECTION)
	{
	}

	Selectable::Selectable(const Selectable& selectable, bool)
		:	selected_(selectable.selected_)
	{
	}

	Selectable::~Selectable()
	{
	}

	void Selectable::dump(ostream& s, Size depth) const
	{
		BALL_DUMP_STREAM_PREFIX(s);

		BALL_DUMP_DEPTH(s, depth);
    BALL_DUMP_HEADER(s, this, this)

		BALL_DUMP_DEPTH(s, depth);
		s << "  selected: " << selected_ << endl;

		BALL_DUMP_STREAM_SUFFIX(s);
	}

  ostream& operator << (ostream& s, const Selectable& selectable)
  {
		s << selectable.selected_;

		return s;
	}

  istream& operator >> (istream& s, Selectable& selectable)
  {
    s >> selectable.selected_;

		return s;
	}

  void Selectable::write(PersistenceManager& pm) const
  {
		pm.writePrimitive(selected_, "selected_");
	}

  bool Selectable::read(PersistenceManager& pm)
  {
		return pm.readPrimitive(selected_, "selected_");
	}

#	ifdef BALL_NO_INLINE_FUNCTIONS
#		include <BALL/CONCEPT/selectable.iC>
#	endif

} // namespace BALL
<commit_msg>added: exception qualifier<commit_after>// $Id: selectable.C,v 1.5 2000/12/09 21:56:04 amoll Exp $

#include <BALL/CONCEPT/selectable.h>
#include <BALL/CONCEPT/persistenceManager.h>

using namespace std;

namespace BALL
{

	Selectable::Selectable()
		throw()
		:	selected_(BALL_SELECTABLE_DEFAULT_SELECTION)
	{
	}

	Selectable::Selectable(const Selectable& selectable, bool)
		throw()
		:	selected_(selectable.selected_)
	{
	}

	Selectable::~Selectable()
		throw()
	{
	}

	void Selectable::dump(ostream& s, Size depth) const
		throw()
	{
		BALL_DUMP_STREAM_PREFIX(s);

		BALL_DUMP_DEPTH(s, depth);
    BALL_DUMP_HEADER(s, this, this)

		BALL_DUMP_DEPTH(s, depth);
		s << "  selected: " << selected_ << endl;

		BALL_DUMP_STREAM_SUFFIX(s);
	}

  ostream& operator << (ostream& s, const Selectable& selectable)
		throw()
  {
		s << selectable.selected_;
		return s;
	}

  istream& operator >> (istream& s, Selectable& selectable)
		throw()
  {
    s >> selectable.selected_;
		return s;
	}

  void Selectable::write(PersistenceManager& pm) const
		throw()
  {
		pm.writePrimitive(selected_, "selected_");
	}

  bool Selectable::read(PersistenceManager& pm)
		throw()
  {
		return pm.readPrimitive(selected_, "selected_");
	}

#	ifdef BALL_NO_INLINE_FUNCTIONS
#		include <BALL/CONCEPT/selectable.iC>
#	endif

} // namespace BALL
<|endoftext|>


<commit_before>#ifndef DynamicImage_HPP
#define DynamicImage_HPP

#include "Streamer.hpp"
#include "DataObject.hpp"
#include <vector>
#include <boost/unordered_map.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include "ProcessObject.hpp"

namespace fast {

template <class T>
class DynamicData : public virtual DataObject {
    public:
        typedef SharedPointer<DynamicData<T> > pointer;
        static typename DynamicData<T>::pointer New() {
            DynamicData<T> * ptr = new DynamicData<T>();
            typename DynamicData<T>::pointer smartPtr(ptr);
            ptr->setPtr(smartPtr);

            return smartPtr;
        }
    private:
        void setPtr(typename DynamicData<T>::pointer ptr) {
            mPtr = ptr;
        }
    public:
        void setMaximumNumberOfFrames(uint nrOfFrames);
        //typename T::pointer getNextFrame();
        typename T::pointer getNextFrame(WeakPointer<Object> processObject);
        typename T::pointer getNextFrame(Object::pointer processObject);
        void addFrame(typename T::pointer frame);
        unsigned int getSize() const;
        ~DynamicData();

        bool hasReachedEnd();
        typename T::pointer getCurrentFrame();
        void registerConsumer(WeakPointer<Object> processObject);
        void registerConsumer(Object::pointer processObject);
    private:

        // If the flag mKeepAllFrames is set to false, this vector will have
        // a max size of 1
        //std::vector<typename T::pointer> mFrames;

        // Keep track of which frame is next, only used when mKeepAllFrames is
        // set to true
        //unsigned long mCurrentFrame;

        boost::unordered_map<WeakPointer<Object>, uint> mConsumerFrameCounters;
        uint getLowestFrameCount() const;
        void removeOldFrames(uint frameCounter);
        void setAllConsumersUpToDate();
        // Maps frame counter to a data
        boost::unordered_map<uint, typename T::pointer> mFrames2;
        // This is the frame number of HEAD
        unsigned long mCurrentFrameCounter;
        // Only used with newest frame only:
        typename T::pointer mCurrentFrame2;

        uint mMaximumNrOfFrames;
        boost::interprocess::interprocess_semaphore* fillCount;
        boost::interprocess::interprocess_semaphore* emptyCount;

        boost::mutex mStreamMutex;

        bool mHasReachedEnd;
    protected:
        DynamicData();
        // TODO not implemented yet
        void free(ExecutionDevice::pointer device) {};
        void freeAll() {};
};

/*
template <class T>
typename T::pointer DynamicData<T>::getNextFrame() {
    Streamer::pointer streamer = mStreamer.lock();
    if(!streamer.isValid()) {
        // If streamer has been deleted, return the current frame instead
        return getCurrentFrame();
    }
    mStreamMutex.lock();

    // Check if no frames are available
    if(mFrames.size() == 0 || mFrames.size() <= mCurrentFrame) {
        if(streamer->hasReachedEnd()) {
            mStreamMutex.unlock();
            throw Exception("Streamer has reached the end.");
        } else {
            mStreamMutex.unlock();
            throw Exception("This exception should not have occured. There is a bug somewhere in which getNextFrame is called more than once for the same timestamp.");
        }
    }

    // Get the frame
    typename T::pointer ret;
    if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
        // Get the next one
        ret = mFrames[mCurrentFrame];
        mCurrentFrame++;
    } else {
        // Always get the one in front
        ret = mFrames[0];
    }

    // Remove the frame from collection if necessary
    if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        // Remove the frame that was read, the one in the front
        mFrames.erase(mFrames.begin());
    }

    // Update modified timestamp so that a process object will read the next frame
    if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
        if(mCurrentFrame < mFrames.size())
            updateModifiedTimestamp();
    } else if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        if(mFrames.size() > 0)
            updateModifiedTimestamp();
    }

    mStreamMutex.unlock();

    mBoundingBox = ret->getBoundingBox();

    return ret;
}
*/

template <class T>
DynamicData<T>::~DynamicData() {
    delete fillCount;
    delete emptyCount;
}
template <class T>
void DynamicData<T>::setMaximumNumberOfFrames(uint nrOfFrames) {
    mMaximumNrOfFrames = nrOfFrames;
    if(mFrames2.size() > 0)
        throw Exception("Must call setMaximumNumberOfFrames before streaming is started");
    delete fillCount;
    delete emptyCount;
    fillCount = new boost::interprocess::interprocess_semaphore(0);
    emptyCount = new boost::interprocess::interprocess_semaphore(nrOfFrames);
}

template <class T>
uint DynamicData<T>::getLowestFrameCount() const {
    if(mConsumerFrameCounters.size() == 0)
        return 0;

    boost::unordered_map<WeakPointer<Object>, uint>::const_iterator it;
    uint lowestFrameCount = std::numeric_limits<uint>::max();
    for(it = mConsumerFrameCounters.begin(); it != mConsumerFrameCounters.end(); it++) {
        if(it->second < lowestFrameCount) {
            lowestFrameCount = it->second;
        }
    }

    return lowestFrameCount;
}

template <class T>
void DynamicData<T>::removeOldFrames(uint frameCounter) {
    // TODO this could be implemented in a faster way
    typename boost::unordered_map<uint, typename T::pointer>::iterator it = mFrames2.begin();
    while(it != mFrames2.end()) {
        if(it->first < frameCounter) {
            it = mFrames2.erase(it);
		} else {
			it++;
		}
    }
}

template <class T>
void DynamicData<T>::registerConsumer(Object::pointer processObject) {
    registerConsumer(WeakPointer<Object>(processObject));
}

template <class T>
void DynamicData<T>::registerConsumer(WeakPointer<Object> processObject) {
    Streamer::pointer streamer = getStreamer();
    mStreamMutex.lock();
     if(mConsumerFrameCounters.count(processObject) == 0) {
        if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
            mConsumerFrameCounters[processObject] = mCurrentFrameCounter;
        } else if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
            mConsumerFrameCounters[processObject] = 0;
        } else {
            mConsumerFrameCounters[processObject] = getLowestFrameCount();
        }
     }
    mStreamMutex.unlock();
}

template <class T>
typename T::pointer DynamicData<T>::getNextFrame(Object::pointer processObject) {
    return getNextFrame(WeakPointer<Object>(processObject));
}

template <class T>
void DynamicData<T>::setAllConsumersUpToDate() {
    unsigned long timestamp = getTimestamp();
    boost::unordered_map<WeakPointer<Object>, uint>::iterator it;
    for(it = mConsumerFrameCounters.begin(); it != mConsumerFrameCounters.end(); it++) {
        ProcessObject::pointer consumer = ProcessObject::pointer(it->first.lock());
        consumer->updateTimestamp(mPtr.lock());
    }
}

template <class T>
typename T::pointer DynamicData<T>::getNextFrame(WeakPointer<Object> processObject) {
    Streamer::pointer streamer = getStreamer();
    if(!streamer.isValid()) {
        // If streamer has been deleted, return the current frame instead
        throw Exception("Streamer has been deleted, but someone has called getNextFrame");
        //return getCurrentFrame();
    }

    // Producer consumer model
    if(mMaximumNrOfFrames > 0 && streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        fillCount->wait(); // decrement
    }
    mStreamMutex.lock();
    if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
        // Always return last frame
        if(mCurrentFrameCounter == 0) {
            mStreamMutex.unlock();
            throw Exception("Trying to get next frame, when no frame has ever been given to dynamic data.");
        }
        typename T::pointer returnData = mCurrentFrame2;
        mStreamMutex.unlock();
        return mCurrentFrame2;
    }
    // If process object is not registered, register it
    if(mConsumerFrameCounters.count(processObject) == 0) {
        if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
            mConsumerFrameCounters[processObject] = mCurrentFrameCounter;
        } else if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
            mConsumerFrameCounters[processObject] = 0;
        } else {
            uint lowestFrameCount = getLowestFrameCount(); // This must be assigned to a variable first to ensure correct result!
            mConsumerFrameCounters[processObject] = lowestFrameCount;
        }
    }
    // Return frame
    typename T::pointer returnData;
    if(mFrames2.count(mConsumerFrameCounters[processObject]) > 0) {
        returnData = mFrames2[mConsumerFrameCounters[processObject]];
    } else {
        mStreamMutex.unlock();
        throw Exception("Frame in dynamic data was not found");
    }

    // Increment
    mConsumerFrameCounters[processObject] = mConsumerFrameCounters[processObject]+1;

    // If PROCESS_ALL and this has smallest frame counter, remove old frame
    if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        removeOldFrames(getLowestFrameCount());
        if(mFrames2.size() > 0) { // Update timestamp if there are more frames available
            updateModifiedTimestamp();
        } else {
            // All frames are gone, make sure timestamps that all POs have are up to date
            setAllConsumersUpToDate();
        }
    } else if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
        // With newest frame only, always remove?
        //mFrames2.erase(removeFrame);
    } else {
        // Update timestamp if there are more frames available
        if(mConsumerFrameCounters[processObject] < mFrames2.size()) {
            updateModifiedTimestamp();
        }
    }

    mStreamMutex.unlock();
    // Producer consumer
    if(mMaximumNrOfFrames > 0 && streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        emptyCount->post(); // increment
    }

    return returnData;
}

template <class T>
typename T::pointer DynamicData<T>::getCurrentFrame() {
    Streamer::pointer streamer = getStreamer();
    mStreamMutex.lock();
    /*
    if(mFrames.size() == 0 || mFrames.size() <= mCurrentFrame) {
        if(!streamer.isValid()) {
            mStreamMutex.unlock();
            throw Exception("Streamer does not exist (anymore), stop.");
        } else {
            if(streamer->hasReachedEnd()) {
                mStreamMutex.unlock();
                throw Exception("Streamer has reached the end.");
            } else {
                mStreamMutex.unlock();
                throw Exception("This exception should not have occured. ");
            }
        }
    }
    */
    typename T::pointer ret = mCurrentFrame2;
    mStreamMutex.unlock();
    return ret;
}

template <class T>
void DynamicData<T>::addFrame(typename T::pointer frame) {
    Streamer::pointer streamer = getStreamer();
    if(!streamer.isValid()) {
        //throw Exception("A DynamicImage must have a streamer set before it can be used.");
        return;
    }
    if(mMaximumNrOfFrames > 0) {
        if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
            // Producer consumer model using semaphores
            emptyCount->wait(); // decrement
            //down(mutex);
        } else if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
            if(mFrames2.size() >= mMaximumNrOfFrames)
                throw NoMoreFramesException("Maximum number of frames reached. You can change the this number using the setMaximumNumberOfFrames method on the streamer/dynamic data objects.");
        }
    }
    mStreamMutex.lock();

    updateModifiedTimestamp();
    if(getStreamer()->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
        mFrames2.clear();
    }
    mFrames2[mCurrentFrameCounter] = frame;
    mCurrentFrame2 = frame;
    mCurrentFrameCounter++;
    mStreamMutex.unlock();
    if(mMaximumNrOfFrames > 0 && streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        fillCount->post(); // increment
    }
}

template <class T>
DynamicData<T>::DynamicData() {
    mCurrentFrameCounter = 0;
    mMaximumNrOfFrames = 0;
    mIsDynamicData = true;
    mHasReachedEnd = false;
    fillCount = NULL;
    emptyCount = NULL;
    updateModifiedTimestamp();
}

template <class T>
unsigned int DynamicData<T>::getSize() const {
    return mFrames2.size();
}

template <class T>
bool DynamicData<T>::hasReachedEnd() {
    Streamer::pointer streamer = getStreamer();
    if(!streamer.isValid()) {
        throw Exception("A DynamicData must have a streamer set before it can be used.");
    }
    mStreamMutex.lock();
    // Check if has reached end can be changed to true
    if(!mHasReachedEnd) {
        // TODO the checks for NEWEST_FRAME AND PROCESS_ALL are not necessarily correct, for a pipeline with several steps
        switch(streamer->getStreamingMode()) {
        case STREAMING_MODE_NEWEST_FRAME_ONLY:
            // Should get frame nr of last to see if we have read the last
            if(streamer->hasReachedEnd())
                mHasReachedEnd = true;
            break;
        case STREAMING_MODE_PROCESS_ALL_FRAMES:
            if(streamer->hasReachedEnd() && mFrames2.size() == 0)
                mHasReachedEnd = true;
            break;
        case STREAMING_MODE_STORE_ALL_FRAMES:
            if(streamer->hasReachedEnd() && streamer->getNrOfFrames() == getLowestFrameCount())
                mHasReachedEnd = true;
            break;
        }
    }
    mStreamMutex.unlock();
    return mHasReachedEnd;
}

} // end namespace fast

#endif
<commit_msg>fixed a problem related to a removal of consumer<commit_after>#ifndef DynamicImage_HPP
#define DynamicImage_HPP

#include "Streamer.hpp"
#include "DataObject.hpp"
#include <vector>
#include <boost/unordered_map.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include "ProcessObject.hpp"

namespace fast {

template <class T>
class DynamicData : public virtual DataObject {
    public:
        typedef SharedPointer<DynamicData<T> > pointer;
        static typename DynamicData<T>::pointer New() {
            DynamicData<T> * ptr = new DynamicData<T>();
            typename DynamicData<T>::pointer smartPtr(ptr);
            ptr->setPtr(smartPtr);

            return smartPtr;
        }
    private:
        void setPtr(typename DynamicData<T>::pointer ptr) {
            mPtr = ptr;
        }
    public:
        void setMaximumNumberOfFrames(uint nrOfFrames);
        //typename T::pointer getNextFrame();
        typename T::pointer getNextFrame(WeakPointer<Object> processObject);
        typename T::pointer getNextFrame(Object::pointer processObject);
        void addFrame(typename T::pointer frame);
        unsigned int getSize() const;
        ~DynamicData();

        bool hasReachedEnd();
        typename T::pointer getCurrentFrame();
        void registerConsumer(WeakPointer<Object> processObject);
        void registerConsumer(Object::pointer processObject);
    private:

        // If the flag mKeepAllFrames is set to false, this vector will have
        // a max size of 1
        //std::vector<typename T::pointer> mFrames;

        // Keep track of which frame is next, only used when mKeepAllFrames is
        // set to true
        //unsigned long mCurrentFrame;

        boost::unordered_map<WeakPointer<Object>, uint> mConsumerFrameCounters;
        uint getLowestFrameCount() const;
        void removeOldFrames(uint frameCounter);
        void setAllConsumersUpToDate();
        // Maps frame counter to a data
        boost::unordered_map<uint, typename T::pointer> mFrames2;
        // This is the frame number of HEAD
        unsigned long mCurrentFrameCounter;
        // Only used with newest frame only:
        typename T::pointer mCurrentFrame2;

        uint mMaximumNrOfFrames;
        boost::interprocess::interprocess_semaphore* fillCount;
        boost::interprocess::interprocess_semaphore* emptyCount;

        boost::mutex mStreamMutex;

        bool mHasReachedEnd;
    protected:
        DynamicData();
        // TODO not implemented yet
        void free(ExecutionDevice::pointer device) {};
        void freeAll() {};
};

/*
template <class T>
typename T::pointer DynamicData<T>::getNextFrame() {
    Streamer::pointer streamer = mStreamer.lock();
    if(!streamer.isValid()) {
        // If streamer has been deleted, return the current frame instead
        return getCurrentFrame();
    }
    mStreamMutex.lock();

    // Check if no frames are available
    if(mFrames.size() == 0 || mFrames.size() <= mCurrentFrame) {
        if(streamer->hasReachedEnd()) {
            mStreamMutex.unlock();
            throw Exception("Streamer has reached the end.");
        } else {
            mStreamMutex.unlock();
            throw Exception("This exception should not have occured. There is a bug somewhere in which getNextFrame is called more than once for the same timestamp.");
        }
    }

    // Get the frame
    typename T::pointer ret;
    if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
        // Get the next one
        ret = mFrames[mCurrentFrame];
        mCurrentFrame++;
    } else {
        // Always get the one in front
        ret = mFrames[0];
    }

    // Remove the frame from collection if necessary
    if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        // Remove the frame that was read, the one in the front
        mFrames.erase(mFrames.begin());
    }

    // Update modified timestamp so that a process object will read the next frame
    if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
        if(mCurrentFrame < mFrames.size())
            updateModifiedTimestamp();
    } else if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        if(mFrames.size() > 0)
            updateModifiedTimestamp();
    }

    mStreamMutex.unlock();

    mBoundingBox = ret->getBoundingBox();

    return ret;
}
*/

template <class T>
DynamicData<T>::~DynamicData() {
    delete fillCount;
    delete emptyCount;
}
template <class T>
void DynamicData<T>::setMaximumNumberOfFrames(uint nrOfFrames) {
    mMaximumNrOfFrames = nrOfFrames;
    if(mFrames2.size() > 0)
        throw Exception("Must call setMaximumNumberOfFrames before streaming is started");
    delete fillCount;
    delete emptyCount;
    fillCount = new boost::interprocess::interprocess_semaphore(0);
    emptyCount = new boost::interprocess::interprocess_semaphore(nrOfFrames);
}

template <class T>
uint DynamicData<T>::getLowestFrameCount() const {
    if(mConsumerFrameCounters.size() == 0)
        return 0;

    boost::unordered_map<WeakPointer<Object>, uint>::const_iterator it;
    uint lowestFrameCount = std::numeric_limits<uint>::max();
    for(it = mConsumerFrameCounters.begin(); it != mConsumerFrameCounters.end(); it++) {
        if(it->second < lowestFrameCount) {
            lowestFrameCount = it->second;
        }
    }

    return lowestFrameCount;
}

template <class T>
void DynamicData<T>::removeOldFrames(uint frameCounter) {
    // TODO this could be implemented in a faster way
    typename boost::unordered_map<uint, typename T::pointer>::iterator it = mFrames2.begin();
    while(it != mFrames2.end()) {
        if(it->first < frameCounter) {

            it = mFrames2.erase(it);
            if(mMaximumNrOfFrames > 0)
                emptyCount->post(); // increment semaphore, indicating that producer can produce more
		} else {
			it++;
		}
    }
}

template <class T>
void DynamicData<T>::registerConsumer(Object::pointer processObject) {
    registerConsumer(WeakPointer<Object>(processObject));
}

template <class T>
void DynamicData<T>::registerConsumer(WeakPointer<Object> processObject) {
    Streamer::pointer streamer = getStreamer();
    mStreamMutex.lock();
     if(mConsumerFrameCounters.count(processObject) == 0) {
        if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
            mConsumerFrameCounters[processObject] = mCurrentFrameCounter;
        } else if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
            mConsumerFrameCounters[processObject] = 0;
        } else {
            mConsumerFrameCounters[processObject] = getLowestFrameCount();
        }
     }
    mStreamMutex.unlock();
}

template <class T>
typename T::pointer DynamicData<T>::getNextFrame(Object::pointer processObject) {
    return getNextFrame(WeakPointer<Object>(processObject));
}

template <class T>
void DynamicData<T>::setAllConsumersUpToDate() {
    unsigned long timestamp = getTimestamp();
    boost::unordered_map<WeakPointer<Object>, uint>::iterator it;
    for(it = mConsumerFrameCounters.begin(); it != mConsumerFrameCounters.end(); it++) {
        ProcessObject::pointer consumer = ProcessObject::pointer(it->first.lock());
        consumer->updateTimestamp(mPtr.lock());
    }
}

template <class T>
typename T::pointer DynamicData<T>::getNextFrame(WeakPointer<Object> processObject) {
    Streamer::pointer streamer = getStreamer();
    if(!streamer.isValid()) {
        // If streamer has been deleted, return the current frame instead
        throw Exception("Streamer has been deleted, but someone has called getNextFrame");
        //return getCurrentFrame();
    }

    mStreamMutex.lock();
    if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
        // Always return last frame
        if(mCurrentFrameCounter == 0) {
            mStreamMutex.unlock();
            throw Exception("Trying to get next frame, when no frame has ever been given to dynamic data.");
        }
        typename T::pointer returnData = mCurrentFrame2;
        mStreamMutex.unlock();
        return mCurrentFrame2;
    }
    // If process object is not registered, register it
    if(mConsumerFrameCounters.count(processObject) == 0) {
        if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
            mConsumerFrameCounters[processObject] = mCurrentFrameCounter;
        } else if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
            mConsumerFrameCounters[processObject] = 0;
        } else {
            uint lowestFrameCount = getLowestFrameCount(); // This must be assigned to a variable first to ensure correct result!
            mConsumerFrameCounters[processObject] = lowestFrameCount;
        }
    }
    // Return frame
    typename T::pointer returnData;
    if(mFrames2.count(mConsumerFrameCounters[processObject]) > 0) {
        if(mMaximumNrOfFrames > 0 && streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
            fillCount->wait(); // decrement semaphore, indicating that consumers have consumed 1
        }
        returnData = mFrames2[mConsumerFrameCounters[processObject]];
    } else {
        mStreamMutex.unlock();
        throw Exception("Frame in dynamic data was not found");
    }

    // Increment
    mConsumerFrameCounters[processObject] = mConsumerFrameCounters[processObject]+1;

    // If PROCESS_ALL and this has smallest frame counter, remove old frame
    if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        // Check if one or more consumers have been removed
        if(mConsumerFrameCounters.size() > 1) {
            bool removed = false;
            do {
                removed = false;
                boost::unordered_map<WeakPointer<Object>, uint>::const_iterator it;
                uint lowestFrameCount = std::numeric_limits<uint>::max();
                WeakPointer<Object> lowestConsumer;
                uint highestFrameCount = 0;
                WeakPointer<Object> highestConsumer;
                for(it = mConsumerFrameCounters.begin(); it != mConsumerFrameCounters.end(); it++) {
                    if(it->second < lowestFrameCount) {
                        lowestFrameCount = it->second;
                        lowestConsumer = it->first;
                    }
                    if(it->second > highestFrameCount) {
                        highestFrameCount = it->second;
                        highestConsumer = it->first;
                    }
                }
                if(highestFrameCount - lowestFrameCount > mMaximumNrOfFrames-1) {
                    // Remove lowest consumer
                    mConsumerFrameCounters.erase(lowestConsumer);
                    removed = true;
                }
            } while(removed);
        }

        removeOldFrames(getLowestFrameCount());
        if(mFrames2.size() > 0) { // Update timestamp if there are more frames available
            updateModifiedTimestamp();
        } else {
            // All frames are gone, make sure timestamps that all POs have are up to date
            setAllConsumersUpToDate();
        }
    } else if(streamer->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
        // With newest frame only, always remove?
        //mFrames2.erase(removeFrame);
    } else {
        // Update timestamp if there are more frames available
        if(mConsumerFrameCounters[processObject] < mFrames2.size()) {
            updateModifiedTimestamp();
        }
    }

    mStreamMutex.unlock(); // should this be unlocked before removeOldFrames??

    return returnData;
}

template <class T>
typename T::pointer DynamicData<T>::getCurrentFrame() {
    Streamer::pointer streamer = getStreamer();
    mStreamMutex.lock();
    typename T::pointer ret = mCurrentFrame2;
    mStreamMutex.unlock();
    return ret;
}

template <class T>
void DynamicData<T>::addFrame(typename T::pointer frame) {
    Streamer::pointer streamer = getStreamer();
    if(!streamer.isValid()) {
        //throw Exception("A DynamicImage must have a streamer set before it can be used.");
        return;
    }
    if(mMaximumNrOfFrames > 0) {
        if(streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
            // Producer consumer model using semaphores
            emptyCount->wait(); // decrement
        } else if(streamer->getStreamingMode() == STREAMING_MODE_STORE_ALL_FRAMES) {
            if(mFrames2.size() >= mMaximumNrOfFrames)
                throw NoMoreFramesException("Maximum number of frames reached. You can change the this number using the setMaximumNumberOfFrames method on the streamer/dynamic data objects.");
        }
    }
    mStreamMutex.lock();

    updateModifiedTimestamp();
    if(getStreamer()->getStreamingMode() == STREAMING_MODE_NEWEST_FRAME_ONLY) {
        mFrames2.clear();
    }
    mFrames2[mCurrentFrameCounter] = frame;
    mCurrentFrame2 = frame;
    mCurrentFrameCounter++;
    mStreamMutex.unlock();
    if(mMaximumNrOfFrames > 0 && streamer->getStreamingMode() == STREAMING_MODE_PROCESS_ALL_FRAMES) {
        fillCount->post(); // increment, indicating that one more item has been produced
    }
}

template <class T>
DynamicData<T>::DynamicData() {
    mCurrentFrameCounter = 0;
    mMaximumNrOfFrames = 0;
    mIsDynamicData = true;
    mHasReachedEnd = false;
    fillCount = NULL;
    emptyCount = NULL;
    updateModifiedTimestamp();
}

template <class T>
unsigned int DynamicData<T>::getSize() const {
    return mFrames2.size();
}

template <class T>
bool DynamicData<T>::hasReachedEnd() {
    Streamer::pointer streamer = getStreamer();
    if(!streamer.isValid()) {
        throw Exception("A DynamicData must have a streamer set before it can be used.");
    }
    mStreamMutex.lock();
    // Check if has reached end can be changed to true
    if(!mHasReachedEnd) {
        // TODO the checks for NEWEST_FRAME AND PROCESS_ALL are not necessarily correct, for a pipeline with several steps
        switch(streamer->getStreamingMode()) {
        case STREAMING_MODE_NEWEST_FRAME_ONLY:
            // Should get frame nr of last to see if we have read the last
            if(streamer->hasReachedEnd())
                mHasReachedEnd = true;
            break;
        case STREAMING_MODE_PROCESS_ALL_FRAMES:
            if(streamer->hasReachedEnd() && mFrames2.size() == 0)
                mHasReachedEnd = true;
            break;
        case STREAMING_MODE_STORE_ALL_FRAMES:
            if(streamer->hasReachedEnd() && streamer->getNrOfFrames() == getLowestFrameCount())
                mHasReachedEnd = true;
            break;
        }
    }
    mStreamMutex.unlock();
    return mHasReachedEnd;
}

} // end namespace fast

#endif
<|endoftext|>


<commit_before>#include <stdint.h>

#include "allfiles.h"
#include "errors.h"
#include "moreio.h"
#include "version.h"
#include "sludger.h"
#include "colours.h"
#include "backdrop.h"
#include "graphics.h"
#include "newfatal.h"

bool freeze ();
void unfreeze (bool);	// Because FREEZE.H needs a load of other includes

int thumbWidth = 0, thumbHeight = 0;

extern GLuint backdropTextureName;

bool saveThumbnail (FILE * fp) {
	GLuint thumbnailTextureName = 0;

	put4bytes (thumbWidth, fp);
	put4bytes (thumbHeight, fp);

	if (thumbWidth && thumbHeight) {
		if (! freeze ()) return false;

		glEnable (GL_TEXTURE_2D);
		setPixelCoords (true);
		glUseProgram(0);

		glGenTextures (1, &thumbnailTextureName);
		glBindTexture(GL_TEXTURE_2D, thumbnailTextureName);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, thumbWidth, thumbHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

		// Render the backdrop (scaled)
		glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
		glBindTexture (GL_TEXTURE_2D, backdropTextureName);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

		const GLint vertices[] = {
			0, 0, 0,
			thumbWidth-1, 0, 0,
			0, thumbHeight-1, 0,
			thumbWidth-1, thumbHeight-1, 0
		};

		const GLfloat texCoords[] = {
			0.0f, 0.0f,
			backdropTexW, 0.0f,
			0.0f, backdropTexH,
			backdropTexW, backdropTexH
		};

		drawTexturedQuad(vertices, texCoords);

		if (gameSettings.antiAlias < 0) {
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		} else {
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		glDeleteTextures (1, &thumbnailTextureName);
		thumbnailTextureName = 0;

		// Save Our ViewPort
		GLushort* image = new GLushort [thumbWidth*thumbHeight];
		if (! checkNew (image)) return false;
		glReadPixels(viewportOffsetX, viewportOffsetY, thumbWidth, thumbHeight, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, image);

		setPixelCoords (false);

		for (int y = 0; y < thumbHeight; y ++) {
			for (int x = 0; x < thumbWidth; x ++) {
				put2bytes ((*(image +y*thumbWidth+x)), fp);
			}
		}
		delete image;
		image = NULL;
		unfreeze (true);
	}
	fputc ('!', fp);
	return true;
}

void showThumbnail (char * filename, int atX, int atY) {
	GLubyte * thumbnailTexture = NULL;
	GLuint thumbnailTextureName = 0;

	int ssgVersion;
	FILE * fp = openAndVerify (filename, 'S', 'A', ERROR_GAME_LOAD_NO, ssgVersion);
	if (ssgVersion >= VERSION(1,4)) {
		if (fp == NULL) return;
		int fileWidth = get4bytes (fp);
		int fileHeight = get4bytes (fp);

		int picWidth = fileWidth;
		int picHeight = fileHeight;
		if (! NPOT_textures) {
			picWidth = getNextPOT(picWidth);
			picHeight = getNextPOT(picHeight);
		}

		thumbnailTexture = new GLubyte [picHeight*picWidth*4];
		if (thumbnailTexture == NULL) return;

		int t1, t2;
		unsigned short c;
		GLubyte * target;
		for (t2 = 0; t2 < fileHeight; t2 ++) {
			t1 = 0;
			while (t1 < fileWidth) {
				c = (unsigned short) get2bytes (fp);
				target = thumbnailTexture + 4*picWidth*t2 + t1*4;
				target[0] = (GLubyte) redValue(c);
				target[1] = (GLubyte) greenValue(c);
				target[2] = (GLubyte) blueValue(c);
				target[3] = (GLubyte) 255;
				t1++;
			}
		}

		fclose (fp);

		glGenTextures (1, &thumbnailTextureName);
		glBindTexture(GL_TEXTURE_2D, thumbnailTextureName);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, picWidth, picHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, thumbnailTexture);

		delete thumbnailTexture;
		thumbnailTexture = NULL;

		if (atX<0){
			fileWidth+= atX;
			atX=0;
		}
		if (atY<0){
			fileHeight+= atY;
			atY=0;
		}
		if (fileWidth + atX > sceneWidth) fileWidth = sceneWidth-atX;
		if (fileHeight + atY > sceneHeight) fileHeight = sceneHeight-atY;

		glEnable (GL_TEXTURE_2D);
		setPixelCoords (true);
		int xoffset = 0;
		while (xoffset < fileWidth) {
			int w = (fileWidth-xoffset < viewportWidth) ? fileWidth-xoffset : viewportWidth;

			int yoffset = 0;
			while (yoffset < fileHeight) {
				int h = (fileHeight-yoffset < viewportHeight) ? fileHeight-yoffset : viewportHeight;

				glBindTexture (GL_TEXTURE_2D, thumbnailTextureName);

				const GLint vertices[] = {
					fileWidth-1-xoffset, -yoffset, 0,
					-xoffset, -yoffset, 0,
					fileWidth-1-xoffset, fileHeight-1-yoffset, 0,
					-xoffset, fileHeight-1-yoffset, 0
				};

				const GLfloat texCoords[] = {
					backdropTexW, 0.0f,
					0.0f, 0.0f,
					backdropTexW, backdropTexH,
					0.0f, backdropTexH
				};

				drawTexturedQuad(vertices, texCoords);

				glDisable(GL_BLEND);

				// Copy Our ViewPort To The Texture
				glBindTexture(GL_TEXTURE_2D, backdropTextureName);
				glCopyTexSubImage2D(GL_TEXTURE_2D, 0, atX+xoffset, atY+yoffset, viewportOffsetX, viewportOffsetY, w, h);

				yoffset += viewportHeight;
			}
			xoffset += viewportWidth;
		}

		setPixelCoords (false);
		glDeleteTextures (1, &thumbnailTextureName);
		thumbnailTextureName = 0;
	}
}

bool skipThumbnail (FILE * fp) {
	thumbWidth = get4bytes (fp);
	thumbHeight = get4bytes (fp);
	uint32_t skippy = thumbWidth;
	skippy *= thumbHeight << 1;
	fseek (fp, skippy, 1);
	return (fgetc (fp) == '!');
}
<commit_msg>Use shader in thumbnail.cpp.<commit_after>#include <stdint.h>

#include "allfiles.h"
#include "errors.h"
#include "moreio.h"
#include "version.h"
#include "sludger.h"
#include "colours.h"
#include "backdrop.h"
#include "graphics.h"
#include "newfatal.h"

bool freeze ();
void unfreeze (bool);	// Because FREEZE.H needs a load of other includes

int thumbWidth = 0, thumbHeight = 0;

extern GLuint backdropTextureName;

bool saveThumbnail (FILE * fp) {
	GLuint thumbnailTextureName = 0;

	put4bytes (thumbWidth, fp);
	put4bytes (thumbHeight, fp);

	if (thumbWidth && thumbHeight) {
		if (! freeze ()) return false;

		glEnable (GL_TEXTURE_2D);
		setPixelCoords (true);
		glUseProgram(shader.texture);
		setPMVMatrix(shader.texture);
		glUniform1i(glGetUniformLocation(shader.texture, "zBuffer"), 0);

		glGenTextures (1, &thumbnailTextureName);
		glBindTexture(GL_TEXTURE_2D, thumbnailTextureName);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, thumbWidth, thumbHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

		// Render the backdrop (scaled)
		glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
		glBindTexture (GL_TEXTURE_2D, backdropTextureName);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

		const GLint vertices[] = {
			0, 0, 0,
			thumbWidth-1, 0, 0,
			0, thumbHeight-1, 0,
			thumbWidth-1, thumbHeight-1, 0
		};

		const GLfloat texCoords[] = {
			0.0f, 0.0f,
			backdropTexW, 0.0f,
			0.0f, backdropTexH,
			backdropTexW, backdropTexH
		};

		drawTexturedQuadNew(shader.texture, vertices, 1, texCoords);

		if (gameSettings.antiAlias < 0) {
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		} else {
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		glDeleteTextures (1, &thumbnailTextureName);
		thumbnailTextureName = 0;

		// Save Our ViewPort
		GLushort* image = new GLushort [thumbWidth*thumbHeight];
		if (! checkNew (image)) return false;
		glReadPixels(viewportOffsetX, viewportOffsetY, thumbWidth, thumbHeight, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, image);

		glUseProgram(0);
		setPixelCoords (false);

		for (int y = 0; y < thumbHeight; y ++) {
			for (int x = 0; x < thumbWidth; x ++) {
				put2bytes ((*(image +y*thumbWidth+x)), fp);
			}
		}
		delete image;
		image = NULL;
		unfreeze (true);
	}
	fputc ('!', fp);
	return true;
}

void showThumbnail (char * filename, int atX, int atY) {
	GLubyte * thumbnailTexture = NULL;
	GLuint thumbnailTextureName = 0;

	int ssgVersion;
	FILE * fp = openAndVerify (filename, 'S', 'A', ERROR_GAME_LOAD_NO, ssgVersion);
	if (ssgVersion >= VERSION(1,4)) {
		if (fp == NULL) return;
		int fileWidth = get4bytes (fp);
		int fileHeight = get4bytes (fp);

		int picWidth = fileWidth;
		int picHeight = fileHeight;
		if (! NPOT_textures) {
			picWidth = getNextPOT(picWidth);
			picHeight = getNextPOT(picHeight);
		}

		thumbnailTexture = new GLubyte [picHeight*picWidth*4];
		if (thumbnailTexture == NULL) return;

		int t1, t2;
		unsigned short c;
		GLubyte * target;
		for (t2 = 0; t2 < fileHeight; t2 ++) {
			t1 = 0;
			while (t1 < fileWidth) {
				c = (unsigned short) get2bytes (fp);
				target = thumbnailTexture + 4*picWidth*t2 + t1*4;
				target[0] = (GLubyte) redValue(c);
				target[1] = (GLubyte) greenValue(c);
				target[2] = (GLubyte) blueValue(c);
				target[3] = (GLubyte) 255;
				t1++;
			}
		}

		fclose (fp);

		glGenTextures (1, &thumbnailTextureName);
		glBindTexture(GL_TEXTURE_2D, thumbnailTextureName);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, picWidth, picHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, thumbnailTexture);

		delete thumbnailTexture;
		thumbnailTexture = NULL;

		if (atX<0){
			fileWidth+= atX;
			atX=0;
		}
		if (atY<0){
			fileHeight+= atY;
			atY=0;
		}
		if (fileWidth + atX > sceneWidth) fileWidth = sceneWidth-atX;
		if (fileHeight + atY > sceneHeight) fileHeight = sceneHeight-atY;

		glEnable (GL_TEXTURE_2D);
		setPixelCoords (true);

		glUseProgram(shader.texture);
		setPMVMatrix(shader.texture);
		glUniform1i(glGetUniformLocation(shader.texture, "zBuffer"), 0);

		int xoffset = 0;
		while (xoffset < fileWidth) {
			int w = (fileWidth-xoffset < viewportWidth) ? fileWidth-xoffset : viewportWidth;

			int yoffset = 0;
			while (yoffset < fileHeight) {
				int h = (fileHeight-yoffset < viewportHeight) ? fileHeight-yoffset : viewportHeight;

				glBindTexture (GL_TEXTURE_2D, thumbnailTextureName);

				const GLint vertices[] = {
					fileWidth-1-xoffset, -yoffset, 0,
					-xoffset, -yoffset, 0,
					fileWidth-1-xoffset, fileHeight-1-yoffset, 0,
					-xoffset, fileHeight-1-yoffset, 0
				};

				const GLfloat texCoords[] = {
					backdropTexW, 0.0f,
					0.0f, 0.0f,
					backdropTexW, backdropTexH,
					0.0f, backdropTexH
				};

				drawTexturedQuadNew(shader.texture, vertices, 1, texCoords);

				glDisable(GL_BLEND);

				// Copy Our ViewPort To The Texture
				glBindTexture(GL_TEXTURE_2D, backdropTextureName);
				glCopyTexSubImage2D(GL_TEXTURE_2D, 0, atX+xoffset, atY+yoffset, viewportOffsetX, viewportOffsetY, w, h);

				yoffset += viewportHeight;
			}
			xoffset += viewportWidth;
		}
		glUseProgram(0);
		setPixelCoords (false);
		glDeleteTextures (1, &thumbnailTextureName);
		thumbnailTextureName = 0;
	}
}

bool skipThumbnail (FILE * fp) {
	thumbWidth = get4bytes (fp);
	thumbHeight = get4bytes (fp);
	uint32_t skippy = thumbWidth;
	skippy *= thumbHeight << 1;
	fseek (fp, skippy, 1);
	return (fgetc (fp) == '!');
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: MNSInclude.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: fs $ $Date: 2002-05-17 12:08:41 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Willem van Dorp, Darren Kenny
 *
 *
 ************************************************************************/
#ifndef _CONNECTIVITY_MAB_NS_INCLUDE_HXX_
#define _CONNECTIVITY_MAB_NS_INCLUDE_HXX_ 1

//
// Only include Mozilla include files once and using this file...
//

#ifndef BOOL
# define MOZ_BOOL

# define BOOL mozBOOL
# define Bool mozBooL
#endif

// Turn off DEBUG Assertions
#ifdef _DEBUG
# define MOZ_TMP_UDEBUG _DEBUG
# undef _DEBUG
#endif
#include <nsDebug.h>
#ifdef MOZ_TMP_UDEBUG
# define _DEBUG MOZ_TMP_UDEBUG
#endif

#include <nsCOMPtr.h>
#include <nsISupportsArray.h>
#include <nsStr.h>
#include <nsString.h>
#include <nsString2.h>
#include <nsMemory.h>
#include <prtypes.h>
#include <nsRDFCID.h>
#include <nsXPIDLString.h>
#include <nsIRDFService.h>
#include <nsIRDFResource.h>
#include <nsReadableUtils.h>
#include <msgCore.h>
#include <nsIServiceManager.h>
#include <nsIAbCard.h>
#include <nsAbBaseCID.h>
#include <nsAbAddressCollecter.h>
#include <nsIPref.h>
#include <nsIAddrBookSession.h>
#include <nsIMsgHeaderParser.h>
#include <nsIAddrBookSession.h>
#include <nsIAbDirectory.h>
#include <nsAbDirectoryQuery.h>
#include <nsIAbDirectoryQuery.h>
#include <nsIAbDirectoryQueryProxy.h>
#include <nsIAbDirFactory.h>

#ifdef MOZ_BOOL
# undef BOOL
# undef Bool
#endif

#endif // _CONNECTIVITY_MAB_NS_INCLUDE_HXX_
<commit_msg>#101400# (temporarily) undef DEBUG and _DEBUG while including all the mozilla headers to prevent incompatibilities<commit_after>/*************************************************************************
 *
 *  $RCSfile: MNSInclude.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: fs $ $Date: 2002-10-10 15:32:47 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Willem van Dorp, Darren Kenny
 *
 *
 ************************************************************************/
#ifndef _CONNECTIVITY_MAB_NS_INCLUDE_HXX_
#define _CONNECTIVITY_MAB_NS_INCLUDE_HXX_ 1

//
// Only include Mozilla include files once and using this file...
//

#ifndef BOOL
# define MOZ_BOOL

# define BOOL mozBOOL
# define Bool mozBooL
#endif

// Turn off DEBUG Assertions
#ifdef _DEBUG
    #define _DEBUG_WAS_DEFINED _DEBUG
    #undef _DEBUG
#else
    #undef _DEBUG_WAS_DEFINED _DEBUG
#endif

// and turn off the additional virtual methods which are part of some interfaces when compiled
// with debug
#ifdef DEBUG
    #define DEBUG_WAS_DEFINED DEBUG
    #undef DEBUG
#else
    #undef DEBUG_WAS_DEFINED DEBUG
#endif

#include <nsDebug.h>

#include <nsCOMPtr.h>
#include <nsISupportsArray.h>
#include <nsStr.h>
#include <nsString.h>
#include <nsString2.h>
#include <nsMemory.h>
#include <prtypes.h>
#include <nsRDFCID.h>
#include <nsXPIDLString.h>
#include <nsIRDFService.h>
#include <nsIRDFResource.h>
#include <nsReadableUtils.h>
#include <msgCore.h>
#include <nsIServiceManager.h>
#include <nsIAbCard.h>
#include <nsAbBaseCID.h>
#include <nsAbAddressCollecter.h>
#include <nsIPref.h>
#include <nsIAddrBookSession.h>
#include <nsIMsgHeaderParser.h>
#include <nsIAddrBookSession.h>
#include <nsIAbDirectory.h>
#include <nsAbDirectoryQuery.h>
#include <nsIAbDirectoryQuery.h>
#include <nsIAbDirectoryQueryProxy.h>
#include <nsIAbDirFactory.h>

#ifdef MOZ_BOOL
# undef BOOL
# undef Bool
#endif

#ifdef DEBUG_WAS_DEFINED
    #define DEBUG DEBUG_WAS_DEFINED
#endif

#ifdef _DEBUG_WAS_DEFINED
    #define _DEBUG _DEBUG_WAS_DEFINED
#endif

#endif // _CONNECTIVITY_MAB_NS_INCLUDE_HXX_
<|endoftext|>


<commit_before>#ifndef CLUSTERING_GENERIC_NONOVERLAPPING_REGIONS_HPP_
#define CLUSTERING_GENERIC_NONOVERLAPPING_REGIONS_HPP_

#include <set>

#include "errors.hpp"
#include "http/json/json_adapter.hpp"
#include "rpc/serialize_macros.hpp"

template <class protocol_t>
class nonoverlapping_regions_t {
public:
    nonoverlapping_regions_t() { }

    // Returns true upon success, false if there's an overlap or the
    // regions don't join to the universal set.  This is like calling
    // add_region in a loop and then valid_for_sharding, only maybe without being O(n^2).
    MUST_USE bool set_regions(const std::vector<typename protocol_t::region_t> &regions);

    // We already know by the public interface that no regions
    // overlap.  This checks that their join is the universe, and that
    // there is no empty region.
    bool valid_for_sharding() const;

    // Returns true upon success, false if there's an overlap.  This is O(n)!
    MUST_USE bool add_region(const typename protocol_t::region_t &region);

    // Yes, both of these are const iterators.
    typedef typename std::set<typename protocol_t::region_t>::iterator iterator;
    iterator begin() const { return regions_.begin(); }
    iterator end() const { return regions_.end(); }

    bool empty() const { return regions_.empty(); }
    size_t size() const { return regions_.size(); }

    void remove_region(iterator it) {
        guarantee(it != regions_.end());
        regions_.erase(it);
    }

    bool operator==(const nonoverlapping_regions_t<protocol_t> &other) const {
        return regions_ == other.regions_;
    }

    RDB_MAKE_ME_SERIALIZABLE_1(regions_);

private:
    std::set<typename protocol_t::region_t> regions_;
};

// ctx-less json adapter concept for nonoverlapping_regions_t.
template <class protocol_t>
json_adapter_if_t::json_adapter_map_t get_json_subfields(nonoverlapping_regions_t<protocol_t> *target);

template <class protocol_t>
cJSON *render_as_json(nonoverlapping_regions_t<protocol_t> *target);

template <class protocol_t>
void apply_json_to(cJSON *change, nonoverlapping_regions_t<protocol_t> *target) THROWS_ONLY(schema_mismatch_exc_t);

template <class protocol_t>
void on_subfield_change(nonoverlapping_regions_t<protocol_t> *target);

#endif  // CLUSTERING_GENERIC_NONOVERLAPPING_REGIONS_HPP_
<commit_msg>Added a TODO telling us to use valid_for_sharding.<commit_after>#ifndef CLUSTERING_GENERIC_NONOVERLAPPING_REGIONS_HPP_
#define CLUSTERING_GENERIC_NONOVERLAPPING_REGIONS_HPP_

#include <set>

#include "errors.hpp"
#include "http/json/json_adapter.hpp"
#include "rpc/serialize_macros.hpp"

template <class protocol_t>
class nonoverlapping_regions_t {
public:
    nonoverlapping_regions_t() { }

    // Returns true upon success, false if there's an overlap or the
    // regions don't join to the universal set.  This is like calling
    // add_region in a loop and then valid_for_sharding, only maybe without being O(n^2).
    MUST_USE bool set_regions(const std::vector<typename protocol_t::region_t> &regions);

    // We already know by the public interface that no regions
    // overlap.  This checks that their join is the universe, and that
    // there is no empty region.
    bool valid_for_sharding() const;

    // TODO: Use valid_for_sharding everywhere we use add_region.

    // Returns true upon success, false if there's an overlap.  This is O(n)!
    MUST_USE bool add_region(const typename protocol_t::region_t &region);

    // Yes, both of these are const iterators.
    typedef typename std::set<typename protocol_t::region_t>::iterator iterator;
    iterator begin() const { return regions_.begin(); }
    iterator end() const { return regions_.end(); }

    bool empty() const { return regions_.empty(); }
    size_t size() const { return regions_.size(); }

    void remove_region(iterator it) {
        guarantee(it != regions_.end());
        regions_.erase(it);
    }

    bool operator==(const nonoverlapping_regions_t<protocol_t> &other) const {
        return regions_ == other.regions_;
    }

    RDB_MAKE_ME_SERIALIZABLE_1(regions_);

private:
    std::set<typename protocol_t::region_t> regions_;
};

// ctx-less json adapter concept for nonoverlapping_regions_t.
template <class protocol_t>
json_adapter_if_t::json_adapter_map_t get_json_subfields(nonoverlapping_regions_t<protocol_t> *target);

template <class protocol_t>
cJSON *render_as_json(nonoverlapping_regions_t<protocol_t> *target);

template <class protocol_t>
void apply_json_to(cJSON *change, nonoverlapping_regions_t<protocol_t> *target) THROWS_ONLY(schema_mismatch_exc_t);

template <class protocol_t>
void on_subfield_change(nonoverlapping_regions_t<protocol_t> *target);

#endif  // CLUSTERING_GENERIC_NONOVERLAPPING_REGIONS_HPP_
<|endoftext|>


<commit_before>#include <babylon/cameras/arc_rotate_camera.h>
#include <babylon/core/random.h>
#include <babylon/engines/scene.h>
#include <babylon/interfaces/irenderable_scene.h>
#include <babylon/lights/point_light.h>
#include <babylon/materials/standard_material.h>
#include <babylon/maths/vector3.h>
#include <babylon/meshes/builders/mesh_builder_options.h>
#include <babylon/meshes/instanced_mesh.h>
#include <babylon/meshes/mesh.h>
#include <babylon/meshes/mesh_builder.h>
#include <babylon/samples/babylon_register_sample.h>

namespace BABYLON {

class AbstractMesh;
class Mesh;
using AbstractMeshPtr = std::shared_ptr<AbstractMesh>;
using MeshPtr         = std::shared_ptr<Mesh>;

namespace Samples {

/**
 * @brief Bouncing Cube Scene.
 *
 * In this simple example, you've got :
 * - a finite world defined by the big box
 * - some random platforms inside it, built with instances
 * - a Mario player, the tiny red box
 *
 * Mario is given an initial random velocity and applied a constant gravity. You can tweak the
 * energy loss against the box walls with the variable restitution (here : 100% = 1.0)
 *
 * When Mario hits a platform coming downward (he's above the platform), he bounces back with some
 * energy loss (variable platformBounceRestitution), when he hits the platform under it, he's just
 * rejected. This is a very simple and naive physics engine because I don't even test if Mario hits
 * the platform borders here. But it is fast.
 *
 * Note that I also test all the platforms what is not performant at all (well, they aren't very
 * numerous). The use of an octree or any preselection (we know where all the obstacles are in the
 * space before the scene starts !) would be better.
 *
 * @see http://www.babylonjs-playground.com/#PBVEM#17
 */
class BouncingCubeScene : public IRenderableScene {

public:
  BouncingCubeScene(ICanvas* iCanvas)
      : IRenderableScene(iCanvas)
      , _limit{0.f}
      , _restitution{0.f}
      , _platformBounceRestitution{0.f}
      , _k{0.f}
      , _mario{nullptr}
  {
  }
  ~BouncingCubeScene() override = default;

  const char* getName() override
  {
    return "Bouncing Cube Scene";
  }
  void initializeScene(ICanvas* canvas, Scene* scene) override
  {
    scene->clearColor = Color3::Black();
    auto camera       = ArcRotateCamera::New("camera1", 0.f, 0.f, 0.f, Vector3::Zero(), scene);
    camera->setPosition(Vector3(0.f, 10.f, -500.f));
    camera->attachControl(canvas, true);

    auto pl       = PointLight::New("pl", Vector3::Zero(), scene);
    pl->diffuse   = Color3(1.f, 1.f, 1.f);
    pl->intensity = 1.f;
    pl->position  = camera->position;

    auto boxSize               = 300.f;
    auto marioSize             = 5.f;
    auto platformNb            = 25;
    auto platformHeight        = 3.f;
    auto platformMaxWidth      = 40.f;
    auto platformMaxDepth      = 20.f;
    auto platformMinSize       = 20.f;
    _gravity                   = Vector3(0.f, -0.2f, 0.f);
    _platformBounceRestitution = 0.97f;
    auto speed                 = 2.f;
    _restitution               = 0.95f;
    _limit                     = (boxSize - marioSize) * 0.5f;
    auto platformLimit         = boxSize - platformMaxWidth - 10.f;
    _velocity                  = Vector3(Math::random(), Math::random(), Math::random());
    _velocity.scaleInPlace(speed);
    auto initialVel = Vector3(0.5f, 2.f, 0.f);
    _velocity.addInPlace(initialVel);

    BoxOptions boxOptions;
    boxOptions.size            = boxSize;
    boxOptions.sideOrientation = Mesh::BACKSIDE;
    auto box                   = MeshBuilder::CreateBox("b", boxOptions, scene);
    auto boxmat                = StandardMaterial::New("boxmat", scene);
    boxmat->diffuseColor       = Color3(0.4f, 0.6f, 1.f);
    boxmat->specularColor      = Color3::Black();
    box->material              = boxmat;

    BoxOptions marioOptions;
    marioOptions.size       = marioSize;
    _mario                  = MeshBuilder::CreateBox("m", marioOptions, scene);
    auto marioMat           = StandardMaterial::New("marioMat", scene);
    marioMat->diffuseColor  = Color3::Red();
    marioMat->specularColor = Color3::Black();
    _mario->material        = marioMat;

    BoxOptions platformOptions;
    platformOptions.size       = 1.f;
    auto platform              = MeshBuilder::CreateBox("p", platformOptions, scene);
    auto platformMat           = StandardMaterial::New("platform0", scene);
    platformMat->diffuseColor  = Color3::Green();
    platformMat->specularColor = Color3::Black();
    platformMat->alpha         = 0.7f;
    platform->material         = platformMat;
    platform->position
      = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                (0.5f - Math::random()) * platformLimit);
    platform->scaling = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                                platformMinSize + Math::random() * platformMaxDepth);

    _platforms.emplace_back(platform);
    for (int i = 1; i < platformNb; ++i) {
      auto instance = platform->createInstance("platform" + std::to_string(i));
      instance->position
        = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                  (0.5f - Math::random()) * platformLimit);
      platform->scaling
        = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                  platformMinSize + Math::random() * platformMaxDepth);
      _platforms.emplace_back(instance);
    }

    scene->registerBeforeRender([this](Scene* /*scene*/, EventState& /*es*/) {
      _applyForces();
      _checkCollisions();
      _moveMario();
      _movePlatforms();
      _k += 0.001f;
    });
  }

private:
  void _applyForces();
  void _checkCollisions();
  void _moveMario();
  void _movePlatforms();

private:
  Vector3 _gravity;
  Vector3 _velocity;
  float _limit;
  float _restitution;
  float _platformBounceRestitution;
  float _k;
  MeshPtr _mario;
  std::vector<AbstractMeshPtr> _platforms;

}; // end of class BouncingCubeScene

} // end of namespace Samples
} // end of namespace BABYLON

namespace BABYLON {
namespace Samples {

void BouncingCubeScene::_applyForces()
{
  _velocity.addInPlace(_gravity);
}

void BouncingCubeScene::_checkCollisions()
{
  // Check box walls
  if (std::abs(_mario->position().x) > _limit) {
    _velocity.x *= -1.f;
    _mario->position().x = (_mario->position().x > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().y) > _limit) {
    _velocity.y *= -1.f * _restitution;
    _mario->position().y = (_mario->position().y > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().z) > _limit) {
    _velocity.z *= -1.f;
    _mario->position().z = (_mario->position().z > 0.f) ? _limit : -_limit;
  }
  // Check platforms
  size_t i = 0;
  for (auto& platform : _platforms) {
    if (_mario->intersectsMesh(*platform)) {
      // naive impact point check
      if (_mario->position().y > platform->position().y) {
        _mario->position().y = platform->position().y + platform->scaling().y * 0.5f;
        _velocity.y *= -_platformBounceRestitution;
      }
      if (_mario->position().y < platform->position().y) {
        _velocity.y *= -1.f;
      }
    }
    ++i;
  }
}

void BouncingCubeScene::_moveMario()
{
  _mario->position().addInPlace(_velocity);
}

void BouncingCubeScene::_movePlatforms()
{
  size_t i = 0;
  for (auto& platform : _platforms) {
    auto p = i % 3;
    switch (p) {
      case 0:
        platform->position().x += 0.1f * std::sin(_k * i);
        break;
      case 1:
        platform->position().y -= 0.2f * std::cos(_k * i);
        break;
      case 2:
        platform->position().z -= 0.03f * std::sin(_k * i);
        break;
    }
    ++i;
  }
}

BABYLON_REGISTER_SAMPLE("Animations", BouncingCubeScene)

} // end of namespace Samples
} // end of namespace BABYLON
<commit_msg>const correctness<commit_after>#include <babylon/cameras/arc_rotate_camera.h>
#include <babylon/core/random.h>
#include <babylon/engines/scene.h>
#include <babylon/interfaces/irenderable_scene.h>
#include <babylon/lights/point_light.h>
#include <babylon/materials/standard_material.h>
#include <babylon/maths/vector3.h>
#include <babylon/meshes/builders/mesh_builder_options.h>
#include <babylon/meshes/instanced_mesh.h>
#include <babylon/meshes/mesh.h>
#include <babylon/meshes/mesh_builder.h>
#include <babylon/samples/babylon_register_sample.h>

namespace BABYLON {

class AbstractMesh;
class Mesh;
using AbstractMeshPtr = std::shared_ptr<AbstractMesh>;
using MeshPtr         = std::shared_ptr<Mesh>;

namespace Samples {

/**
 * @brief Bouncing Cube Scene.
 *
 * In this simple example, you've got :
 * - a finite world defined by the big box
 * - some random platforms inside it, built with instances
 * - a Mario player, the tiny red box
 *
 * Mario is given an initial random velocity and applied a constant gravity. You can tweak the
 * energy loss against the box walls with the variable restitution (here : 100% = 1.0)
 *
 * When Mario hits a platform coming downward (he's above the platform), he bounces back with some
 * energy loss (variable platformBounceRestitution), when he hits the platform under it, he's just
 * rejected. This is a very simple and naive physics engine because I don't even test if Mario hits
 * the platform borders here. But it is fast.
 *
 * Note that I also test all the platforms what is not performant at all (well, they aren't very
 * numerous). The use of an octree or any preselection (we know where all the obstacles are in the
 * space before the scene starts !) would be better.
 *
 * @see http://www.babylonjs-playground.com/#PBVEM#17
 */
class BouncingCubeScene : public IRenderableScene {

public:
  BouncingCubeScene(ICanvas* iCanvas)
      : IRenderableScene(iCanvas)
      , _limit{0.f}
      , _restitution{0.f}
      , _platformBounceRestitution{0.f}
      , _k{0.f}
      , _mario{nullptr}
  {
  }
  ~BouncingCubeScene() override = default;

  const char* getName() override
  {
    return "Bouncing Cube Scene";
  }
  void initializeScene(ICanvas* canvas, Scene* scene) override
  {
    scene->clearColor = Color3::Black();
    auto camera       = ArcRotateCamera::New("camera1", 0.f, 0.f, 0.f, Vector3::Zero(), scene);
    camera->setPosition(Vector3(0.f, 10.f, -500.f));
    camera->attachControl(canvas, true);

    auto pl       = PointLight::New("pl", Vector3::Zero(), scene);
    pl->diffuse   = Color3(1.f, 1.f, 1.f);
    pl->intensity = 1.f;
    pl->position  = camera->position;

    auto boxSize               = 300.f;
    auto marioSize             = 5.f;
    auto platformNb            = 25;
    auto platformHeight        = 3.f;
    auto platformMaxWidth      = 40.f;
    auto platformMaxDepth      = 20.f;
    auto platformMinSize       = 20.f;
    _gravity                   = Vector3(0.f, -0.2f, 0.f);
    _platformBounceRestitution = 0.97f;
    auto speed                 = 2.f;
    _restitution               = 0.95f;
    _limit                     = (boxSize - marioSize) * 0.5f;
    auto platformLimit         = boxSize - platformMaxWidth - 10.f;
    _velocity                  = Vector3(Math::random(), Math::random(), Math::random());
    _velocity.scaleInPlace(speed);
    auto initialVel = Vector3(0.5f, 2.f, 0.f);
    _velocity.addInPlace(initialVel);

    BoxOptions boxOptions;
    boxOptions.size            = boxSize;
    boxOptions.sideOrientation = Mesh::BACKSIDE;
    auto box                   = MeshBuilder::CreateBox("b", boxOptions, scene);
    auto boxmat                = StandardMaterial::New("boxmat", scene);
    boxmat->diffuseColor       = Color3(0.4f, 0.6f, 1.f);
    boxmat->specularColor      = Color3::Black();
    box->material              = boxmat;

    BoxOptions marioOptions;
    marioOptions.size       = marioSize;
    _mario                  = MeshBuilder::CreateBox("m", marioOptions, scene);
    auto marioMat           = StandardMaterial::New("marioMat", scene);
    marioMat->diffuseColor  = Color3::Red();
    marioMat->specularColor = Color3::Black();
    _mario->material        = marioMat;

    BoxOptions platformOptions;
    platformOptions.size       = 1.f;
    auto platform              = MeshBuilder::CreateBox("p", platformOptions, scene);
    auto platformMat           = StandardMaterial::New("platform0", scene);
    platformMat->diffuseColor  = Color3::Green();
    platformMat->specularColor = Color3::Black();
    platformMat->alpha         = 0.7f;
    platform->material         = platformMat;
    platform->position
      = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                (0.5f - Math::random()) * platformLimit);
    platform->scaling = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                                platformMinSize + Math::random() * platformMaxDepth);

    _platforms.emplace_back(platform);
    for (int i = 1; i < platformNb; ++i) {
      const auto instance = platform->createInstance("platform" + std::to_string(i));
      instance->position
        = Vector3((0.5f - Math::random()) * platformLimit, (0.5f - Math::random()) * platformLimit,
                  (0.5f - Math::random()) * platformLimit);
      platform->scaling
        = Vector3(platformMinSize + platformMaxWidth * Math::random(), platformHeight,
                  platformMinSize + Math::random() * platformMaxDepth);
      _platforms.emplace_back(instance);
    }

    scene->registerBeforeRender([this](Scene* /*scene*/, EventState& /*es*/) {
      _applyForces();
      _checkCollisions();
      _moveMario();
      _movePlatforms();
      _k += 0.001f;
    });
  }

private:
  void _applyForces();
  void _checkCollisions();
  void _moveMario();
  void _movePlatforms();

private:
  Vector3 _gravity;
  Vector3 _velocity;
  float _limit;
  float _restitution;
  float _platformBounceRestitution;
  float _k;
  MeshPtr _mario;
  std::vector<AbstractMeshPtr> _platforms;

}; // end of class BouncingCubeScene

} // end of namespace Samples
} // end of namespace BABYLON

namespace BABYLON {
namespace Samples {

void BouncingCubeScene::_applyForces()
{
  _velocity.addInPlace(_gravity);
}

void BouncingCubeScene::_checkCollisions()
{
  // Check box walls
  if (std::abs(_mario->position().x) > _limit) {
    _velocity.x *= -1.f;
    _mario->position().x = (_mario->position().x > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().y) > _limit) {
    _velocity.y *= -1.f * _restitution;
    _mario->position().y = (_mario->position().y > 0.f) ? _limit : -_limit;
  }
  if (std::abs(_mario->position().z) > _limit) {
    _velocity.z *= -1.f;
    _mario->position().z = (_mario->position().z > 0.f) ? _limit : -_limit;
  }
  // Check platforms
  size_t i = 0;
  for (auto& platform : _platforms) {
    if (_mario->intersectsMesh(*platform)) {
      // naive impact point check
      if (_mario->position().y > platform->position().y) {
        _mario->position().y = platform->position().y + platform->scaling().y * 0.5f;
        _velocity.y *= -_platformBounceRestitution;
      }
      if (_mario->position().y < platform->position().y) {
        _velocity.y *= -1.f;
      }
    }
    ++i;
  }
}

void BouncingCubeScene::_moveMario()
{
  _mario->position().addInPlace(_velocity);
}

void BouncingCubeScene::_movePlatforms()
{
  size_t i = 0;
  for (auto& platform : _platforms) {
    auto p = i % 3;
    switch (p) {
      case 0:
        platform->position().x += 0.1f * std::sin(_k * i);
        break;
      case 1:
        platform->position().y -= 0.2f * std::cos(_k * i);
        break;
      case 2:
        platform->position().z -= 0.03f * std::sin(_k * i);
        break;
    }
    ++i;
  }
}

BABYLON_REGISTER_SAMPLE("Animations", BouncingCubeScene)

} // end of namespace Samples
} // end of namespace BABYLON
<|endoftext|>