<commit_before>//
// a21 — Arduino Toolkit.
// Copyright (C) 2016-2017, Aleh Dzenisiuk. http://github.com/aleh/a21
//

#pragma once

#include <Arduino.h>

#include <a21/pcd8544fonts.hpp>
#include <a21/spi.hpp>

namespace a21 {

/**
 * Basic wrapper for a PCD8544 LCD display (such as the one that was used on Nokia 5110).
 */
template<typename pinRST, typename pinCE, typename pinDC, typename pinDIN, typename pinCLK, uint32_t maxFrequency = 4000000L>
class PCD8544 {

private:

  typedef SPI<pinDIN, pinCLK, pinCE, maxFrequency> spi;

  enum ValueType : uint8_t {
    Command,
    Data
  };

  static void write(ValueType valueType, uint8_t value) {
    pinDC::write(valueType == Data);
    spi::write(value);
  }

  static void beginWriting() {
    spi::beginWriting();
  }

  static void endWriting() {
    spi::endWriting();
  }

  enum FunctionSetCommand : uint8_t {
    FunctionSet = 0x20,
    /** 0 - basic command set, 1 - extended command set. */
    H = 1,
    /** 0 - horizontal addressing mode, 1 - vertical addressing mode. */
    V = 2,
    /** 0 - chip active, 1 - chip in power down mode. */
    PD = 4
  };

  enum DisplayControlCommand : uint8_t {
    DisplayControl = 0x08,
    D = 0x04,
    E = 0x01,
    DisplayBlank = (uint8_t)(~(D | E)),
    NormalMode = (uint8_t)(D & ~E),
    AllSegmentsOn = (uint8_t)(~D & E),
    InverseVideoMode = (uint8_t)(D | E)
  };

  enum SetXAddressCommand : uint8_t {
    SetXAddress = 0x80,
    SetXAddressMask = 0x7F
  };

  enum SetYAddressCommand : uint8_t {
    SetYAddress = 0x40,
    SetYAddressMask = 0x07
  };

  enum TemperatureControlExtendedCommand : uint8_t {
    TemperatureControl = 0x04,
    TemperatureControlMask = 0x3
  };

  enum BiasSystemExtendedCommand : uint8_t {
    BiasSystem = 0x10,
    BiasSystemMask = 0x07
  };

  enum SetVopExtendedCommand : uint8_t {
    SetVop = 0x80,
    SetVopMask = 0x7F
  };

  static inline void extendedCommandSet(bool extended) {
    write(
      Command,
      extended ? (FunctionSet | H) & ~(PD | V)
        : (FunctionSet | 0) & ~(PD | V | H)
    );
  }

  static inline void setAddressInternal(uint8_t col, uint8_t row) {
    extendedCommandSet(false);
    write(Command, SetXAddress | col);
    write(Command, SetYAddress | row);
  }

  static inline void config(uint8_t operatingVoltage, uint8_t biasSystem, uint8_t temperatureControl) {

    beginWriting();

    // Not making the display mode a parameter here as those don't seem to be useful.
    extendedCommandSet(false);
    write(Command, DisplayControl | NormalMode);

    extendedCommandSet(true);
    write(Command, SetVop | (operatingVoltage & SetVopMask));
    write(Command, BiasSystem | (biasSystem & BiasSystemMask));
    write(Command, TemperatureControl | (temperatureControl & TemperatureControlMask));

    endWriting();
  }

public:

  /** Number of addressable rows, with every row corresponding to 8 horizontal lines of actual pixels. */
  static const int Rows = 6;

  /** Number of addressable columns, though unlike rows every column corresponds to 1 vertical line of pixels. */
  static const int Cols = 84;

  /** Maximum value for the parameter of operatingVoltage function, though the actual usable values are usually much smaller. */
  static const uint8_t MaxVoltage = 0x7F;

  /** Sets operational voltage affecting the contrast of the display. */
  static void operatingVoltage(uint8_t value) {
    beginWriting();
    extendedCommandSet(true);
    write(Command, SetVop | value);
    endWriting();
  }

  /** Clears the display. */
  static void clear() {
    beginWriting();
    setAddressInternal(0, 0);
    for (int i = 0; i < Rows * Cols; i++) {
      write(Data, 0);
    }
    endWriting();
  }

  /** Initializes the display. */
  static void begin(uint8_t operatingVoltage = 52, uint8_t biasSystem = 4, uint8_t temperatureControl = 2) {

    spi::begin();

    pinDC::setOutput();
    pinDC::setLow();

    pinRST::setOutput();
    pinRST::setLow();

    // TODO: add delay template instead
    delayMicroseconds(1000000.0 / maxFrequency);

    pinRST::setHigh();

    config(operatingVoltage, biasSystem, temperatureControl);

    clear();
  }

  /**
   * Transports a bunch of bytes for the given row. The layout directly corresponds with the memory layout of the LCD,
   * where each byte is responsible for a 8 pixel column within the row (MSB is in the bottom of the row,
   * LSB is in the top).
   *
   * The row is filled from left to right (i.e. column address is automatically incremented).
   *                    col      col + 1
   *  line row * 8:     # bit 0  # bit 0  ...
   *  line row * 8 + 1: # bit 1  # bit 1  ...
   *     ...
   *  line row * 8 + 7: # bit 7  # bit 7  ...
   *                    ^        ^
   *                    byte 0   byte 1
   *
   * Note that if more bytes are provided than is left in the row, then they'll be written to the next one
   * (or the first one in case of the last row).
   */
  static void writeRow(uint8_t col, uint8_t row, const uint8_t *data, uint8_t data_length) {
    beginWriting();
    setAddressInternal(col, row);
    const uint8_t *src = data;
    for (uint8_t c = data_length; c > 0; c--) {
      write(Data, *src++);
    }
    endWriting();
  }

  /**
   * Similar to writeRow, but the same byte is sent `length` times.
   */
  static void fillRow(uint8_t col, uint8_t row, uint8_t filler, uint8_t length) {
    beginWriting();
    setAddressInternal(col, row);
    for (uint8_t c = length; c > 0; c--) {
      write(Data, filler);
    }
    endWriting();
  }

  //
  // Support for simple 8px high fonts fitting rows of the display exactly
  //

  /**
   * Returns the width of the glyph corresponding to a character in the given font and, if a buffer is provided,
   * copies glyph's bitmap bytes into it.
   */
  static uint8_t dataForCharacter(PCD8544Font font, char ch, uint8_t *buffer) {

    const uint8_t *p = font;

    uint8_t options = pgm_read_byte(p++);
    if ((options & 1) && 'a' <= ch && ch <= 'z') {
      ch = ch - 'a' + 'A';
    }

    while (true) {

      // First character in the range (0 would mean no more ranges are defined).
      uint8_t first = pgm_read_byte(p++);
      if (first == 0)
        break;

      // Last character in the range.
      uint8_t last = pgm_read_byte(p++);

      // Number of bytes every character in the range occupies.
      uint8_t bytes_per_character = pgm_read_byte(p++);

      if (first <= ch && ch <= last) {

        // Our character is in the range, let's copy the data for it.

        p += (ch - first) * bytes_per_character;
        // The first byte of the glyph data is the actual width of the glyph.
        uint8_t width = pgm_read_byte(p++);
        // Copy the bitmap if the caller expects it.
        if (buffer) {
          memcpy_PF(buffer, (uint_farptr_t)p, width);
        }

        return width;
      }

      // Well, let's skip to the next range of characters.
      p += (last + 1 - first) * bytes_per_character;
    }

    // Let's return data for sort of a default character.
    return dataForCharacter(font, '?', buffer);
  }

  /** The width of the string drawn with the given font. */
  static uint8_t textWidth(PCD8544Font font, const char *text) {

    char ch;
    const char *src = text;
    uint8_t result = 0;
    while ((ch = *src++)) {
        uint8_t width = dataForCharacter(font, ch, NULL);
        result += width + 1;
    }

    return result;
  }

  /**
   * Renders a text string by sending the corresponding bytes directly to the LCD.
   * The row and col parameters use LCD addressing system, where each rows occupies 8 pixels.
   * The max_width parameter is not clipped to the actual width available.
   * The xor_mask set to 0xFF or 0x7E can be used to render inverted text, for example.
   */
  static uint8_t drawText(
    PCD8544Font font,
    const uint8_t col,
    const uint8_t row,
    const uint8_t max_width,
    const char *text,
    const uint8_t xor_mask = 0
  ) {

    beginWriting();

    setAddressInternal(col, row);

    char ch;
    const char *src = text;

    // Well, let's clip it just in case.
    uint8_t m = Cols - col;
    uint8_t width_left = max_width < m ? max_width : m;

    while ((ch = *src++)) {

        uint8_t bitmap[8];
        uint8_t width = dataForCharacter(font, ch, bitmap);

        for (uint8_t i = 0; i < width; i++) {
          write(Data, bitmap[i] ^ xor_mask);
          if (--width_left == 0) {
            endWriting();
            return 0;
          }
        }

        write(Data, xor_mask);
        if (--width_left == 0)
          break;
    }

    endWriting();

    return max_width - width_left;
  }

  /** Returns how many characters will fit max_width pixels without being truncacted. */
  static uint8_t numberOfCharsFittingWidth(PCD8544Font font, const char *text, uint8_t max_width) {

    uint8_t result = 0;

    char ch;
    const char *src = text;
    uint8_t total_width = 0;
    while ((ch = *src++)) {
      uint8_t new_total_width = total_width + dataForCharacter(font, ch, NULL) + 1;
      if (new_total_width > max_width)
        break;
      total_width = new_total_width;
      result++;
    }

    return result;
  }

};

/**
 * Turns a PCD8544 LCD into a simple text-only display with autoscrolling.
 * Note that we don't inherit Arduino's Print class to keep the compiled code size small.
 */
template<typename lcd, typename font>
class PCD8544Console {

private:

  static const uint8_t MaxCols = lcd::Cols / 4;

  char _buffer[lcd::Rows][MaxCols + 1];
  uint8_t _row;
  uint8_t _col;
  uint8_t _rowWidth;
  uint8_t _filledRows;
  bool _dirty;

  void lf() {

    _col = 0;
    _rowWidth = 0;

    _row++;
    if (_row >= lcd::Rows) {
      _row = 0;
    }
    _filledRows++;
    if (_filledRows >= lcd::Rows) {
      _filledRows--;
    }
    _buffer[_row][_col] = 0;
  }

  void cr() {
    _col = 0;
    _rowWidth = 0;
  }

public:

  PCD8544Console()
    : _row(0), _col(0), _rowWidth(0), _filledRows(0)
  {}

  /** Clears the console without redrawing it on the LCD. */
  void clear() {
    _row = _filledRows = 0;
    _col = 0;
    _rowWidth = 0;
    for (uint8_t row = 0; row < lcd::Rows; row++) {
      _buffer[row][0] = 0;
    }
    _dirty = true;
  }

  /** Transfers the contents of the console buffer to the LCD.
   * Note that this is not called automatically for every print() function. */
  void draw() {

    if (!_dirty)
      return;

    _dirty = false;

    for (uint8_t i = 0; i < lcd::Rows; i++) {

      int8_t row_index = _row - _filledRows + i;
      if (row_index < 0)
        row_index += lcd::Rows;

      // Print the row and erase the space after the last character.
      uint8_t width = lcd::drawText(font::font(), 0, i, lcd::Cols, _buffer[row_index]);
      lcd::fillRow(width, i, 0, lcd::Cols - width);
    }
  }

  void print(uint8_t c) {

    uint8_t ch = ch & 0x7F;

    if (ch >= ' ') {

      uint8_t width = lcd::dataForCharacter(font::font(), ch, NULL);
      if (_col >= MaxCols || _rowWidth + width >= lcd::Cols) {
        lf();
      }

      _buffer[_row][_col] = ch;
      _col++;
      _buffer[_row][_col] = 0;
      _rowWidth += width + 1;

    } else if (ch == '\n') {

      lf();

    } else if (ch == '\r') {

      cr();
    }

    _dirty = true;
  }

  void print(const char *str) {
    const char *src = str;
    uint8_t ch;
    while (ch = *src++) {
      print(ch);
    }
  }

  void print(fstr_t *str) {
    const char *src = (const char *)str;
    uint8_t ch;
    while (ch = pgm_read_byte(src++)) {
      print(ch);
    }
  }

  void print(int n) {
    char buf[5 + 2];
    itoa(n, buf, 10);
    print(buf);
  }

  void print(unsigned int n) {
    char buf[5 + 1];
    utoa(n, buf, 10);
    print(buf);
  }

  void print(long n) {
    char buf[10 + 2];
    ltoa(n, buf, 10);
    print(buf);
  }

  void print(unsigned long n) {
    char buf[10 + 1];
    ltoa(n, buf, 10);
    print(buf);
  }

  void println(const char *str) {
    print(str);
    lf();
  }

  void println(fstr_t *str) {
    print(str);
    lf();
  }

  void println(int n) {
    print(n);
    lf();
  }

  void println(unsigned int n) {
    print(n);
    lf();
  }

  void println(long n) {
    print(n);
    lf();
  }

  void println(unsigned long n) {
    print(n);
    lf();
  }

  void println() {
    lf();
  }
};

} // namespace
<commit_msg>PCD8544: Add video mode as a config parameter<commit_after>//
// a21 — Arduino Toolkit.
// Copyright (C) 2016-2017, Aleh Dzenisiuk. http://github.com/aleh/a21
//

#pragma once

#include <Arduino.h>

#include <a21/pcd8544fonts.hpp>
#include <a21/spi.hpp>

namespace a21 {

/**
 * Basic wrapper for a PCD8544 LCD display (such as the one that was used on Nokia 5110).
 */
template<typename pinRST, typename pinCE, typename pinDC, typename pinDIN, typename pinCLK, uint32_t maxFrequency = 4000000L>
class PCD8544 {

public:

  enum Flags {
    InverseVideo,
    NormalVideo
  };

private:

  typedef SPI<pinDIN, pinCLK, pinCE, maxFrequency> spi;

  enum ValueType : uint8_t {
    Command,
    Data
  };

  static void write(ValueType valueType, uint8_t value) {
    pinDC::write(valueType == Data);
    spi::write(value);
  }

  static void beginWriting() {
    spi::beginWriting();
  }

  static void endWriting() {
    spi::endWriting();
  }

  enum FunctionSetCommand : uint8_t {
    FunctionSet = 0x20,
    /** 0 - basic command set, 1 - extended command set. */
    H = 1,
    /** 0 - horizontal addressing mode, 1 - vertical addressing mode. */
    V = 2,
    /** 0 - chip active, 1 - chip in power down mode. */
    PD = 4
  };

  enum DisplayControlCommand : uint8_t {
    DisplayControl = 0x08,
    D = 0x04,
    E = 0x01,
    DisplayBlank = (uint8_t)(~(D | E)),
    NormalMode = (uint8_t)(D & ~E),
    AllSegmentsOn = (uint8_t)(~D & E),
    InverseVideoMode = (uint8_t)(D | E)
  };

  enum SetXAddressCommand : uint8_t {
    SetXAddress = 0x80,
    SetXAddressMask = 0x7F
  };

  enum SetYAddressCommand : uint8_t {
    SetYAddress = 0x40,
    SetYAddressMask = 0x07
  };

  enum TemperatureControlExtendedCommand : uint8_t {
    TemperatureControl = 0x04,
    TemperatureControlMask = 0x3
  };

  enum BiasSystemExtendedCommand : uint8_t {
    BiasSystem = 0x10,
    BiasSystemMask = 0x07
  };

  enum SetVopExtendedCommand : uint8_t {
    SetVop = 0x80,
    SetVopMask = 0x7F
  };

  static inline void extendedCommandSet(bool extended) {
    write(
      Command,
      extended ? (FunctionSet | H) & ~(PD | V)
        : (FunctionSet | 0) & ~(PD | V | H)
    );
  }

  static inline void setAddressInternal(uint8_t col, uint8_t row) {
    extendedCommandSet(false);
    write(Command, SetXAddress | col);
    write(Command, SetYAddress | row);
  }

  static inline void config(Flags flags, uint8_t operatingVoltage, uint8_t biasSystem, uint8_t temperatureControl) {

    beginWriting();

    // Not making the display mode a parameter here as those don't seem to be useful.
    extendedCommandSet(false);
    write(Command, (flags == InverseVideo) ? (DisplayControl | InverseVideoMode) : (DisplayControl | NormalMode));

    extendedCommandSet(true);
    write(Command, SetVop | (operatingVoltage & SetVopMask));
    write(Command, BiasSystem | (biasSystem & BiasSystemMask));
    write(Command, TemperatureControl | (temperatureControl & TemperatureControlMask));

    endWriting();
  }

public:

  /** Number of addressable rows, with every row corresponding to 8 horizontal lines of actual pixels. */
  static const int Rows = 6;

  /** Number of addressable columns, though unlike rows every column corresponds to 1 vertical line of pixels. */
  static const int Cols = 84;

  /** Maximum value for the parameter of operatingVoltage function, though the actual usable values are usually much smaller. */
  static const uint8_t MaxVoltage = 0x7F;

  /** Sets operational voltage affecting the contrast of the display. */
  static void operatingVoltage(uint8_t value) {
    beginWriting();
    extendedCommandSet(true);
    write(Command, SetVop | value);
    endWriting();
  }

  /** Clears the display. */
  static void clear() {
    beginWriting();
    setAddressInternal(0, 0);
    for (int i = 0; i < Rows * Cols; i++) {
      write(Data, 0);
    }
    endWriting();
  }

  /** Initializes the display. */
  static void begin(Flags flags = NormalVideo, uint8_t operatingVoltage = 52, uint8_t biasSystem = 4, uint8_t temperatureControl = 2) {

    spi::begin();

    pinDC::setOutput();
    pinDC::setLow();

    pinRST::setOutput();
    pinRST::setLow();
    // TODO: add delay template instead
    delayMicroseconds(1000000.0 / maxFrequency);
    pinRST::setHigh();

    config(flags, operatingVoltage, biasSystem, temperatureControl);

    clear();
  }

  /**
   * Transports a bunch of bytes for the given row. The layout directly corresponds with the memory layout of the LCD,
   * where each byte is responsible for a 8 pixel column within the row (MSB is in the bottom of the row,
   * LSB is in the top).
   *
   * The row is filled from left to right (i.e. column address is automatically incremented).
   *                    col      col + 1
   *  line row * 8:     # bit 0  # bit 0  ...
   *  line row * 8 + 1: # bit 1  # bit 1  ...
   *     ...
   *  line row * 8 + 7: # bit 7  # bit 7  ...
   *                    ^        ^
   *                    byte 0   byte 1
   *
   * Note that if more bytes are provided than is left in the row, then they'll be written to the next one
   * (or the first one in case of the last row).
   */
  static void writeRow(uint8_t col, uint8_t row, const uint8_t *data, uint8_t data_length) {
    beginWriting();
    setAddressInternal(col, row);
    const uint8_t *src = data;
    for (uint8_t c = data_length; c > 0; c--) {
      write(Data, *src++);
    }
    endWriting();
  }

  /**
   * Similar to writeRow, but the same byte is sent `length` times.
   */
  static void fillRow(uint8_t col, uint8_t row, uint8_t filler, uint8_t length) {
    beginWriting();
    setAddressInternal(col, row);
    for (uint8_t c = length; c > 0; c--) {
      write(Data, filler);
    }
    endWriting();
  }

  //
  // Support for simple 8px high fonts fitting rows of the display exactly
  //

  /**
   * Returns the width of the glyph corresponding to a character in the given font and, if a buffer is provided,
   * copies glyph's bitmap bytes into it.
   */
  static uint8_t dataForCharacter(PCD8544Font font, char ch, uint8_t *buffer) {

    const uint8_t *p = font;

    uint8_t options = pgm_read_byte(p++);
    if ((options & 1) && 'a' <= ch && ch <= 'z') {
      ch = ch - 'a' + 'A';
    }

    while (true) {

      // First character in the range (0 would mean no more ranges are defined).
      uint8_t first = pgm_read_byte(p++);
      if (first == 0)
        break;

      // Last character in the range.
      uint8_t last = pgm_read_byte(p++);

      // Number of bytes every character in the range occupies.
      uint8_t bytes_per_character = pgm_read_byte(p++);

      if (first <= ch && ch <= last) {

        // Our character is in the range, let's copy the data for it.

        p += (ch - first) * bytes_per_character;
        // The first byte of the glyph data is the actual width of the glyph.
        uint8_t width = pgm_read_byte(p++);
        // Copy the bitmap if the caller expects it.
        if (buffer) {
          memcpy_PF(buffer, (uint_farptr_t)p, width);
        }

        return width;
      }

      // Well, let's skip to the next range of characters.
      p += (last + 1 - first) * bytes_per_character;
    }

    // Let's return data for sort of a default character.
    return dataForCharacter(font, '?', buffer);
  }

  /** The width of the string drawn with the given font. */
  static uint8_t textWidth(PCD8544Font font, const char *text) {

    char ch;
    const char *src = text;
    uint8_t result = 0;
    while ((ch = *src++)) {
        uint8_t width = dataForCharacter(font, ch, NULL);
        result += width + 1;
    }

    return result;
  }

  /**
   * Renders a text string by sending the corresponding bytes directly to the LCD.
   * The row and col parameters use LCD addressing system, where each rows occupies 8 pixels.
   * The max_width parameter is not clipped to the actual width available.
   * The xor_mask set to 0xFF or 0x7E can be used to render inverted text, for example.
   */
  static uint8_t drawText(
    PCD8544Font font,
    const uint8_t col,
    const uint8_t row,
    const uint8_t max_width,
    const char *text,
    const uint8_t xor_mask = 0
  ) {

    beginWriting();

    setAddressInternal(col, row);

    char ch;
    const char *src = text;

    // Well, let's clip it just in case.
    uint8_t m = Cols - col;
    uint8_t width_left = max_width < m ? max_width : m;

    while ((ch = *src++)) {

        uint8_t bitmap[8];
        uint8_t width = dataForCharacter(font, ch, bitmap);

        for (uint8_t i = 0; i < width; i++) {
          write(Data, bitmap[i] ^ xor_mask);
          if (--width_left == 0) {
            endWriting();
            return 0;
          }
        }

        write(Data, xor_mask);
        if (--width_left == 0)
          break;
    }

    endWriting();

    return max_width - width_left;
  }

  /** Returns how many characters will fit max_width pixels without being truncacted. */
  static uint8_t numberOfCharsFittingWidth(PCD8544Font font, const char *text, uint8_t max_width) {

    uint8_t result = 0;

    char ch;
    const char *src = text;
    uint8_t total_width = 0;
    while ((ch = *src++)) {
      uint8_t new_total_width = total_width + dataForCharacter(font, ch, NULL) + 1;
      if (new_total_width > max_width)
        break;
      total_width = new_total_width;
      result++;
    }

    return result;
  }

};

/**
 * Turns a PCD8544 LCD into a simple text-only display with autoscrolling.
 * Note that we don't inherit Arduino's Print class to keep the compiled code size small.
 */
template<typename lcd, typename font>
class PCD8544Console {

private:

  static const uint8_t MaxCols = lcd::Cols / 4;

  char _buffer[lcd::Rows][MaxCols + 1];
  uint8_t _row;
  uint8_t _col;
  uint8_t _rowWidth;
  uint8_t _filledRows;
  bool _dirty;

  void lf() {

    _col = 0;
    _rowWidth = 0;

    _row++;
    if (_row >= lcd::Rows) {
      _row = 0;
    }
    _filledRows++;
    if (_filledRows >= lcd::Rows) {
      _filledRows--;
    }
    _buffer[_row][_col] = 0;
  }

  void cr() {
    _col = 0;
    _rowWidth = 0;
  }

public:

  PCD8544Console()
    : _row(0), _col(0), _rowWidth(0), _filledRows(0)
  {}

  /** Clears the console without redrawing it on the LCD. */
  void clear() {
    _row = _filledRows = 0;
    _col = 0;
    _rowWidth = 0;
    for (uint8_t row = 0; row < lcd::Rows; row++) {
      _buffer[row][0] = 0;
    }
    _dirty = true;
  }

  /** Transfers the contents of the console buffer to the LCD.
   * Note that this is not called automatically for every print() function. */
  void draw() {

    if (!_dirty)
      return;

    _dirty = false;

    for (uint8_t i = 0; i < lcd::Rows; i++) {

      int8_t row_index = _row - _filledRows + i;
      if (row_index < 0)
        row_index += lcd::Rows;

      // Print the row and erase the space after the last character.
      uint8_t width = lcd::drawText(font::font(), 0, i, lcd::Cols, _buffer[row_index]);
      lcd::fillRow(width, i, 0, lcd::Cols - width);
    }
  }

  void print(char ch) {

    if (ch >= ' ') {

      uint8_t width = lcd::dataForCharacter(font::font(), ch, NULL);
      if (_col >= MaxCols || _rowWidth + width >= lcd::Cols) {
        lf();
      }

      _buffer[_row][_col] = ch;
      _col++;
      _buffer[_row][_col] = 0;
      _rowWidth += width + 1;

    } else if (ch == '\n') {

      lf();

    } else if (ch == '\r') {

      cr();
    }

    _dirty = true;
  }

  void print(const char *str) {
    const char *src = str;
    char ch;
    while (ch = *src++) {
      print(ch);
    }
  }

  void print(fstr_t *str) {
    const char *src = (const char *)str;
    char ch;
    while (ch = pgm_read_byte(src++)) {
      print(ch);
    }
  }

  void print(int n) {
    char buf[5 + 2];
    itoa(n, buf, 10);
    print(buf);
  }

  void print(unsigned int n) {
    char buf[5 + 1];
    utoa(n, buf, 10);
    print(buf);
  }

  void print(long n) {
    char buf[10 + 2];
    ltoa(n, buf, 10);
    print(buf);
  }

  void print(unsigned long n) {
    char buf[10 + 1];
    ltoa(n, buf, 10);
    print(buf);
  }

  void println(const char *str) {
    print(str);
    lf();
  }

  void println(fstr_t *str) {
    print(str);
    lf();
  }

  void println(int n) {
    print(n);
    lf();
  }

  void println(unsigned int n) {
    print(n);
    lf();
  }

  void println(long n) {
    print(n);
    lf();
  }

  void println(unsigned long n) {
    print(n);
    lf();
  }

  void println() {
    lf();
  }
};

} // namespace
<|endoftext|>


<commit_before>#ifndef Compile_Assert_hh_
#define Compile_Assert_hh_

#include <stdlib.h>
#include <iostream>

/** \file CompileAssert.hh
  \author Kevin Wierman
  \date April 12th, 2014
  \brief Defines static and runtime assertions.
  These are to be used as follows:
  ~~~~~~~~
        Compile_RUNTIME_ASSERT(true, ThisIsATrueStatement);
        Compile_RUNTIME_ASSERT(false, ThisIsAFalseStatement);
  ~~~~~~~~
  \note The second argument must be a single word, or else it will be interpreted as several arguments.
**/

//! Body-less template
template<int>
struct CompileTimeError;

//! Fully-defined template
template<>
struct CompileTimeError<true> {};

//! Use for performing static assertion
#define Compile_STATIC_ASSERT(expr, msg) \
    { CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }

//! Use for runtime assertions
#define Compile_RUNTIME_ASSERT(expr, msg)\
    {if(!expr) std::cerr<<#msg<<std::endl; abort();}

#endif //Compile_Assert_h_<commit_msg>Compile time fix for runtime assert<commit_after>#ifndef Compile_Assert_hh_
#define Compile_Assert_hh_

#include <stdlib.h>
#include <iostream>

/** \file CompileAssert.hh
  \author Kevin Wierman
  \date April 12th, 2014
  \brief Defines static and runtime assertions.
  These are to be used as follows:
  ~~~~~~~~
        Compile_RUNTIME_ASSERT(true, ThisIsATrueStatement);
        Compile_RUNTIME_ASSERT(false, ThisIsAFalseStatement);
  ~~~~~~~~
  \note The second argument must be a single word, or else it will be interpreted as several arguments.
**/

//! Body-less template
template<int>
struct CompileTimeError;

//! Fully-defined template
template<>
struct CompileTimeError<true> {};

//! Use for performing static assertion
#define Compile_STATIC_ASSERT(expr, msg) \
    { CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }

//! Use for runtime assertions
#define Compile_RUNTIME_ASSERT(expr, msg) \
    { if(!expr) std::cerr<<#msg<<std::endl; abort(); }

#endif //Compile_Assert_h_<|endoftext|>


<commit_before>// -*-c++-*-

#include <osgProducer/Viewer>

#include <osgDB/ReadFile>

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/StateSet>
#include <osg/Material>
#include <osg/Texture2D>
#include <osg/TextureRectangle>
#include <osg/TexMat>
#include <osg/CullFace>
#include <osg/ImageStream>

#include <osgGA/TrackballManipulator>

osg::ImageStream* s_imageStream = 0;
class PostSwapFinishCallback : public Producer::Camera::Callback
{
public:

    PostSwapFinishCallback() {}

    virtual void operator()(const Producer::Camera& camera)
    {
        // osg::Timer_t start_tick = osg::Timer::instance()->tick();

        osgProducer::OsgSceneHandler* sh = const_cast<osgProducer::OsgSceneHandler*>(dynamic_cast<const osgProducer::OsgSceneHandler*>(camera.getSceneHandler()));

        if (s_imageStream && s_imageStream->getPixelBufferObject()) s_imageStream->getPixelBufferObject()->compileBuffer(*(sh->getSceneView()->getState()));
        // glFinish();

        //osg::notify(osg::NOTICE)<<"callback after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
    }
};

class MovieEventHandler : public osgGA::GUIEventHandler
{
public:

    MovieEventHandler() {}

    void set(osg::Node* node);

    virtual void accept(osgGA::GUIEventHandlerVisitor& v) { v.visit(*this); }

    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);

    virtual void getUsage(osg::ApplicationUsage& usage) const;

    typedef std::vector< osg::ref_ptr<osg::ImageStream> > ImageStreamList;

protected:

    virtual ~MovieEventHandler() {}

    class FindImageStreamsVisitor : public osg::NodeVisitor
    {
    public:
        FindImageStreamsVisitor(ImageStreamList& imageStreamList):
            _imageStreamList(imageStreamList) {}

        virtual void apply(osg::Geode& geode)
        {
            apply(geode.getStateSet());

            for(unsigned int i=0;i<geode.getNumDrawables();++i)
            {
                apply(geode.getDrawable(i)->getStateSet());
            }

            traverse(geode);
        }

        virtual void apply(osg::Node& node)
        {
            apply(node.getStateSet());
            traverse(node);
        }

        inline void apply(osg::StateSet* stateset)
        {
            if (!stateset) return;

            osg::StateAttribute* attr = stateset->getTextureAttribute(0,osg::StateAttribute::TEXTURE);
            if (attr)
            {
                osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(attr);
                if (texture2D) apply(dynamic_cast<osg::ImageStream*>(texture2D->getImage()));

                osg::TextureRectangle* textureRec = dynamic_cast<osg::TextureRectangle*>(attr);
                if (textureRec) apply(dynamic_cast<osg::ImageStream*>(textureRec->getImage()));
            }
        }

        inline void apply(osg::ImageStream* imagestream)
        {
            if (imagestream)
            {
                _imageStreamList.push_back(imagestream);
                s_imageStream = imagestream;
            }
        }

        ImageStreamList& _imageStreamList;
    };

    ImageStreamList _imageStreamList;

};

void MovieEventHandler::set(osg::Node* node)
{
    _imageStreamList.clear();
    if (node)
    {
        FindImageStreamsVisitor fisv(_imageStreamList);
        node->accept(fisv);
    }
}

bool MovieEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
{
    switch(ea.getEventType())
    {
        case(osgGA::GUIEventAdapter::KEYDOWN):
        {
            if (ea.getKey()=='s')
            {
                for(ImageStreamList::iterator itr=_imageStreamList.begin();
                    itr!=_imageStreamList.end();
                    ++itr)
                {
                    std::cout<<"Play"<<std::endl;
                     (*itr)->play();
                }
                return true;
            }
            else if (ea.getKey()=='p')
            {
                for(ImageStreamList::iterator itr=_imageStreamList.begin();
                    itr!=_imageStreamList.end();
                    ++itr)
                {
                    std::cout<<"Pause"<<std::endl;
                    (*itr)->pause();
                }
                return true;
            }
            else if (ea.getKey()=='r')
            {
                return true;
            }
            else if (ea.getKey()=='l')
            {
                return true;
            }
            return false;
        }

        default:
            return false;
    }
}

void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
{
    usage.addKeyboardMouseBinding("p","Pause movie");
    usage.addKeyboardMouseBinding("s","Play movie");
    usage.addKeyboardMouseBinding("r","Start movie");
    usage.addKeyboardMouseBinding("l","Toggle looping of movie");
}

osg::Geometry* createTexturedQuadGeometry(const osg::Vec3& pos,float width,float height, osg::Image* image, bool useTextureRectangle)
{
    if (useTextureRectangle)
    {
        osg::Geometry* pictureQuad = createTexturedQuadGeometry(pos,
                                           osg::Vec3(width,0.0f,0.0f),
                                           osg::Vec3(0.0f,0.0f,height),
                                           0.0f,image->t(), image->s(),0.0f);

        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                    new osg::TextureRectangle(image),
                    osg::StateAttribute::ON);

        return pictureQuad;
    }
    else
    {
        osg::Geometry* pictureQuad = createTexturedQuadGeometry(pos,
                                           osg::Vec3(width,0.0f,0.0f),
                                           osg::Vec3(0.0f,0.0f,height),
                                           0.0f,1.0f, 1.0f,0.0f);

        osg::Texture2D* texture = new osg::Texture2D(image);
        texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);

        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                    texture,
                    osg::StateAttribute::ON);

        return pictureQuad;
    }
}

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

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    bool useTextureRectangle = true;
    bool useShader = false;

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

    while (arguments.read("--texture2D")) useTextureRectangle=false;
    while (arguments.read("--shader")) useShader=true;

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

    // register the handler to add keyboard and mosue handling.
    MovieEventHandler* meh = new MovieEventHandler();
    viewer.getEventHandlerList().push_front(meh);

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

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

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::Vec3 pos(0.0f,0.0f,0.0f);

    osg::StateSet* stateset = geode->getOrCreateStateSet();
    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);

    if (useShader)
    {
        //useTextureRectangle = false;

        static const char *shaderSourceTextureRec = {
            "uniform vec4 cutoff_color;\n"
            "uniform samplerRect movie_texture;"
            "void main(void)\n"
            "{\n"
            "    vec4 texture_color = textureRect(movie_texture, gl_TexCoord[0]); \n"
            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
            "    gl_FragColor = texture_color;\n"
            "}\n"
        };

        static const char *shaderSourceTexture2D = {
            "uniform vec4 cutoff_color;\n"
            "uniform sampler2D movie_texture;"
            "void main(void)\n"
            "{\n"
            "    vec4 texture_color = texture2D(movie_texture, gl_TexCoord[0]); \n"
            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
            "    gl_FragColor = texture_color;\n"
            "}\n"
        };

        osg::Program* program = new osg::Program;

        program->addShader(new osg::Shader(osg::Shader::FRAGMENT,
                                           useTextureRectangle ? shaderSourceTextureRec : shaderSourceTexture2D));

        stateset->addUniform(new osg::Uniform("cutoff_color",osg::Vec4(0.1f,0.1f,0.1f,1.0f)));
        stateset->addUniform(new osg::Uniform("movie_texture",0));

        stateset->setAttribute(program);

    }

    for(int i=1;i<arguments.argc();++i)
    {
        if (arguments.isString(i))
        {
            osg::Image* image = osgDB::readImageFile(arguments[i]);
            osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image);
            if (imagestream) imagestream->play();

            if (image)
            {
                geode->addDrawable(createTexturedQuadGeometry(pos,image->s(),image->t(),image, useTextureRectangle));

                pos.z() += image->t()*1.5f;
            }
            else
            {
                std::cout<<"Unable to read file "<<arguments[i]<<std::endl;
            }
        }
    }

    if (geode->getNumDrawables()==0)
    {
        // nothing loaded.
        return 1;
    }

    // pass the model to the MovieEventHandler so it can pick out ImageStream's to manipulate.
    meh->set(geode.get());

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

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

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

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
    }
/*
    // set up a post swap callback to flush deleted GL objects and compile new GL objects
    for(unsigned int cameraNum=0;cameraNum<viewer.getNumberOfCameras();++cameraNum)
    {
        Producer::Camera* camera=viewer.getCamera(cameraNum);
        camera->addPostSwapCallback(new PostSwapFinishCallback());
    }
*/
    // set the scene to render
    viewer.setSceneData(geode.get());

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

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

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

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

    }

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

    return 0;

}
<commit_msg>Added \n to end of a couple shader source lines.<commit_after>// -*-c++-*-

#include <osgProducer/Viewer>

#include <osgDB/ReadFile>

#include <osg/Geode>
#include <osg/Geometry>
#include <osg/StateSet>
#include <osg/Material>
#include <osg/Texture2D>
#include <osg/TextureRectangle>
#include <osg/TexMat>
#include <osg/CullFace>
#include <osg/ImageStream>

#include <osgGA/TrackballManipulator>

osg::ImageStream* s_imageStream = 0;
class PostSwapFinishCallback : public Producer::Camera::Callback
{
public:

    PostSwapFinishCallback() {}

    virtual void operator()(const Producer::Camera& camera)
    {
        // osg::Timer_t start_tick = osg::Timer::instance()->tick();

        osgProducer::OsgSceneHandler* sh = const_cast<osgProducer::OsgSceneHandler*>(dynamic_cast<const osgProducer::OsgSceneHandler*>(camera.getSceneHandler()));

        if (s_imageStream && s_imageStream->getPixelBufferObject()) s_imageStream->getPixelBufferObject()->compileBuffer(*(sh->getSceneView()->getState()));
        // glFinish();

        //osg::notify(osg::NOTICE)<<"callback after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
    }
};

class MovieEventHandler : public osgGA::GUIEventHandler
{
public:

    MovieEventHandler() {}

    void set(osg::Node* node);

    virtual void accept(osgGA::GUIEventHandlerVisitor& v) { v.visit(*this); }

    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);

    virtual void getUsage(osg::ApplicationUsage& usage) const;

    typedef std::vector< osg::ref_ptr<osg::ImageStream> > ImageStreamList;

protected:

    virtual ~MovieEventHandler() {}

    class FindImageStreamsVisitor : public osg::NodeVisitor
    {
    public:
        FindImageStreamsVisitor(ImageStreamList& imageStreamList):
            _imageStreamList(imageStreamList) {}

        virtual void apply(osg::Geode& geode)
        {
            apply(geode.getStateSet());

            for(unsigned int i=0;i<geode.getNumDrawables();++i)
            {
                apply(geode.getDrawable(i)->getStateSet());
            }

            traverse(geode);
        }

        virtual void apply(osg::Node& node)
        {
            apply(node.getStateSet());
            traverse(node);
        }

        inline void apply(osg::StateSet* stateset)
        {
            if (!stateset) return;

            osg::StateAttribute* attr = stateset->getTextureAttribute(0,osg::StateAttribute::TEXTURE);
            if (attr)
            {
                osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(attr);
                if (texture2D) apply(dynamic_cast<osg::ImageStream*>(texture2D->getImage()));

                osg::TextureRectangle* textureRec = dynamic_cast<osg::TextureRectangle*>(attr);
                if (textureRec) apply(dynamic_cast<osg::ImageStream*>(textureRec->getImage()));
            }
        }

        inline void apply(osg::ImageStream* imagestream)
        {
            if (imagestream)
            {
                _imageStreamList.push_back(imagestream);
                s_imageStream = imagestream;
            }
        }

        ImageStreamList& _imageStreamList;
    };

    ImageStreamList _imageStreamList;

};

void MovieEventHandler::set(osg::Node* node)
{
    _imageStreamList.clear();
    if (node)
    {
        FindImageStreamsVisitor fisv(_imageStreamList);
        node->accept(fisv);
    }
}

bool MovieEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
{
    switch(ea.getEventType())
    {
        case(osgGA::GUIEventAdapter::KEYDOWN):
        {
            if (ea.getKey()=='s')
            {
                for(ImageStreamList::iterator itr=_imageStreamList.begin();
                    itr!=_imageStreamList.end();
                    ++itr)
                {
                    std::cout<<"Play"<<std::endl;
                     (*itr)->play();
                }
                return true;
            }
            else if (ea.getKey()=='p')
            {
                for(ImageStreamList::iterator itr=_imageStreamList.begin();
                    itr!=_imageStreamList.end();
                    ++itr)
                {
                    std::cout<<"Pause"<<std::endl;
                    (*itr)->pause();
                }
                return true;
            }
            else if (ea.getKey()=='r')
            {
                return true;
            }
            else if (ea.getKey()=='l')
            {
                return true;
            }
            return false;
        }

        default:
            return false;
    }
}

void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
{
    usage.addKeyboardMouseBinding("p","Pause movie");
    usage.addKeyboardMouseBinding("s","Play movie");
    usage.addKeyboardMouseBinding("r","Start movie");
    usage.addKeyboardMouseBinding("l","Toggle looping of movie");
}

osg::Geometry* createTexturedQuadGeometry(const osg::Vec3& pos,float width,float height, osg::Image* image, bool useTextureRectangle)
{
    if (useTextureRectangle)
    {
        osg::Geometry* pictureQuad = createTexturedQuadGeometry(pos,
                                           osg::Vec3(width,0.0f,0.0f),
                                           osg::Vec3(0.0f,0.0f,height),
                                           0.0f,image->t(), image->s(),0.0f);

        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                    new osg::TextureRectangle(image),
                    osg::StateAttribute::ON);

        return pictureQuad;
    }
    else
    {
        osg::Geometry* pictureQuad = createTexturedQuadGeometry(pos,
                                           osg::Vec3(width,0.0f,0.0f),
                                           osg::Vec3(0.0f,0.0f,height),
                                           0.0f,1.0f, 1.0f,0.0f);

        osg::Texture2D* texture = new osg::Texture2D(image);
        texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);

        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                    texture,
                    osg::StateAttribute::ON);

        return pictureQuad;
    }
}

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

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    bool useTextureRectangle = true;
    bool useShader = false;

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

    while (arguments.read("--texture2D")) useTextureRectangle=false;
    while (arguments.read("--shader")) useShader=true;

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

    // register the handler to add keyboard and mosue handling.
    MovieEventHandler* meh = new MovieEventHandler();
    viewer.getEventHandlerList().push_front(meh);

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

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

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::Vec3 pos(0.0f,0.0f,0.0f);

    osg::StateSet* stateset = geode->getOrCreateStateSet();
    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);

    if (useShader)
    {
        //useTextureRectangle = false;

        static const char *shaderSourceTextureRec = {
            "uniform vec4 cutoff_color;\n"
            "uniform samplerRect movie_texture;\n"
            "void main(void)\n"
            "{\n"
            "    vec4 texture_color = textureRect(movie_texture, gl_TexCoord[0]); \n"
            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
            "    gl_FragColor = texture_color;\n"
            "}\n"
        };

        static const char *shaderSourceTexture2D = {
            "uniform vec4 cutoff_color;\n"
            "uniform sampler2D movie_texture;\n"
            "void main(void)\n"
            "{\n"
            "    vec4 texture_color = texture2D(movie_texture, gl_TexCoord[0]); \n"
            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
            "    gl_FragColor = texture_color;\n"
            "}\n"
        };

        osg::Program* program = new osg::Program;

        program->addShader(new osg::Shader(osg::Shader::FRAGMENT,
                                           useTextureRectangle ? shaderSourceTextureRec : shaderSourceTexture2D));

        stateset->addUniform(new osg::Uniform("cutoff_color",osg::Vec4(0.1f,0.1f,0.1f,1.0f)));
        stateset->addUniform(new osg::Uniform("movie_texture",0));

        stateset->setAttribute(program);

    }

    for(int i=1;i<arguments.argc();++i)
    {
        if (arguments.isString(i))
        {
            osg::Image* image = osgDB::readImageFile(arguments[i]);
            osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image);
            if (imagestream) imagestream->play();

            if (image)
            {
                geode->addDrawable(createTexturedQuadGeometry(pos,image->s(),image->t(),image, useTextureRectangle));

                pos.z() += image->t()*1.5f;
            }
            else
            {
                std::cout<<"Unable to read file "<<arguments[i]<<std::endl;
            }
        }
    }

    if (geode->getNumDrawables()==0)
    {
        // nothing loaded.
        return 1;
    }

    // pass the model to the MovieEventHandler so it can pick out ImageStream's to manipulate.
    meh->set(geode.get());

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

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

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

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
    }
/*
    // set up a post swap callback to flush deleted GL objects and compile new GL objects
    for(unsigned int cameraNum=0;cameraNum<viewer.getNumberOfCameras();++cameraNum)
    {
        Producer::Camera* camera=viewer.getCamera(cameraNum);
        camera->addPostSwapCallback(new PostSwapFinishCallback());
    }
*/
    // set the scene to render
    viewer.setSceneData(geode.get());

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

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

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

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

    }

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

    return 0;

}
<|endoftext|>


<commit_before>/*
 * SpawnAreaImplementation.cpp
 *
 *  Created on: 11/12/2011
 *      Author: victor
 */

#include "server/zone/objects/area/SpawnArea.h"
#include "server/zone/Zone.h"
#include "server/zone/managers/creature/CreatureManager.h"
#include "server/zone/managers/creature/CreatureTemplateManager.h"
#include "server/zone/managers/creature/SpawnGroup.h"
#include "server/zone/managers/collision/CollisionManager.h"
#include "server/zone/managers/planet/PlanetManager.h"
#include "server/zone/objects/area/SpawnAreaObserver.h"
#include "server/zone/objects/area/areashapes/AreaShape.h"
#include "server/ServerCore.h"
#include "events/RemoveNoSpawnAreaTask.h"

Vector3 SpawnAreaImplementation::getRandomPosition(SceneObject* player) {
	Vector3 position;
	bool positionFound = false;
	int retries = 10;

	while (!positionFound && retries-- > 0) {
		position = areaShape->getRandomPosition(player->getWorldPosition(), 64.0f, 256.0f);

		positionFound = true;

		for (int i = 0; i < noSpawnAreas.size(); ++i) {
			SpawnArea* noSpawnArea = noSpawnAreas.get(i);

			if (noSpawnArea->containsPoint(position.getX(), position.getY())) {
				positionFound = false;
				break;
			}
		}
	}

	if (!positionFound) {
		position.set(0, 0, 0);
	}

	return position;
}

int SpawnAreaImplementation::notifyObserverEvent(unsigned int eventType, Observable* observable, ManagedObject* arg1, int64 arg2) {
	if (eventType != ObserverEventType::OBJECTREMOVEDFROMZONE)
		return 1;

	TangibleObject* tano = dynamic_cast<TangibleObject*>(observable);

	if (tano == NULL)
		return 1;

	Locker locker(_this.get());

	uint32 lairTemplate = spawnTypes.remove(tano->getObjectID());

	if (lairTemplate != 0) {
		int currentSpawnCount = spawnCountByType.get(lairTemplate) - 1;

		if (currentSpawnCount < 1)
			spawnCountByType.remove(lairTemplate);
		else
			spawnCountByType.put(lairTemplate, currentSpawnCount);

		--totalSpawnCount;

		locker.release();

		ManagedReference<ActiveArea*> area = (ServerCore::getZoneServer()->createObject(String("object/active_area.iff").hashCode(), 0)).castTo<ActiveArea*>();

		area->setRadius(64);
		area->setNoSpawnArea(true);
		area->initializePosition(tano->getPositionX(), tano->getPositionZ(), tano->getPositionY());

		zone->transferObject(area, -1, true);

		Reference<Task*> task = new RemoveNoSpawnAreaTask(area);
		task->schedule(300000);
	}

	return 1;
}

SpawnGroup* SpawnAreaImplementation::getSpawnGroup() {
	if (spawnGroup == NULL && spawnGroupTemplateCRC != 0)
		spawnGroup = CreatureTemplateManager::instance()->getSpawnGroup(spawnGroupTemplateCRC);

	return spawnGroup;
}

void SpawnAreaImplementation::notifyEnter(SceneObject* object) {
	if (tier & SpawnAreaMap::NOSPAWNAREA) {
		ActiveAreaImplementation::notifyEnter(object);
		return;
	}

	if (!object->isPlayerCreature())
		return;

	ManagedReference<SceneObject*> parent = object->getParent();

	if (parent != NULL && parent->isCellObject())
		return;

	if (object->getCityRegion() != NULL)
		return;

	tryToSpawn(object);
}

void SpawnAreaImplementation::notifyPositionUpdate(QuadTreeEntry* obj) {
	if (tier & SpawnAreaMap::NOSPAWNAREA)
		return;

	CreatureObject* creature = dynamic_cast<CreatureObject*>(obj);

	if (creature == NULL)
		return;

	if (!creature->isPlayerCreature())
		return;

	ManagedReference<SceneObject*> parent = creature->getParent();

	if (parent != NULL && parent->isCellObject())
		return;

	if (System::random(25) == 1)
		tryToSpawn(creature);
}

void SpawnAreaImplementation::notifyExit(SceneObject* object) {
	if (tier & SpawnAreaMap::NOSPAWNAREA)
		ActiveAreaImplementation::notifyExit(object);
}

int SpawnAreaImplementation::tryToSpawn(SceneObject* object) {
	if (spawnGroup == NULL && spawnGroupTemplateCRC != 0)
		spawnGroup = CreatureTemplateManager::instance()->getSpawnGroup(spawnGroupTemplateCRC);

	if (spawnGroup == NULL) {
		error("spawnGroup is NULL in spawn area: " + getDisplayedName());
		return 1;
	}

	Vector<Reference<LairSpawn*> >* lairs = spawnGroup->getSpawnList();

	int totalSize = lairs->size();

	if (totalSize == 0) {
		error("totalSize is NULL");
		return 2;
	}

	Zone* zone = getZone();

	if (zone == NULL) {
		error("zone is NULL");
		return 3;
	}

	if (totalSpawnCount >= maxSpawnLimit)
		return 4;

	if (lastSpawn.miliDifference() < MINSPAWNINTERVAL)
		return 5;

	//Lets choose 3 random spawns;
	LairSpawn* firstSpawn = lairs->get(System::random(totalSize - 1));
	LairSpawn* secondSpawn = lairs->get(System::random(totalSize - 1));
	LairSpawn* thirdSpawn = lairs->get(System::random(totalSize - 1));

	LairSpawn* finalSpawn = NULL;

	int totalWeights = firstSpawn->getWeighting() + secondSpawn->getWeighting() + thirdSpawn->getWeighting();

	int finalChoice = System::random(totalWeights);

	if (finalChoice <= firstSpawn->getWeighting()) {
		finalSpawn = firstSpawn;
	} else if (finalChoice <= firstSpawn->getWeighting() + secondSpawn->getWeighting()) {
		finalSpawn = secondSpawn;
	} else {
		finalSpawn = thirdSpawn;
	}

	ManagedReference<PlanetManager*> planetManager = zone->getPlanetManager();

	Vector3 randomPosition = getRandomPosition(object);

	if (randomPosition.getX() == 0 && randomPosition.getY() == 0) {
		return 6;
	}

	float spawnZ = zone->getHeight(randomPosition.getX(), randomPosition.getY());

	randomPosition.setZ(spawnZ);

	//lets check if we intersect with some object (buildings, etc..)
	if (CollisionManager::checkSphereCollision(randomPosition, 64.f + finalSpawn->getSize(), zone))
		return 7;

	//don't spawn in cities
	SortedVector<ManagedReference<ActiveArea* > > activeAreas;
	zone->getInRangeActiveAreas(randomPosition.getX(), randomPosition.getY(), &activeAreas, true);

	for (int i = 0; i < activeAreas.size(); ++i) {
		ActiveArea* area = activeAreas.get(i);

		if (area->isRegion() || area->isMunicipalZone() || area->isNoSpawnArea())
			return 8;
	}

	//check in range objects for no build radi
	if (!planetManager->isBuildingPermittedAt(randomPosition.getX(), randomPosition.getY(), object, finalSpawn->getSize() + 64.f)) {
		return 9;
	}

	// Only spawn on relatively flat land
	if (planetManager->getTerrainManager()->getHighestHeightDifference(randomPosition.getX() - 10, randomPosition.getY() - 10, randomPosition.getX() + 10, randomPosition.getY() + 10) > 10.0) {
		return 13;
	}

	int spawnLimit = finalSpawn->getSpawnLimit();

	Locker _locker(_this.get());

	lastSpawn.updateToCurrentTime();

	String lairTemplate = finalSpawn->getLairTemplateName();
	uint32 lairHashCode = lairTemplate.hashCode();

	int currentSpawnCount = spawnCountByType.get(lairHashCode);

	if (spawnLimit != -1) {
		if (currentSpawnCount >= spawnLimit)
			return 10;
	}

	int maxDiff = finalSpawn->getMaxDifficulty();
	int minDiff = finalSpawn->getMinDifficulty();
	int difficultyLevel = System::random(maxDiff - minDiff) + minDiff;
	int difficulty = (difficultyLevel - minDiff) / ((maxDiff > (minDiff + 5) ? maxDiff - minDiff : 5) / 5);

	if (difficulty == 5)
		difficulty = 4;

	CreatureManager* creatureManager = zone->getCreatureManager();

	ManagedReference<SceneObject*> obj = creatureManager->spawn(lairHashCode, difficultyLevel, difficulty, randomPosition.getX(), spawnZ, randomPosition.getY(), finalSpawn->getSize());

	if (obj != NULL) {
		StringBuffer msg;
		msg << "lair spawned at " << obj->getPositionX() << " " << obj->getPositionY();
		obj->info(msg.toString());
	} else {
		error("could not spawn lair " + lairTemplate);

		return 11;
	}

	if (exitObserver == NULL) {
		exitObserver = new SpawnAreaObserver(_this.get());
		exitObserver->deploy();
	}

	spawnTypes.put(obj->getObjectID(), lairHashCode);

	Locker objLocker(obj);

	obj->registerObserver(ObserverEventType::OBJECTREMOVEDFROMZONE, exitObserver);

	++totalSpawnCount;

	spawnCountByType.put(lairTemplate.hashCode(), currentSpawnCount);

	return 0;
}
<commit_msg>[Fixed] removal of dynamic spawn from a spawn area not being handled properly<commit_after>/*
 * SpawnAreaImplementation.cpp
 *
 *  Created on: 11/12/2011
 *      Author: victor
 */

#include "server/zone/objects/area/SpawnArea.h"
#include "server/zone/Zone.h"
#include "server/zone/managers/creature/CreatureManager.h"
#include "server/zone/managers/creature/CreatureTemplateManager.h"
#include "server/zone/managers/creature/SpawnGroup.h"
#include "server/zone/managers/collision/CollisionManager.h"
#include "server/zone/managers/planet/PlanetManager.h"
#include "server/zone/objects/area/SpawnAreaObserver.h"
#include "server/zone/objects/area/areashapes/AreaShape.h"
#include "server/ServerCore.h"
#include "events/RemoveNoSpawnAreaTask.h"

Vector3 SpawnAreaImplementation::getRandomPosition(SceneObject* player) {
	Vector3 position;
	bool positionFound = false;
	int retries = 10;

	while (!positionFound && retries-- > 0) {
		position = areaShape->getRandomPosition(player->getWorldPosition(), 64.0f, 256.0f);

		positionFound = true;

		for (int i = 0; i < noSpawnAreas.size(); ++i) {
			SpawnArea* noSpawnArea = noSpawnAreas.get(i);

			if (noSpawnArea->containsPoint(position.getX(), position.getY())) {
				positionFound = false;
				break;
			}
		}
	}

	if (!positionFound) {
		position.set(0, 0, 0);
	}

	return position;
}

int SpawnAreaImplementation::notifyObserverEvent(unsigned int eventType, Observable* observable, ManagedObject* arg1, int64 arg2) {
	if (eventType != ObserverEventType::OBJECTREMOVEDFROMZONE)
		return 1;

	SceneObject* sceno = dynamic_cast<SceneObject*>(observable);

	if (sceno == NULL)
		return 1;

	Locker locker(_this.get());

	uint32 lairTemplate = spawnTypes.remove(sceno->getObjectID());

	if (lairTemplate != 0) {
		int currentSpawnCount = spawnCountByType.get(lairTemplate) - 1;

		if (currentSpawnCount < 1)
			spawnCountByType.remove(lairTemplate);
		else
			spawnCountByType.put(lairTemplate, currentSpawnCount);

		--totalSpawnCount;

		locker.release();

		ManagedReference<ActiveArea*> area = (ServerCore::getZoneServer()->createObject(String("object/active_area.iff").hashCode(), 0)).castTo<ActiveArea*>();

		area->setRadius(64);
		area->setNoSpawnArea(true);
		area->initializePosition(sceno->getPositionX(), sceno->getPositionZ(), sceno->getPositionY());

		zone->transferObject(area, -1, true);

		Reference<Task*> task = new RemoveNoSpawnAreaTask(area);
		task->schedule(300000);
	}

	return 1;
}

SpawnGroup* SpawnAreaImplementation::getSpawnGroup() {
	if (spawnGroup == NULL && spawnGroupTemplateCRC != 0)
		spawnGroup = CreatureTemplateManager::instance()->getSpawnGroup(spawnGroupTemplateCRC);

	return spawnGroup;
}

void SpawnAreaImplementation::notifyEnter(SceneObject* object) {
	if (tier & SpawnAreaMap::NOSPAWNAREA) {
		ActiveAreaImplementation::notifyEnter(object);
		return;
	}

	if (!object->isPlayerCreature())
		return;

	ManagedReference<SceneObject*> parent = object->getParent();

	if (parent != NULL && parent->isCellObject())
		return;

	if (object->getCityRegion() != NULL)
		return;

	tryToSpawn(object);
}

void SpawnAreaImplementation::notifyPositionUpdate(QuadTreeEntry* obj) {
	if (tier & SpawnAreaMap::NOSPAWNAREA)
		return;

	CreatureObject* creature = dynamic_cast<CreatureObject*>(obj);

	if (creature == NULL)
		return;

	if (!creature->isPlayerCreature())
		return;

	ManagedReference<SceneObject*> parent = creature->getParent();

	if (parent != NULL && parent->isCellObject())
		return;

	if (System::random(25) == 1)
		tryToSpawn(creature);
}

void SpawnAreaImplementation::notifyExit(SceneObject* object) {
	if (tier & SpawnAreaMap::NOSPAWNAREA)
		ActiveAreaImplementation::notifyExit(object);
}

int SpawnAreaImplementation::tryToSpawn(SceneObject* object) {
	if (spawnGroup == NULL && spawnGroupTemplateCRC != 0)
		spawnGroup = CreatureTemplateManager::instance()->getSpawnGroup(spawnGroupTemplateCRC);

	if (spawnGroup == NULL) {
		error("spawnGroup is NULL in spawn area: " + getDisplayedName());
		return 1;
	}

	Vector<Reference<LairSpawn*> >* lairs = spawnGroup->getSpawnList();

	int totalSize = lairs->size();

	if (totalSize == 0) {
		error("totalSize is NULL");
		return 2;
	}

	Zone* zone = getZone();

	if (zone == NULL) {
		error("zone is NULL");
		return 3;
	}

	if (totalSpawnCount >= maxSpawnLimit)
		return 4;

	if (lastSpawn.miliDifference() < MINSPAWNINTERVAL)
		return 5;

	//Lets choose 3 random spawns;
	LairSpawn* firstSpawn = lairs->get(System::random(totalSize - 1));
	LairSpawn* secondSpawn = lairs->get(System::random(totalSize - 1));
	LairSpawn* thirdSpawn = lairs->get(System::random(totalSize - 1));

	LairSpawn* finalSpawn = NULL;

	int totalWeights = firstSpawn->getWeighting() + secondSpawn->getWeighting() + thirdSpawn->getWeighting();

	int finalChoice = System::random(totalWeights);

	if (finalChoice <= firstSpawn->getWeighting()) {
		finalSpawn = firstSpawn;
	} else if (finalChoice <= firstSpawn->getWeighting() + secondSpawn->getWeighting()) {
		finalSpawn = secondSpawn;
	} else {
		finalSpawn = thirdSpawn;
	}

	ManagedReference<PlanetManager*> planetManager = zone->getPlanetManager();

	Vector3 randomPosition = getRandomPosition(object);

	if (randomPosition.getX() == 0 && randomPosition.getY() == 0) {
		return 6;
	}

	float spawnZ = zone->getHeight(randomPosition.getX(), randomPosition.getY());

	randomPosition.setZ(spawnZ);

	//lets check if we intersect with some object (buildings, etc..)
	if (CollisionManager::checkSphereCollision(randomPosition, 64.f + finalSpawn->getSize(), zone))
		return 7;

	//don't spawn in cities
	SortedVector<ManagedReference<ActiveArea* > > activeAreas;
	zone->getInRangeActiveAreas(randomPosition.getX(), randomPosition.getY(), &activeAreas, true);

	for (int i = 0; i < activeAreas.size(); ++i) {
		ActiveArea* area = activeAreas.get(i);

		if (area->isRegion() || area->isMunicipalZone() || area->isNoSpawnArea())
			return 8;
	}

	//check in range objects for no build radi
	if (!planetManager->isBuildingPermittedAt(randomPosition.getX(), randomPosition.getY(), object, finalSpawn->getSize() + 64.f)) {
		return 9;
	}

	// Only spawn on relatively flat land
	if (planetManager->getTerrainManager()->getHighestHeightDifference(randomPosition.getX() - 10, randomPosition.getY() - 10, randomPosition.getX() + 10, randomPosition.getY() + 10) > 10.0) {
		return 13;
	}

	int spawnLimit = finalSpawn->getSpawnLimit();

	Locker _locker(_this.get());

	lastSpawn.updateToCurrentTime();

	String lairTemplate = finalSpawn->getLairTemplateName();
	uint32 lairHashCode = lairTemplate.hashCode();

	int currentSpawnCount = spawnCountByType.get(lairHashCode);

	if (spawnLimit != -1) {
		if (currentSpawnCount >= spawnLimit)
			return 10;
	}

	int maxDiff = finalSpawn->getMaxDifficulty();
	int minDiff = finalSpawn->getMinDifficulty();
	int difficultyLevel = System::random(maxDiff - minDiff) + minDiff;
	int difficulty = (difficultyLevel - minDiff) / ((maxDiff > (minDiff + 5) ? maxDiff - minDiff : 5) / 5);

	if (difficulty == 5)
		difficulty = 4;

	CreatureManager* creatureManager = zone->getCreatureManager();

	ManagedReference<SceneObject*> obj = creatureManager->spawn(lairHashCode, difficultyLevel, difficulty, randomPosition.getX(), spawnZ, randomPosition.getY(), finalSpawn->getSize());

	if (obj != NULL) {
		StringBuffer msg;
		msg << "lair spawned at " << obj->getPositionX() << " " << obj->getPositionY();
		obj->info(msg.toString());
	} else {
		error("could not spawn lair " + lairTemplate);

		return 11;
	}

	if (exitObserver == NULL) {
		exitObserver = new SpawnAreaObserver(_this.get());
		exitObserver->deploy();
	}

	spawnTypes.put(obj->getObjectID(), lairHashCode);

	Locker objLocker(obj);

	obj->registerObserver(ObserverEventType::OBJECTREMOVEDFROMZONE, exitObserver);

	++totalSpawnCount;

	spawnCountByType.put(lairTemplate.hashCode(), currentSpawnCount);

	return 0;
}
<|endoftext|>


<commit_before>#include "Scene.h"

Scene::Scene(void)
{
	view_matrix = glm::lookAt(glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 0.f, -1.f), glm::vec3(0.f, 1.f, 0.f));
	memset(&KeyStates, 0, sizeof(KeyStates));
	// Init Player
	player = new Player(this, 0.0f, 0.0f);

	bool game = true;
	int score = 0;

	// Init Objects
	AddObstacle(new Obstacle(this, 15.0, 15.0, 7.00));
	AddObstacle(new Obstacle(this, -12.0, -17.0, 9.00));
	AddObstacle(new Obstacle(this, 12.0, -6.0, 5.00));
	AddObstacle(new Obstacle(this, -16.0, 15.0, 6.00));

	for (unsigned int i = 0; i < 10; ++i) AddZombie(new Zombie(this));

}

Scene::~Scene(void)
{
	if (player != 0) delete player;
	//if (test_zombie != 0) delete test_zombie;
	for (int i = 0; i < objects.size(); i++){
		if (objects[i] != 0) delete objects[i];
	}

}

bool Scene::CheckVictoryCondition(void)
{
	int z = zombies.size();
	game = true;
	for(unsigned int i=0; i<zombies.size(); ++i)
	{
		if(GetDistance(player->GetObjectPosition(), zombies[i]->GetObjectPosition()) < 2)
		{
			game = false;
			cout << "PRZEGRALES!" << endl;
		}
		if (GetDistance(player->GetObjectPosition(), zombies[i]->GetObjectPosition()) > 200) --z;
	}

	if(z == 0)
	{
		game = false;
		cout << "WYGRALES!" << endl;
	}

	return game;
}

void Scene::Update(double delta_time)
{
	if (CheckVictoryCondition()){

		GroupZombies();
		for (unsigned int i = 0; i < objects.size(); i++)
		{
			objects[i]->Update(delta_time);
		}

		if (KeyStates['w'] || KeyStates['W']) player->Move(glm::vec2(0, 0.3), delta_time);
		if (KeyStates['s'] || KeyStates['S']) player->Move(glm::vec2(0, -0.3), delta_time);
		if (KeyStates['a'] || KeyStates['A']) player->Move(glm::vec2(-0.3, 0), delta_time);
		if (KeyStates['d'] || KeyStates['D']) player->Move(glm::vec2(0.3, 0), delta_time);

		player->Update(delta_time);
	}

	//if (KeyStates['r'] || KeyStates['R']) Restart();
}

void Scene::Draw(void)
{
	player->Draw();
	for(unsigned int i = 0; i < objects.size(); i++)
	{
		objects[i]->Draw();
	}

}

void Scene::PlayerRotate(glm::vec2 heading)
{
	player->Rotate(heading);

}

void Scene::PlayerShoot(glm::vec2 aim)
{
	player->Shoot(aim);
}

void Scene::ZombieTarget(glm::vec2 target)
{
	test_zombie->MousePoint(target);
}

void Scene::Key(unsigned char key)
{
	if (KeyStates['r']) test_zombie->RandomPoint();
}

void Scene::KeyState(unsigned char key, bool tf)
{
	KeyStates[key] = tf;
}

void Scene::AddObject(GameEntity *entity)
{
	objects.push_back(entity);
}
void Scene::AddZombie(Zombie *entity)
{
	zombies.push_back(entity);
	objects.push_back(entity);
}
void Scene::AddObstacle(Obstacle *entity)
{
	obstacles.push_back(entity);
	objects.push_back(entity);
}

void Scene::GroupZombies(void)
{

}

ostream& operator<<(ostream &o, const Scene &gw)
{
	o << "---------------- SCENE ---------------" << "\n";

	o << "--------------------------------------" << endl;
	return o;
}
<commit_msg>Update<commit_after>#include "Scene.h"

Scene::Scene(void)
{
	view_matrix = glm::lookAt(glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 0.f, -1.f), glm::vec3(0.f, 1.f, 0.f));
	memset(&KeyStates, 0, sizeof(KeyStates));
	// Init Player
	player = new Player(this, 0.0f, 0.0f);

	bool game = true;
	int score = 0;

	// Init Objects
	AddObstacle(new Obstacle(this, 15.0, 15.0, 7.00));
	AddObstacle(new Obstacle(this, -12.0, -17.0, 9.00));
	AddObstacle(new Obstacle(this, 12.0, -6.0, 5.00));
	AddObstacle(new Obstacle(this, -16.0, 15.0, 6.00));

	for (unsigned int i = 0; i < 10; ++i) AddZombie(new Zombie(this));

}

Scene::~Scene(void)
{
	if (player != 0) delete player;
	//if (test_zombie != 0) delete test_zombie;
	for (int i = 0; i < objects.size(); i++){
		if (objects[i] != 0) delete objects[i];
	}

}

bool Scene::CheckVictoryCondition(void)
{
	int z = zombies.size();
	game = true;
	for(unsigned int i=0; i<zombies.size(); ++i)
	{
		if(GetDistance(player->GetObjectPosition(), zombies[i]->GetObjectPosition()) < 2)
		{
			game = false;
			cout << "PRZEGRALES!" << endl;
		}
		if (GetDistance(player->GetObjectPosition(), zombies[i]->GetObjectPosition()) > 200) --z;
	}

	if(z == 0)
	{
		game = false;
		cout << "WYGRALES!" << endl;
	}

	return game;
}

void RenderBitmapString(float x, float y, char *string)
{
	char *c;
	glColor3f(1, 0, 0);
	glRasterPos3f(x, y, -0.1);
	for(c=string; *c != '\0'; c++)
	{
		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);
	}
}

float GlutPrint(float x, float y, char *txt, float scale)
{
	int i;
	int len=strlen(txt);

	for(i=0; i<len; i++)
	{
		glRasterPos2f(x, y);
		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, txt[i]);
		x += glutBitmapWidth(GLUT_BITMAP_TIMES_ROMAN_24, txt[i])*scale;
	}

	return 0;
}

void PrintText(char* string, int x, int y) {

	if(string && strlen(string))
	{
		glPushMatrix();
		glLoadIdentity();
		glScalef(0.003f, 0.003f,0.003f);
		glColor3f(1, 0, 0);
		glRasterPos3d(x, y, 0.1);
		while(*string)
		{
			glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *string);
			string++;
		}
		glPopMatrix();
	}

}

void Scene::Update(double delta_time)
{
	if (CheckVictoryCondition()){

		GroupZombies();
		for (unsigned int i = 0; i < objects.size(); i++)
		{
			objects[i]->Update(delta_time);
		}

		if (KeyStates['w'] || KeyStates['W']) player->Move(glm::vec2(0, 0.3), delta_time);
		if (KeyStates['s'] || KeyStates['S']) player->Move(glm::vec2(0, -0.3), delta_time);
		if (KeyStates['a'] || KeyStates['A']) player->Move(glm::vec2(-0.3, 0), delta_time);
		if (KeyStates['d'] || KeyStates['D']) player->Move(glm::vec2(0.3, 0), delta_time);

		player->Update(delta_time);
	}

	//if (KeyStates['r'] || KeyStates['R']) Restart();
}

void Scene::Draw(void)
{
	player->Draw();
	for(unsigned int i = 0; i < objects.size(); i++)
	{
		objects[i]->Draw();
	}

}

void Scene::PlayerRotate(glm::vec2 heading)
{
	player->Rotate(heading);

}

void Scene::PlayerShoot(glm::vec2 aim)
{
	player->Shoot(aim);
}

void Scene::ZombieTarget(glm::vec2 target)
{
	test_zombie->MousePoint(target);
}

void Scene::Key(unsigned char key)
{
	if (KeyStates['r']) test_zombie->RandomPoint();
}

void Scene::KeyState(unsigned char key, bool tf)
{
	KeyStates[key] = tf;
}

void Scene::AddObject(GameEntity *entity)
{
	objects.push_back(entity);
}
void Scene::AddZombie(Zombie *entity)
{
	zombies.push_back(entity);
	objects.push_back(entity);
}
void Scene::AddObstacle(Obstacle *entity)
{
	obstacles.push_back(entity);
	objects.push_back(entity);
}

void Scene::GroupZombies(void)
{

}

ostream& operator<<(ostream &o, const Scene &gw)
{
	o << "---------------- SCENE ---------------" << "\n";

	o << "--------------------------------------" << endl;
	return o;
}
<|endoftext|>


<commit_before>//ArmCollisionDetector2018
//Created by Etienne C.-C.
// coucaste@informatik.hu-berlin.de

#include "ArmCollisionDetector2018.h"
#include <PlatformInterface/Platform.h>
#include "Tools/Math/Polygon.h"

using namespace naoth;

ArmCollisionDetector2018::ArmCollisionDetector2018()
{
  //Debug Requests
  DEBUG_REQUEST_REGISTER("Motion:ArmCollisionDetector2018:showReferenceHull", "", false);
  DEBUG_REQUEST_REGISTER("Motion:ArmCollisionDetector2018:showLeftBuffer", "", false);
  DEBUG_REQUEST_REGISTER("Motion:ArmCollisionDetector2018:showRightBuffer", "", false);

  getDebugParameterList().add(&params);
  double alpha, beta;
  const std::string& dirlocation = Platform::getInstance().theConfigDirectory;

  std::ifstream fileLeft(dirlocation + params.point_configLeft);
  while (fileLeft>>alpha>>beta) {
    getCollisionPercept().referenceHullLeft.emplace_back(alpha, beta);
  }
  fileLeft.close();

  std::ifstream fileRight(dirlocation + params.point_configRight);
  while (fileRight >> alpha >> beta) {
    getCollisionPercept().referenceHullRight.emplace_back(alpha, beta);
  }
  fileRight.close();

  getCollisionPercept().referenceHullLeft = ConvexHull::convexHull(getCollisionPercept().referenceHullLeft);
  getCollisionPercept().referenceHullRight = ConvexHull::convexHull(getCollisionPercept().referenceHullRight);

  refpolyL.makeFromPointSet(getCollisionPercept().referenceHullLeft);
  refpolyR.makeFromPointSet(getCollisionPercept().referenceHullRight);

}

ArmCollisionDetector2018::~ArmCollisionDetector2018()
{
  getDebugParameterList().remove(&params);
}

void ArmCollisionDetector2018::execute()
{
  //Check if robot is in a suitable situation to recognize collisions#
    const bool bodymodeOK = getBodyState().fall_down_state != BodyState::upright;
  const bool armModeOK =
    getMotionRequest().armMotionRequest.id == ArmMotionRequest::arms_synchronised_with_walk ||
    getMotionRequest().armMotionRequest.id == ArmMotionRequest::arms_down;
    const bool motionModeOK = getMotionStatus().currentMotion == motion::walk || getMotionStatus().currentMotion == motion::stand;

  // clear the joint command history in order to not check for collision while the robot is already executing a evasive movement for example
  if (!armModeOK || !motionModeOK || !bodymodeOK)
  {
    jointDataBufferLeft.clear();
    jointDataBufferRight.clear();

    collisionBufferLeft.clear();
    collisionBufferRight.clear();

    collisionBufferLeftRoll.clear();
    collisionBufferRightRoll.clear();
    return;
  }

    //collect Motorjoint Data and adjust timelag (Motor is 4 Frames ahead of Sensor)
  jointDataBufferLeft.add(getMotorJointData().position[JointData::LShoulderPitch]);
  jointDataBufferRight.add(getMotorJointData().position[JointData::RShoulderPitch]);

  jointDataBufferLeftRoll.add(getMotorJointData().position[JointData::LShoulderRoll]);
  jointDataBufferRightRoll.add(getMotorJointData().position[JointData::RShoulderRoll]);

  //When the robots arms are down, they are less sensible to collisions, so in that case we lower the sensitivity
  //by using the more sensitive threshold method
  if (getMotionRequest().armMotionRequest.id == ArmMotionRequest::arms_down)
  {
    if (jointDataBufferLeft.isFull()) {
      double e = jointDataBufferLeft.first() - getSensorJointData().position[JointData::LShoulderPitch];
      collisionBufferLeft.add(std::fabs(e));
    }
    if (jointDataBufferRight.isFull()) {
      double e = jointDataBufferRight.first() - getSensorJointData().position[JointData::RShoulderPitch];
      collisionBufferRight.add(std::fabs(e));
    }
    double max_error = params.maxErrorStand;

    // collision arm left
    if (collisionBufferLeft.isFull() && collisionBufferLeft.getAverage() > max_error) {
      getCollisionPercept().timeCollisionArmLeft = getFrameInfo().getTime();
      jointDataBufferLeft.clear();
      collisionBufferLeft.clear();

    }

    // collision arm right
    if (collisionBufferRight.isFull() && collisionBufferRight.getAverage() > max_error) {
      getCollisionPercept().timeCollisionArmRight = getFrameInfo().getTime();
      jointDataBufferRight.clear();
      collisionBufferRight.clear();
    }

    return;
  }
  else
  {
    collisionBufferLeft.clear();
    collisionBufferRight.clear();
  }

  { // Arm Roll Collision
    if (jointDataBufferLeftRoll.isFull()) {
      double e = jointDataBufferLeftRoll.first() - getSensorJointData().position[JointData::LShoulderRoll];
      collisionBufferLeftRoll.add(e);
    }
    if (jointDataBufferRightRoll.isFull()) {
      double e = jointDataBufferRightRoll.first() - getSensorJointData().position[JointData::RShoulderRoll];
      collisionBufferRightRoll.add(e);
    }
    double max_error = params.armRollError;

    // collision arm left
    if (collisionBufferLeftRoll.isFull() && std::fabs(collisionBufferLeftRoll.getAverage()) > max_error) {
      getCollisionPercept().timeCollisionArmLeft = getFrameInfo().getTime();
      jointDataBufferLeftRoll.clear();
      collisionBufferLeftRoll.clear();

    }

    // collision arm right
    if (collisionBufferRightRoll.isFull() && std::fabs(collisionBufferRightRoll.getAverage()) > max_error) {
      getCollisionPercept().timeCollisionArmRight = getFrameInfo().getTime();
      jointDataBufferRightRoll.clear();
      collisionBufferRightRoll.clear();
    }
  }

  //In this part we check for collision using the "Polygon method"

  if (jointDataBufferLeft.isFull())
  {
    double a = jointDataBufferLeft.first();
    double b = getSensorJointData().position[JointData::LShoulderPitch];
    double er = (b - a);
    if (!refpolyL.isInside(Vector2d(a, er)))
    {
      //collision
      getCollisionPercept().timeCollisionArmLeft = getFrameInfo().getTime();
      jointDataBufferLeft.clear();
    }
  }

  if (jointDataBufferRight.isFull())
  {
    double a = jointDataBufferRight.first();
    double b = getSensorJointData().position[JointData::RShoulderPitch];
    double er = (b - a);
    if (!refpolyR.isInside(Vector2d(a, er)))
    {
      //collision
      getCollisionPercept().timeCollisionArmRight = getFrameInfo().getTime();
      jointDataBufferRight.clear();
     }
  }

}<commit_msg>reformatted<commit_after>//ArmCollisionDetector2018
//Created by Etienne C.-C.
// coucaste@informatik.hu-berlin.de

#include "ArmCollisionDetector2018.h"
#include <PlatformInterface/Platform.h>
#include "Tools/Math/Polygon.h"

using namespace naoth;

ArmCollisionDetector2018::ArmCollisionDetector2018()
{
    //Debug Requests
    //Debug Requests end

    getDebugParameterList().add(&params);
    double alpha, beta;
    const std::string& dirlocation = Platform::getInstance().theConfigDirectory;

    std::ifstream fileLeft(dirlocation + params.point_configLeft);
    while (fileLeft >> alpha >> beta) {
        getCollisionPercept().referenceHullLeft.emplace_back(alpha, beta);
    }
    fileLeft.close();

    std::ifstream fileRight(dirlocation + params.point_configRight);
    while (fileRight >> alpha >> beta) {
        getCollisionPercept().referenceHullRight.emplace_back(alpha, beta);
    }
    fileRight.close();

    getCollisionPercept().referenceHullLeft = ConvexHull::convexHull(getCollisionPercept().referenceHullLeft);
    getCollisionPercept().referenceHullRight = ConvexHull::convexHull(getCollisionPercept().referenceHullRight);

    refpolyL.makeFromPointSet(getCollisionPercept().referenceHullLeft);
    refpolyR.makeFromPointSet(getCollisionPercept().referenceHullRight);

}

ArmCollisionDetector2018::~ArmCollisionDetector2018()
{
    getDebugParameterList().remove(&params);
}

void ArmCollisionDetector2018::execute()
{
    //Check if robot is in a suitable situation to recognize collisions#
    const bool bodymodeOK = getBodyState().fall_down_state != BodyState::upright;
    const bool armModeOK =
        getMotionRequest().armMotionRequest.id == ArmMotionRequest::arms_synchronised_with_walk ||
        getMotionRequest().armMotionRequest.id == ArmMotionRequest::arms_down;
    const bool motionModeOK = getMotionStatus().currentMotion == motion::walk || getMotionStatus().currentMotion == motion::stand;

    // clear the joint command history in order to not check for collision while the robot is already executing a evasive movement for example
    if (!armModeOK || !motionModeOK || !bodymodeOK)
    {
        jointDataBufferLeft.clear();
        jointDataBufferRight.clear();

        collisionBufferLeft.clear();
        collisionBufferRight.clear();

        collisionBufferLeftRoll.clear();
        collisionBufferRightRoll.clear();
        return;
    }

    //collect Motorjoint Data and adjust timelag (Motor is 4 Frames ahead of Sensor)
    jointDataBufferLeft.add(getMotorJointData().position[JointData::LShoulderPitch]);
    jointDataBufferRight.add(getMotorJointData().position[JointData::RShoulderPitch]);

    jointDataBufferLeftRoll.add(getMotorJointData().position[JointData::LShoulderRoll]);
    jointDataBufferRightRoll.add(getMotorJointData().position[JointData::RShoulderRoll]);

    //When the robots arms are down, they are less sensible to collisions, so in that case we lower the sensitivity
    //by using the more sensitive threshold method
    if (getMotionRequest().armMotionRequest.id == ArmMotionRequest::arms_down)
    {
        if (jointDataBufferLeft.isFull()) {
            double e = jointDataBufferLeft.first() - getSensorJointData().position[JointData::LShoulderPitch];
            collisionBufferLeft.add(std::fabs(e));
        }
        if (jointDataBufferRight.isFull()) {
            double e = jointDataBufferRight.first() - getSensorJointData().position[JointData::RShoulderPitch];
            collisionBufferRight.add(std::fabs(e));
        }
        double max_error = params.maxErrorStand;

        // collision arm left
        if (collisionBufferLeft.isFull() && collisionBufferLeft.getAverage() > max_error) {
            getCollisionPercept().timeCollisionArmLeft = getFrameInfo().getTime();
            jointDataBufferLeft.clear();
            collisionBufferLeft.clear();

        }

        // collision arm right
        if (collisionBufferRight.isFull() && collisionBufferRight.getAverage() > max_error) {
            getCollisionPercept().timeCollisionArmRight = getFrameInfo().getTime();
            jointDataBufferRight.clear();
            collisionBufferRight.clear();
        }

        return;
    } //End of threshold method
    else
    {
        collisionBufferLeft.clear();
        collisionBufferRight.clear();
    }

    // Arm Roll Collision
    if (jointDataBufferLeftRoll.isFull()) {
        double e = jointDataBufferLeftRoll.first() - getSensorJointData().position[JointData::LShoulderRoll];
        collisionBufferLeftRoll.add(e);
    }
    if (jointDataBufferRightRoll.isFull()) {
        double e = jointDataBufferRightRoll.first() - getSensorJointData().position[JointData::RShoulderRoll];
        collisionBufferRightRoll.add(e);
    }
    double max_error = params.armRollError;

    // Arm Roll collision arm left
    if (collisionBufferLeftRoll.isFull() && std::fabs(collisionBufferLeftRoll.getAverage()) > max_error) {
        getCollisionPercept().timeCollisionArmLeft = getFrameInfo().getTime();
        jointDataBufferLeftRoll.clear();
        collisionBufferLeftRoll.clear();

    }

    // Arm Roll collision arm right
    if (collisionBufferRightRoll.isFull() && std::fabs(collisionBufferRightRoll.getAverage()) > max_error) {
        getCollisionPercept().timeCollisionArmRight = getFrameInfo().getTime();
        jointDataBufferRightRoll.clear();
        collisionBufferRightRoll.clear();
    }

    //In this part we check for collision using the "Polygon method"

    if (jointDataBufferLeft.isFull())
    {
        double a = jointDataBufferLeft.first();
        double b = getSensorJointData().position[JointData::LShoulderPitch];
        double er = (b - a);// er < 0 means collision from behind, er > 0 from front
        if (!refpolyL.isInside(Vector2d(a, er)))
        {
            //collision
            getCollisionPercept().timeCollisionArmLeft = getFrameInfo().getTime();
            jointDataBufferLeft.clear();
        }
    }

    if (jointDataBufferRight.isFull())
    {
        double a = jointDataBufferRight.first();
        double b = getSensorJointData().position[JointData::RShoulderPitch];
        double er = (b - a); // er < 0 means collision from behind, er > 0 from front
        if (!refpolyR.isInside(Vector2d(a, er)))
        {
            //collision
            getCollisionPercept().timeCollisionArmRight = getFrameInfo().getTime();
            jointDataBufferRight.clear();
        }
    }

}<|endoftext|>


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

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "webdavhandler.h"

#ifdef HAVE_VALUES_H
#include <values.h>
#else
#ifdef HAVE_SYS_LIMITS_H
#include <sys/limits.h>
#endif
#endif

#include <libkcal/incidence.h>

#include <libkdepim/kpimprefs.h>

#include <kdebug.h>
#include <kconfig.h>

#include <qfile.h>

SloxItem::SloxItem()
  : status( Invalid )
{
}

WebdavHandler::WebdavHandler()
  : mLogCount( 0 )
{
  KConfig cfg( "sloxrc" );

  cfg.setGroup( "General" );
  mLogFile = cfg.readEntry( "LogFile" );

  kdDebug() << "LOG FILE: " << mLogFile << endl;
}

void WebdavHandler::setUserId( const QString &id )
{
  mUserId = id;
}

QString WebdavHandler::userId() const
{
  return mUserId;
}

void WebdavHandler::log( const QString &text )
{
  if ( mLogFile.isEmpty() ) return;

  QString filename = mLogFile + "-" + QString::number( mLogCount );
  QFile file( filename );
  if ( !file.open( IO_WriteOnly ) ) {
    kdWarning() << "Unable to open log file '" << filename << "'" << endl;
    return;
  }

  QCString textUtf8 = text.utf8();
  file.writeBlock( textUtf8.data(), textUtf8.size() - 1 );

  if ( ++mLogCount > 5 ) mLogCount = 0;
}

QValueList<SloxItem> WebdavHandler::getSloxItems( const QDomDocument &doc )
{
  kdDebug() << "getSloxItems" << endl;

  QValueList<SloxItem> items;

  QDomElement docElement = doc.documentElement();

  QDomNode responseNode;
  for( responseNode = docElement.firstChild(); !responseNode.isNull();
       responseNode = responseNode.nextSibling() ) {
    QDomElement responseElement = responseNode.toElement();
    if ( responseElement.tagName() == "response" ) {
      QDomNode propstat = responseElement.namedItem( "propstat" );
      if ( propstat.isNull() ) {
        kdError() << "Unable to find propstat tag." << endl;
        continue;
      }

      QDomNode prop = propstat.namedItem( "prop" );
      if ( prop.isNull() ) {
        kdError() << "Unable to find WebDAV property" << endl;
        continue;
      }

      QDomNode sloxIdNode = prop.namedItem( "sloxid" );
      if ( sloxIdNode.isNull() ) {
        kdError() << "Unable to find SLOX id." << endl;
        continue;
      }
      QDomElement sloxIdElement = sloxIdNode.toElement();
      QString sloxId = sloxIdElement.text();

      QDomNode sloxStatus = prop.namedItem( "sloxstatus" );
      if ( sloxStatus.isNull() ) {
        kdError() << "Unable to find SLOX status." << endl;
        continue;
      }

      SloxItem item;
      item.sloxId = sloxId;
      item.domNode = prop;

      QDomElement sloxStatusElement = sloxStatus.toElement();
      if ( sloxStatusElement.text() == "DELETE" ) {
        item.status = SloxItem::Delete;
      } else if ( sloxStatusElement.text() == "CREATE" ) {
        item.status = SloxItem::Create;
      }

      items.append( item );
    }
  }

  return items;
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt )
{
  uint ticks = -dt.secsTo( QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0 ) ) );

  return QString::number( ticks ) + "000";
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt,
                                        const QString &timeZoneId )
{
  QDateTime utc = KPimPrefs::localTimeToUtc( dt, timeZoneId );

  uint ticks = -utc.secsTo( QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0 ) ) );

  return QString::number( ticks ) + "000";
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str )
{
  QString s = str.mid( 0, str.length() - 3 );

  bool preEpoch = s.startsWith("-");
  if (preEpoch)
     s = s.mid(1);

  unsigned long ticks = s.toULong();

  QDateTime dt;

  if (preEpoch) {
    dt.setTime_t( 0, Qt::UTC );
    if (ticks > INT_MAX) {
      dt = dt.addSecs(-INT_MAX);
      ticks -= INT_MAX;
    }
    dt = dt.addSecs(-((long) ticks));
  }
  else
  {
    dt.setTime_t( ticks, Qt::UTC );
  }

  return dt;
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str,
                                          const QString &timeZoneId )
{
  return KPimPrefs::utcToLocalTime( sloxToQDateTime(str), timeZoneId );
}

QDomElement WebdavHandler::addElement( QDomDocument &doc, QDomNode &node,
                                       const QString &tag )
{
  QDomElement el = doc.createElement( tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addDavElement( QDomDocument &doc, QDomNode &node,
                                          const QString &tag )
{
  QDomElement el = doc.createElementNS( "DAV", tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addSloxElement( QDomDocument &doc, QDomNode &node,
                                           const QString &tag,
                                           const QString &text )
{
  QDomElement el = doc.createElementNS( "SLOX", tag );
  if ( !text.isEmpty() ) {
    QDomText textnode = doc.createTextNode( text );
    el.appendChild( textnode );
  }
  node.appendChild( el );
  return el;
}

void WebdavHandler::parseSloxAttribute( const QDomElement &e )
{
//  kdDebug() << "parseSloxAttribute" << endl;

  QString tag = e.tagName();
  QString text = QString::fromUtf8( e.text().latin1() );
  if ( text.isEmpty() ) return;

  if ( tag == "owner" ) {
    if ( text == mUserId ) mWritable = true;
  } else if ( tag == "writerights" ) {
    QDomNode n;
    for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e2 = n.toElement();
      if ( e2.tagName() == "member" ) {
        if ( e2.text() == mUserId ) mWritable = true;
      }
      // TODO: Process group write rights
    }
  }
}

void WebdavHandler::clearSloxAttributeStatus()
{
  mWritable = false;
}

void WebdavHandler::setSloxAttributes( KCal::Incidence *i )
{
  i->setReadOnly( !mWritable );
}

void WebdavHandler::setSloxAttributes( KABC::Addressee & )
{
  // FIXME: libkabc doesn't allow to set an individual addressee to read-only
}
<commit_msg>Save things to the server in the correct timezone - remove a double conversion bug.<commit_after>/*
    This file is part of kdepim.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "webdavhandler.h"

#ifdef HAVE_VALUES_H
#include <values.h>
#else
#ifdef HAVE_SYS_LIMITS_H
#include <sys/limits.h>
#endif
#endif

#include <stdlib.h>

#include <libkcal/incidence.h>

#include <libkdepim/kpimprefs.h>

#include <kdebug.h>
#include <kconfig.h>

#include <qfile.h>

SloxItem::SloxItem()
  : status( Invalid )
{
}

WebdavHandler::WebdavHandler()
  : mLogCount( 0 )
{
  KConfig cfg( "sloxrc" );

  cfg.setGroup( "General" );
  mLogFile = cfg.readEntry( "LogFile" );

  kdDebug() << "LOG FILE: " << mLogFile << endl;
}

void WebdavHandler::setUserId( const QString &id )
{
  mUserId = id;
}

QString WebdavHandler::userId() const
{
  return mUserId;
}

void WebdavHandler::log( const QString &text )
{
  if ( mLogFile.isEmpty() ) return;

  QString filename = mLogFile + "-" + QString::number( mLogCount );
  QFile file( filename );
  if ( !file.open( IO_WriteOnly ) ) {
    kdWarning() << "Unable to open log file '" << filename << "'" << endl;
    return;
  }

  QCString textUtf8 = text.utf8();
  file.writeBlock( textUtf8.data(), textUtf8.size() - 1 );

  if ( ++mLogCount > 5 ) mLogCount = 0;
}

QValueList<SloxItem> WebdavHandler::getSloxItems( const QDomDocument &doc )
{
  kdDebug() << "getSloxItems" << endl;

  QValueList<SloxItem> items;

  QDomElement docElement = doc.documentElement();

  QDomNode responseNode;
  for( responseNode = docElement.firstChild(); !responseNode.isNull();
       responseNode = responseNode.nextSibling() ) {
    QDomElement responseElement = responseNode.toElement();
    if ( responseElement.tagName() == "response" ) {
      QDomNode propstat = responseElement.namedItem( "propstat" );
      if ( propstat.isNull() ) {
        kdError() << "Unable to find propstat tag." << endl;
        continue;
      }

      QDomNode prop = propstat.namedItem( "prop" );
      if ( prop.isNull() ) {
        kdError() << "Unable to find WebDAV property" << endl;
        continue;
      }

      QDomNode sloxIdNode = prop.namedItem( "sloxid" );
      if ( sloxIdNode.isNull() ) {
        kdError() << "Unable to find SLOX id." << endl;
        continue;
      }
      QDomElement sloxIdElement = sloxIdNode.toElement();
      QString sloxId = sloxIdElement.text();

      QDomNode sloxStatus = prop.namedItem( "sloxstatus" );
      if ( sloxStatus.isNull() ) {
        kdError() << "Unable to find SLOX status." << endl;
        continue;
      }

      SloxItem item;
      item.sloxId = sloxId;
      item.domNode = prop;

      QDomElement sloxStatusElement = sloxStatus.toElement();
      if ( sloxStatusElement.text() == "DELETE" ) {
        item.status = SloxItem::Delete;
      } else if ( sloxStatusElement.text() == "CREATE" ) {
        item.status = SloxItem::Create;
      }

      items.append( item );
    }
  }

  return items;
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt )
{
  uint ticks = -dt.secsTo( QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0 ) ) );

  return QString::number( ticks ) + "000";
}

QString WebdavHandler::qDateTimeToSlox( const QDateTime &dt,
                                        const QString &timeZoneId )
{
  QDateTime utc = KPimPrefs::localTimeToUtc( dt, timeZoneId );

  // secsTo and toTime_t etc also perform a timezone conversion using the system timezone,
  // but we want to use the calendar timezone, so we have to convert ourself and spoof the tz to UTC before
  // converting to ticks to prevent this
  QCString origTz = getenv("TZ");
  setenv( "TZ", "UTC", 1 );
  uint ticks = utc.toTime_t();
  if ( origTz.isNull() )
    unsetenv( "TZ" );
  else
    setenv( "TZ", origTz, 1 );

  return QString::number( ticks ) + "000";
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str )
{
  QString s = str.mid( 0, str.length() - 3 );

  bool preEpoch = s.startsWith("-");
  if (preEpoch)
     s = s.mid(1);

  unsigned long ticks = s.toULong();

  QDateTime dt;

  if (preEpoch) {
    dt.setTime_t( 0, Qt::UTC );
    if (ticks > INT_MAX) {
      dt = dt.addSecs(-INT_MAX);
      ticks -= INT_MAX;
    }
    dt = dt.addSecs(-((long) ticks));
  }
  else
  {
    dt.setTime_t( ticks, Qt::UTC );
  }

  return dt;
}

QDateTime WebdavHandler::sloxToQDateTime( const QString &str,
                                          const QString &timeZoneId )
{
  return KPimPrefs::utcToLocalTime( sloxToQDateTime(str), timeZoneId );
}

QDomElement WebdavHandler::addElement( QDomDocument &doc, QDomNode &node,
                                       const QString &tag )
{
  QDomElement el = doc.createElement( tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addDavElement( QDomDocument &doc, QDomNode &node,
                                          const QString &tag )
{
  QDomElement el = doc.createElementNS( "DAV", tag );
  node.appendChild( el );
  return el;
}

QDomElement WebdavHandler::addSloxElement( QDomDocument &doc, QDomNode &node,
                                           const QString &tag,
                                           const QString &text )
{
  QDomElement el = doc.createElementNS( "SLOX", tag );
  if ( !text.isEmpty() ) {
    QDomText textnode = doc.createTextNode( text );
    el.appendChild( textnode );
  }
  node.appendChild( el );
  return el;
}

void WebdavHandler::parseSloxAttribute( const QDomElement &e )
{
//  kdDebug() << "parseSloxAttribute" << endl;

  QString tag = e.tagName();
  QString text = QString::fromUtf8( e.text().latin1() );
  if ( text.isEmpty() ) return;

  if ( tag == "owner" ) {
    if ( text == mUserId ) mWritable = true;
  } else if ( tag == "writerights" ) {
    QDomNode n;
    for( n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) {
      QDomElement e2 = n.toElement();
      if ( e2.tagName() == "member" ) {
        if ( e2.text() == mUserId ) mWritable = true;
      }
      // TODO: Process group write rights
    }
  }
}

void WebdavHandler::clearSloxAttributeStatus()
{
  mWritable = false;
}

void WebdavHandler::setSloxAttributes( KCal::Incidence *i )
{
  i->setReadOnly( !mWritable );
}

void WebdavHandler::setSloxAttributes( KABC::Addressee & )
{
  // FIXME: libkabc doesn't allow to set an individual addressee to read-only
}
<|endoftext|>


<commit_before>#include <iostream>

int main(int argc, char* argv[]) {
    std::cout << "Hello World!" << std::endl;
    return 0;
}<commit_msg>feat: make it work<commit_after>#include <iostream>

int main(int argc, char* argv[]) {
    std::cout << "Hello World!" << std::endl;
    std::system("PAUSE");
    return 0;
}<|endoftext|>