<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <SDL.h>

#include <iostream>
#include <vector>
#include <cstring>

#include "music_player.hxx"
#include "audio_source.hxx"
#include "vorbis_decoder.hxx"

using namespace std;

unsigned MusicDecoder::select(Sint16* dst, unsigned lc, unsigned rc, unsigned n,
                              unsigned len) const {
  unsigned total = 0;
  //If there are any partial samples at the end, just drop them
  //(Hence i+n <= len)
  for (unsigned i = 0; i+n <= len; i += n) {
    *dst++ = tempBuff[i+lc];
    *dst++ = tempBuff[i+rc];
    ++total;
  }

  return total * 2;
}

unsigned MusicDecoder::resample(Sint16* buff, unsigned len, unsigned maxlen,
                                unsigned rate) const {
  if (rate == AUDIO_SAMPLE_RATE)
    return len;

  float ratio = AUDIO_SAMPLE_RATE / (float)rate;
  float iratio = 1.0f / ratio;
  unsigned outlen = (unsigned)(len*ratio);

  //Ensure outlen is under the maximum and ends on a sample boundary.
  if (outlen > maxlen)
    outlen = maxlen;
  else if (outlen & 1)
    ++outlen;

  if (rate < AUDIO_SAMPLE_RATE) {
    //We'll be expanding the stream, so work right to left
    for (unsigned i = outlen-2; i < outlen; i -= 2) {
      unsigned src = i * iratio;
      if (src & 1) ++src;
      if (src != i)
        memcpy(buff+src, buff+i, 2 * sizeof(*buff));
    }
  } else {
    //Contracting stream, work from left to right
    for (unsigned i = 0; i < outlen; i += 2) {
      unsigned src = i * iratio;
      if (src & 1) --src;
      if (src != i)
        memcpy(buff+i, buff+src, 2 * sizeof(*buff));
    }
  }

  return outlen;
}

unsigned MusicDecoder::ensureCapacity(unsigned len, unsigned channels,
                                      unsigned rate) {
  unsigned samples = len / 2;
  unsigned samplePoints = channels * samples;

  float ratio = rate / (float)AUDIO_SAMPLE_RATE;
  unsigned outlen = (unsigned)(samplePoints * ratio);
  //Ensure we request a whole number of samples
  outlen = (outlen*channels + channels - 1) / channels;

  if (tempBuff.size() < outlen)
    tempBuff.resize(outlen);

  return outlen;
}

MusicPlayer::MusicPlayer(const char*const* files_,
                         unsigned numFiles_,
                         void (*cb)(void*, float),
                         void* ud)
: decoder(NULL),
  amplitudeCallback(cb),
  callbackUserdata(ud),
  files(files_),
  numFiles(numFiles_),
  fileIx(0)
{ }

MusicPlayer::~MusicPlayer() {
  if (decoder)
    delete decoder;
}

struct {
  const char* extension;
  MusicDecoder* (*open)(const char*);
} static decoders[] = {
  { "ogg", openVorbisDecoder },
  { NULL, NULL }
};

signed MusicPlayer::getAudio(Sint16* dst, unsigned len) {
  //Die immediately if the file list is empty
  if (0 == numFiles)
    return -1;

  //If there is currently no decoder, start decoding the next file
  if (!decoder) {
    const char* path = files[fileIx++];
    fileIx %= numFiles;

    //Find the extension
    const char* ext = path;
    for (const char* i = path; *i; ++i)
      if (*i == '.')
        ext = i+1;

    //Find a decoder for the file
    //Note: This won't handle non-lowercase extensions, but few people use those
    //for oggs and mp3s anyway
    for (unsigned i = 0; decoders[i].extension; ++i) {
      if (0 == strcmp(ext, decoders[i].extension)) {
        decoder = decoders[i].open(path);
        break;
      }
    }

    //No decoder for this extension
    cerr << "Note: File type " << ext << " unknown" << endl;
  }

  //If opening that was unsuccessful, return no audio this frame and try again
  //next frame
  if (!decoder) return 0;

  //Get data from the decoder
  signed ret = decoder->decode(dst, len);
  if (ret == -1) {
    //That decoder's done
    delete decoder;
    decoder = NULL;
    ret = 0;
  }

  return ret;
}

<commit_msg>Correct logic for determining whether a decoder matched an extension.<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <SDL.h>

#include <iostream>
#include <vector>
#include <cstring>

#include "music_player.hxx"
#include "audio_source.hxx"
#include "vorbis_decoder.hxx"

using namespace std;

unsigned MusicDecoder::select(Sint16* dst, unsigned lc, unsigned rc, unsigned n,
                              unsigned len) const {
  unsigned total = 0;
  //If there are any partial samples at the end, just drop them
  //(Hence i+n <= len)
  for (unsigned i = 0; i+n <= len; i += n) {
    *dst++ = tempBuff[i+lc];
    *dst++ = tempBuff[i+rc];
    ++total;
  }

  return total * 2;
}

unsigned MusicDecoder::resample(Sint16* buff, unsigned len, unsigned maxlen,
                                unsigned rate) const {
  if (rate == AUDIO_SAMPLE_RATE)
    return len;

  float ratio = AUDIO_SAMPLE_RATE / (float)rate;
  float iratio = 1.0f / ratio;
  unsigned outlen = (unsigned)(len*ratio);

  //Ensure outlen is under the maximum and ends on a sample boundary.
  if (outlen > maxlen)
    outlen = maxlen;
  else if (outlen & 1)
    ++outlen;

  if (rate < AUDIO_SAMPLE_RATE) {
    //We'll be expanding the stream, so work right to left
    for (unsigned i = outlen-2; i < outlen; i -= 2) {
      unsigned src = i * iratio;
      if (src & 1) ++src;
      if (src != i)
        memcpy(buff+src, buff+i, 2 * sizeof(*buff));
    }
  } else {
    //Contracting stream, work from left to right
    for (unsigned i = 0; i < outlen; i += 2) {
      unsigned src = i * iratio;
      if (src & 1) --src;
      if (src != i)
        memcpy(buff+i, buff+src, 2 * sizeof(*buff));
    }
  }

  return outlen;
}

unsigned MusicDecoder::ensureCapacity(unsigned len, unsigned channels,
                                      unsigned rate) {
  unsigned samples = len / 2;
  unsigned samplePoints = channels * samples;

  float ratio = rate / (float)AUDIO_SAMPLE_RATE;
  unsigned outlen = (unsigned)(samplePoints * ratio);
  //Ensure we request a whole number of samples
  outlen = (outlen*channels + channels - 1) / channels;

  if (tempBuff.size() < outlen)
    tempBuff.resize(outlen);

  return outlen;
}

MusicPlayer::MusicPlayer(const char*const* files_,
                         unsigned numFiles_,
                         void (*cb)(void*, float),
                         void* ud)
: decoder(NULL),
  amplitudeCallback(cb),
  callbackUserdata(ud),
  files(files_),
  numFiles(numFiles_),
  fileIx(0)
{ }

MusicPlayer::~MusicPlayer() {
  if (decoder)
    delete decoder;
}

struct {
  const char* extension;
  MusicDecoder* (*open)(const char*);
} static decoders[] = {
  { "ogg", openVorbisDecoder },
  { NULL, NULL }
};

signed MusicPlayer::getAudio(Sint16* dst, unsigned len) {
  //Die immediately if the file list is empty
  if (0 == numFiles)
    return -1;

  //If there is currently no decoder, start decoding the next file
  if (!decoder) {
    const char* path = files[fileIx++];
    fileIx %= numFiles;

    //Find the extension
    const char* ext = path;
    for (const char* i = path; *i; ++i)
      if (*i == '.')
        ext = i+1;

    //Find a decoder for the file
    //Note: This won't handle non-lowercase extensions, but few people use those
    //for oggs and mp3s anyway
    for (unsigned i = 0; decoders[i].extension; ++i) {
      if (0 == strcmp(ext, decoders[i].extension)) {
        decoder = decoders[i].open(path);
        goto have_decoder;
      }
    }

    //No decoder for this extension
    cerr << "Note: File type " << ext << " unknown" << endl;
  }

  have_decoder:

  //If opening that was unsuccessful, return no audio this frame and try again
  //next frame
  if (!decoder) return 0;

  //Get data from the decoder
  signed ret = decoder->decode(dst, len);
  if (ret == -1) {
    //That decoder's done
    delete decoder;
    decoder = NULL;
    ret = 0;
  }

  return ret;
}

<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <net/checksum.hpp>
#include <net/util.hpp>

#if defined(__AVX2__)
 #include <immintrin.h>
#endif
#elif defined(__SSSE3__)
 #include <tmmintrin.h>
#endif

#include <cassert>
#include <common>

namespace net {

uint16_t checksum(uint32_t tsum, const void* data, size_t length) noexcept
{
  const char* buffer = (const char*) data;
  int64_t sum = tsum;
  if (UNLIKELY(length == 0))
    return 0xffff;

  if (UNLIKELY(buffer == 0))
    return 0xffff;

#if defined(__SSSE3__)
    static __m128i swap16a = _mm_setr_epi16(0x0001, 0xffff, 0x0203, 0xffff,
                                         0x0405, 0xffff, 0x0607, 0xffff);
    static __m128i swap16b = _mm_setr_epi16(0x0809, 0xffff, 0x0a0b, 0xffff,
                      0x0c0d, 0xffff, 0x0e0f, 0xffff);
    size_t count;
    __m128i zero = _mm_setzero_si128();
    __m128i suma=zero;
    __m128i sumb=zero;
    __m128i oldsum;

    //according to godbolt its sligtly better to count index than incrementing pointer
    for(count = 0; (count+64) < length; count+=64)
    {
      __m128i dblock1,dblock2;
      dblock1 = _mm_loadu_si128((__m128i *) (&buffer[count +  0]));
      dblock2 = _mm_loadu_si128((__m128i *) (&buffer[count + 16]));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock1,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock1,swap16b));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock2,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock2,swap16b));

      dblock1 = _mm_loadu_si128((__m128i *) (&buffer[count + 32]));
      dblock2 = _mm_loadu_si128((__m128i *) (&buffer[count + 48]));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock1,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock1,swap16b));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock2,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock2,swap16b));
    }
    //why are we not doing a 32 ?
    while ((count+16) <= length)
    {
      __m128i dblock;
      dblock= _mm_loadu_si128((__m128i *) (&buffer[count]));
      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock,swap16b));
      count+=16;
    }

    /*alignas(16) this can be unaligned as we most likely are accessing it unaligned anyays*/
    alignas(16) static const uint8_t shift_tab[48]={
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
    };
    /* we could extend this to fast convert 4 words to LE from BE */
    alignas(16) static const uint8_t swap32[16]{
        0x03,0x02,0x01,0x00,0x80,0x80,0x80,0x80,
        0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    };
    int rest=16-(length-count);
    //this over reads but who cares?!
    if (LIKELY(rest != 16))
    {
       __m128i dblock;
       dblock = _mm_loadu_si128((__m128i *)(&buffer[count]));
       //shifting the data up then down gives us leading zeroes clearing out any over read data
       //the shift up shuffles the data bytewise into place
       dblock = _mm_shuffle_epi8(dblock, _mm_loadu_si128((__m128i *)(&shift_tab[16 - rest])));
       dblock = _mm_shuffle_epi8(dblock, _mm_loadu_si128((__m128i *)(&shift_tab[16 + rest])));
       suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock,swap16a));
       sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock,swap16b));
    }

     suma = _mm_add_epi32(suma, sumb);
     //add 0 and 1 to 0 and 2 and 3 to 1
     suma = _mm_hadd_epi32(suma, _mm_setzero_si128());
     //add 0 and 1 to 1 ..
     suma = _mm_hadd_epi32(suma, _mm_setzero_si128());

     oldsum = _mm_shuffle_epi8(_mm_cvtsi32_si128(tsum), _mm_loadu_si128((__m128i *)&swap32[0]));
     suma = _mm_add_epi32(suma,oldsum); //adds the old csum to this
     //fix endianess

     //extract the 32 bit sum from vector
     uint32_t vsum;
     vsum=(uint32_t) _mm_cvtsi128_si32(suma);

    //printf("Vsum + swapped(tsum) %08x\n",vsum);
    //maybe this only works if tsum is byteswapped ?
    while (vsum >>16)
    {
      vsum=(vsum & 0xFFFF)+(vsum>>16);
    }
    //allways right in this case as its allways little endian x86
    return ~net::ntohs((uint16_t)(vsum));
#elif defined(__AVX2__)
  // VEX-align buffer
  while (((uintptr_t) buffer & 15) && length >= 4) {
    sum += *(uint32_t*) buffer;
    length -= 4; buffer += 4;
  }
  // run 4 32-bit adds in parallell
  union vec4 {
    __m256i  mm;
    int64_t  epi64[4];
  };
  vec4 vsum; vsum.mm = _mm256_set1_epi32(0);
  while (length >= 64)
  {
    __m128i tmp1 = _mm_load_si128((__m128i*) (buffer + 0));
    __m128i tmp2 = _mm_load_si128((__m128i*) (buffer + 16));
    __m128i tmp3 = _mm_load_si128((__m128i*) (buffer + 32));
    __m128i tmp4 = _mm_load_si128((__m128i*) (buffer + 48));

    // unpack 16x 32-bit values
    __m256i epi64_1 = _mm256_cvtepu32_epi64(tmp1);
    __m256i epi64_2 = _mm256_cvtepu32_epi64(tmp2);
    __m256i epi64_3 = _mm256_cvtepu32_epi64(tmp3);
    __m256i epi64_4 = _mm256_cvtepu32_epi64(tmp4);

    // sum 16x 32-bit values
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_1);
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_2);
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_3);
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_4);

    length -= 64; buffer += 64;
  }
  // horizontal add
  sum += vsum.epi64[0];
  sum += vsum.epi64[1];
  sum += vsum.epi64[2];
  sum += vsum.epi64[3];
#endif

  // unrolled 8 32-bit adds
  while (length >= 32)
  {
    auto* v = (uint32_t*) buffer;
    sum += v[0];
    sum += v[1];
    sum += v[2];
    sum += v[3];
    sum += v[4];
    sum += v[5];
    sum += v[6];
    sum += v[7];
    length -= 32; buffer += 32;
  }

  while (length >= 4)
  {
    auto v = *(uint32_t*) buffer;
    sum += v;
    length -= 4; buffer += 4;
  }
  if (length & 2)
  {
    auto v = *(uint16_t*) buffer;
    sum += v;
    buffer += 2;
  }
  if (length & 1)
  {
    auto v = *(uint8_t*) buffer;
    sum += v;
  }
  // fold to 32-bit
  uint32_t a32 = sum & 0xffffffff;
  uint32_t b32 = sum >> 32;
  a32 += b32;
  if (a32 < b32) a32++;
  // fold again to 16-bit
  uint16_t a16 = a32 & 0xffff;
  uint16_t b16 = a32 >> 16;
  a16 += b16;
  if (a16 < b16) a16++;
  // return 2s complement
  return ~a16;
}

// Taken from https://tools.ietf.org/html/rfc3022#page-9
void checksum_adjust(uint8_t* chksum, const void* odata,
   int olen, const void* ndata, int nlen)
{
  assert(olen % 2 == 0 and nlen % 2 == 0);

  const auto* optr = reinterpret_cast<const uint8_t*>(odata);
  const auto* nptr = reinterpret_cast<const uint8_t*>(ndata);

  int32_t x, o32, n32;
  x=chksum[0]*256+chksum[1];
  x=~x & 0xFFFF;
  while (olen)
  {
    o32=optr[0]*256+optr[1]; optr+=2;
    x-=o32 & 0xffff;
    if (x<=0) { x--; x&=0xffff; }
    olen-=2;
  }
  while (nlen)
  {
    n32=nptr[0]*256+nptr[1]; nptr+=2;
    x+=n32 & 0xffff;
    if (x & 0x10000) { x++; x&=0xffff; }
    nlen-=2;
  }
  x=~x & 0xFFFF;
  chksum[0]=x/256; chksum[1]=x & 0xff;
}

} //< namespace net
<commit_msg>net: remove wrong endif from new checksum.cpp<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <net/checksum.hpp>
#include <net/util.hpp>

#if defined(__AVX2__)
 #include <immintrin.h>
#elif defined(__SSSE3__)
 #include <tmmintrin.h>
#endif

#include <cassert>
#include <common>

namespace net {

uint16_t checksum(uint32_t tsum, const void* data, size_t length) noexcept
{
  const char* buffer = (const char*) data;
  int64_t sum = tsum;
  if (UNLIKELY(length == 0))
    return 0xffff;

  if (UNLIKELY(buffer == 0))
    return 0xffff;

#if defined(__SSSE3__)
    static __m128i swap16a = _mm_setr_epi16(0x0001, 0xffff, 0x0203, 0xffff,
                                         0x0405, 0xffff, 0x0607, 0xffff);
    static __m128i swap16b = _mm_setr_epi16(0x0809, 0xffff, 0x0a0b, 0xffff,
                      0x0c0d, 0xffff, 0x0e0f, 0xffff);
    size_t count;
    __m128i zero = _mm_setzero_si128();
    __m128i suma=zero;
    __m128i sumb=zero;
    __m128i oldsum;

    //according to godbolt its sligtly better to count index than incrementing pointer
    for(count = 0; (count+64) < length; count+=64)
    {
      __m128i dblock1,dblock2;
      dblock1 = _mm_loadu_si128((__m128i *) (&buffer[count +  0]));
      dblock2 = _mm_loadu_si128((__m128i *) (&buffer[count + 16]));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock1,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock1,swap16b));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock2,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock2,swap16b));

      dblock1 = _mm_loadu_si128((__m128i *) (&buffer[count + 32]));
      dblock2 = _mm_loadu_si128((__m128i *) (&buffer[count + 48]));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock1,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock1,swap16b));

      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock2,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock2,swap16b));
    }
    //why are we not doing a 32 ?
    while ((count+16) <= length)
    {
      __m128i dblock;
      dblock= _mm_loadu_si128((__m128i *) (&buffer[count]));
      suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock,swap16a));
      sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock,swap16b));
      count+=16;
    }

    /*alignas(16) this can be unaligned as we most likely are accessing it unaligned anyays*/
    alignas(16) static const uint8_t shift_tab[48]={
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
    };
    /* we could extend this to fast convert 4 words to LE from BE */
    alignas(16) static const uint8_t swap32[16]{
        0x03,0x02,0x01,0x00,0x80,0x80,0x80,0x80,
        0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
    };
    int rest=16-(length-count);
    //this over reads but who cares?!
    if (LIKELY(rest != 16))
    {
       __m128i dblock;
       dblock = _mm_loadu_si128((__m128i *)(&buffer[count]));
       //shifting the data up then down gives us leading zeroes clearing out any over read data
       //the shift up shuffles the data bytewise into place
       dblock = _mm_shuffle_epi8(dblock, _mm_loadu_si128((__m128i *)(&shift_tab[16 - rest])));
       dblock = _mm_shuffle_epi8(dblock, _mm_loadu_si128((__m128i *)(&shift_tab[16 + rest])));
       suma = _mm_add_epi32(suma,_mm_shuffle_epi8(dblock,swap16a));
       sumb = _mm_add_epi32(sumb,_mm_shuffle_epi8(dblock,swap16b));
    }

     suma = _mm_add_epi32(suma, sumb);
     //add 0 and 1 to 0 and 2 and 3 to 1
     suma = _mm_hadd_epi32(suma, _mm_setzero_si128());
     //add 0 and 1 to 1 ..
     suma = _mm_hadd_epi32(suma, _mm_setzero_si128());

     oldsum = _mm_shuffle_epi8(_mm_cvtsi32_si128(tsum), _mm_loadu_si128((__m128i *)&swap32[0]));
     suma = _mm_add_epi32(suma,oldsum); //adds the old csum to this
     //fix endianess

     //extract the 32 bit sum from vector
     uint32_t vsum;
     vsum=(uint32_t) _mm_cvtsi128_si32(suma);

    //printf("Vsum + swapped(tsum) %08x\n",vsum);
    //maybe this only works if tsum is byteswapped ?
    while (vsum >>16)
    {
      vsum=(vsum & 0xFFFF)+(vsum>>16);
    }
    //allways right in this case as its allways little endian x86
    return ~net::ntohs((uint16_t)(vsum));
#elif defined(__AVX2__)
  // VEX-align buffer
  while (((uintptr_t) buffer & 15) && length >= 4) {
    sum += *(uint32_t*) buffer;
    length -= 4; buffer += 4;
  }
  // run 4 32-bit adds in parallell
  union vec4 {
    __m256i  mm;
    int64_t  epi64[4];
  };
  vec4 vsum; vsum.mm = _mm256_set1_epi32(0);
  while (length >= 64)
  {
    __m128i tmp1 = _mm_load_si128((__m128i*) (buffer + 0));
    __m128i tmp2 = _mm_load_si128((__m128i*) (buffer + 16));
    __m128i tmp3 = _mm_load_si128((__m128i*) (buffer + 32));
    __m128i tmp4 = _mm_load_si128((__m128i*) (buffer + 48));

    // unpack 16x 32-bit values
    __m256i epi64_1 = _mm256_cvtepu32_epi64(tmp1);
    __m256i epi64_2 = _mm256_cvtepu32_epi64(tmp2);
    __m256i epi64_3 = _mm256_cvtepu32_epi64(tmp3);
    __m256i epi64_4 = _mm256_cvtepu32_epi64(tmp4);

    // sum 16x 32-bit values
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_1);
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_2);
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_3);
    vsum.mm = _mm256_add_epi64(vsum.mm, epi64_4);

    length -= 64; buffer += 64;
  }
  // horizontal add
  sum += vsum.epi64[0];
  sum += vsum.epi64[1];
  sum += vsum.epi64[2];
  sum += vsum.epi64[3];
#endif

  // unrolled 8 32-bit adds
  while (length >= 32)
  {
    auto* v = (uint32_t*) buffer;
    sum += v[0];
    sum += v[1];
    sum += v[2];
    sum += v[3];
    sum += v[4];
    sum += v[5];
    sum += v[6];
    sum += v[7];
    length -= 32; buffer += 32;
  }

  while (length >= 4)
  {
    auto v = *(uint32_t*) buffer;
    sum += v;
    length -= 4; buffer += 4;
  }
  if (length & 2)
  {
    auto v = *(uint16_t*) buffer;
    sum += v;
    buffer += 2;
  }
  if (length & 1)
  {
    auto v = *(uint8_t*) buffer;
    sum += v;
  }
  // fold to 32-bit
  uint32_t a32 = sum & 0xffffffff;
  uint32_t b32 = sum >> 32;
  a32 += b32;
  if (a32 < b32) a32++;
  // fold again to 16-bit
  uint16_t a16 = a32 & 0xffff;
  uint16_t b16 = a32 >> 16;
  a16 += b16;
  if (a16 < b16) a16++;
  // return 2s complement
  return ~a16;
}

// Taken from https://tools.ietf.org/html/rfc3022#page-9
void checksum_adjust(uint8_t* chksum, const void* odata,
   int olen, const void* ndata, int nlen)
{
  assert(olen % 2 == 0 and nlen % 2 == 0);

  const auto* optr = reinterpret_cast<const uint8_t*>(odata);
  const auto* nptr = reinterpret_cast<const uint8_t*>(ndata);

  int32_t x, o32, n32;
  x=chksum[0]*256+chksum[1];
  x=~x & 0xFFFF;
  while (olen)
  {
    o32=optr[0]*256+optr[1]; optr+=2;
    x-=o32 & 0xffff;
    if (x<=0) { x--; x&=0xffff; }
    olen-=2;
  }
  while (nlen)
  {
    n32=nptr[0]*256+nptr[1]; nptr+=2;
    x+=n32 & 0xffff;
    if (x & 0x10000) { x++; x&=0xffff; }
    nlen-=2;
  }
  x=~x & 0xFFFF;
  chksum[0]=x/256; chksum[1]=x & 0xff;
}

} //< namespace net
<|endoftext|>


<commit_before>#include "command.hh"
#include "shared.hh"
#include "store-api.hh"
#include "json.hh"
#include "common-args.hh"

#include <algorithm>
#include <array>

using namespace nix;

struct CmdPathInfo : StorePathsCommand, MixJSON
{
    bool showSize = false;
    bool showClosureSize = false;
    bool humanReadable = false;
    bool showSigs = false;

    CmdPathInfo()
    {
        mkFlag('s', "size", "print size of the NAR dump of each path", &showSize);
        mkFlag('S', "closure-size", "print sum size of the NAR dumps of the closure of each path", &showClosureSize);
        mkFlag('h', "human-readable", "with -s and -S, print sizes like 1K 234M 5.67G etc.", &humanReadable);
        mkFlag(0, "sigs", "show signatures", &showSigs);
    }

    std::string name() override
    {
        return "path-info";
    }

    std::string description() override
    {
        return "query information about store paths";
    }

    Examples examples() override
    {
        return {
            Example{
                "To show the closure sizes of every path in the current NixOS system closure, sorted by size:",
                "nix path-info -rS /run/current-system | sort -nk2"
            },
            Example{
                "To show a package's closure size and all its dependencies with human readable sizes:",
                "nix path-info -rsSh nixpkgs.rust"
            },
            Example{
                "To check the existence of a path in a binary cache:",
                "nix path-info -r /nix/store/7qvk5c91...-geeqie-1.1 --store https://cache.nixos.org/"
            },
            Example{
                "To print the 10 most recently added paths (using --json and the jq(1) command):",
                "nix path-info --json --all | jq -r 'sort_by(.registrationTime)[-11:-1][].path'"
            },
            Example{
                "To show the size of the entire Nix store:",
                "nix path-info --json --all | jq 'map(.narSize) | add'"
            },
            Example{
                "To show every path whose closure is bigger than 1 GB, sorted by closure size:",
                "nix path-info --json --all -S | jq 'map(select(.closureSize > 1e9)) | sort_by(.closureSize) | map([.path, .closureSize])'"
            },
        };
    }

    void printSize(unsigned long long value)
    {
        if (!humanReadable) {
            std::cout << fmt("\t%11d", value);
            return;
        }

        static const std::array<char, 9> idents{{
            ' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
        }};
        size_t power = 0;
        double res = value;
        while (res > 1024 && power < idents.size()) {
            ++power;
            res /= 1024;
        }
        std::cout << fmt("\t%6.1f%c", res, idents.at(power));
    }

    void run(ref<Store> store, Paths storePaths) override
    {
        size_t pathLen = 0;
        for (auto & storePath : storePaths)
            pathLen = std::max(pathLen, storePath.size());

        if (json) {
            JSONPlaceholder jsonRoot(std::cout);
            store->pathInfoToJSON(jsonRoot,
                // FIXME: preserve order?
                PathSet(storePaths.begin(), storePaths.end()),
                true, showClosureSize, AllowInvalid);
        }

        else {

            for (auto storePath : storePaths) {
                auto info = store->queryPathInfo(storePath);
                storePath = info->path; // FIXME: screws up padding

                std::cout << storePath << std::string(std::max(0, (int) pathLen - (int) storePath.size()), ' ');

                if (showSize)
                    printSize(info->narSize);

                if (showClosureSize)
                    printSize(store->getClosureSize(storePath).first);

                if (showSigs) {
                    std::cout << '\t';
                    Strings ss;
                    if (info->ultimate) ss.push_back("ultimate");
                    if (info->ca != "") ss.push_back("ca:" + info->ca);
                    for (auto & sig : info->sigs) ss.push_back(sig);
                    std::cout << concatStringsSep(" ", ss);
                }

                std::cout << std::endl;
            }

        }
    }
};

static RegisterCommand r1(make_ref<CmdPathInfo>());
<commit_msg>nix path-info: Remove trailing spaces<commit_after>#include "command.hh"
#include "shared.hh"
#include "store-api.hh"
#include "json.hh"
#include "common-args.hh"

#include <algorithm>
#include <array>

using namespace nix;

struct CmdPathInfo : StorePathsCommand, MixJSON
{
    bool showSize = false;
    bool showClosureSize = false;
    bool humanReadable = false;
    bool showSigs = false;

    CmdPathInfo()
    {
        mkFlag('s', "size", "print size of the NAR dump of each path", &showSize);
        mkFlag('S', "closure-size", "print sum size of the NAR dumps of the closure of each path", &showClosureSize);
        mkFlag('h', "human-readable", "with -s and -S, print sizes like 1K 234M 5.67G etc.", &humanReadable);
        mkFlag(0, "sigs", "show signatures", &showSigs);
    }

    std::string name() override
    {
        return "path-info";
    }

    std::string description() override
    {
        return "query information about store paths";
    }

    Examples examples() override
    {
        return {
            Example{
                "To show the closure sizes of every path in the current NixOS system closure, sorted by size:",
                "nix path-info -rS /run/current-system | sort -nk2"
            },
            Example{
                "To show a package's closure size and all its dependencies with human readable sizes:",
                "nix path-info -rsSh nixpkgs.rust"
            },
            Example{
                "To check the existence of a path in a binary cache:",
                "nix path-info -r /nix/store/7qvk5c91...-geeqie-1.1 --store https://cache.nixos.org/"
            },
            Example{
                "To print the 10 most recently added paths (using --json and the jq(1) command):",
                "nix path-info --json --all | jq -r 'sort_by(.registrationTime)[-11:-1][].path'"
            },
            Example{
                "To show the size of the entire Nix store:",
                "nix path-info --json --all | jq 'map(.narSize) | add'"
            },
            Example{
                "To show every path whose closure is bigger than 1 GB, sorted by closure size:",
                "nix path-info --json --all -S | jq 'map(select(.closureSize > 1e9)) | sort_by(.closureSize) | map([.path, .closureSize])'"
            },
        };
    }

    void printSize(unsigned long long value)
    {
        if (!humanReadable) {
            std::cout << fmt("\t%11d", value);
            return;
        }

        static const std::array<char, 9> idents{{
            ' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
        }};
        size_t power = 0;
        double res = value;
        while (res > 1024 && power < idents.size()) {
            ++power;
            res /= 1024;
        }
        std::cout << fmt("\t%6.1f%c", res, idents.at(power));
    }

    void run(ref<Store> store, Paths storePaths) override
    {
        size_t pathLen = 0;
        for (auto & storePath : storePaths)
            pathLen = std::max(pathLen, storePath.size());

        if (json) {
            JSONPlaceholder jsonRoot(std::cout);
            store->pathInfoToJSON(jsonRoot,
                // FIXME: preserve order?
                PathSet(storePaths.begin(), storePaths.end()),
                true, showClosureSize, AllowInvalid);
        }

        else {

            for (auto storePath : storePaths) {
                auto info = store->queryPathInfo(storePath);
                storePath = info->path; // FIXME: screws up padding

                std::cout << storePath;

                if (showSize || showClosureSize || showSigs)
                    std::cout << std::string(std::max(0, (int) pathLen - (int) storePath.size()), ' ');

                if (showSize)
                    printSize(info->narSize);

                if (showClosureSize)
                    printSize(store->getClosureSize(storePath).first);

                if (showSigs) {
                    std::cout << '\t';
                    Strings ss;
                    if (info->ultimate) ss.push_back("ultimate");
                    if (info->ca != "") ss.push_back("ca:" + info->ca);
                    for (auto & sig : info->sigs) ss.push_back(sig);
                    std::cout << concatStringsSep(" ", ss);
                }

                std::cout << std::endl;
            }

        }
    }
};

static RegisterCommand r1(make_ref<CmdPathInfo>());
<|endoftext|>


<commit_before>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

#include <ltdl.h>

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>
#include <libport/cstdlib>
#include <libport/format.hh>
#include <libport/program-name.hh>

#include <cerrno>
#include <memory>
#include <sstream>

#include <kernel/uconnection.hh>
#include <kernel/uobject.hh>
#include <kernel/userver.hh>

#include <object/code.hh>
#include <object/cxx-primitive.hh>
#include <object/dictionary.hh>
#include <object/float.hh>
#include <object/global.hh>
#include <object/list.hh>
#include <object/lobby.hh>
#include <object/path.hh>
#include <object/symbols.hh>
#include <object/system.hh>
#include <object/tag.hh>
#include <object/task.hh>
#include <parser/transform.hh>
#include <runner/at-handler.hh>
#include <runner/interpreter.hh>
#include <runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace object
{
  using kernel::urbiserver;

  static inline
  runner::Runner&
  runner()
  {
    return ::kernel::urbiserver->getCurrentRunner();
  }

  static inline
  runner::Interpreter&
  interpreter()
  {
    return dynamic_cast<runner::Interpreter&>(runner());
  }

  // Extract a filename from a String or a Path object
  static std::string
  filename_get(const rObject& o)
  {
    if (o.is_a<Path>())
      return o->as<Path>()->as_string();
    type_check<String>(o);
    return o->as<String>()->value_get();
  }

  rObject
  execute_parsed(parser::parse_result_type p,
                 libport::Symbol fun, std::string e)
  {
    runner::Interpreter& run = interpreter();

    // Report potential errors
    {
      ast::rNary errs = new ast::Nary();
      p->process_errors(*errs);
      run(errs.get());
    }

    ast::rConstAst ast = parser::transform(p->ast_get());
    if (!ast)
      RAISE(e);

    runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
    // So that it will resist to the call to yield_until_terminated,
    // and will be reclaimed at the end of the scope.
    sched::rJob job = sub;
    libport::Finally finally;
    runner().register_child(sub, finally);
    sub->start_job();
    try
    {
      run.yield_until_terminated(*job);
    }
    catch (const sched::ChildException& ce)
    {
      // Kill the sub-job and propagate.
      ce.rethrow_child_exception();
    }
    return sub->result_get();
  }

  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)               \
  static void                                   \
  system_ ## Function()                         \
  {                                             \
    urbiserver->Function();                     \
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static void
  system_sleep(const rObject&, libport::ufloat seconds)
  {
    runner::Runner& r = runner();
    if (seconds == std::numeric_limits<ufloat>::infinity())
      r.yield_until_terminated(r);
    else
      r.yield_until(r.scheduler_get().get_time()
                    + static_cast<libport::utime_t>(seconds * 1000000.0));
  }

  static float
  system_time()
  {
    return runner().scheduler_get().get_time() / 1000000.0;
  }

  static float
  system_shiftedTime()
  {
    runner::Runner& r = runner();
    return (r.scheduler_get().get_time() - r.time_shift_get()) / 1000000.0;
  }

  static void
  system_assert_(const rObject&,
                 const rObject& value, const std::string& assertion)
  {
    if (!is_true(value))
      RAISE("failed assertion: " + assertion);
  }

  static rObject
  system_eval(const rObject&, const std::string& code)
  {
    return execute_parsed(parser::parse(code, ast::loc()),
                          SYMBOL(eval),
                          "error executing command: " + code);
  }

  static void
  system_registerAtJob(const rObject&,
                       const rObject& condition,
                       const rObject& clause,
                       const rObject& on_leave)
  {
    runner::register_at_job(interpreter(),
			    condition, clause, on_leave);
  }

  static rObject
  system_scopeTag()
  {
    return new Tag(interpreter().scope_tag());
  }

  static rObject
  system_searchFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    try
    {
      return new Path(urbiserver->find_file(filename));
    }
    catch (libport::file_library::Not_found&)
    {
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static List::value_type
  system_searchPath()
  {
    List::value_type res;
    foreach (const libport::path& p, urbiserver->search_path.search_path_get())
      res.push_back(new Path(p));
    return res;
  }

  static rObject
  system_loadFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    if (!libport::path(filename).exists())
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
    return
      execute_parsed(parser::parse_file(filename),
                     SYMBOL(loadFile),
		     "error loading file: " + filename);
  }

  static rObject
  system_currentRunner()
  {
    return runner().as_task();
  }

  static float
  system_cycle()
  {
    return runner().scheduler_get().cycle_get();
  }

  static libport::Symbol
  system_fresh()
  {
    return libport::Symbol::fresh();
  }

  static rObject
  system_lobby()
  {
    return runner().lobby_get();
  }

  static void
  system_nonInterruptible()
  {
    runner().non_interruptible_set(true);
  }

  static void
  system_quit()
  {
    runner().lobby_get()->connection_get().close();
  }

  static void
  system_spawn(const rObject&,
	       const rCode& code,
               const rObject& clear_tags)
  {
    runner::Runner& r = runner();
    runner::Interpreter* new_runner =
      new runner::Interpreter(interpreter(),
                              rObject(code),
                              libport::Symbol::fresh(r.name_get()));

    if (is_true(clear_tags))
      new_runner->tag_stack_clear();

    new_runner->time_shift_set(r.time_shift_get());
    new_runner->start_job();
  }

  static rObject
  system_stats()
  {
    Dictionary::value_type res;
    const sched::scheduler_stats_type& stats =
      runner().scheduler_get().stats_get();

    // If statistics have just been reset, return "nil" since we cannot
    // return anything significant.
    if (stats.empty())
      return nil_class;

    // The space after "Symbol(" is mandatory to avoid triggering an error in
    // symbol generation code
#define ADDSTAT(Suffix, Function, Divisor)      \
    res[libport::Symbol("cycles" # Suffix)] =   \
      new Float(stats.Function() / Divisor)
    ADDSTAT(, size, 1);
    ADDSTAT(Max, max, 1e6);
    ADDSTAT(Mean, mean, 1e6);
    ADDSTAT(Min, min, 1e6);
    ADDSTAT(StdDev, standard_deviation, 1e6);
    ADDSTAT(Variance, variance, 1e3);
#undef ADDSTAT
    return new Dictionary(res);
  }

  static void
  system_resetStats()
  {
    runner().scheduler_get().stats_reset();
  }

  // This should give a backtrace as an urbi object.
  static void
  system_backtrace()
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    runner::Runner::backtrace_type bt = runner().backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      runner().send_message("backtrace", elt.first + " (" + elt.second + ")");
  }

  static List::value_type
  system_jobs()
  {
    List::value_type res;
    foreach(sched::rJob job, runner().scheduler_get().jobs_get())
      res.push_back(dynamic_cast<runner::Runner*>(job.get())->as_task());
    return res;
  }

  static int
  system_aliveJobs()
  {
    return sched::Job::alive_jobs();
  }

  static void
  system_breakpoint()
  {
    return;
  }

#define SERVER_SET_VAR(Function, Variable, Value)       \
  static void                                           \
  system_ ## Function ()                                \
  {                                                     \
    urbiserver->Variable = Value;                       \
  }

  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  static rObject
  system_getenv(const rObject&, const std::string& name)
  {
    char* res = getenv(name.c_str());
    return res ? new String(res) : nil_class;
  }

  static rObject
  system_setenv(const rObject&, const std::string& name, rObject value)
  {
    rString v = value->call(SYMBOL(asString))->as<String>();
    setenv(name.c_str(), v->value_get().c_str(), 1);
    return v;
  }

  static rObject
  system_unsetenv(const rObject&, const std::string& name)
  {
    rObject res = system_getenv(0, name);
    unsetenv(name.c_str());
    return res;
  }

  static libport::InstanceTracker<Lobby>::set_type
  system_lobbies()
  {
    return Lobby::instances_get();
  }

  static void
  system_loadModule(const rObject&, const std::string& name)
  {
    static bool initialized = false;

    if (!initialized)
    {
      initialized = true;
      lt_dlinit();
    }
    lt_dlhandle handle = lt_dlopenext(name.c_str());
    if (!handle)
      RAISE("Failed to open `" + name + "': " + lt_dlerror());

    // Reload uobjects
    uobjects_reload();

    // Reload CxxObjects
    CxxObject::create();
    CxxObject::initialize(global_class);
    CxxObject::cleanup();
  }

  static libport::cli_args_type urbi_arguments_;
  static boost::optional<std::string> urbi_program_name_;

  void
  system_push_argument(const std::string& arg)
  {
    urbi_arguments_.push_back(arg);
  }

  void
  system_set_program_name(const std::string& name)
  {
    urbi_program_name_ = name;
  }

  static const libport::cli_args_type&
  system_arguments()
  {
    return urbi_arguments_;
  }

  static boost::optional<std::string>
  system_programName()
  {
    return urbi_program_name_;
  }

  static void
  system__exit(const rObject&, int status)
  {
    exit(status);
  }

  static int
  system_system(const rObject&, const std::string& s)
  {
    int res = system(s.c_str());
    switch (res)
    {
    case -1:
      // FIXME: This is potentially widly used, see also path.cc.
      RAISE(libport::format("%1%: %2%", strerror(errno), s));
      break;
    case 127:
      RAISE(libport::format("shell failed: %1%", s));
      break;
    }
    return res;
  }

  void
  system_class_initialize()
  {
#define DECLARE(Name)                                                   \
    system_class->slot_set(SYMBOL(Name),                                \
                           make_primitive(&system_##Name))              \

    DECLARE(_exit);
    DECLARE(aliveJobs);
    DECLARE(arguments);
    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(breakpoint);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(getenv);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(loadModule);
    DECLARE(lobbies);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(programName);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(resetStats);
    DECLARE(scopeTag);
    DECLARE(searchFile);
    DECLARE(searchPath);
    DECLARE(setenv);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(spawn);
    DECLARE(stats);
    DECLARE(stopall);
    DECLARE(system);
    DECLARE(time);
    DECLARE(unsetenv);

#undef DECLARE
  }

} // namespace object
<commit_msg>Coding style changes.<commit_after>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

#include <ltdl.h>

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>
#include <libport/cstdlib>
#include <libport/format.hh>
#include <libport/program-name.hh>

#include <cerrno>
#include <memory>
#include <sstream>

#include <kernel/uconnection.hh>
#include <kernel/uobject.hh>
#include <kernel/userver.hh>

#include <object/code.hh>
#include <object/cxx-primitive.hh>
#include <object/dictionary.hh>
#include <object/float.hh>
#include <object/global.hh>
#include <object/list.hh>
#include <object/lobby.hh>
#include <object/path.hh>
#include <object/symbols.hh>
#include <object/system.hh>
#include <object/tag.hh>
#include <object/task.hh>
#include <parser/transform.hh>
#include <runner/at-handler.hh>
#include <runner/interpreter.hh>
#include <runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace object
{
  using kernel::urbiserver;

  static inline
  runner::Runner&
  runner()
  {
    return ::kernel::urbiserver->getCurrentRunner();
  }

  static inline
  runner::Interpreter&
  interpreter()
  {
    return dynamic_cast<runner::Interpreter&>(runner());
  }

  // Extract a filename from a String or a Path object
  static std::string
  filename_get(const rObject& o)
  {
    if (o.is_a<Path>())
      return o->as<Path>()->as_string();
    type_check<String>(o);
    return o->as<String>()->value_get();
  }

  rObject
  execute_parsed(parser::parse_result_type p,
                 libport::Symbol fun, std::string e)
  {
    runner::Interpreter& run = interpreter();

    // Report potential errors
    {
      ast::rNary errs = new ast::Nary();
      p->process_errors(*errs);
      run(errs.get());
    }

    ast::rConstAst ast = parser::transform(p->ast_get());
    if (!ast)
      RAISE(e);

    runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
    // So that it will resist to the call to yield_until_terminated,
    // and will be reclaimed at the end of the scope.
    sched::rJob job = sub;
    libport::Finally finally;
    runner().register_child(sub, finally);
    sub->start_job();
    try
    {
      run.yield_until_terminated(*job);
    }
    catch (const sched::ChildException& ce)
    {
      // Kill the sub-job and propagate.
      ce.rethrow_child_exception();
    }
    return sub->result_get();
  }

  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)               \
  static void                                   \
  system_ ## Function()                         \
  {                                             \
    urbiserver->Function();                     \
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static void
  system_sleep(const rObject&, libport::ufloat seconds)
  {
    runner::Runner& r = runner();
    if (seconds == std::numeric_limits<ufloat>::infinity())
      r.yield_until_terminated(r);
    else
      r.yield_until(r.scheduler_get().get_time()
                    + static_cast<libport::utime_t>(seconds * 1000000.0));
  }

  static float
  system_time()
  {
    return runner().scheduler_get().get_time() / 1000000.0;
  }

  static float
  system_shiftedTime()
  {
    runner::Runner& r = runner();
    return (r.scheduler_get().get_time() - r.time_shift_get()) / 1000000.0;
  }

  static void
  system_assert_(const rObject&,
                 const rObject& value, const std::string& assertion)
  {
    if (!is_true(value))
      RAISE("failed assertion: " + assertion);
  }

  static rObject
  system_eval(const rObject&, const std::string& code)
  {
    return execute_parsed(parser::parse(code, ast::loc()),
                          SYMBOL(eval),
                          "error executing command: " + code);
  }

  static void
  system_registerAtJob(const rObject&,
                       const rObject& condition,
                       const rObject& clause,
                       const rObject& on_leave)
  {
    runner::register_at_job(interpreter(),
			    condition, clause, on_leave);
  }

  static rObject
  system_scopeTag()
  {
    return new Tag(interpreter().scope_tag());
  }

  static rObject
  system_searchFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    try
    {
      return new Path(urbiserver->find_file(filename));
    }
    catch (libport::file_library::Not_found&)
    {
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static List::value_type
  system_searchPath()
  {
    List::value_type res;
    foreach (const libport::path& p, urbiserver->search_path.search_path_get())
      res.push_back(new Path(p));
    return res;
  }

  static rObject
  system_loadFile(const rObject&, const rObject& f)
  {
    const std::string& filename = filename_get(f);
    if (!libport::path(filename).exists())
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
    return
      execute_parsed(parser::parse_file(filename),
                     SYMBOL(loadFile),
		     "error loading file: " + filename);
  }

  static rObject
  system_currentRunner()
  {
    return runner().as_task();
  }

  static float
  system_cycle()
  {
    return runner().scheduler_get().cycle_get();
  }

  static libport::Symbol
  system_fresh()
  {
    return libport::Symbol::fresh();
  }

  static rObject
  system_lobby()
  {
    return runner().lobby_get();
  }

  static void
  system_nonInterruptible()
  {
    runner().non_interruptible_set(true);
  }

  static void
  system_quit()
  {
    runner().lobby_get()->connection_get().close();
  }

  static void
  system_spawn(const rObject&,
	       const rCode& code,
               const rObject& clear_tags)
  {
    runner::Runner& r = runner();
    runner::Interpreter* new_runner =
      new runner::Interpreter(interpreter(),
                              rObject(code),
                              libport::Symbol::fresh(r.name_get()));

    if (is_true(clear_tags))
      new_runner->tag_stack_clear();

    new_runner->time_shift_set(r.time_shift_get());
    new_runner->start_job();
  }

  static rObject
  system_stats()
  {
    const sched::scheduler_stats_type& stats =
      runner().scheduler_get().stats_get();

    // If statistics have just been reset, return "nil" since we cannot
    // return anything significant.
    if (stats.empty())
      return nil_class;

    // The space after "Symbol(" is mandatory to avoid triggering an error in
    // symbol generation code
    Dictionary::value_type res;
#define ADDSTAT(Suffix, Function, Divisor)      \
    res[libport::Symbol("cycles" # Suffix)] =   \
      new Float(stats.Function() / Divisor)
    ADDSTAT(, size, 1);
    ADDSTAT(Max, max, 1e6);
    ADDSTAT(Mean, mean, 1e6);
    ADDSTAT(Min, min, 1e6);
    ADDSTAT(StdDev, standard_deviation, 1e6);
    ADDSTAT(Variance, variance, 1e3);
#undef ADDSTAT
    return new Dictionary(res);
  }

  static void
  system_resetStats()
  {
    runner().scheduler_get().stats_reset();
  }

  // This should give a backtrace as an urbi object.
  static void
  system_backtrace()
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    runner::Runner::backtrace_type bt = runner().backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      runner().send_message("backtrace", elt.first + " (" + elt.second + ")");
  }

  static List::value_type
  system_jobs()
  {
    List::value_type res;
    foreach(sched::rJob job, runner().scheduler_get().jobs_get())
      res.push_back(dynamic_cast<runner::Runner*>(job.get())->as_task());
    return res;
  }

  static int
  system_aliveJobs()
  {
    return sched::Job::alive_jobs();
  }

  static void
  system_breakpoint()
  {
    return;
  }

#define SERVER_SET_VAR(Function, Variable, Value)       \
  static void                                           \
  system_ ## Function ()                                \
  {                                                     \
    urbiserver->Variable = Value;                       \
  }

  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  static rObject
  system_getenv(const rObject&, const std::string& name)
  {
    char* res = getenv(name.c_str());
    return res ? new String(res) : nil_class;
  }

  static rObject
  system_setenv(const rObject&, const std::string& name, rObject value)
  {
    rString v = value->call(SYMBOL(asString))->as<String>();
    setenv(name.c_str(), v->value_get().c_str(), 1);
    return v;
  }

  static rObject
  system_unsetenv(const rObject&, const std::string& name)
  {
    rObject res = system_getenv(0, name);
    unsetenv(name.c_str());
    return res;
  }

  static libport::InstanceTracker<Lobby>::set_type
  system_lobbies()
  {
    return Lobby::instances_get();
  }

  static void
  system_loadModule(const rObject&, const std::string& name)
  {
    static bool initialized = false;

    if (!initialized)
    {
      initialized = true;
      lt_dlinit();
    }
    lt_dlhandle handle = lt_dlopenext(name.c_str());
    if (!handle)
      RAISE("Failed to open `" + name + "': " + lt_dlerror());

    // Reload uobjects
    uobjects_reload();

    // Reload CxxObjects
    CxxObject::create();
    CxxObject::initialize(global_class);
    CxxObject::cleanup();
  }

  static libport::cli_args_type urbi_arguments_;
  static boost::optional<std::string> urbi_program_name_;

  void
  system_push_argument(const std::string& arg)
  {
    urbi_arguments_.push_back(arg);
  }

  void
  system_set_program_name(const std::string& name)
  {
    urbi_program_name_ = name;
  }

  static const libport::cli_args_type&
  system_arguments()
  {
    return urbi_arguments_;
  }

  static boost::optional<std::string>
  system_programName()
  {
    return urbi_program_name_;
  }

  static void
  system__exit(const rObject&, int status)
  {
    exit(status);
  }

  static int
  system_system(const rObject&, const std::string& s)
  {
    int res = system(s.c_str());
    switch (res)
    {
    case -1:
      // FIXME: This is potentially widly used, see also path.cc.
      RAISE(libport::format("%1%: %2%", strerror(errno), s));
      break;
    case 127:
      RAISE(libport::format("shell failed: %1%", s));
      break;
    }
    return res;
  }

  void
  system_class_initialize()
  {
#define DECLARE(Name)                                                   \
    system_class->slot_set(SYMBOL(Name),                                \
                           make_primitive(&system_##Name))              \

    DECLARE(_exit);
    DECLARE(aliveJobs);
    DECLARE(arguments);
    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(breakpoint);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(getenv);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(loadModule);
    DECLARE(lobbies);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(programName);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(resetStats);
    DECLARE(scopeTag);
    DECLARE(searchFile);
    DECLARE(searchPath);
    DECLARE(setenv);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(spawn);
    DECLARE(stats);
    DECLARE(stopall);
    DECLARE(system);
    DECLARE(time);
    DECLARE(unsetenv);

#undef DECLARE
  }

} // namespace object
<|endoftext|>


<commit_before>#include <cmath>

#include <osg/Matrix>
#include <osg/Point>
#include <osg/PointSprite>
#include <osg/Texture2D>
#include <osg/BlendFunc>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgGA/StateSetManipulator>
#include <osgParticle/ParticleSystemUpdater>
#include <osgParticle/ModularEmitter>
#include <osgParticle/ModularProgram>
#include <osgParticle/AccelOperator>
#include <osgParticle/RadialShooter>

#include "Ship.h"

//Define the filelocation of the ship's .obj file here
string ph::Ship::fileLocation = "../resources/cruiser.obj";

//Creating a Particlesystem at thegiven location
ParticleSystem* ph::Ship::createParticleSystem(Group* _parent) {
    ref_ptr<Group> parent = _parent;
    ref_ptr<ParticleSystem> ps = new ParticleSystem();
    ps->getDefaultParticleTemplate().setShape(Particle::POINT);

    ref_ptr<BlendFunc> blendFunc = new BlendFunc();
    blendFunc->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    //Setting the texture
    ref_ptr<Texture2D> texture = new Texture2D;
    texture->setImage( osgDB::readImageFile("../resources/particle.rgb") );

    //Rendering attributes
    ref_ptr<StateSet> ss = ps->getOrCreateStateSet();
    ss->setAttributeAndModes(blendFunc.get());
    ss->setTextureAttributeAndModes(0, texture.get());
    ref_ptr<Point> attribute = new Point(3.0f);
    ss->setAttribute(attribute);
    ref_ptr<PointSprite> sprite = new PointSprite;
    ss->setTextureAttributeAndModes(0, sprite);
    ss->setMode( GL_LIGHTING, StateAttribute::OFF);
    ss->setRenderingHint( StateSet::TRANSPARENT_BIN );

    //Create a RandomRateCounter so the amount of particles emmited varies
    ref_ptr<RandomRateCounter> rrc = new RandomRateCounter();
    rrc->setRateRange( 100, 500 );

    //Create a ParticleShooter that sets the proper vector in the particles
    ref_ptr<RadialShooter> myshooter = new RadialShooter();
    myshooter->setThetaRange(-1.7,-1.4); // Neigung z-x-ebene gegen UZS
    myshooter->setPhiRange(-0.2,0.2); //Neigung x-y-ebene gegen UZS
    myshooter->setInitialSpeedRange(5,15); //Geschwindigkeit

    //Create an Emmiter, which is a container for the Shooter, the Counter and the Particlesystem
    ref_ptr<ModularEmitter> emitter = new ModularEmitter();
    emitter->setParticleSystem( ps.get() );
    emitter->setCounter( rrc.get() );
    emitter->setShooter(myshooter.get());

    //Create another container, which contains the Emmitter and Updateallbacks
    ref_ptr<ModularProgram> program = new ModularProgram();
    program->setParticleSystem( ps.get() );

    //Adding the Particlesystem to a Geode so it will be drawn
    ref_ptr<Geode> geode = new Geode();
    geode->addDrawable( ps.get() );

    parent->addChild( emitter.get() );
    parent->addChild( program.get() );
    parent->addChild( geode.get() );
    return ps.release();
}

ph::Ship::Ship() {

    //Set the transformations up for animation
    rotate = new MatrixTransform();
    rotate->setMatrix(Matrix::rotate(0,Vec3d(0,0,0)));
    translate = new MatrixTransform();
    translate->setMatrix(Matrix::translate(Vec3d(0,0,0)));

    translate->addChild(rotate.get());

    //Loading the model of the ship + adding it as a Child
    rotate->addChild(osgDB::readNodeFile(fileLocation));

    //Moving the origin of particles
    ref_ptr<MatrixTransform> mt = new MatrixTransform();
    mt->setMatrix( Matrix::translate(-1.5f, 0.0f, 0.0f) );

    //Creating the particlesystem at the point defined above
    ref_ptr<ParticleSystem> ps = createParticleSystem(mt.get());
    ref_ptr<ParticleSystemUpdater> updater = new ParticleSystemUpdater();
    updater->addParticleSystem(ps);

    //Adding particlesystem and updater to ship's node
    rotate->addChild(updater.get());
    rotate->addChild(mt.get());

    this->addChild(translate.get());

    //Setting up the Camera
    camera = new Camera;

    // Setup animation callback
    callback = new ShipNodeCallback;
    //this->setUpdateCallback(callback.get());

}

// void ph::Ship::Ship::addNode(Node* node) {
    // rotate->addChild(node);
// }
<commit_msg>Removing a debug-setting in ship. Don't know why it's even up<commit_after>#include <cmath>

#include <osg/Matrix>
#include <osg/Point>
#include <osg/PointSprite>
#include <osg/Texture2D>
#include <osg/BlendFunc>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgGA/StateSetManipulator>
#include <osgParticle/ParticleSystemUpdater>
#include <osgParticle/ModularEmitter>
#include <osgParticle/ModularProgram>
#include <osgParticle/AccelOperator>
#include <osgParticle/RadialShooter>

#include "Ship.h"

//Define the filelocation of the ship's .obj file here
string ph::Ship::fileLocation = "../resources/cruiser.obj";

//Creating a Particlesystem at thegiven location
ParticleSystem* ph::Ship::createParticleSystem(Group* _parent) {
    ref_ptr<Group> parent = _parent;
    ref_ptr<ParticleSystem> ps = new ParticleSystem();
    ps->getDefaultParticleTemplate().setShape(Particle::POINT);

    ref_ptr<BlendFunc> blendFunc = new BlendFunc();
    blendFunc->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    //Setting the texture
    ref_ptr<Texture2D> texture = new Texture2D;
    texture->setImage( osgDB::readImageFile("../resources/particle.rgb") );

    //Rendering attributes
    ref_ptr<StateSet> ss = ps->getOrCreateStateSet();
    ss->setAttributeAndModes(blendFunc.get());
    ss->setTextureAttributeAndModes(0, texture.get());
    ref_ptr<Point> attribute = new Point(3.0f);
    ss->setAttribute(attribute);
    ref_ptr<PointSprite> sprite = new PointSprite;
    ss->setTextureAttributeAndModes(0, sprite);
    ss->setMode( GL_LIGHTING, StateAttribute::OFF);
    ss->setRenderingHint( StateSet::TRANSPARENT_BIN );

    //Create a RandomRateCounter so the amount of particles emmited varies
    ref_ptr<RandomRateCounter> rrc = new RandomRateCounter();
    rrc->setRateRange( 100, 500 );

    //Create a ParticleShooter that sets the proper vector in the particles
    ref_ptr<RadialShooter> myshooter = new RadialShooter();
    myshooter->setThetaRange(-1.7,-1.4); // Neigung z-x-ebene gegen UZS
    myshooter->setPhiRange(-0.2,0.2); //Neigung x-y-ebene gegen UZS
    myshooter->setInitialSpeedRange(5,15); //Geschwindigkeit

    //Create an Emmiter, which is a container for the Shooter, the Counter and the Particlesystem
    ref_ptr<ModularEmitter> emitter = new ModularEmitter();
    emitter->setParticleSystem( ps.get() );
    emitter->setCounter( rrc.get() );
    emitter->setShooter(myshooter.get());

    //Create another container, which contains the Emmitter and Updateallbacks
    ref_ptr<ModularProgram> program = new ModularProgram();
    program->setParticleSystem( ps.get() );

    //Adding the Particlesystem to a Geode so it will be drawn
    ref_ptr<Geode> geode = new Geode();
    geode->addDrawable( ps.get() );

    parent->addChild( emitter.get() );
    parent->addChild( program.get() );
    parent->addChild( geode.get() );
    return ps.release();
}

ph::Ship::Ship() {

    //Set the transformations up for animation
    rotate = new MatrixTransform();
    rotate->setMatrix(Matrix::rotate(0,Vec3d(0,0,0)));
    translate = new MatrixTransform();
    translate->setMatrix(Matrix::translate(Vec3d(0,0,0)));

    translate->addChild(rotate.get());

    //Loading the model of the ship + adding it as a Child
    rotate->addChild(osgDB::readNodeFile(fileLocation));

    //Moving the origin of particles
    ref_ptr<MatrixTransform> mt = new MatrixTransform();
    mt->setMatrix( Matrix::translate(-1.5f, 0.0f, 0.0f) );

    //Creating the particlesystem at the point defined above
    ref_ptr<ParticleSystem> ps = createParticleSystem(mt.get());
    ref_ptr<ParticleSystemUpdater> updater = new ParticleSystemUpdater();
    updater->addParticleSystem(ps);

    //Adding particlesystem and updater to ship's node
    rotate->addChild(updater.get());
    rotate->addChild(mt.get());

    this->addChild(translate.get());

    //Setting up the Camera
    camera = new Camera;

    // Setup animation callback
    callback = new ShipNodeCallback;
    this->setUpdateCallback(callback.get());

}

// void ph::Ship::Ship::addNode(Node* node) {
    // rotate->addChild(node);
// }
<|endoftext|>


<commit_before>/* BZWorkbench
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "objects/zone.h"

#include <osg/PolygonMode>

// constructor
zone::zone() : bz2object("zone", "<name><position><size><rotation><team><flag><safety><zoneflag>") {
	setDefaults();
}

void zone::setDefaults() {
	updateGeometry();

	teams = vector<int>();
	safety = vector<int>();
	setSize( osg::Vec3( 10, 10, 10 ) );
}

// getter
string zone::get(void) { return toString(); }

int zone::update( UpdateMessage& message ) {
	switch( message.type ) {
		case UpdateMessage::SET_POSITION: 	// handle a new position
			setPos( *(message.getAsPosition()) );
			break;

		case UpdateMessage::SET_POSITION_FACTOR:	// handle a translation
			setPos( getPos() + *(message.getAsPositionFactor()) );
			break;

		case UpdateMessage::SET_ROTATION:		// handle a new rotation
			setRotationZ( message.getAsRotation()->z() );
			break;

		case UpdateMessage::SET_ROTATION_FACTOR:	// handle an angular translation
			setRotationZ( getRotation().z() + message.getAsRotationFactor()->z() );
			break;

		case UpdateMessage::SET_SCALE:		// handle a new scale
			setSize( *(message.getAsScale()) );
			break;

		case UpdateMessage::SET_SCALE_FACTOR:	// handle a scaling factor
			setSize( getSize() + *(message.getAsScaleFactor()) );
			break;

		default:	// unknown event; don't handle
			return 0;
	}

	return 1;
}

// bzw methods
bool zone::parse( std::string& line ) {
	// check if we reached the end of the section
	if ( line == "end" )
		return false;

	string key = BZWParser::key( line.c_str() );
	string value = BZWParser::value( key.c_str(), line.c_str() );

	// parse keys
	if ( key == "team" ) {
		vector<string> teamElements = BZWParser::getLineElements( value.c_str() );

		// candidate teams
		vector<int> teamCandidates = vector<int>();

		// determine whether or not the given teams are valid (throw a error if invalid)
		for(vector<string>::iterator i = teamElements.begin(); i != teamElements.end(); i++) {
			int teamNumber = atoi( i->c_str() );
			if(teamNumber < 0 || teamNumber > 4) {
				throw BZWReadError( this, string( "Undefined team, " ) + value);
			}
			teamCandidates.push_back(teamNumber);
		}

		teams = teamCandidates;
	}
	else if ( key == "safety" ) {
		vector<string> safetyElements = BZWParser::getLineElements( value.c_str() );

		// candidate safeties
		vector<int> safetyCandidates = vector<int>();

		// determine whether or not the given safety values are valid (throw a warning if not)
		if(safetyElements.size() > 0) {
			for(vector<string>::iterator i = safetyElements.begin(); i != safetyElements.end(); i++) {
				int teamNumber = atoi( i->c_str() );
				if(teamNumber < 0 || teamNumber > 4) {
					throw BZWReadError( this, string( "Undefined safety, " ) + value );
				}
				safetyCandidates.push_back(teamNumber);
			}
		}

		safety = safetyCandidates;
	}
	else if ( key == "flag" ) {
		vector<string> flagElements = BZWParser::getLineElements(value.c_str());

		// determine whether or not the given flags are valid (throw a error if its invalid)
		for(vector<string>::iterator i = flagElements.begin(); i != flagElements.end(); i++) {
			if(	! (Flag::isFlag( i->c_str() )  || (*i) == "good" || (*i) == "bad") ) {
				throw BZWReadError( this, string( "Unrecognized flag type, " ) + *i);
			}
		}

		flags = flagElements;
	}
	else if ( key == "zoneflag" ) {
		vector<string> elems = BZWParser::getLineElements( value.c_str() );

		// there should be only two elements, a flag and a quantity
		if ( elems.size() != 2 )
			throw BZWReadError( this, string( "Invalid zoneflag, " ) + value );

		// read the flag
		string flag = TextUtils::toupper( elems[0] );
		// see if its valid
		if( !Flag::isFlag( flag.c_str() ) )
			throw BZWReadError( this, string( "Unrecognized flag type, " ) + flag );

		// try to read the quantity
		int num = atoi( elems[1].c_str() );

		// num will be zero if atoi() failed...
		if(num == 0)
			throw BZWReadError( this, string( "Unrecognized flag quantity, " ) + elems[1] );

		zoneflags.push_back( FlagElement( flag, num ) );
	}
	else {
		return bz2object::parse( line );
	}

	return true;
}

void zone::finalize() {

}

// toString
string zone::toString(void) {
	// string-ify the teams, safeties, zoneflags, and flags
	string teamString = string("");
	string safetyString = string("");
	string zoneflagString = string("");
	string flagString = string("");

	// make the "safety" string
	if(safety.size() > 0) {
		for(vector<int>::iterator index = safety.begin(); index != safety.end(); index++) {
			safetyString += string(itoa(*index)) + " ";
		}
		safetyString += "\n";
	}

	if(teams.size() > 0) {
		// make the "team" string
		for(vector<int>::iterator index = teams.begin(); index != teams.end(); index++) {
			teamString += string(itoa(*index)) + " ";
		}
		teamString += "\n";
	}

	if(flags.size() > 0) {
		// make the "flag" string
		for(vector<string>::iterator index = flags.begin(); index != flags.end(); index++) {
			flagString += (*index) + " ";
		}
		flagString += "\n";
	}

	if(zoneflags.size() > 0) {
		// make the "zoneflag" strings
		for(vector<FlagElement>::iterator index = zoneflags.begin(); index != zoneflags.end(); index++) {
			zoneflagString += "  zoneflag " + index->toString() + "\n";
		}
	}

	return string("zone\n") +
				  BZWLines( this ) +
				  (safetyString.length() == 0 ? "# safety\n" : "  safety " + safetyString) +
				  (teamString.length() == 0 ? "# team\n" : "  team " + teamString) +
				  (flagString.length() == 0 ? "# flag\n" : "  flag " + flagString) +
				  (zoneflagString.length() == 0 ? "# zoneflag\n" : zoneflagString) +
				  "end\n";
}

// render
int zone::render(void) {
	return 0;
}

void zone::updateGeometry() {
	// create unit box
	osg::ref_ptr< osg::Geode > boxGeode = new osg::Geode();
	osg::ref_ptr< osg::Box > box = new osg::Box( osg::Vec3( 0, 0, 0.5f ), 2, 2, 1 );
	osg::ref_ptr< osg::ShapeDrawable > boxDrawable = new osg::ShapeDrawable( box.get() );
	boxGeode->addDrawable( boxDrawable.get() );

	// make material
	boxDrawable->setColor( osg::Vec4( 0, 0, 1, 1 ) );
	osg::ref_ptr< osg::StateSet > stateset = boxDrawable->getOrCreateStateSet();
	osg::ref_ptr< osg::PolygonMode > polyMode = new osg::PolygonMode();
	polyMode->setMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
	stateset->setAttribute( polyMode.get(), osg::StateAttribute::ON);

	setThisNode( boxGeode.get() );
}
<commit_msg>- fixes zone color bug.<commit_after>/* BZWorkbench
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "objects/zone.h"

#include <osg/PolygonMode>

// constructor
zone::zone() : bz2object("zone", "<name><position><size><rotation><team><flag><safety><zoneflag>") {
	setDefaults();
}

void zone::setDefaults() {
	updateGeometry();

	teams = vector<int>();
	safety = vector<int>();
	setSize( osg::Vec3( 10, 10, 10 ) );
}

// getter
string zone::get(void) { return toString(); }

int zone::update( UpdateMessage& message ) {
	switch( message.type ) {
		case UpdateMessage::SET_POSITION: 	// handle a new position
			setPos( *(message.getAsPosition()) );
			break;

		case UpdateMessage::SET_POSITION_FACTOR:	// handle a translation
			setPos( getPos() + *(message.getAsPositionFactor()) );
			break;

		case UpdateMessage::SET_ROTATION:		// handle a new rotation
			setRotationZ( message.getAsRotation()->z() );
			break;

		case UpdateMessage::SET_ROTATION_FACTOR:	// handle an angular translation
			setRotationZ( getRotation().z() + message.getAsRotationFactor()->z() );
			break;

		case UpdateMessage::SET_SCALE:		// handle a new scale
			setSize( *(message.getAsScale()) );
			break;

		case UpdateMessage::SET_SCALE_FACTOR:	// handle a scaling factor
			setSize( getSize() + *(message.getAsScaleFactor()) );
			break;

		default:	// unknown event; don't handle
			return 0;
	}

	return 1;
}

// bzw methods
bool zone::parse( std::string& line ) {
	// check if we reached the end of the section
	if ( line == "end" )
		return false;

	string key = BZWParser::key( line.c_str() );
	string value = BZWParser::value( key.c_str(), line.c_str() );

	// parse keys
	if ( key == "team" ) {
		vector<string> teamElements = BZWParser::getLineElements( value.c_str() );

		// candidate teams
		vector<int> teamCandidates = vector<int>();

		// determine whether or not the given teams are valid (throw a error if invalid)
		for(vector<string>::iterator i = teamElements.begin(); i != teamElements.end(); i++) {
			int teamNumber = atoi( i->c_str() );
			if(teamNumber < 0 || teamNumber > 4) {
				throw BZWReadError( this, string( "Undefined team, " ) + value);
			}
			teamCandidates.push_back(teamNumber);
		}

		teams = teamCandidates;
	}
	else if ( key == "safety" ) {
		vector<string> safetyElements = BZWParser::getLineElements( value.c_str() );

		// candidate safeties
		vector<int> safetyCandidates = vector<int>();

		// determine whether or not the given safety values are valid (throw a warning if not)
		if(safetyElements.size() > 0) {
			for(vector<string>::iterator i = safetyElements.begin(); i != safetyElements.end(); i++) {
				int teamNumber = atoi( i->c_str() );
				if(teamNumber < 0 || teamNumber > 4) {
					throw BZWReadError( this, string( "Undefined safety, " ) + value );
				}
				safetyCandidates.push_back(teamNumber);
			}
		}

		safety = safetyCandidates;
	}
	else if ( key == "flag" ) {
		vector<string> flagElements = BZWParser::getLineElements(value.c_str());

		// determine whether or not the given flags are valid (throw a error if its invalid)
		for(vector<string>::iterator i = flagElements.begin(); i != flagElements.end(); i++) {
			if(	! (Flag::isFlag( i->c_str() )  || (*i) == "good" || (*i) == "bad") ) {
				throw BZWReadError( this, string( "Unrecognized flag type, " ) + *i);
			}
		}

		flags = flagElements;
	}
	else if ( key == "zoneflag" ) {
		vector<string> elems = BZWParser::getLineElements( value.c_str() );

		// there should be only two elements, a flag and a quantity
		if ( elems.size() != 2 )
			throw BZWReadError( this, string( "Invalid zoneflag, " ) + value );

		// read the flag
		string flag = TextUtils::toupper( elems[0] );
		// see if its valid
		if( !Flag::isFlag( flag.c_str() ) )
			throw BZWReadError( this, string( "Unrecognized flag type, " ) + flag );

		// try to read the quantity
		int num = atoi( elems[1].c_str() );

		// num will be zero if atoi() failed...
		if(num == 0)
			throw BZWReadError( this, string( "Unrecognized flag quantity, " ) + elems[1] );

		zoneflags.push_back( FlagElement( flag, num ) );
	}
	else {
		return bz2object::parse( line );
	}

	return true;
}

void zone::finalize() {

}

// toString
string zone::toString(void) {
	// string-ify the teams, safeties, zoneflags, and flags
	string teamString = string("");
	string safetyString = string("");
	string zoneflagString = string("");
	string flagString = string("");

	// make the "safety" string
	if(safety.size() > 0) {
		for(vector<int>::iterator index = safety.begin(); index != safety.end(); index++) {
			safetyString += string(itoa(*index)) + " ";
		}
		safetyString += "\n";
	}

	if(teams.size() > 0) {
		// make the "team" string
		for(vector<int>::iterator index = teams.begin(); index != teams.end(); index++) {
			teamString += string(itoa(*index)) + " ";
		}
		teamString += "\n";
	}

	if(flags.size() > 0) {
		// make the "flag" string
		for(vector<string>::iterator index = flags.begin(); index != flags.end(); index++) {
			flagString += (*index) + " ";
		}
		flagString += "\n";
	}

	if(zoneflags.size() > 0) {
		// make the "zoneflag" strings
		for(vector<FlagElement>::iterator index = zoneflags.begin(); index != zoneflags.end(); index++) {
			zoneflagString += "  zoneflag " + index->toString() + "\n";
		}
	}

	return string("zone\n") +
				  BZWLines( this ) +
				  (safetyString.length() == 0 ? "# safety\n" : "  safety " + safetyString) +
				  (teamString.length() == 0 ? "# team\n" : "  team " + teamString) +
				  (flagString.length() == 0 ? "# flag\n" : "  flag " + flagString) +
				  (zoneflagString.length() == 0 ? "# zoneflag\n" : zoneflagString) +
				  "end\n";
}

// render
int zone::render(void) {
	return 0;
}

void zone::updateGeometry() {
	// create unit box
	osg::ref_ptr< osg::Geode > boxGeode = new osg::Geode();
	osg::ref_ptr< osg::Box > box = new osg::Box( osg::Vec3( 0, 0, 0.5f ), 2, 2, 1 );
	osg::ref_ptr< osg::ShapeDrawable > boxDrawable = new osg::ShapeDrawable( box.get() );
	boxGeode->addDrawable( boxDrawable.get() );

	// assign material
	SceneBuilder::assignMaterial( osg::Vec4f( 0.0, 0.0, 1.0, 1.0 ),
								 osg::Vec4f( 0.0, 0.0, 0.0, 1.0 ),
								 osg::Vec4f( 0.0, 0.0, 0.0, 0.0 ),
								 osg::Vec4f( 0.0, 0.0, 0.0, 0.0 ),
								 0.0f,
								 1.0f,
								 boxGeode.get() );

	osg::ref_ptr< osg::StateSet > stateset = boxDrawable->getOrCreateStateSet();
	osg::ref_ptr< osg::PolygonMode > polyMode = new osg::PolygonMode();
	polyMode->setMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
	stateset->setAttribute( polyMode.get(), osg::StateAttribute::ON);

	setThisNode( boxGeode.get() );
}
<|endoftext|>