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

#include "riegeli/bytes/buffered_reader.h"

#include <stddef.h>

#include <cstring>
#include <limits>
#include <utility>

#include "absl/base/optimization.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "riegeli/base/base.h"
#include "riegeli/base/chain.h"
#include "riegeli/bytes/backward_writer.h"
#include "riegeli/bytes/reader.h"
#include "riegeli/bytes/writer.h"

namespace riegeli {

inline size_t BufferedReader::BufferLength() const {
  size_t length = buffer_size_;
  if (limit_pos_ < size_hint_) {
    // Avoid allocating more than needed for size_hint_.
    length = UnsignedMin(length, size_hint_ - limit_pos_);
  }
  return length;
}

inline size_t BufferedReader::LengthToReadDirectly() const {
  // Read directly if reading through buffer_ would need more than one read,
  // or if buffer_ would be full. Read directly also if size_hint_ is reached.
  return SaturatingAdd(available(), BufferLength());
}

void BufferedReader::VerifyEnd() {
  // No more data are expected, so allocate a minimal non-empty buffer for
  // verifying that.
  set_size_hint(SaturatingAdd(pos(), Position{1}));
  Reader::VerifyEnd();
}

bool BufferedReader::PullSlow() {
  RIEGELI_ASSERT_EQ(available(), 0u)
      << "Failed precondition of Reader::PullSlow(): "
         "data available, use Pull() instead";
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  absl::Span<char> flat_buffer = buffer_.AppendBuffer(0);
  if (flat_buffer.empty()) {
    // Make a new buffer.
    RIEGELI_ASSERT_GT(buffer_size_, 0u)
        << "Failed invariant of BufferedReader: no buffer size specified";
    buffer_.Clear();
    flat_buffer = buffer_.AppendBuffer(BufferLength());
    start_ = flat_buffer.data();
    cursor_ = start_;
  } else if (flat_buffer.size() == buffer_.size()) {
    // buffer_ was empty.
    start_ = buffer_.data();
    cursor_ = start_;
  }
  RIEGELI_ASSERT(start_ == buffer_.data())
      << "Failed invariant of BufferedReader: "
         "buffer pointer does not point to buffer_";
  limit_ = flat_buffer.data();
  // Read more data into buffer_.
  const Position pos_before = limit_pos_;
  const bool ok = ReadInternal(flat_buffer.data(), 1, flat_buffer.size());
  RIEGELI_ASSERT_GE(limit_pos_, pos_before)
      << "BufferedReader::ReadInternal() decreased limit_pos_";
  const Position length_read = limit_pos_ - pos_before;
  RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
      << "BufferedReader::ReadInternal() read more than requested";
  buffer_.RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
  limit_ += length_read;
  return ok;
}

bool BufferedReader::ReadSlow(char* dest, size_t length) {
  RIEGELI_ASSERT_GT(length, available())
      << "Failed precondition of Reader::ReadSlow(char*): "
         "length too small, use Read(char*) instead";
  if (length >= LengthToReadDirectly()) {
    if (ABSL_PREDICT_FALSE(!healthy())) return false;
    const size_t available_length = available();
    if (available_length > 0) {  // memcpy(_, nullptr, 0) is undefined.
      std::memcpy(dest, cursor_, available_length);
      dest += available_length;
      length -= available_length;
    }
    ClearBuffer();
    return ReadInternal(dest, length, length);
  }
  return Reader::ReadSlow(dest, length);
}

bool BufferedReader::ReadSlow(Chain* dest, size_t length) {
  RIEGELI_ASSERT_GT(length, UnsignedMin(available(), kMaxBytesToCopy))
      << "Failed precondition of Reader::ReadSlow(Chain*): "
         "length too small, use Read(Chain*) instead";
  RIEGELI_ASSERT_LE(length, std::numeric_limits<size_t>::max() - dest->size())
      << "Failed precondition of Reader::ReadSlow(Chain*): "
         "Chain size overflow";
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  bool ok = true;
  while (length > available()) {
    if (available() == 0 && length >= LengthToReadDirectly()) {
      ClearBuffer();
      const absl::Span<char> flat_buffer = dest->AppendFixedBuffer(length);
      const Position pos_before = limit_pos_;
      if (ABSL_PREDICT_FALSE(!ReadInternal(
              flat_buffer.data(), flat_buffer.size(), flat_buffer.size()))) {
        RIEGELI_ASSERT_GE(limit_pos_, pos_before)
            << "BufferedReader::ReadInternal() decreased limit_pos_";
        const Position length_read = limit_pos_ - pos_before;
        RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
            << "BufferedReader::ReadInternal() read more than requested";
        dest->RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
        return false;
      }
      return true;
    }
    absl::Span<char> flat_buffer = buffer_.AppendBuffer(0);
    if (flat_buffer.empty()) {
      // Append a part of buffer_ to dest and make a new buffer.
      RIEGELI_ASSERT_GT(buffer_size_, 0u)
          << "Failed invariant of BufferedReader: no buffer size specified";
      const size_t available_length = available();
      buffer_.AppendSubstrTo(absl::string_view(cursor_, available_length),
                             dest);
      length -= available_length;
      buffer_.Clear();
      flat_buffer = buffer_.AppendBuffer(BufferLength());
      start_ = flat_buffer.data();
      cursor_ = start_;
    } else if (flat_buffer.size() == buffer_.size()) {
      // buffer_ was empty.
      start_ = buffer_.data();
      cursor_ = start_;
    }
    RIEGELI_ASSERT(start_ == buffer_.data())
        << "Failed invariant of BufferedReader: "
           "buffer pointer does not point to buffer_";
    limit_ = flat_buffer.data();
    // Read more data into buffer_.
    const Position pos_before = limit_pos_;
    ok = ReadInternal(flat_buffer.data(), 1, flat_buffer.size());
    RIEGELI_ASSERT_GE(limit_pos_, pos_before)
        << "BufferedReader::ReadInternal() decreased limit_pos_";
    const Position length_read = limit_pos_ - pos_before;
    RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
        << "BufferedReader::ReadInternal() read more than requested";
    buffer_.RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
    limit_ += length_read;
    if (ABSL_PREDICT_FALSE(!ok)) {
      if (length > available()) {
        length = available();
      } else {
        ok = true;
      }
      break;
    }
  }
  RIEGELI_ASSERT_LE(length, available())
      << "Bug in BufferedReader::ReadSlow(Chain*): "
         "remaining length larger than available data";
  buffer_.AppendSubstrTo(absl::string_view(cursor_, length), dest);
  cursor_ += length;
  return ok;
}

bool BufferedReader::CopyToSlow(Writer* dest, Position length) {
  RIEGELI_ASSERT_GT(length, UnsignedMin(available(), kMaxBytesToCopy))
      << "Failed precondition of Reader::CopyToSlow(Writer*): "
         "length too small, use CopyTo(Writer*) instead";
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  bool read_ok = true;
  while (length > available()) {
    absl::Span<char> flat_buffer = buffer_.AppendBuffer(0);
    if (flat_buffer.empty()) {
      // Write a part of buffer_ to dest and make a new buffer.
      RIEGELI_ASSERT_GT(buffer_size_, 0u)
          << "Failed invariant of BufferedReader: no buffer size specified";
      const size_t available_length = available();
      if (available_length > 0) {
        bool write_ok;
        if (available_length == buffer_.size()) {
          write_ok = dest->Write(Chain(buffer_));
        } else {
          Chain data;
          buffer_.AppendSubstrTo(absl::string_view(cursor_, available_length),
                                 &data, available_length);
          write_ok = dest->Write(std::move(data));
        }
        if (ABSL_PREDICT_FALSE(!write_ok)) {
          cursor_ = limit_;
          return false;
        }
        length -= available_length;
      }
      buffer_.Clear();
      flat_buffer = buffer_.AppendBuffer(BufferLength());
      start_ = flat_buffer.data();
      cursor_ = start_;
    } else if (flat_buffer.size() == buffer_.size()) {
      // buffer_ was empty.
      start_ = buffer_.data();
      cursor_ = start_;
    }
    RIEGELI_ASSERT(start_ == buffer_.data())
        << "Failed invariant of BufferedReader: "
           "buffer pointer does not point to buffer_";
    limit_ = flat_buffer.data();
    // Read more data into buffer_.
    const Position pos_before = limit_pos_;
    read_ok = ReadInternal(flat_buffer.data(), 1, flat_buffer.size());
    RIEGELI_ASSERT_GE(limit_pos_, pos_before)
        << "BufferedReader::ReadInternal() decreased limit_pos_";
    const Position length_read = limit_pos_ - pos_before;
    RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
        << "BufferedReader::ReadInternal() read more than requested";
    buffer_.RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
    limit_ += length_read;
    if (ABSL_PREDICT_FALSE(!read_ok)) {
      if (length > available()) {
        length = available();
      } else {
        read_ok = true;
      }
      break;
    }
  }
  RIEGELI_ASSERT_LE(length, available())
      << "Bug in BufferedReader::CopyToSlow(Writer*): "
         "remaining length larger than available data";
  bool write_ok = true;
  if (length > 0) {
    if (length == buffer_.size()) {
      write_ok = dest->Write(Chain(buffer_));
    } else {
      Chain data;
      buffer_.AppendSubstrTo(absl::string_view(cursor_, length), &data, length);
      write_ok = dest->Write(std::move(data));
    }
    cursor_ += length;
  }
  return write_ok && read_ok;
}

bool BufferedReader::CopyToSlow(BackwardWriter* dest, size_t length) {
  RIEGELI_ASSERT_GT(length, UnsignedMin(available(), kMaxBytesToCopy))
      << "Failed precondition of Reader::CopyToSlow(Writer*): "
         "length too small, use CopyTo(Writer*) instead";
  if (length <= kMaxBytesToCopy) {
    char buffer[kMaxBytesToCopy];
    if (ABSL_PREDICT_FALSE(!ReadSlow(buffer, length))) return false;
    return dest->Write(absl::string_view(buffer, length));
  }
  Chain data;
  if (ABSL_PREDICT_FALSE(!ReadSlow(&data, length))) return false;
  return dest->Write(std::move(data));
}

void BufferedReader::ClearBuffer() {
  buffer_.Clear();
  start_ = nullptr;
  cursor_ = nullptr;
  limit_ = nullptr;
}

}  // namespace riegeli
<commit_msg>Cosmetics in BufferedReader:<commit_after>// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "riegeli/bytes/buffered_reader.h"

#include <stddef.h>

#include <cstring>
#include <limits>
#include <utility>

#include "absl/base/optimization.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "riegeli/base/base.h"
#include "riegeli/base/chain.h"
#include "riegeli/bytes/backward_writer.h"
#include "riegeli/bytes/reader.h"
#include "riegeli/bytes/writer.h"

namespace riegeli {

inline size_t BufferedReader::BufferLength() const {
  RIEGELI_ASSERT_GT(buffer_size_, 0u)
      << "Failed invariant of BufferedReader: no buffer size specified";
  size_t length = buffer_size_;
  if (limit_pos_ < size_hint_) {
    // Avoid allocating more than needed for size_hint_.
    length = UnsignedMin(length, size_hint_ - limit_pos_);
  }
  return length;
}

inline size_t BufferedReader::LengthToReadDirectly() const {
  // Read directly if reading through buffer_ would need more than one read,
  // or if buffer_ would be full. Read directly also if size_hint_ is reached.
  return SaturatingAdd(available(), BufferLength());
}

void BufferedReader::VerifyEnd() {
  // No more data are expected, so allocate a minimal non-empty buffer for
  // verifying that.
  set_size_hint(SaturatingAdd(pos(), Position{1}));
  Reader::VerifyEnd();
}

bool BufferedReader::PullSlow() {
  RIEGELI_ASSERT_EQ(available(), 0u)
      << "Failed precondition of Reader::PullSlow(): "
         "data available, use Pull() instead";
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  absl::Span<char> flat_buffer = buffer_.AppendBuffer(0);
  if (flat_buffer.empty()) {
    // Make a new buffer.
    buffer_.Clear();
    flat_buffer = buffer_.AppendBuffer(BufferLength());
    start_ = flat_buffer.data();
    cursor_ = start_;
    limit_ = flat_buffer.data();
  } else if (flat_buffer.size() == buffer_.size()) {
    // buffer_ was empty.
    start_ = buffer_.data();
    cursor_ = start_;
    limit_ = start_;
  }
  RIEGELI_ASSERT(start_ == buffer_.data())
      << "Bug in BufferedReader::PullSlow(): "
         "start_ does not point to buffer_";
  RIEGELI_ASSERT(limit_ == flat_buffer.data())
      << "Bug in BufferedReader::PullSlow(): "
         "limit_ does not point to flat_buffer";
  // Read more data into buffer_.
  const Position pos_before = limit_pos_;
  const bool ok = ReadInternal(flat_buffer.data(), 1, flat_buffer.size());
  RIEGELI_ASSERT_GE(limit_pos_, pos_before)
      << "BufferedReader::ReadInternal() decreased limit_pos_";
  const Position length_read = limit_pos_ - pos_before;
  RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
      << "BufferedReader::ReadInternal() read more than requested";
  buffer_.RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
  limit_ += length_read;
  return ok;
}

bool BufferedReader::ReadSlow(char* dest, size_t length) {
  RIEGELI_ASSERT_GT(length, available())
      << "Failed precondition of Reader::ReadSlow(char*): "
         "length too small, use Read(char*) instead";
  if (length >= LengthToReadDirectly()) {
    if (ABSL_PREDICT_FALSE(!healthy())) return false;
    const size_t available_length = available();
    if (available_length > 0) {  // memcpy(_, nullptr, 0) is undefined.
      std::memcpy(dest, cursor_, available_length);
      dest += available_length;
      length -= available_length;
    }
    ClearBuffer();
    return ReadInternal(dest, length, length);
  }
  return Reader::ReadSlow(dest, length);
}

bool BufferedReader::ReadSlow(Chain* dest, size_t length) {
  RIEGELI_ASSERT_GT(length, UnsignedMin(available(), kMaxBytesToCopy))
      << "Failed precondition of Reader::ReadSlow(Chain*): "
         "length too small, use Read(Chain*) instead";
  RIEGELI_ASSERT_LE(length, std::numeric_limits<size_t>::max() - dest->size())
      << "Failed precondition of Reader::ReadSlow(Chain*): "
         "Chain size overflow";
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  bool ok = true;
  while (length > available()) {
    if (available() == 0 && length >= LengthToReadDirectly()) {
      ClearBuffer();
      const absl::Span<char> flat_buffer = dest->AppendFixedBuffer(length);
      const Position pos_before = limit_pos_;
      if (ABSL_PREDICT_FALSE(!ReadInternal(
              flat_buffer.data(), flat_buffer.size(), flat_buffer.size()))) {
        RIEGELI_ASSERT_GE(limit_pos_, pos_before)
            << "BufferedReader::ReadInternal() decreased limit_pos_";
        const Position length_read = limit_pos_ - pos_before;
        RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
            << "BufferedReader::ReadInternal() read more than requested";
        dest->RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
        return false;
      }
      return true;
    }
    absl::Span<char> flat_buffer = buffer_.AppendBuffer(0);
    if (flat_buffer.empty()) {
      // Append a part of buffer_ to dest and make a new buffer.
      const size_t available_length = available();
      buffer_.AppendSubstrTo(absl::string_view(cursor_, available_length),
                             dest);
      length -= available_length;
      buffer_.Clear();
      flat_buffer = buffer_.AppendBuffer(BufferLength());
      start_ = flat_buffer.data();
      cursor_ = start_;
      limit_ = start_;
    } else if (flat_buffer.size() == buffer_.size()) {
      // buffer_ was empty.
      start_ = buffer_.data();
      cursor_ = start_;
      limit_ = start_;
    }
    RIEGELI_ASSERT(start_ == buffer_.data())
        << "Bug in BufferedReader::ReadSlow(Chain*): "
           "start_ does not point to buffer_";
    RIEGELI_ASSERT(limit_ == flat_buffer.data())
        << "Bug in BufferedReader::ReadSlow(Chain*): "
           "limit_ does not point to flat_buffer";
    // Read more data into buffer_.
    const Position pos_before = limit_pos_;
    ok = ReadInternal(flat_buffer.data(), 1, flat_buffer.size());
    RIEGELI_ASSERT_GE(limit_pos_, pos_before)
        << "BufferedReader::ReadInternal() decreased limit_pos_";
    const Position length_read = limit_pos_ - pos_before;
    RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
        << "BufferedReader::ReadInternal() read more than requested";
    buffer_.RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
    limit_ += length_read;
    if (ABSL_PREDICT_FALSE(!ok)) {
      if (length > available()) {
        length = available();
      } else {
        ok = true;
      }
      break;
    }
  }
  RIEGELI_ASSERT_LE(length, available())
      << "Bug in BufferedReader::ReadSlow(Chain*): "
         "remaining length larger than available data";
  buffer_.AppendSubstrTo(absl::string_view(cursor_, length), dest);
  cursor_ += length;
  return ok;
}

bool BufferedReader::CopyToSlow(Writer* dest, Position length) {
  RIEGELI_ASSERT_GT(length, UnsignedMin(available(), kMaxBytesToCopy))
      << "Failed precondition of Reader::CopyToSlow(Writer*): "
         "length too small, use CopyTo(Writer*) instead";
  if (ABSL_PREDICT_FALSE(!healthy())) return false;
  bool read_ok = true;
  while (length > available()) {
    absl::Span<char> flat_buffer = buffer_.AppendBuffer(0);
    if (flat_buffer.empty()) {
      // Write a part of buffer_ to dest and make a new buffer.
      const size_t available_length = available();
      if (available_length > 0) {
        bool write_ok;
        if (available_length == buffer_.size()) {
          write_ok = dest->Write(Chain(buffer_));
        } else {
          Chain data;
          buffer_.AppendSubstrTo(absl::string_view(cursor_, available_length),
                                 &data, available_length);
          write_ok = dest->Write(std::move(data));
        }
        if (ABSL_PREDICT_FALSE(!write_ok)) {
          cursor_ = limit_;
          return false;
        }
        length -= available_length;
      }
      buffer_.Clear();
      flat_buffer = buffer_.AppendBuffer(BufferLength());
      start_ = flat_buffer.data();
      cursor_ = start_;
      limit_ = start_;
    } else if (flat_buffer.size() == buffer_.size()) {
      // buffer_ was empty.
      start_ = buffer_.data();
      cursor_ = start_;
      limit_ = start_;
    }
    RIEGELI_ASSERT(start_ == buffer_.data())
        << "Bug in BufferedReader::CopyToSlow(Writer*): "
           "start_ does not point to buffer_";
    RIEGELI_ASSERT(limit_ == flat_buffer.data())
        << "Bug in BufferedReader::CopyToSlow(Writer*): "
           "limit_ does not point to flat_buffer";
    // Read more data into buffer_.
    const Position pos_before = limit_pos_;
    read_ok = ReadInternal(flat_buffer.data(), 1, flat_buffer.size());
    RIEGELI_ASSERT_GE(limit_pos_, pos_before)
        << "BufferedReader::ReadInternal() decreased limit_pos_";
    const Position length_read = limit_pos_ - pos_before;
    RIEGELI_ASSERT_LE(length_read, flat_buffer.size())
        << "BufferedReader::ReadInternal() read more than requested";
    buffer_.RemoveSuffix(flat_buffer.size() - IntCast<size_t>(length_read));
    limit_ += length_read;
    if (ABSL_PREDICT_FALSE(!read_ok)) {
      if (length > available()) {
        length = available();
      } else {
        read_ok = true;
      }
      break;
    }
  }
  RIEGELI_ASSERT_LE(length, available())
      << "Bug in BufferedReader::CopyToSlow(Writer*): "
         "remaining length larger than available data";
  bool write_ok = true;
  if (length > 0) {
    if (length == buffer_.size()) {
      write_ok = dest->Write(Chain(buffer_));
    } else {
      Chain data;
      buffer_.AppendSubstrTo(absl::string_view(cursor_, length), &data, length);
      write_ok = dest->Write(std::move(data));
    }
    cursor_ += length;
  }
  return write_ok && read_ok;
}

bool BufferedReader::CopyToSlow(BackwardWriter* dest, size_t length) {
  RIEGELI_ASSERT_GT(length, UnsignedMin(available(), kMaxBytesToCopy))
      << "Failed precondition of Reader::CopyToSlow(BackwardWriter*): "
         "length too small, use CopyTo(BackwardWriter*) instead";
  if (length <= kMaxBytesToCopy) {
    char buffer[kMaxBytesToCopy];
    if (ABSL_PREDICT_FALSE(!ReadSlow(buffer, length))) return false;
    return dest->Write(absl::string_view(buffer, length));
  }
  Chain data;
  if (ABSL_PREDICT_FALSE(!ReadSlow(&data, length))) return false;
  return dest->Write(std::move(data));
}

void BufferedReader::ClearBuffer() {
  buffer_.Clear();
  start_ = nullptr;
  cursor_ = nullptr;
  limit_ = nullptr;
}

}  // namespace riegeli
<|endoftext|>


<commit_before>/*
 * Configuration backend
 *
 * This file is part of softrig, a simple software defined radio transceiver.
 *
 * Copyright 2017-2018 Alexandru Csete OZ9AEC.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <new>          // std::nothrow
#include <QDebug>
#include <QSettings>

#include "app_config.h"

#define CONFIG_VERSION  1

#define APP                "app"
#define APP_CFG_VER         APP"/config_version"

#define SDR_INPUT           "sdr_input"
#define SDR_INPUT_TYPE      SDR_INPUT"/type"
#define SDR_INPUT_FREQ      SDR_INPUT"/frequency"
#define SDR_INPUT_LNB       SDR_INPUT"/transverter"
#define SDR_INPUT_RATE      SDR_INPUT"/sample_rate"
#define SDR_INPUT_DECIM     SDR_INPUT"/decimation"
#define SDR_INPUT_BW        SDR_INPUT"/bandwidth"
#define SDR_INPUT_CORR      SDR_INPUT"/frequency_correction"

AppConfig::AppConfig()
{
    settings = nullptr;
}

AppConfig::~AppConfig()
{
    close();
}

int AppConfig::load(const QString &filename)
{
    if (filename.isEmpty()) // FIXME: check that it is a correct path
        return APP_CONFIG_EINVAL;

    close();

    settings = new (std::nothrow) QSettings(filename, QSettings::IniFormat);
    if (!settings)
        return APP_CONFIG_EFILE;

    app_config.version = settings->value(APP_CFG_VER, CONFIG_VERSION).toUInt();
    readDeviceConf();

    return APP_CONFIG_OK;
}

void AppConfig::save(void)
{
    if (!settings)
        return;

    settings->setValue(APP_CFG_VER, app_config.version);
    saveDeviceConf();
    settings->sync();
}

void AppConfig::close(void)
{
    if (!settings)
        return;

    settings->sync();
    delete settings;
    settings = nullptr;
}

void AppConfig::readDeviceConf(void)
{
    device_config_t     *input = &app_config.input;

    input->type = settings->value(SDR_INPUT_TYPE, "").toString();
    input->frequency = settings->value(SDR_INPUT_FREQ, 0).toULongLong();
    input->transverter = settings->value(SDR_INPUT_LNB, 0).toULongLong();
    input->rate = settings->value(SDR_INPUT_RATE, 0).toUInt();
    input->decimation = settings->value(SDR_INPUT_DECIM, 1).toUInt();
    input->bandwidth = settings->value(SDR_INPUT_BW, 0).toUInt();
    input->freq_corr_ppb = settings->value(SDR_INPUT_CORR, 0).toInt();
}

void AppConfig::saveDeviceConf(void)
{
    device_config_t     *input = &app_config.input;

    if (input->type.isEmpty())
        settings->remove(SDR_INPUT_TYPE);
    else
        settings->setValue(SDR_INPUT_TYPE, input->type);

    if (input->frequency)
        settings->setValue(SDR_INPUT_FREQ, input->frequency);
    else
        settings->remove(SDR_INPUT_FREQ);

    if (input->transverter)
        settings->setValue(SDR_INPUT_LNB, input->transverter);
    else
        settings->remove(SDR_INPUT_LNB);

    if (input->rate)
        settings->setValue(SDR_INPUT_RATE, input->rate);
    else
        settings->remove(SDR_INPUT_RATE);

    if (input->decimation < 2)
        settings->remove(SDR_INPUT_DECIM);
    else
        settings->setValue(SDR_INPUT_DECIM, input->decimation);

    if (input->bandwidth)
        settings->setValue(SDR_INPUT_BW, input->bandwidth);
    else
        settings->remove(SDR_INPUT_BW);

    if (input->freq_corr_ppb)
        settings->setValue(SDR_INPUT_CORR, input->freq_corr_ppb);
    else
        settings->remove(SDR_INPUT_CORR);
}

<commit_msg>Fix incorrect conversion of transverter frequency<commit_after>/*
 * Configuration backend
 *
 * This file is part of softrig, a simple software defined radio transceiver.
 *
 * Copyright 2017-2019 Alexandru Csete OZ9AEC.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <new>          // std::nothrow
#include <QDebug>
#include <QSettings>

#include "app_config.h"

#define CONFIG_VERSION  1

#define APP                "app"
#define APP_CFG_VER         APP"/config_version"

#define SDR_INPUT           "sdr_input"
#define SDR_INPUT_TYPE      SDR_INPUT"/type"
#define SDR_INPUT_FREQ      SDR_INPUT"/frequency"
#define SDR_INPUT_LNB       SDR_INPUT"/transverter"
#define SDR_INPUT_RATE      SDR_INPUT"/sample_rate"
#define SDR_INPUT_DECIM     SDR_INPUT"/decimation"
#define SDR_INPUT_BW        SDR_INPUT"/bandwidth"
#define SDR_INPUT_CORR      SDR_INPUT"/frequency_correction"

AppConfig::AppConfig()
{
    settings = nullptr;
}

AppConfig::~AppConfig()
{
    close();
}

int AppConfig::load(const QString &filename)
{
    if (filename.isEmpty()) // FIXME: check that it is a correct path
        return APP_CONFIG_EINVAL;

    close();

    settings = new (std::nothrow) QSettings(filename, QSettings::IniFormat);
    if (!settings)
        return APP_CONFIG_EFILE;

    app_config.version = settings->value(APP_CFG_VER, CONFIG_VERSION).toUInt();
    readDeviceConf();

    return APP_CONFIG_OK;
}

void AppConfig::save(void)
{
    if (!settings)
        return;

    settings->setValue(APP_CFG_VER, app_config.version);
    saveDeviceConf();
    settings->sync();
}

void AppConfig::close(void)
{
    if (!settings)
        return;

    settings->sync();
    delete settings;
    settings = nullptr;
}

void AppConfig::readDeviceConf(void)
{
    device_config_t     *input = &app_config.input;

    input->type = settings->value(SDR_INPUT_TYPE, "").toString();
    input->frequency = settings->value(SDR_INPUT_FREQ, 0).toULongLong();
    input->transverter = settings->value(SDR_INPUT_LNB, 0).toLongLong();
    input->rate = settings->value(SDR_INPUT_RATE, 0).toUInt();
    input->decimation = settings->value(SDR_INPUT_DECIM, 1).toUInt();
    input->bandwidth = settings->value(SDR_INPUT_BW, 0).toUInt();
    input->freq_corr_ppb = settings->value(SDR_INPUT_CORR, 0).toInt();
}

void AppConfig::saveDeviceConf(void)
{
    device_config_t     *input = &app_config.input;

    if (input->type.isEmpty())
        settings->remove(SDR_INPUT_TYPE);
    else
        settings->setValue(SDR_INPUT_TYPE, input->type);

    if (input->frequency)
        settings->setValue(SDR_INPUT_FREQ, input->frequency);
    else
        settings->remove(SDR_INPUT_FREQ);

    if (input->transverter)
        settings->setValue(SDR_INPUT_LNB, input->transverter);
    else
        settings->remove(SDR_INPUT_LNB);

    if (input->rate)
        settings->setValue(SDR_INPUT_RATE, input->rate);
    else
        settings->remove(SDR_INPUT_RATE);

    if (input->decimation < 2)
        settings->remove(SDR_INPUT_DECIM);
    else
        settings->setValue(SDR_INPUT_DECIM, input->decimation);

    if (input->bandwidth)
        settings->setValue(SDR_INPUT_BW, input->bandwidth);
    else
        settings->remove(SDR_INPUT_BW);

    if (input->freq_corr_ppb)
        settings->setValue(SDR_INPUT_CORR, input->freq_corr_ppb);
    else
        settings->remove(SDR_INPUT_CORR);
}

<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "projectmodel.h"

#include "core/gluonobject.h"
#include "core/debughelper.h"
#include "engine/game.h"
#include "engine/gameproject.h"
#include "engine/asset.h"
#include "engine/scene.h"

#include <KDebug>
#include <KLocalizedString>
#include <KMimeType>
#include <KIcon>

#include <QtCore/QMimeData>
#include <kmimetype.h>
#include <QtCore/QFileInfo>
#include <engine/filelocation.h>
#include <QDir>
#include <historymanager.h>
#include <objectmanager.h>

using namespace GluonCreator;

class ProjectModel::ProjectModelPrivate
{
    public:
        ProjectModelPrivate()
        {
            root = 0;
            project = 0;
        }

        QObject* root;
        GluonEngine::GameProject* project;

        QStringList acceptedMimeTypes;
};

ProjectModel::ProjectModel(QObject* parent): QAbstractItemModel(parent), d(new ProjectModelPrivate)
{
    connect(HistoryManager::instance(), SIGNAL(historyChanged()), SIGNAL(layoutChanged()));
}

ProjectModel::~ProjectModel()
{
    delete d;
}

GluonEngine::GameProject*
ProjectModel::project()
{
    return d->project;
}

void
ProjectModel::setProject(GluonEngine::GameProject* project)
{
    if(project)
    {
        d->root = new QObject(this);
        d->project = project;
        project->setParent(d->root);

        reset();
    }
}

QVariant
ProjectModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (role == Qt::DecorationRole)
    {
        GluonCore::GluonObject* gobj = qobject_cast<GluonCore::GluonObject*>(static_cast<QObject*>(index.internalPointer()));
        if(gobj)
        {
            QVariant filename = gobj->property("file");
            if(filename.isValid())
            {
                QString name = filename.value<QString>();
                return KIcon(KMimeType::iconNameForUrl(KUrl(name)));
            }
            else
                return KIcon("text-x-generic");
        }
    }

    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        GluonCore::GluonObject* gobj = qobject_cast<GluonCore::GluonObject*>(static_cast<QObject*>(index.internalPointer()));
        if (gobj)
            return gobj->name();
    }

    return QVariant();
}

int
ProjectModel::columnCount(const QModelIndex& parent) const
{
    Q_UNUSED(parent)
    return 1;
}

int
ProjectModel::rowCount(const QModelIndex& parent) const
{
    if (parent.column() > 0)
        return 0;

    QObject *parentItem = d->root;
    if (parent.isValid())
        parentItem = static_cast<QObject*>(parent.internalPointer());

    if (parentItem)
    {
        if (qobject_cast<GluonCore::GluonObject*>(parentItem))
        {
            if (qobject_cast<GluonEngine::Scene*>(parentItem))
                return 0;

            int childCount = 0;
            const QObjectList allChildren = parentItem->children();
            foreach(const QObject* child, allChildren)
            {
                if(qobject_cast<const GluonCore::GluonObject* >(child))
                    ++childCount;
            }
            return childCount;
        }
        else
            return parentItem->children().count();
    }

    return 0;
}

QModelIndex
ProjectModel::parent(const QModelIndex& child) const
{
    if (!child.isValid())
        return QModelIndex();

    QObject *childItem = static_cast<QObject*>(child.internalPointer());
    QObject *parentItem = childItem->parent();

    if (parentItem == d->root)
        return QModelIndex();

    QObject *grandParent = parentItem->parent();
    if(grandParent)
    {
        int childCount = -1;
        const QObjectList allChildren = grandParent->children();
        foreach(const QObject* grandChild, allChildren)
        {
            if(qobject_cast<const GluonCore::GluonObject* >(grandChild))
                ++childCount;
            if(grandChild == parentItem)
                return createIndex(childCount, 0, parentItem);
        }
    }
    return createIndex(-1, 0, grandParent);
}

QModelIndex
ProjectModel::index(int row, int column, const QModelIndex& parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    QObject *parentItem = d->root;
    if (parent.isValid())
        parentItem = static_cast<QObject*>(parent.internalPointer());

    int childCount = -1;
    const QObjectList allChildren = parentItem->children();
    foreach(const QObject* child, allChildren)
    {
        if(qobject_cast<const GluonCore::GluonObject*>(child))
            ++childCount;
        if(childCount == row)
            return createIndex(row, column, const_cast<QObject*>(child));
    }

    return QModelIndex();
}

QVariant
ProjectModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    Q_UNUSED(section)
    Q_UNUSED(orientation)
    Q_UNUSED(role)

    return QVariant();
}

Qt::DropActions
ProjectModel::supportedDropActions() const
{
    return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
}

Qt::ItemFlags
ProjectModel::flags(const QModelIndex& index) const
{
    if (index.isValid())
    {
        QObject * obj = static_cast<QObject*>(index.internalPointer());
        //Gluon::Asset *obj = qobject_cast<Gluon::Asset*>();
        // One does not simply drop Assets into Mord...other Assets!
        if (obj->inherits("GluonEngine::Asset"))
        {
            return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
        }
        else
        {
            return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
        }
    }
    else
    {
        return Qt::ItemIsDropEnabled;
    }
}

QStringList
ProjectModel::mimeTypes() const
{
    if (d->acceptedMimeTypes.count() < 1)
    {
        DEBUG_FUNC_NAME
        d->acceptedMimeTypes.append("application/gluoncreator.projectmodel.gluonobject");
        d->acceptedMimeTypes.append("text/uri-list");
        d->acceptedMimeTypes.append(GluonCore::GluonObjectFactory::instance()->objectMimeTypes());
        foreach(const QString &theName, d->acceptedMimeTypes)
        {
            DEBUG_TEXT(QString("%1").arg(theName));
        }
    }

    return d->acceptedMimeTypes;
}

bool
ProjectModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
    Q_UNUSED(row)
    Q_UNUSED(column)
    DEBUG_FUNC_NAME

    if (action == Qt::IgnoreAction)
        return false;

    if (data->hasUrls())
    {
        foreach(const QUrl& theUrl, data->urls())
        {
            ObjectManager::instance()->createNewAsset(theUrl.toLocalFile());
        }
    }
    else if (data->hasFormat("application/gluoncreator.projectmodel.gluonobject"))
    {
    }
    else
    {
    }

    if (data->formats().length() < 1)
        return false;

    return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
}

bool
ProjectModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (index.isValid() && role == Qt::EditRole)
    {
        static_cast<GluonCore::GluonObject*>(index.internalPointer())->setName(value.toString());
        emit dataChanged(index, index);
        return true;
    }
    return false;
}

bool
ProjectModel::removeRows(int row, int count, const QModelIndex& parent)
{
    DEBUG_FUNC_NAME
    if (!parent.isValid())
        return false;

    GluonCore::GluonObject * parentObject = static_cast<GluonCore::GluonObject*>(parent.internalPointer());
    DEBUG_TEXT("Object removal begins...");

    beginRemoveRows(parent, row, row + count);
    for (int i = row; i < row + count; ++i)
    {
        DEBUG_TEXT(QString("Removing child at row %1").arg(i));
        GluonCore::GluonObject * child = parentObject->child(row);
        if (parentObject->removeChild(child))
            delete(child);
    }
    endRemoveRows();

    return true;
}

//#include "projectmodel.moc"
<commit_msg>Pass the test when removing items in the project pane (you're removing row + count - 1 items, not row + count)<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "projectmodel.h"

#include "core/gluonobject.h"
#include "core/debughelper.h"
#include "engine/game.h"
#include "engine/gameproject.h"
#include "engine/asset.h"
#include "engine/scene.h"

#include <KDebug>
#include <KLocalizedString>
#include <KMimeType>
#include <KIcon>

#include <QtCore/QMimeData>
#include <kmimetype.h>
#include <QtCore/QFileInfo>
#include <engine/filelocation.h>
#include <QDir>
#include <historymanager.h>
#include <objectmanager.h>

using namespace GluonCreator;

class ProjectModel::ProjectModelPrivate
{
    public:
        ProjectModelPrivate()
        {
            root = 0;
            project = 0;
        }

        QObject* root;
        GluonEngine::GameProject* project;

        QStringList acceptedMimeTypes;
};

ProjectModel::ProjectModel(QObject* parent): QAbstractItemModel(parent), d(new ProjectModelPrivate)
{
    connect(HistoryManager::instance(), SIGNAL(historyChanged()), SIGNAL(layoutChanged()));
}

ProjectModel::~ProjectModel()
{
    delete d;
}

GluonEngine::GameProject*
ProjectModel::project()
{
    return d->project;
}

void
ProjectModel::setProject(GluonEngine::GameProject* project)
{
    if(project)
    {
        d->root = new QObject(this);
        d->project = project;
        project->setParent(d->root);

        reset();
    }
}

QVariant
ProjectModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (role == Qt::DecorationRole)
    {
        GluonCore::GluonObject* gobj = qobject_cast<GluonCore::GluonObject*>(static_cast<QObject*>(index.internalPointer()));
        if(gobj)
        {
            QVariant filename = gobj->property("file");
            if(filename.isValid())
            {
                QString name = filename.value<QString>();
                return KIcon(KMimeType::iconNameForUrl(KUrl(name)));
            }
            else
                return KIcon("text-x-generic");
        }
    }

    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        GluonCore::GluonObject* gobj = qobject_cast<GluonCore::GluonObject*>(static_cast<QObject*>(index.internalPointer()));
        if (gobj)
            return gobj->name();
    }

    return QVariant();
}

int
ProjectModel::columnCount(const QModelIndex& parent) const
{
    Q_UNUSED(parent)
    return 1;
}

int
ProjectModel::rowCount(const QModelIndex& parent) const
{
    if (parent.column() > 0)
        return 0;

    QObject *parentItem = d->root;
    if (parent.isValid())
        parentItem = static_cast<QObject*>(parent.internalPointer());

    if (parentItem)
    {
        if (qobject_cast<GluonCore::GluonObject*>(parentItem))
        {
            if (qobject_cast<GluonEngine::Scene*>(parentItem))
                return 0;

            int childCount = 0;
            const QObjectList allChildren = parentItem->children();
            foreach(const QObject* child, allChildren)
            {
                if(qobject_cast<const GluonCore::GluonObject* >(child))
                    ++childCount;
            }
            return childCount;
        }
        else
            return parentItem->children().count();
    }

    return 0;
}

QModelIndex
ProjectModel::parent(const QModelIndex& child) const
{
    if (!child.isValid())
        return QModelIndex();

    QObject *childItem = static_cast<QObject*>(child.internalPointer());
    QObject *parentItem = childItem->parent();

    if (parentItem == d->root)
        return QModelIndex();

    QObject *grandParent = parentItem->parent();
    if(grandParent)
    {
        int childCount = -1;
        const QObjectList allChildren = grandParent->children();
        foreach(const QObject* grandChild, allChildren)
        {
            if(qobject_cast<const GluonCore::GluonObject* >(grandChild))
                ++childCount;
            if(grandChild == parentItem)
                return createIndex(childCount, 0, parentItem);
        }
    }
    return createIndex(-1, 0, grandParent);
}

QModelIndex
ProjectModel::index(int row, int column, const QModelIndex& parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    QObject *parentItem = d->root;
    if (parent.isValid())
        parentItem = static_cast<QObject*>(parent.internalPointer());

    int childCount = -1;
    const QObjectList allChildren = parentItem->children();
    foreach(const QObject* child, allChildren)
    {
        if(qobject_cast<const GluonCore::GluonObject*>(child))
            ++childCount;
        if(childCount == row)
            return createIndex(row, column, const_cast<QObject*>(child));
    }

    return QModelIndex();
}

QVariant
ProjectModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    Q_UNUSED(section)
    Q_UNUSED(orientation)
    Q_UNUSED(role)

    return QVariant();
}

Qt::DropActions
ProjectModel::supportedDropActions() const
{
    return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
}

Qt::ItemFlags
ProjectModel::flags(const QModelIndex& index) const
{
    if (index.isValid())
    {
        QObject * obj = static_cast<QObject*>(index.internalPointer());
        //Gluon::Asset *obj = qobject_cast<Gluon::Asset*>();
        // One does not simply drop Assets into Mord...other Assets!
        if (obj->inherits("GluonEngine::Asset"))
        {
            return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
        }
        else
        {
            return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
        }
    }
    else
    {
        return Qt::ItemIsDropEnabled;
    }
}

QStringList
ProjectModel::mimeTypes() const
{
    if (d->acceptedMimeTypes.count() < 1)
    {
        DEBUG_FUNC_NAME
        d->acceptedMimeTypes.append("application/gluoncreator.projectmodel.gluonobject");
        d->acceptedMimeTypes.append("text/uri-list");
        d->acceptedMimeTypes.append(GluonCore::GluonObjectFactory::instance()->objectMimeTypes());
        foreach(const QString &theName, d->acceptedMimeTypes)
        {
            DEBUG_TEXT(QString("%1").arg(theName));
        }
    }

    return d->acceptedMimeTypes;
}

bool
ProjectModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
    Q_UNUSED(row)
    Q_UNUSED(column)
    DEBUG_FUNC_NAME

    if (action == Qt::IgnoreAction)
        return false;

    if (data->hasUrls())
    {
        foreach(const QUrl& theUrl, data->urls())
        {
            ObjectManager::instance()->createNewAsset(theUrl.toLocalFile());
        }
    }
    else if (data->hasFormat("application/gluoncreator.projectmodel.gluonobject"))
    {
    }
    else
    {
    }

    if (data->formats().length() < 1)
        return false;

    return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
}

bool
ProjectModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (index.isValid() && role == Qt::EditRole)
    {
        static_cast<GluonCore::GluonObject*>(index.internalPointer())->setName(value.toString());
        emit dataChanged(index, index);
        return true;
    }
    return false;
}

bool
ProjectModel::removeRows(int row, int count, const QModelIndex& parent)
{
    DEBUG_FUNC_NAME
    if (!parent.isValid())
        return false;

   if(count < 1)
       return false;

    GluonCore::GluonObject * parentObject = static_cast<GluonCore::GluonObject*>(parent.internalPointer());
    DEBUG_TEXT("Object removal begins...");

    beginRemoveRows(parent, row, row + count - 1);
    for (int i = row; i < row + count; ++i)
    {
        DEBUG_TEXT(QString("Removing child at row %1").arg(i));
        GluonCore::GluonObject * child = parentObject->child(row);
        if (parentObject->removeChild(child))
            delete(child);
    }
    endRemoveRows();

    return true;
}

//#include "projectmodel.moc"
<|endoftext|>


<commit_before>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/ConvexHull.h"
#include "cinder/Rand.h"
#include "cinder/params/Params.h"
#include "cinder/Font.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class ConvexHullApp : public App {
  public:
	void setup();
	void makeNewLetter();
	void mouseDown( MouseEvent event );
	void mouseDrag( MouseEvent event );
	void update();
	void draw();

	bool				mUsingShape;
	vector<vec2>		mPoints;
	Shape2d				mShape;

	PolyLine2f			mConvexHull;

	params::InterfaceGlRef	mParams;
};

void ConvexHullApp::setup()
{
	mUsingShape = true;
	mParams = params::InterfaceGl::create( "App parameters", ivec2( 180, 100 ) );
	mParams->addParam( "Use Glyph", &mUsingShape );
	mParams->addButton( "Clear Points", [&] { mPoints.clear(); } );

	if( mUsingShape )
		makeNewLetter();
}

void ConvexHullApp::makeNewLetter()
{
	Font arial( "Times", 512 );
	mShape = arial.getGlyphShape( arial.getGlyphChar( '!' + randInt( 92 ) ) );
	MatrixAffine2f transform = MatrixAffine2f::makeTranslate( vec2( 100, getWindowHeight() - 100 ) );
	mShape.transform( transform );
}

void ConvexHullApp::update()
{
	// this should be cached but doesn't matter for this demo
	if( mUsingShape )
		mConvexHull = calcConvexHull( mShape );
	else
		mConvexHull = calcConvexHull( mPoints );
}

void ConvexHullApp::mouseDown( MouseEvent event )
{
	if( mUsingShape )
		makeNewLetter();
	else
		mPoints.push_back( event.getPos() );
}

void ConvexHullApp::mouseDrag( MouseEvent event )
{
	if( mUsingShape )
		makeNewLetter();
	else
		mPoints.back() = event.getPos();
}

void ConvexHullApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) );
	gl::enableAlphaBlending();

	// draw solid convex hull
	gl::color( ColorA( 0.8f, 0, 1.0f, 0.2f ) );
	gl::drawSolid( mConvexHull );
	gl::color( ColorA( 0.8f, 0, 1.0f, 0.8f ) );
	gl::draw( mConvexHull );

	// draw convex hull points
	gl::color( Color( 0.0f, 0, 1.0f ) );
	for( auto ptIt = mConvexHull.begin(); ptIt != mConvexHull.end(); ++ptIt ) {
		gl::drawSolidCircle( *ptIt, 4 );
	}

	gl::color( ColorA( 1.0f, 0.8f, 0, 0.6f ) );
	if( mUsingShape ) {
		gl::draw( mShape );
	}
	else {
		for( auto ptIt = mPoints.begin(); ptIt != mPoints.end(); ++ptIt ) {
			gl::drawSolidCircle( *ptIt, 3 );
		}
	}

	mParams->draw();
}

CINDER_APP( ConvexHullApp, RendererGl )<commit_msg>glNext update for ConvexHull sample<commit_after>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/ConvexHull.h"
#include "cinder/Rand.h"
#include "cinder/params/Params.h"
#include "cinder/Font.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class ConvexHullApp : public App {
  public:
	void setup();
	void makeNewLetter();
	void mouseDown( MouseEvent event );
	void mouseDrag( MouseEvent event );
	void update();
	void draw();

	bool				mUsingShape;
	vector<vec2>		mPoints;
	Shape2d				mShape;

	PolyLine2f			mConvexHull;

	params::InterfaceGlRef	mParams;
};

void ConvexHullApp::setup()
{
	mUsingShape = true;
	mParams = params::InterfaceGl::create( "App parameters", ivec2( 180, 100 ) );
	mParams->addParam( "Use Glyph", &mUsingShape );
	mParams->addButton( "Clear Points", [&] { mPoints.clear(); } );

	if( mUsingShape )
		makeNewLetter();
}

void ConvexHullApp::makeNewLetter()
{
	Font arial( "Times", 512 );
	mShape = arial.getGlyphShape( arial.getGlyphChar( '!' + randInt( 92 ) ) );
//	mat2 transform = MatrixAffine2f::makeTranslate( vec2( 100, getWindowHeight() - 100 ) );
	mShape.transform( translate( mat3(), vec2( 100, getWindowHeight() - 100 ) ) );
}

void ConvexHullApp::update()
{
	// this should be cached but doesn't matter for this demo
	if( mUsingShape )
		mConvexHull = calcConvexHull( mShape );
	else
		mConvexHull = calcConvexHull( mPoints );
}

void ConvexHullApp::mouseDown( MouseEvent event )
{
	if( mUsingShape )
		makeNewLetter();
	else
		mPoints.push_back( event.getPos() );
}

void ConvexHullApp::mouseDrag( MouseEvent event )
{
	if( mUsingShape )
		makeNewLetter();
	else
		mPoints.back() = event.getPos();
}

void ConvexHullApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) );
	gl::enableAlphaBlending();

	// draw solid convex hull
	gl::color( ColorA( 0.8f, 0, 1.0f, 0.2f ) );
	gl::drawSolid( mConvexHull );
	gl::color( ColorA( 0.8f, 0, 1.0f, 0.8f ) );
	gl::draw( mConvexHull );

	// draw convex hull points
	gl::color( Color( 0.0f, 0, 1.0f ) );
	for( auto ptIt = mConvexHull.begin(); ptIt != mConvexHull.end(); ++ptIt ) {
		gl::drawSolidCircle( *ptIt, 4 );
	}

	gl::color( ColorA( 1.0f, 0.8f, 0, 0.6f ) );
	if( mUsingShape ) {
		gl::draw( mShape );
	}
	else {
		for( auto ptIt = mPoints.begin(); ptIt != mPoints.end(); ++ptIt ) {
			gl::drawSolidCircle( *ptIt, 3 );
		}
	}

	mParams->draw();
}

CINDER_APP( ConvexHullApp, RendererGl )<|endoftext|>


<commit_before>#ifndef K3_RUNTIME_MESSAGEPROC_H
#define K3_RUNTIME_MESSAGEPROC_H

#include <Dispatch.hpp>

namespace K3
{
  //-------------------
  // Message processor

  enum class LoopStatus { Continue, Error, Done };

  // template <typename Error, typename Result>
  // class MPStatus {
    // public:
      // LoopStatus tag;
      // Error error;
      // Result result;
  // };

  using EnvStrFunction = std::function<std::map<std::string,std::string>()>;

  class MessageProcessor {

    public:
      MessageProcessor(EnvStrFunction f): _status(LoopStatus::Continue), _get_env(f) {}
      virtual void initialize() {}
      virtual void finalize() {}
      virtual LoopStatus process( Message msg) = 0;
      LoopStatus status() { return _status; };
      std::map<std::string, std::string> get_env() { auto x = _get_env(); return x;};
    private:
      LoopStatus _status;
      EnvStrFunction _get_env;

  };

  using MPStatus = LoopStatus;

  using NativeMessageProcessor = MessageProcessor;

  template <class E>
  class VirtualizedMessageProcessor: public MessageProcessor {
    public:
      VirtualizedMessageProcessor(E e, EnvStrFunction f): MessageProcessor(f), env(e) {}
    private:
      E env;
  };

  // Message Processor used by generated code. Processing is done by dispatch messages using a
  // generated table of triggers. The trigger wrapper functions perform the deserialization of the
  // message payload themeselves.
  class DispatchMessageProcessor : public NativeMessageProcessor {
    public:
      DispatchMessageProcessor(TriggerDispatch td)
        : NativeMessageProcessor(empty_map), table(td)
      {}

      DispatchMessageProcessor(TriggerDispatch td, EnvStrFunction f)
        : NativeMessageProcessor(f), table(td)
      {}

      LoopStatus process(Message msg)
      {
        TriggerWrapper tw;

        // Look the trigger up in the dispatch table, error out if not present.
        try {
            tw = table.at(msg.id());
        } catch (std::out_of_range e) {
            return LoopStatus::Error;
        }

        // Call the trigger.
        tw(msg.contents());

        // Message was processed, signal the engine to continue.
        // TODO: Propagate trigger errors to engine, K3 error semantics?
        return LoopStatus::Continue;
      }

    private:
      TriggerDispatch table;
      static std::map<std::string, std::string> empty_map() { return std::map<std::string, std::string>(); };
    };
}

#endif
<commit_msg>Implement virtualizing message processors.<commit_after>#ifndef K3_RUNTIME_MESSAGEPROC_H
#define K3_RUNTIME_MESSAGEPROC_H

#include <map>
#include <string>

#include "Dispatch.hpp"

namespace K3
{
  //-------------------
  // Message processor

  enum class LoopStatus { Continue, Error, Done };

  // template <typename Error, typename Result>
  // class MPStatus {
    // public:
      // LoopStatus tag;
      // Error error;
      // Result result;
  // };

  using EnvStrFunction = std::function<std::map<std::string,std::string>()>;

  class MessageProcessor {
    public:
      MessageProcessor(): _status(LoopStatus::Continue) {}
      virtual void initialize() {}
      virtual void finalize() {}
      virtual LoopStatus process( Message msg) = 0;
      LoopStatus status() { return _status; };

      virtual map<string, string> bindings(Address) = 0;
    private:
      LoopStatus _status;
  };

  using MPStatus = LoopStatus;

  class NativeMessageProcessor: public MessageProcessor {
   public:
    NativeMessageProcessor(EnvStrFunction get_env): MessageProcessor(),  _get_env(get_env) {}

    map<string, string> bindings(Address) override {
      return _get_env();
    }

   private:
    EnvStrFunction _get_env;
  };

  // Message Processor used by generated code. Processing is done by dispatch messages using a
  // generated table of triggers. The trigger wrapper functions perform the deserialization of the
  // message payload themeselves.
  class DispatchMessageProcessor : public NativeMessageProcessor {
    public:
      DispatchMessageProcessor(TriggerDispatch td)
        : NativeMessageProcessor(empty_map), table(td)
      {}

      DispatchMessageProcessor(TriggerDispatch td, EnvStrFunction f)
        : NativeMessageProcessor(f), table(td)
      {}

      LoopStatus process(Message msg)
      {
        TriggerWrapper tw;

        // Look the trigger up in the dispatch table, error out if not present.
        try {
            tw = table.at(msg.id());
        } catch (std::out_of_range e) {
            return LoopStatus::Error;
        }

        // Call the trigger.
        tw(msg.contents());

        // Message was processed, signal the engine to continue.
        // TODO: Propagate trigger errors to engine, K3 error semantics?
        return LoopStatus::Continue;
      }

    private:
      TriggerDispatch table;
      static std::map<std::string, std::string> empty_map() { return std::map<std::string, std::string>(); };
    };

  class Engine;

  class __program_context {
   public:
    __program_context(Engine& e): __engine(e) {}

    virtual void __dispatch(std::string) = 0;
    virtual std::map<std::string, std::string> __prettify() = 0;
    virtual void __patch(std::string) = 0;

   protected:
    Engine& __engine;
  };

  class virtualizing_message_processor: public MessageProcessor {
   public:
    virtualizing_message_processor(): MessageProcessor() {}

    virtualizing_message_processor(std::map<Address, shared_ptr<__program_context>> m):
      MessageProcessor(), contexts(m) {}

    void add_context(Address a, std::shared_ptr<__program_context> p) {
      contexts[a] = p;
    }

    LoopStatus process(Message msg) {
      try {
        contexts[msg.address()]->__dispatch(msg.contents());
      } catch(std::out_of_range e) {
        return LoopStatus::Error;
      }

      return LoopStatus::Continue;
    }

    std::map<std::string, std::string> bindings(Address a) override {
      return contexts[a]->__prettify();
    }

   private:
    std::map<Address, shared_ptr<__program_context>> contexts;
  };
}

#endif
<|endoftext|>


<commit_before>#include <Graphics.h>
#include <Surface.h>
#include <directfb.h>

namespace nme
{

// --- HardwareContext -----------------------------

class DirectFBHardwareContext : public HardwareContext
{
public:
   IDirectFB *mDirectFB;
   IDirectFBSurface *mPrimarySurface;
   int mWidth;
   int mHeight;

   DirectFBHardwareContext(IDirectFB *inDirectFB, IDirectFBSurface *inSurface)
   {
      mDirectFB = inDirectFB;
      mPrimarySurface = inSurface;
      mWidth = mHeight = 0;
   }

   void SetWindowSize(int inWidth, int inHeight)
   {
      mWidth = inWidth;
      mHeight = inHeight;
   }

   void SetQuality(StageQuality inQuality) {}

   void BeginRender(const Rect &inRect,bool inForHitTest)
   {
      mPrimarySurface->Clear(mPrimarySurface, 0xFF, 0xFF, 0xFF, 0xFF);
   }

   void EndRender()
   {
      mPrimarySurface->Flip(mPrimarySurface, NULL, (DFBSurfaceFlipFlags)0);
   }

   void SetViewport(const Rect &inRect) {}
   void Clear(uint32 inColour,const Rect *inRect=0) {}
   void Flip() {}
   void DestroyNativeTexture(void *) {}

   int Width() const { return mWidth; }
   int Height() const { return mHeight; }

   class Texture *CreateTexture(class Surface *inSurface, unsigned int inFlags);
   void Render(const RenderState &inState, const HardwareCalls &inCalls) {}
   void BeginBitmapRender(Surface *inSurface,uint32 inTint, bool inRepeat, bool inSmooth) {}
   void RenderBitmap(const Rect &inSrc, int inX, int inY) {}
   void EndBitmapRender() {}
};

class DirectFBTexture : public Texture
{
public:
   unsigned int flags;
   int          width;
   int          height;

   DirectFBTexture(DirectFBHardwareContext *inContext, Surface *inSurface, unsigned int inFlags)
   {

   }

   ~DirectFBTexture()
   {

   }

   void Bind(class Surface *inSurface, int inSlot) {}
   void BindFlags(bool inRepeat, bool inSmooth) {}

   UserPoint PixelToTex(const UserPoint &inPixels)
   {
      return UserPoint(inPixels.x/width, inPixels.y/height);
   }

   UserPoint TexToPaddedTex(const UserPoint &inPixels)
   {
      return inPixels;
   }
};

class Texture *DirectFBHardwareContext::CreateTexture(class Surface *inSurface, unsigned int inFlags)
{
   return new DirectFBTexture(this, inSurface, inFlags);
}

HardwareContext *HardwareContext::current = 0;

HardwareContext *HardwareContext::CreateDirectFB(void *inDirectFB, void *inSurface)
{
   return new DirectFBHardwareContext((IDirectFB*)inDirectFB, (IDirectFBSurface*)inSurface);
}

HardwareContext *HardwareContext::CreateOpenGL(void *inWindow, void *inGLCtx, bool shaders)
{
   return NULL;
}

// --- Hardware Jobs ---------------------------------------------------------------------

class HardwareRenderer : public Renderer
{
public:
   HardwareRenderer(const GraphicsJob &inJob, const GraphicsPath &inPath, HardwareContext &inHardware)
   {
      mJob = &inJob;
      mPath = &inPath;
      mContext = &inHardware;

      DirectFBHardwareContext *context = (DirectFBHardwareContext*)&inHardware;
      mPrimarySurface = context->mPrimarySurface;
   }

   void Destroy() {};

   bool Render(const RenderTarget &inTarget, const RenderState &inState)
   {
      IDirectFBSurface *bitmapSurface = NULL;

      if (mJob->mIsTileJob)
      {
         printf("Render tile\n");
      }
      else if (mJob->mFill)
      {
         GraphicsSolidFill *solid = mJob->mFill->AsSolidFill();
         if (solid)
         {
            mPrimarySurface->SetColor(mPrimarySurface, solid->mRGB.c0, solid->mRGB.c1, solid->mRGB.c2, solid->mRGB.a);
         }
         else
         {
            GraphicsGradientFill *grad = mJob->mFill->AsGradientFill();
            if (grad)
            {

            }
            else
            {
               GraphicsBitmapFill *bmp = mJob->mFill->AsBitmapFill();
               Surface *surface = bmp->bitmapData->IncRef();

               DFBSurfaceDescription dsc;
               dsc.width = surface->Width();
               dsc.height = surface->Height();
               dsc.flags = (DFBSurfaceDescriptionFlags)(DSDESC_HEIGHT | DSDESC_WIDTH | DSDESC_PREALLOCATED | DSDESC_PIXELFORMAT);
               dsc.caps = DSCAPS_NONE;
               dsc.pixelformat = DSPF_ARGB;
               dsc.preallocated[0].data = (void *)surface->GetBase();
               dsc.preallocated[0].pitch = surface->GetStride();
               dsc.preallocated[1].data = NULL;
               dsc.preallocated[1].pitch = 0;

               DirectFBHardwareContext *context = (DirectFBHardwareContext*)mContext;
               context->mDirectFB->CreateSurface(context->mDirectFB, &dsc, &bitmapSurface);
             }
          }
      }

      if (mJob->mTriangles)
      {
         printf("Render triangle\n");
      }
      else if (mJob->mIsPointJob)
      {
         printf("Render point\n");
      }
      else if (mJob->mStroke)
      {
         printf("Render stroke\n");
      }
      else
      {
         const uint8* inCommands = (const uint8*)&mPath->commands[mJob->mCommand0];
         UserPoint *point = (UserPoint *)&mPath->data[mJob->mData0];

         float x0, y0, x1, y1;

         for(int i=0; i< mJob->mCommandCount; i++)
         {
            switch(inCommands[i])
            {
               case pcBeginAt:
                  //printf("begin at\n");
                  // fallthrough
               case pcMoveTo:
                  //printf("move to\n");
                  //printf("move to: %d %d \n", point->x, point->y);
                  x0 = point->x;
                  y0 = point->y;
                  point++;
                  break;

               case pcLineTo:
                  if (point->x > x1) x1 = point->x;
                  if (point->x < x0) x0 = point->x;
                  if (point->y > y1) y1 = point->y;
                  if (point->y < y0) y0 = point->y;
                  point++;
                  break;

               case pcCurveTo:
                  //printf("curve to\n");
                  point++;
                  break;
            }
         }

         if (bitmapSurface)
         {
            mPrimarySurface->Blit(mPrimarySurface, bitmapSurface, NULL, inState.mTransform.mMatrix->mtx, inState.mTransform.mMatrix->mty);
         }
         else
         {
            mPrimarySurface->FillRectangle(mPrimarySurface, inState.mTransform.mMatrix->mtx + x0, inState.mTransform.mMatrix->mty + y0, x1 - x0, y1 - y0);
         }
      }
      return true;
   };

   bool GetExtent(const Transform &inTransform,Extent2DF &ioExtent, bool inIncludeStroke) { return false; };
   bool Hits(const RenderState &inState) { return false; }

private:
   const GraphicsJob *mJob;
   const GraphicsPath *mPath;
   HardwareContext *mContext;
   IDirectFBSurface *mPrimarySurface;
};

Renderer *Renderer::CreateHardware(const GraphicsJob &inJob, const GraphicsPath &inPath, HardwareContext &inHardware)
{
   return new HardwareRenderer(inJob, inPath, inHardware);
}

// --- HardwareArrays ---------------------------------------------------------------------

HardwareArrays::HardwareArrays(Surface *inSurface,unsigned int inFlags)
{
   mFlags = inFlags;
   mSurface = inSurface;
   if (inSurface)
      inSurface->IncRef();
}

HardwareArrays::~HardwareArrays()
{
   if (mSurface)
      mSurface->DecRef();
}

bool HardwareArrays::ColourMatch(bool inWantColour)
{
   if (mVertices.empty())
      return true;
   return mColours.empty() != inWantColour;
}

// --- HardwareData ---------------------------------------------------------------------
HardwareData::~HardwareData()
{
   mCalls.DeleteAll();
}

HardwareArrays &HardwareData::GetArrays(Surface *inSurface,bool inWithColour,unsigned int inFlags)
{
   if (mCalls.empty() || mCalls.last()->mSurface != inSurface ||
           !mCalls.last()->ColourMatch(inWithColour) ||
           mCalls.last()->mFlags != inFlags )
   {
       HardwareArrays *arrays = new HardwareArrays(inSurface,inFlags);
       mCalls.push_back(arrays);
   }

   return *mCalls.last();
}

// --- Texture -----------------------------
void Texture::Dirty(const Rect &inRect)
{
   if (!mDirtyRect.HasPixels())
      mDirtyRect = inRect;
   else
      mDirtyRect = mDirtyRect.Union(inRect);
}

// --- HardwareContext -----------------------------

// Cache line thickness transforms...
static Matrix sLastMatrix;
double sLineScaleV = -1;
double sLineScaleH = -1;
double sLineScaleNormal = -1;

bool HardwareContext::Hits(const RenderState &inState, const HardwareCalls &inCalls )
{
   if (inState.mClipRect.w!=1 || inState.mClipRect.h!=1)
      return false;

   UserPoint screen(inState.mClipRect.x, inState.mClipRect.y);
   UserPoint pos = inState.mTransform.mMatrix->ApplyInverse(screen);

   if (sLastMatrix!=*inState.mTransform.mMatrix)
   {
      sLastMatrix=*inState.mTransform.mMatrix;
      sLineScaleV = -1;
      sLineScaleH = -1;
      sLineScaleNormal = -1;
   }

    for(int c=0;c<inCalls.size();c++)
   {
      HardwareArrays &arrays = *inCalls[c];
      Vertices &vert = arrays.mVertices;

      // TODO: include extent in HardwareArrays

      DrawElements &elements = arrays.mElements;
      for(int e=0;e<elements.size();e++)
      {
         DrawElement draw = elements[e];

         if (draw.mPrimType == ptLineStrip)
         {
            if ( draw.mCount < 2 || draw.mWidth==0)
               continue;

            double width = 1;
            Matrix &m = sLastMatrix;
            switch(draw.mScaleMode)
            {
               case ssmNone: width = draw.mWidth; break;
               case ssmNormal:
               case ssmOpenGL:
                  if (sLineScaleNormal<0)
                     sLineScaleNormal =
                        sqrt( 0.5*( m.m00*m.m00 + m.m01*m.m01 +
                                    m.m10*m.m10 + m.m11*m.m11 ) );
                  width = draw.mWidth*sLineScaleNormal;
                  break;
               case ssmVertical:
                  if (sLineScaleV<0)
                     sLineScaleV =
                        sqrt( m.m00*m.m00 + m.m01*m.m01 );
                  width = draw.mWidth*sLineScaleV;
                  break;

               case ssmHorizontal:
                  if (sLineScaleH<0)
                     sLineScaleH =
                        sqrt( m.m10*m.m10 + m.m11*m.m11 );
                  width = draw.mWidth*sLineScaleH;
                  break;
            }

            double x0 = pos.x - width;
            double x1 = pos.x + width;
            double y0 = pos.y - width;
            double y1 = pos.y + width;
            double w2 = width*width;

            UserPoint *v = &vert[ draw.mFirst ];
            UserPoint p0 = *v;

            int prev = 0;
            if (p0.x<x0) prev |= 0x01;
            if (p0.x>x1) prev |= 0x02;
            if (p0.y<y0) prev |= 0x04;
            if (p0.y>y1) prev |= 0x08;
            if (prev==0 && pos.Dist2(p0)<=w2)
               return true;
            for(int i=1;i<draw.mCount;i++)
            {
               UserPoint p = v[i];
               int flags = 0;
               if (p.x<x0) flags |= 0x01;
               if (p.x>x1) flags |= 0x02;
               if (p.y<y0) flags |= 0x04;
               if (p.y>y1) flags |= 0x08;
               if (flags==0 && pos.Dist2(p)<=w2)
                  return true;
               if ( !(flags & prev) )
               {
                  // Line *may* pass though the point...
                  UserPoint vec = p-p0;
                  double len = sqrt(vec.x*vec.x + vec.y*vec.y);
                  if (len>0)
                  {
                     double a = vec.Dot(pos-p0)/len;
                     if (a>0 && a<1)
                     {
                        if ( (p0 + vec*a).Dist2(pos) < w2 )
                           return true;
                     }
                  }
               }
               prev = flags;
               p0 = p;
            }
         }
         else if (draw.mPrimType == ptTriangleFan)
         {
            if (draw.mCount<3)
               continue;
            UserPoint *v = &vert[ draw.mFirst ];
            UserPoint p0 = *v;
            int count_left = 0;
            for(int i=1;i<=draw.mCount;i++)
            {
               UserPoint p = v[i%draw.mCount];
               if ( (p.y<pos.y) != (p0.y<pos.y) )
               {
                  // Crosses, but to the left?
                  double ratio = (pos.y-p0.y)/(p.y-p0.y);
                  double x = p0.x + (p.x-p0.x) * ratio;
                  if (x<pos.x)
                     count_left++;
               }
               p0 = p;
            }
            if (count_left & 1)
               return true;
         }
         else if (draw.mPrimType == ptTriangles)
         {
            if (draw.mCount<3)
               continue;
            UserPoint *v = &vert[ draw.mFirst ];

			   int numTriangles = draw.mCount / 3;

            for(int i=0;i<numTriangles;i++)
            {
               UserPoint base = *v++;
               bool bgx = pos.x>base.x;
               if ( bgx!=(pos.x>v[0].x) || bgx!=(pos.x>v[1].x) )
               {
                  bool bgy = pos.y>base.y;
                  if ( bgy!=(pos.y>v[0].y) || bgy!=(pos.y>v[1].y) )
                  {
                     UserPoint v0 = v[0] - base;
                     UserPoint v1 = v[1] - base;
                     UserPoint v2 = pos - base;
                     double dot00 = v0.Dot(v0);
                     double dot01 = v0.Dot(v1);
                     double dot02 = v0.Dot(v2);
                     double dot11 = v1.Dot(v1);
                     double dot12 = v1.Dot(v2);

                     // Compute barycentric coordinates
                     double denom = (dot00 * dot11 - dot01 * dot01);
                     if (denom!=0)
                     {
                        denom = 1 / denom;
                        double u = (dot11 * dot02 - dot01 * dot12) * denom;
                        if (u>=0)
                        {
                           double v = (dot00 * dot12 - dot01 * dot02) * denom;

                           // Check if point is in triangle
                           if ( (v >= 0) && (u + v < 1) )
                              return true;
                        }
                     }
                  }
               }
               v+=2;
            }
         }
      }
   }

   return false;
}

} // end namespace nme

<commit_msg>Fix DirectFB bitmap color order<commit_after>#include <Graphics.h>
#include <Surface.h>
#include <directfb.h>

namespace nme
{

// --- HardwareContext -----------------------------

class DirectFBHardwareContext : public HardwareContext
{
public:
   IDirectFB *mDirectFB;
   IDirectFBSurface *mPrimarySurface;
   int mWidth;
   int mHeight;

   DirectFBHardwareContext(IDirectFB *inDirectFB, IDirectFBSurface *inSurface)
   {
      mDirectFB = inDirectFB;
      mPrimarySurface = inSurface;
      mWidth = mHeight = 0;
   }

   void SetWindowSize(int inWidth, int inHeight)
   {
      mWidth = inWidth;
      mHeight = inHeight;
   }

   void SetQuality(StageQuality inQuality) {}

   void BeginRender(const Rect &inRect,bool inForHitTest)
   {
      mPrimarySurface->Clear(mPrimarySurface, 0xFF, 0xFF, 0xFF, 0xFF);
   }

   void EndRender()
   {
      mPrimarySurface->Flip(mPrimarySurface, NULL, (DFBSurfaceFlipFlags)0);
   }

   void SetViewport(const Rect &inRect) {}
   void Clear(uint32 inColour,const Rect *inRect=0) {}
   void Flip() {}
   void DestroyNativeTexture(void *) {}

   int Width() const { return mWidth; }
   int Height() const { return mHeight; }

   class Texture *CreateTexture(class Surface *inSurface, unsigned int inFlags);
   void Render(const RenderState &inState, const HardwareCalls &inCalls) {}
   void BeginBitmapRender(Surface *inSurface,uint32 inTint, bool inRepeat, bool inSmooth) {}
   void RenderBitmap(const Rect &inSrc, int inX, int inY) {}
   void EndBitmapRender() {}
};

class DirectFBTexture : public Texture
{
public:
   unsigned int flags;
   int          width;
   int          height;

   DirectFBTexture(DirectFBHardwareContext *inContext, Surface *inSurface, unsigned int inFlags)
   {

   }

   ~DirectFBTexture()
   {

   }

   void Bind(class Surface *inSurface, int inSlot) {}
   void BindFlags(bool inRepeat, bool inSmooth) {}

   UserPoint PixelToTex(const UserPoint &inPixels)
   {
      return UserPoint(inPixels.x/width, inPixels.y/height);
   }

   UserPoint TexToPaddedTex(const UserPoint &inPixels)
   {
      return inPixels;
   }
};

class Texture *DirectFBHardwareContext::CreateTexture(class Surface *inSurface, unsigned int inFlags)
{
   return new DirectFBTexture(this, inSurface, inFlags);
}

HardwareContext *HardwareContext::current = 0;

HardwareContext *HardwareContext::CreateDirectFB(void *inDirectFB, void *inSurface)
{
   return new DirectFBHardwareContext((IDirectFB*)inDirectFB, (IDirectFBSurface*)inSurface);
}

HardwareContext *HardwareContext::CreateOpenGL(void *inWindow, void *inGLCtx, bool shaders)
{
   return NULL;
}

// --- Hardware Jobs ---------------------------------------------------------------------

class HardwareRenderer : public Renderer
{
public:
   HardwareRenderer(const GraphicsJob &inJob, const GraphicsPath &inPath, HardwareContext &inHardware)
   {
      mJob = &inJob;
      mPath = &inPath;
      mContext = &inHardware;

      DirectFBHardwareContext *context = (DirectFBHardwareContext*)&inHardware;
      mPrimarySurface = context->mPrimarySurface;
   }

   void Destroy() {};

   bool Render(const RenderTarget &inTarget, const RenderState &inState)
   {
      IDirectFBSurface *bitmapSurface = NULL;

      if (mJob->mIsTileJob)
      {
         printf("Render tile\n");
      }
      else if (mJob->mFill)
      {
         GraphicsSolidFill *solid = mJob->mFill->AsSolidFill();
         if (solid)
         {
            mPrimarySurface->SetColor(mPrimarySurface, solid->mRGB.c0, solid->mRGB.c1, solid->mRGB.c2, solid->mRGB.a);
         }
         else
         {
            GraphicsGradientFill *grad = mJob->mFill->AsGradientFill();
            if (grad)
            {

            }
            else
            {
               GraphicsBitmapFill *bmp = mJob->mFill->AsBitmapFill();
               Surface *surface = bmp->bitmapData->IncRef();

               DFBSurfaceDescription dsc;
               dsc.width = surface->Width();
               dsc.height = surface->Height();
               dsc.flags = (DFBSurfaceDescriptionFlags)(DSDESC_HEIGHT | DSDESC_WIDTH | DSDESC_PREALLOCATED | DSDESC_PIXELFORMAT);
               dsc.caps = DSCAPS_NONE;
               dsc.pixelformat = DSPF_ARGB;

               uint8 *data = (uint8 *)malloc(surface->Width()*surface->Height()*4);

               for (int y=0;y<surface->Height();y++)
               {
                  const uint8 *source = surface->Row(y);
                  uint8 *dest = data + (y*surface->GetStride());
                  for (int x=0;x<surface->Width();x++)
                  {
                     dest[0] = source[2];
                     dest[1] = source[1];
                     dest[2] = source[0];
                     dest[3] = source[3];
                     dest += 4;
                     source += 4;
                  }
               }

               dsc.preallocated[0].data = data;
               dsc.preallocated[0].pitch = surface->GetStride();
               dsc.preallocated[1].data = NULL;
               dsc.preallocated[1].pitch = 0;

               DirectFBHardwareContext *context = (DirectFBHardwareContext*)mContext;
               context->mDirectFB->CreateSurface(context->mDirectFB, &dsc, &bitmapSurface);
             }
          }
      }

      if (mJob->mTriangles)
      {
         printf("Render triangle\n");
      }
      else if (mJob->mIsPointJob)
      {
         printf("Render point\n");
      }
      else if (mJob->mStroke)
      {
         printf("Render stroke\n");
      }
      else
      {
         const uint8* inCommands = (const uint8*)&mPath->commands[mJob->mCommand0];
         UserPoint *point = (UserPoint *)&mPath->data[mJob->mData0];

         float x0, y0, x1, y1;

         for(int i=0; i< mJob->mCommandCount; i++)
         {
            switch(inCommands[i])
            {
               case pcBeginAt:
                  //printf("begin at\n");
                  // fallthrough
               case pcMoveTo:
                  //printf("move to\n");
                  //printf("move to: %d %d \n", point->x, point->y);
                  x0 = point->x;
                  y0 = point->y;
                  point++;
                  break;

               case pcLineTo:
                  if (point->x > x1) x1 = point->x;
                  if (point->x < x0) x0 = point->x;
                  if (point->y > y1) y1 = point->y;
                  if (point->y < y0) y0 = point->y;
                  point++;
                  break;

               case pcCurveTo:
                  //printf("curve to\n");
                  point++;
                  break;
            }
         }

         if (bitmapSurface)
         {
            mPrimarySurface->Blit(mPrimarySurface, bitmapSurface, NULL, inState.mTransform.mMatrix->mtx, inState.mTransform.mMatrix->mty);
         }
         else
         {
            mPrimarySurface->FillRectangle(mPrimarySurface, inState.mTransform.mMatrix->mtx + x0, inState.mTransform.mMatrix->mty + y0, x1 - x0, y1 - y0);
         }
      }
      return true;
   };

   bool GetExtent(const Transform &inTransform,Extent2DF &ioExtent, bool inIncludeStroke) { return false; };
   bool Hits(const RenderState &inState) { return false; }

private:
   const GraphicsJob *mJob;
   const GraphicsPath *mPath;
   HardwareContext *mContext;
   IDirectFBSurface *mPrimarySurface;
};

Renderer *Renderer::CreateHardware(const GraphicsJob &inJob, const GraphicsPath &inPath, HardwareContext &inHardware)
{
   return new HardwareRenderer(inJob, inPath, inHardware);
}

// --- HardwareArrays ---------------------------------------------------------------------

HardwareArrays::HardwareArrays(Surface *inSurface,unsigned int inFlags)
{
   mFlags = inFlags;
   mSurface = inSurface;
   if (inSurface)
      inSurface->IncRef();
}

HardwareArrays::~HardwareArrays()
{
   if (mSurface)
      mSurface->DecRef();
}

bool HardwareArrays::ColourMatch(bool inWantColour)
{
   if (mVertices.empty())
      return true;
   return mColours.empty() != inWantColour;
}

// --- HardwareData ---------------------------------------------------------------------
HardwareData::~HardwareData()
{
   mCalls.DeleteAll();
}

HardwareArrays &HardwareData::GetArrays(Surface *inSurface,bool inWithColour,unsigned int inFlags)
{
   if (mCalls.empty() || mCalls.last()->mSurface != inSurface ||
           !mCalls.last()->ColourMatch(inWithColour) ||
           mCalls.last()->mFlags != inFlags )
   {
       HardwareArrays *arrays = new HardwareArrays(inSurface,inFlags);
       mCalls.push_back(arrays);
   }

   return *mCalls.last();
}

// --- Texture -----------------------------
void Texture::Dirty(const Rect &inRect)
{
   if (!mDirtyRect.HasPixels())
      mDirtyRect = inRect;
   else
      mDirtyRect = mDirtyRect.Union(inRect);
}

// --- HardwareContext -----------------------------

// Cache line thickness transforms...
static Matrix sLastMatrix;
double sLineScaleV = -1;
double sLineScaleH = -1;
double sLineScaleNormal = -1;

bool HardwareContext::Hits(const RenderState &inState, const HardwareCalls &inCalls )
{
   if (inState.mClipRect.w!=1 || inState.mClipRect.h!=1)
      return false;

   UserPoint screen(inState.mClipRect.x, inState.mClipRect.y);
   UserPoint pos = inState.mTransform.mMatrix->ApplyInverse(screen);

   if (sLastMatrix!=*inState.mTransform.mMatrix)
   {
      sLastMatrix=*inState.mTransform.mMatrix;
      sLineScaleV = -1;
      sLineScaleH = -1;
      sLineScaleNormal = -1;
   }

    for(int c=0;c<inCalls.size();c++)
   {
      HardwareArrays &arrays = *inCalls[c];
      Vertices &vert = arrays.mVertices;

      // TODO: include extent in HardwareArrays

      DrawElements &elements = arrays.mElements;
      for(int e=0;e<elements.size();e++)
      {
         DrawElement draw = elements[e];

         if (draw.mPrimType == ptLineStrip)
         {
            if ( draw.mCount < 2 || draw.mWidth==0)
               continue;

            double width = 1;
            Matrix &m = sLastMatrix;
            switch(draw.mScaleMode)
            {
               case ssmNone: width = draw.mWidth; break;
               case ssmNormal:
               case ssmOpenGL:
                  if (sLineScaleNormal<0)
                     sLineScaleNormal =
                        sqrt( 0.5*( m.m00*m.m00 + m.m01*m.m01 +
                                    m.m10*m.m10 + m.m11*m.m11 ) );
                  width = draw.mWidth*sLineScaleNormal;
                  break;
               case ssmVertical:
                  if (sLineScaleV<0)
                     sLineScaleV =
                        sqrt( m.m00*m.m00 + m.m01*m.m01 );
                  width = draw.mWidth*sLineScaleV;
                  break;

               case ssmHorizontal:
                  if (sLineScaleH<0)
                     sLineScaleH =
                        sqrt( m.m10*m.m10 + m.m11*m.m11 );
                  width = draw.mWidth*sLineScaleH;
                  break;
            }

            double x0 = pos.x - width;
            double x1 = pos.x + width;
            double y0 = pos.y - width;
            double y1 = pos.y + width;
            double w2 = width*width;

            UserPoint *v = &vert[ draw.mFirst ];
            UserPoint p0 = *v;

            int prev = 0;
            if (p0.x<x0) prev |= 0x01;
            if (p0.x>x1) prev |= 0x02;
            if (p0.y<y0) prev |= 0x04;
            if (p0.y>y1) prev |= 0x08;
            if (prev==0 && pos.Dist2(p0)<=w2)
               return true;
            for(int i=1;i<draw.mCount;i++)
            {
               UserPoint p = v[i];
               int flags = 0;
               if (p.x<x0) flags |= 0x01;
               if (p.x>x1) flags |= 0x02;
               if (p.y<y0) flags |= 0x04;
               if (p.y>y1) flags |= 0x08;
               if (flags==0 && pos.Dist2(p)<=w2)
                  return true;
               if ( !(flags & prev) )
               {
                  // Line *may* pass though the point...
                  UserPoint vec = p-p0;
                  double len = sqrt(vec.x*vec.x + vec.y*vec.y);
                  if (len>0)
                  {
                     double a = vec.Dot(pos-p0)/len;
                     if (a>0 && a<1)
                     {
                        if ( (p0 + vec*a).Dist2(pos) < w2 )
                           return true;
                     }
                  }
               }
               prev = flags;
               p0 = p;
            }
         }
         else if (draw.mPrimType == ptTriangleFan)
         {
            if (draw.mCount<3)
               continue;
            UserPoint *v = &vert[ draw.mFirst ];
            UserPoint p0 = *v;
            int count_left = 0;
            for(int i=1;i<=draw.mCount;i++)
            {
               UserPoint p = v[i%draw.mCount];
               if ( (p.y<pos.y) != (p0.y<pos.y) )
               {
                  // Crosses, but to the left?
                  double ratio = (pos.y-p0.y)/(p.y-p0.y);
                  double x = p0.x + (p.x-p0.x) * ratio;
                  if (x<pos.x)
                     count_left++;
               }
               p0 = p;
            }
            if (count_left & 1)
               return true;
         }
         else if (draw.mPrimType == ptTriangles)
         {
            if (draw.mCount<3)
               continue;
            UserPoint *v = &vert[ draw.mFirst ];

			   int numTriangles = draw.mCount / 3;

            for(int i=0;i<numTriangles;i++)
            {
               UserPoint base = *v++;
               bool bgx = pos.x>base.x;
               if ( bgx!=(pos.x>v[0].x) || bgx!=(pos.x>v[1].x) )
               {
                  bool bgy = pos.y>base.y;
                  if ( bgy!=(pos.y>v[0].y) || bgy!=(pos.y>v[1].y) )
                  {
                     UserPoint v0 = v[0] - base;
                     UserPoint v1 = v[1] - base;
                     UserPoint v2 = pos - base;
                     double dot00 = v0.Dot(v0);
                     double dot01 = v0.Dot(v1);
                     double dot02 = v0.Dot(v2);
                     double dot11 = v1.Dot(v1);
                     double dot12 = v1.Dot(v2);

                     // Compute barycentric coordinates
                     double denom = (dot00 * dot11 - dot01 * dot01);
                     if (denom!=0)
                     {
                        denom = 1 / denom;
                        double u = (dot11 * dot02 - dot01 * dot12) * denom;
                        if (u>=0)
                        {
                           double v = (dot00 * dot12 - dot01 * dot02) * denom;

                           // Check if point is in triangle
                           if ( (v >= 0) && (u + v < 1) )
                              return true;
                        }
                     }
                  }
               }
               v+=2;
            }
         }
      }
   }

   return false;
}

} // end namespace nme

<|endoftext|>