<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/fileapi/file_writer_delegate.h"

#include "base/file_util_proxy.h"
#include "base/message_loop.h"
#include "base/threading/thread_restrictions.h"
#include "net/base/net_errors.h"
#include "webkit/fileapi/file_system_context.h"
#include "webkit/fileapi/file_system_operation.h"
#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_path_manager.h"
#include "webkit/fileapi/file_system_quota_util.h"
#include "webkit/fileapi/quota_file_util.h"

namespace fileapi {

static const int kReadBufSize = 32768;

namespace {

typedef Callback2<base::PlatformFileError /* error code */,
                  const base::PlatformFileInfo& /* file_info */
                  >::Type InitializeTaskCallback;

class InitializeTask : public base::RefCountedThreadSafe<InitializeTask> {
 public:
  InitializeTask(
      base::PlatformFile file,
      FileSystemOperationContext* context,
      InitializeTaskCallback* callback)
      : origin_message_loop_proxy_(
            base::MessageLoopProxy::CreateForCurrentThread()),
        error_code_(base::PLATFORM_FILE_OK),
        file_(file),
        context_(*context),
        callback_(callback) {
    DCHECK(callback);
  }

  bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
             const tracked_objects::Location& from_here) {
    return message_loop_proxy->PostTask(from_here, NewRunnableMethod(this,
        &InitializeTask::ProcessOnTargetThread));
  }

 private:
  friend class base::RefCountedThreadSafe<InitializeTask>;

  void RunCallback() {
    callback_->Run(error_code_, file_info_);
    delete callback_;
  }

  void ProcessOnTargetThread() {
    DCHECK(context_.file_system_context());
    FileSystemQuotaUtil* quota_util = context_.file_system_context()->
        GetQuotaUtil(context_.src_type());
    if (quota_util) {
      DCHECK(quota_util->proxy());
      quota_util->proxy()->StartUpdateOrigin(
          context_.src_origin_url(), context_.src_type());
    }
    if (!base::GetPlatformFileInfo(file_, &file_info_))
      error_code_ = base::PLATFORM_FILE_ERROR_FAILED;
    origin_message_loop_proxy_->PostTask(FROM_HERE, NewRunnableMethod(this,
        &InitializeTask::RunCallback));
  }

  scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
  base::PlatformFileError error_code_;

  base::PlatformFile file_;
  FileSystemOperationContext context_;
  InitializeTaskCallback* callback_;

  base::PlatformFileInfo file_info_;
};

}  // namespace (anonymous)

FileWriterDelegate::FileWriterDelegate(
    FileSystemOperation* file_system_operation, int64 offset,
    scoped_refptr<base::MessageLoopProxy> proxy)
    : file_system_operation_(file_system_operation),
      file_(base::kInvalidPlatformFileValue),
      offset_(offset),
      proxy_(proxy),
      bytes_written_backlog_(0),
      bytes_written_(0),
      bytes_read_(0),
      total_bytes_written_(0),
      allowed_bytes_to_write_(0),
      io_buffer_(new net::IOBufferWithSize(kReadBufSize)),
      io_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this),
                   &FileWriterDelegate::OnDataWritten),
      method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}

FileWriterDelegate::~FileWriterDelegate() {
}

void FileWriterDelegate::OnGetFileInfoAndCallStartUpdate(
    base::PlatformFileError error,
    const base::PlatformFileInfo& file_info) {
  if (error) {
    OnError(error);
    return;
  }
  int64 allowed_bytes_growth =
      file_system_operation_context()->allowed_bytes_growth();
  if (allowed_bytes_growth == QuotaFileUtil::kNoLimit ||
      file_system_operation_->file_system_context()->IsStorageUnlimited(
          file_system_operation_context()->src_origin_url())) {
    // TODO(kinuko): kNoLimit is kint64max therefore all the calculation/
    // comparison with the value should just work, but we should drop
    // such implicit assumption and should use an explicit boolean flag
    // or something.
    allowed_bytes_to_write_ = QuotaFileUtil::kNoLimit;
  } else {
    if (allowed_bytes_growth < 0)
      allowed_bytes_growth = 0;
    allowed_bytes_to_write_ = file_info.size - offset_ + allowed_bytes_growth;
  }
  size_ = file_info.size;
  file_stream_.reset(new net::FileStream(file_,
      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE |
      base::PLATFORM_FILE_ASYNC));
  request_->Start();
}

void FileWriterDelegate::Start(base::PlatformFile file,
                               net::URLRequest* request) {
  file_ = file;
  request_ = request;

  scoped_refptr<InitializeTask> relay = new InitializeTask(
      file_, file_system_operation_context(),
      callback_factory_.NewCallback(
          &FileWriterDelegate::OnGetFileInfoAndCallStartUpdate));
  relay->Start(proxy_, FROM_HERE);
}

void FileWriterDelegate::OnReceivedRedirect(
    net::URLRequest* request, const GURL& new_url, bool* defer_redirect) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnAuthRequired(
    net::URLRequest* request, net::AuthChallengeInfo* auth_info) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnCertificateRequested(
    net::URLRequest* request, net::SSLCertRequestInfo* cert_request_info) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnSSLCertificateError(
    net::URLRequest* request, int cert_error, net::X509Certificate* cert) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnResponseStarted(net::URLRequest* request) {
  DCHECK_EQ(request_, request);
  // file_stream_->Seek() blocks the IO thread.
  // See http://crbug.com/75548.
  base::ThreadRestrictions::ScopedAllowIO allow_io;
  if (!request->status().is_success()) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
    return;
  }
  int64 error = file_stream_->Seek(net::FROM_BEGIN, offset_);
  if (error != offset_) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
    return;
  }
  Read();
}

void FileWriterDelegate::OnReadCompleted(net::URLRequest* request,
                                         int bytes_read) {
  DCHECK_EQ(request_, request);
  if (!request->status().is_success()) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
    return;
  }
  OnDataReceived(bytes_read);
}

void FileWriterDelegate::Read() {
  bytes_written_ = 0;
  bytes_read_ = 0;
  if (request_->Read(io_buffer_.get(), io_buffer_->size(), &bytes_read_)) {
    MessageLoop::current()->PostTask(
        FROM_HERE,
        method_factory_.NewRunnableMethod(
            &FileWriterDelegate::OnDataReceived, bytes_read_));
  } else if (!request_->status().is_io_pending()) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
  }
}

void FileWriterDelegate::OnDataReceived(int bytes_read) {
  bytes_read_ = bytes_read;
  if (!bytes_read_) {  // We're done.
    OnProgress(0, true);
  } else {
    // This could easily be optimized to rotate between a pool of buffers, so
    // that we could read and write at the same time.  It's not yet clear that
    // it's necessary.
    Write();
  }
}

void FileWriterDelegate::Write() {
  // allowed_bytes_to_write could be negative if the file size is
  // greater than the current (possibly new) quota.
  // (The UI should clear the entire origin data if the smaller quota size
  // is set in general, though the UI/deletion code is not there yet.)
  DCHECK(total_bytes_written_ <= allowed_bytes_to_write_ ||
         allowed_bytes_to_write_ < 0);
  if (total_bytes_written_ >= allowed_bytes_to_write_) {
    OnError(base::PLATFORM_FILE_ERROR_NO_SPACE);
    return;
  }

  int64 bytes_to_write = bytes_read_ - bytes_written_;
  if (bytes_to_write > allowed_bytes_to_write_ - total_bytes_written_)
    bytes_to_write = allowed_bytes_to_write_ - total_bytes_written_;

  int write_response = file_stream_->Write(io_buffer_->data() + bytes_written_,
                                           static_cast<int>(bytes_to_write),
                                           &io_callback_);
  if (write_response > 0)
    MessageLoop::current()->PostTask(
        FROM_HERE,
        method_factory_.NewRunnableMethod(
            &FileWriterDelegate::OnDataWritten, write_response));
  else if (net::ERR_IO_PENDING != write_response)
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
}

void FileWriterDelegate::OnDataWritten(int write_response) {
  if (write_response > 0) {
    OnProgress(write_response, false);
    bytes_written_ += write_response;
    total_bytes_written_ += write_response;
    if (bytes_written_ == bytes_read_)
      Read();
    else
      Write();
  } else {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
  }
}

void FileWriterDelegate::OnError(base::PlatformFileError error) {
  request_->set_delegate(NULL);
  request_->Cancel();

  if (quota_util()) {
    quota_util()->proxy()->EndUpdateOrigin(
        file_system_operation_context()->src_origin_url(),
        file_system_operation_context()->src_type());
  }

  file_system_operation_->DidWrite(error, 0, true);
}

void FileWriterDelegate::OnProgress(int bytes_written, bool done) {
  DCHECK(bytes_written + bytes_written_backlog_ >= bytes_written_backlog_);
  if (bytes_written > 0 &&
      total_bytes_written_ + bytes_written + offset_ > size_) {
    int overlapped = 0;
    if (total_bytes_written_ + offset_ < size_)
      overlapped = size_ - total_bytes_written_ - offset_;
    quota_util()->proxy()->UpdateOriginUsage(
        file_system_operation_->file_system_context()->quota_manager_proxy(),
        file_system_operation_context()->src_origin_url(),
        file_system_operation_context()->src_type(),
        bytes_written - overlapped);
  }
  static const int kMinProgressDelayMS = 200;
  base::Time currentTime = base::Time::Now();
  if (done || last_progress_event_time_.is_null() ||
      (currentTime - last_progress_event_time_).InMilliseconds() >
          kMinProgressDelayMS) {
    bytes_written += bytes_written_backlog_;
    last_progress_event_time_ = currentTime;
    bytes_written_backlog_ = 0;
    if (done && quota_util()) {
      if (quota_util()) {
        quota_util()->proxy()->EndUpdateOrigin(
            file_system_operation_context()->src_origin_url(),
            file_system_operation_context()->src_type());
      }
    }
    file_system_operation_->DidWrite(
        base::PLATFORM_FILE_OK, bytes_written, done);
    return;
  }
  bytes_written_backlog_ += bytes_written;
}

FileSystemOperationContext*
FileWriterDelegate::file_system_operation_context() const {
  DCHECK(file_system_operation_);
  DCHECK(file_system_operation_->file_system_operation_context());
  return file_system_operation_->file_system_operation_context();
}

FileSystemQuotaUtil* FileWriterDelegate::quota_util() const {
  DCHECK(file_system_operation_);
  DCHECK(file_system_operation_->file_system_context());
  DCHECK(file_system_operation_->file_system_operation_context());
  return file_system_operation_->file_system_context()->GetQuotaUtil(
      file_system_operation_context()->src_type());
}

}  // namespace fileapi
<commit_msg>ChromiumOS build fix attempt for 86988<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/fileapi/file_writer_delegate.h"

#include "base/file_util_proxy.h"
#include "base/message_loop.h"
#include "base/threading/thread_restrictions.h"
#include "net/base/net_errors.h"
#include "webkit/fileapi/file_system_context.h"
#include "webkit/fileapi/file_system_operation.h"
#include "webkit/fileapi/file_system_operation_context.h"
#include "webkit/fileapi/file_system_path_manager.h"
#include "webkit/fileapi/file_system_quota_util.h"
#include "webkit/fileapi/quota_file_util.h"

namespace fileapi {

static const int kReadBufSize = 32768;

namespace {

typedef Callback2<base::PlatformFileError /* error code */,
                  const base::PlatformFileInfo& /* file_info */
                  >::Type InitializeTaskCallback;

class InitializeTask : public base::RefCountedThreadSafe<InitializeTask> {
 public:
  InitializeTask(
      base::PlatformFile file,
      FileSystemOperationContext* context,
      InitializeTaskCallback* callback)
      : origin_message_loop_proxy_(
            base::MessageLoopProxy::CreateForCurrentThread()),
        error_code_(base::PLATFORM_FILE_OK),
        file_(file),
        context_(*context),
        callback_(callback) {
    DCHECK(callback);
  }

  bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
             const tracked_objects::Location& from_here) {
    return message_loop_proxy->PostTask(from_here, NewRunnableMethod(this,
        &InitializeTask::ProcessOnTargetThread));
  }

 private:
  friend class base::RefCountedThreadSafe<InitializeTask>;

  void RunCallback() {
    callback_->Run(error_code_, file_info_);
    delete callback_;
  }

  void ProcessOnTargetThread() {
    DCHECK(context_.file_system_context());
    FileSystemQuotaUtil* quota_util = context_.file_system_context()->
        GetQuotaUtil(context_.src_type());
    if (quota_util) {
      DCHECK(quota_util->proxy());
      quota_util->proxy()->StartUpdateOrigin(
          context_.src_origin_url(), context_.src_type());
    }
    if (!base::GetPlatformFileInfo(file_, &file_info_))
      error_code_ = base::PLATFORM_FILE_ERROR_FAILED;
    origin_message_loop_proxy_->PostTask(FROM_HERE, NewRunnableMethod(this,
        &InitializeTask::RunCallback));
  }

  scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
  base::PlatformFileError error_code_;

  base::PlatformFile file_;
  FileSystemOperationContext context_;
  InitializeTaskCallback* callback_;

  base::PlatformFileInfo file_info_;
};

}  // namespace (anonymous)

FileWriterDelegate::FileWriterDelegate(
    FileSystemOperation* file_system_operation, int64 offset,
    scoped_refptr<base::MessageLoopProxy> proxy)
    : file_system_operation_(file_system_operation),
      file_(base::kInvalidPlatformFileValue),
      offset_(offset),
      proxy_(proxy),
      bytes_written_backlog_(0),
      bytes_written_(0),
      bytes_read_(0),
      total_bytes_written_(0),
      allowed_bytes_to_write_(0),
      io_buffer_(new net::IOBufferWithSize(kReadBufSize)),
      io_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this),
                   &FileWriterDelegate::OnDataWritten),
      method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}

FileWriterDelegate::~FileWriterDelegate() {
}

void FileWriterDelegate::OnGetFileInfoAndCallStartUpdate(
    base::PlatformFileError error,
    const base::PlatformFileInfo& file_info) {
  if (error) {
    OnError(error);
    return;
  }
  int64 allowed_bytes_growth =
      file_system_operation_context()->allowed_bytes_growth();
  if (allowed_bytes_growth == QuotaFileUtil::kNoLimit ||
      file_system_operation_->file_system_context()->IsStorageUnlimited(
          file_system_operation_context()->src_origin_url())) {
    // TODO(kinuko): kNoLimit is kint64max therefore all the calculation/
    // comparison with the value should just work, but we should drop
    // such implicit assumption and should use an explicit boolean flag
    // or something.
    allowed_bytes_to_write_ = QuotaFileUtil::kNoLimit;
  } else {
    if (allowed_bytes_growth < 0)
      allowed_bytes_growth = 0;
    allowed_bytes_to_write_ = file_info.size - offset_ + allowed_bytes_growth;
  }
  size_ = file_info.size;
  file_stream_.reset(new net::FileStream(file_,
      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE |
      base::PLATFORM_FILE_ASYNC));
  request_->Start();
}

void FileWriterDelegate::Start(base::PlatformFile file,
                               net::URLRequest* request) {
  file_ = file;
  request_ = request;

  scoped_refptr<InitializeTask> relay = new InitializeTask(
      file_, file_system_operation_context(),
      callback_factory_.NewCallback(
          &FileWriterDelegate::OnGetFileInfoAndCallStartUpdate));
  relay->Start(proxy_, FROM_HERE);
}

void FileWriterDelegate::OnReceivedRedirect(
    net::URLRequest* request, const GURL& new_url, bool* defer_redirect) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnAuthRequired(
    net::URLRequest* request, net::AuthChallengeInfo* auth_info) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnCertificateRequested(
    net::URLRequest* request, net::SSLCertRequestInfo* cert_request_info) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnSSLCertificateError(
    net::URLRequest* request, int cert_error, net::X509Certificate* cert) {
  NOTREACHED();
  OnError(base::PLATFORM_FILE_ERROR_SECURITY);
}

void FileWriterDelegate::OnResponseStarted(net::URLRequest* request) {
  DCHECK_EQ(request_, request);
  // file_stream_->Seek() blocks the IO thread.
  // See http://crbug.com/75548.
  base::ThreadRestrictions::ScopedAllowIO allow_io;
  if (!request->status().is_success()) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
    return;
  }
  int64 error = file_stream_->Seek(net::FROM_BEGIN, offset_);
  if (error != offset_) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
    return;
  }
  Read();
}

void FileWriterDelegate::OnReadCompleted(net::URLRequest* request,
                                         int bytes_read) {
  DCHECK_EQ(request_, request);
  if (!request->status().is_success()) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
    return;
  }
  OnDataReceived(bytes_read);
}

void FileWriterDelegate::Read() {
  bytes_written_ = 0;
  bytes_read_ = 0;
  if (request_->Read(io_buffer_.get(), io_buffer_->size(), &bytes_read_)) {
    MessageLoop::current()->PostTask(
        FROM_HERE,
        method_factory_.NewRunnableMethod(
            &FileWriterDelegate::OnDataReceived, bytes_read_));
  } else if (!request_->status().is_io_pending()) {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
  }
}

void FileWriterDelegate::OnDataReceived(int bytes_read) {
  bytes_read_ = bytes_read;
  if (!bytes_read_) {  // We're done.
    OnProgress(0, true);
  } else {
    // This could easily be optimized to rotate between a pool of buffers, so
    // that we could read and write at the same time.  It's not yet clear that
    // it's necessary.
    Write();
  }
}

void FileWriterDelegate::Write() {
  // allowed_bytes_to_write could be negative if the file size is
  // greater than the current (possibly new) quota.
  // (The UI should clear the entire origin data if the smaller quota size
  // is set in general, though the UI/deletion code is not there yet.)
  DCHECK(total_bytes_written_ <= allowed_bytes_to_write_ ||
         allowed_bytes_to_write_ < 0);
  if (total_bytes_written_ >= allowed_bytes_to_write_) {
    OnError(base::PLATFORM_FILE_ERROR_NO_SPACE);
    return;
  }

  int64 bytes_to_write = bytes_read_ - bytes_written_;
  if (bytes_to_write > allowed_bytes_to_write_ - total_bytes_written_)
    bytes_to_write = allowed_bytes_to_write_ - total_bytes_written_;

  int write_response = file_stream_->Write(io_buffer_->data() + bytes_written_,
                                           static_cast<int>(bytes_to_write),
                                           &io_callback_);
  if (write_response > 0)
    MessageLoop::current()->PostTask(
        FROM_HERE,
        method_factory_.NewRunnableMethod(
            &FileWriterDelegate::OnDataWritten, write_response));
  else if (net::ERR_IO_PENDING != write_response)
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
}

void FileWriterDelegate::OnDataWritten(int write_response) {
  if (write_response > 0) {
    OnProgress(write_response, false);
    bytes_written_ += write_response;
    total_bytes_written_ += write_response;
    if (bytes_written_ == bytes_read_)
      Read();
    else
      Write();
  } else {
    OnError(base::PLATFORM_FILE_ERROR_FAILED);
  }
}

void FileWriterDelegate::OnError(base::PlatformFileError error) {
  request_->set_delegate(NULL);
  request_->Cancel();

  if (quota_util()) {
    quota_util()->proxy()->EndUpdateOrigin(
        file_system_operation_context()->src_origin_url(),
        file_system_operation_context()->src_type());
  }

  file_system_operation_->DidWrite(error, 0, true);
}

void FileWriterDelegate::OnProgress(int bytes_written, bool done) {
  DCHECK(bytes_written + bytes_written_backlog_ >= bytes_written_backlog_);
  if (quota_util() &&
      bytes_written > 0 &&
      total_bytes_written_ + bytes_written + offset_ > size_) {
    int overlapped = 0;
    if (total_bytes_written_ + offset_ < size_)
      overlapped = size_ - total_bytes_written_ - offset_;
    quota_util()->proxy()->UpdateOriginUsage(
        file_system_operation_->file_system_context()->quota_manager_proxy(),
        file_system_operation_context()->src_origin_url(),
        file_system_operation_context()->src_type(),
        bytes_written - overlapped);
  }
  static const int kMinProgressDelayMS = 200;
  base::Time currentTime = base::Time::Now();
  if (done || last_progress_event_time_.is_null() ||
      (currentTime - last_progress_event_time_).InMilliseconds() >
          kMinProgressDelayMS) {
    bytes_written += bytes_written_backlog_;
    last_progress_event_time_ = currentTime;
    bytes_written_backlog_ = 0;
    if (done && quota_util()) {
      if (quota_util()) {
        quota_util()->proxy()->EndUpdateOrigin(
            file_system_operation_context()->src_origin_url(),
            file_system_operation_context()->src_type());
      }
    }
    file_system_operation_->DidWrite(
        base::PLATFORM_FILE_OK, bytes_written, done);
    return;
  }
  bytes_written_backlog_ += bytes_written;
}

FileSystemOperationContext*
FileWriterDelegate::file_system_operation_context() const {
  DCHECK(file_system_operation_);
  DCHECK(file_system_operation_->file_system_operation_context());
  return file_system_operation_->file_system_operation_context();
}

FileSystemQuotaUtil* FileWriterDelegate::quota_util() const {
  DCHECK(file_system_operation_);
  DCHECK(file_system_operation_->file_system_context());
  DCHECK(file_system_operation_->file_system_operation_context());
  return file_system_operation_->file_system_context()->GetQuotaUtil(
      file_system_operation_context()->src_type());
}

}  // namespace fileapi
<|endoftext|>


<commit_before>/*
 * server.cpp
 *
 *  Created on: Aug 7, 2015
 *      Author: netmind
 */

#define LOG_LEVEL LOG_INFO

#include "app.h"
#include <ednio/EdNio.h>
#include <cahttp/CaHttpServer.h>
#include <climits>
#include <cahttp/HttpFileReadStream.h>
#include "FileUtil.h"

using namespace edft;
using namespace std;
using namespace cahttp;

struct App {
	App() {
		port = 9000;
		rootDir = "/usr/lib";
	}
	int port;
	string rootDir;
};

App gApp;

class ListFileUrl: public CaHttpUrlCtrl {
	void OnHttpReqMsg() override {
		string resp;
		resp= "";
		string ls;
		auto fl = FileUtil::getFileList(gApp.rootDir.data(), FileUtil::DIR_ONLY);
		ls = "
";
		for(auto &f: fl) {
			ls += "
"+f+"
\n";
		}
		fl = FileUtil::getFileList(gApp.rootDir.data(), FileUtil::FILE_ONLY);
		for(auto &f: fl) {
			ls += "
" + f+ "
\n";
		}
		ls += "
\n";
		resp += ls;
		resp += "\n";

		response(200, resp, CAS::CT_TEXT_HTML);
	}
};

class DirUrl: public CaHttpUrlCtrl {
	void OnHttpReqMsg() override {
		auto mph = getUrlMatchStr();
		string dirpath = gApp.rootDir;
		for(auto &ps: mph) {
			dirpath += "/" + ps;
		}

		string resp;
		resp= "";
		string ls;
		auto fl = FileUtil::getFileList(dirpath.data(), FileUtil::DIR_ONLY);
		ls = "
";
		for(auto &f: fl) {
			ls += "
"+f+"
\n";
		}
		fl = FileUtil::getFileList(dirpath.data(), FileUtil::FILE_ONLY);
		for(auto &f: fl) {
			ls += "
" + f+  "
\n";
		}
		ls += "
\n";
		resp += ls;
		resp += "\n";

		response(200, resp, CAS::CT_TEXT_HTML);
	}
};

class DownloadUrl: public CaHttpUrlCtrl {
	HttpFileReadStream mFileStrm;
	void OnHttpReqMsg() override {
		auto &vs = getUrlMatchStr();
		if(vs.empty()) {
			response(404, "File Not Found");
			return;
		}
		string path;
		path = gApp.rootDir+"/"+vs[0];
		if(FileUtil::isExist(path)) {
			mFileStrm.open(path.data());
			addRespHdr(CAS::HS_CONTENT_TYPE, CAS::CT_APP_OCTET);
			setRespContent(&mFileStrm, (int64_t)mFileStrm.remain());
			response(200);
		} else {
			response(404, "File Not Found");
			return;
		}

		string downpath = gApp.rootDir+"/"+ path;
		mFileStrm.open(downpath.data());
	}

	void OnHttpEnd() override {
		mFileStrm.close();
	}
};
class MainTask: public EdTask {
	CaHttpServer mServer;
	int OnEventProc(EdMsg &msg) {
		if (msg.msgid == EDM_INIT) {
			mServer.config("port", to_string(gApp.port).data());
			mServer.setUrl<ListFileUrl>(HTTP_GET, "/file/list");
			mServer.setUrlRegEx<DirUrl>(HTTP_GET, "/file/dir/(.*)");
			mServer.setUrlRegEx<DownloadUrl>(HTTP_GET, "/file/download/(.*)");
			mServer.start(0);
		}
		else if (msg.msgid == EDM_CLOSE) {
			mServer.close();
		}
		return 0;
	}
};

int main(int argc, char* argv[]) {
	EdNioInit();
	MainTask task;
	task.runMain();
	return 0;
}
<commit_msg>update server example<commit_after>/*
 * server.cpp
 *
 *  Created on: Aug 7, 2015
 *      Author: netmind
 */

#define LOG_LEVEL LOG_INFO

#include "app.h"
#include <ednio/EdNio.h>
#include <cahttp/CaHttpServer.h>
#include <climits>
#include <iostream>
#include <cahttp/HttpFileReadStream.h>
#include "FileUtil.h"

using namespace edft;
using namespace std;
using namespace cahttp;

struct App {
	App() {
		port = 9000;
		rootDir = "/usr/lib";
	}
	int port;
	string rootDir;
};

App gApp;

class ListFileUrl: public CaHttpUrlCtrl {
	void OnHttpReqMsg() override {
		string resp;
		resp= "";
		string ls;
		auto fl = FileUtil::getFileList(gApp.rootDir.data(), FileUtil::DIR_ONLY);
		ls = "
";
		for(auto &f: fl) {
			ls += "
"+f+"
\n";
		}
		fl = FileUtil::getFileList(gApp.rootDir.data(), FileUtil::FILE_ONLY);
		for(auto &f: fl) {
			ls += "
" + f+ "
\n";
		}
		ls += "
\n";
		resp += ls;
		resp += "\n";

		response(200, resp, CAS::CT_TEXT_HTML);
	}
};

class DirUrl: public CaHttpUrlCtrl {
	void OnHttpReqMsg() override {
		auto mph = getUrlMatchStr();

		string dirpath = gApp.rootDir;
		for(auto &ps: mph) {
			dirpath += ps;
		}

		string resp;
		resp= "";
		string ls;
		auto fl = FileUtil::getFileList(dirpath.data(), FileUtil::DIR_ONLY);
		ls = "
";
		for(auto &f: fl) {
			ls += "
"+f+"
\n";
		}
		fl = FileUtil::getFileList(dirpath.data(), FileUtil::FILE_ONLY);
		for(auto &f: fl) {
			ls += "
" + f+  "
\n";
		}
		ls += "
\n";
		resp += ls;
		resp += "\n";

		response(200, resp, CAS::CT_TEXT_HTML);
	}
};

class DownloadUrl: public CaHttpUrlCtrl {
	HttpFileReadStream mFileStrm;
	void OnHttpReqMsg() override {
		auto &vs = getUrlMatchStr();
		if(vs.empty()) {
			response(404, "File Not Found");
			return;
		}
		string path;
		path = gApp.rootDir+"/"+vs[0];
		if(FileUtil::isExist(path)) {
			mFileStrm.open(path.data());
			addRespHdr(CAS::HS_CONTENT_TYPE, CAS::CT_APP_OCTET);
			setRespContent(&mFileStrm, (int64_t)mFileStrm.remain());
			response(200);
		} else {
			response(404, "File Not Found");
			return;
		}

		string downpath = gApp.rootDir+"/"+ path;
		mFileStrm.open(downpath.data());
	}

	void OnHttpEnd() override {
		mFileStrm.close();
	}
};
class MainTask: public EdTask {
	CaHttpServer mServer;
	int OnEventProc(EdMsg &msg) {
		if (msg.msgid == EDM_INIT) {
			mServer.config("port", to_string(gApp.port).data());
			mServer.setUrl<ListFileUrl>(HTTP_GET, "/file/list");
			mServer.setUrlRegEx<DirUrl>(HTTP_GET, "/file/dir(/[^\\?]*)");
//			mServer.setUrlRegEx<DirUrl>(HTTP_GET, "/file/dir(/[^\\?]*)(.*)");
			mServer.setUrlRegEx<DownloadUrl>(HTTP_GET, "/file/download/(.*)");
			mServer.start(0);
		}
		else if (msg.msgid == EDM_CLOSE) {
			mServer.close();
		}
		return 0;
	}
};

int main(int argc, char* argv[]) {
	EdNioInit();
	MainTask task;
	task.runMain();
	return 0;
}
<|endoftext|>


<commit_before>/*{{{
    Copyright © 2015 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

This work is derived from a class in ALICE with the following copyright notice:
    **************************************************************************
    * This file is property of and copyright by the ALICE HLT Project        *
    * ALICE Experiment at CERN, All rights reserved.                         *
    *                                                                        *
    * Primary Authors: Sergey Gorbunov <sergey.gorbunov@cern.ch>             *
    *                  for The ALICE HLT Project.                            *
    *                                                                        *
    * Permission to use, copy, modify and distribute this software and its   *
    * documentation strictly for non-commercial purposes is hereby granted   *
    * without fee, provided that the above copyright notice appears in all   *
    * copies and that both the copyright notice and this permission notice   *
    * appear in the supporting documentation. The authors make no claims     *
    * about the suitability of this software for any purpose. It is          *
    * provided "as is" without express or implied warranty.                  *
    **************************************************************************
}}}*/

#include "spline.h"
#include <Vc/Vc>

#include <iostream>
#include <iomanip>

using namespace std;

Spline::Spline(float minA, float maxA, int nBinsA, float minB, float maxB,  //{{{1
               int nBinsB)
    : fNA(nBinsA < 4 ? 4 : nBinsA)
    , fNB(nBinsB < 4 ? 4 : nBinsB)
    , fN(fNA * fNB)
    , fMinA(minA)
    , fMinB(minB)
    , fStepA(((maxA <= minA ? minA + 1 : maxA) - minA) / (fNA - 1))
    , fStepB(((maxB <= minB ? minB + 1 : maxB) - minB) / (fNB - 1))
    , fScaleA(1.f / fStepA)
    , fScaleB(1.f / fStepB)
    , fXYZ(fN, DataPoint::Zero())
{
}

// spline 3-st order,  4 points, da = a - point 1 {{{1
template <typename T> static inline T GetSpline3(T v0, T v1, T v2, T v3, T x)
{
    const T dv = v2 - v1;
    const T z0 = 0.5f * (v2 - v0);
    const T z1 = 0.5f * (v3 - v1);
    return (x * x) * ((z1 - dv) * (x - 1) + (z0 - dv) * (x - 2)) + (z0 * x + v1);
    //return x * x * ((z1 - dv + z0 - dv) * (x - 1) - (z0 - dv)) + z0 * x + v1;
}

template <typename T> static inline T GetSpline3(const T *v, T x)
{
    return GetSpline3(v[0], v[1], v[2], v[3], x);
}

Point3 Spline::GetValue(Point2 ab) const  //{{{1
{
    float da1, db1;
    int iA, iB;
    std::tie(iA, iB, da1, db1) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);
    int ind = iA * fNB + iB;

    typedef Vc::SimdArray<float, 4> float4;
    const float4 da = da1;
    const float4 db = db1;

    float4 v[4];
    const float4 *m = &fXYZ[0];

    for (int i = 0; i < 4; i++) {
        v[i] = GetSpline3(m[ind + 0], m[ind + 1], m[ind + 2], m[ind + 3], db);
        ind += fNB;
    }
    float4 res = GetSpline3(v[0], v[1], v[2], v[3], da);
    return {{res[0], res[1], res[2]}};
}

Point3 Spline::GetValue16(Point2 ab) const  //{{{1
{
    float da1, db1;
    int iA, iB;
    std::tie(iA, iB, da1, db1) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);

    typedef Vc::SimdArray<float, 4> float4;
    typedef Vc::SimdArray<float, 16> float16;
    const float4 da = da1;
    const float16 db = db1;

    const float4 *m0 = &fXYZ[iA * fNB + iB];
    const float4 *m1 = m0 + fNB;
    const float4 *m2 = m1 + fNB;
    const float4 *m3 = m2 + fNB;
    const float16 v0123 =
        GetSpline3(Vc::simd_cast<float16>(m0[0], m1[0], m2[0], m3[0]),
                   Vc::simd_cast<float16>(m0[1], m1[1], m2[1], m3[1]),
                   Vc::simd_cast<float16>(m0[2], m1[2], m2[2], m3[2]),
                   Vc::simd_cast<float16>(m0[3], m1[3], m2[3], m3[3]), db);
    const float4 res =
        GetSpline3(Vc::simd_cast<float4, 0>(v0123), Vc::simd_cast<float4, 1>(v0123),
                   Vc::simd_cast<float4, 2>(v0123), Vc::simd_cast<float4, 3>(v0123), da);
    return {{res[0], res[1], res[2]}};
}

Point3 Spline::GetValueScalar(Point2 ab) const  //{{{1
{
    float da, db;
    int iA, iB;
    std::tie(iA, iB, da, db) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);
    int ind = iA * fNB + iB;

    float vx[4];
    float vy[4];
    float vz[4];
    for (int i = 0; i < 4; i++) {
        vx[i] = GetSpline3(fXYZ[ind][0], fXYZ[ind + 1][0], fXYZ[ind + 2][0],
                           fXYZ[ind + 3][0], db);
        vy[i] = GetSpline3(fXYZ[ind][1], fXYZ[ind + 1][1], fXYZ[ind + 2][1],
                           fXYZ[ind + 3][1], db);
        vz[i] = GetSpline3(fXYZ[ind][2], fXYZ[ind + 1][2], fXYZ[ind + 2][2],
                           fXYZ[ind + 3][2], db);
        ind += fNB;
    }
    return {{GetSpline3(vx, da), GetSpline3(vy, da), GetSpline3(vz, da)}};
}

Point3 Spline::GetValueAutovec(Point2 ab) const  //{{{1
{
    float da, db;
    int iA, iB;
    std::tie(iA, iB, da, db) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);
    int ind = iA * fNB + iB;

    float vx[4];
    float vy[4];
    float vz[4];
    const float *m = reinterpret_cast<const float *>(&fXYZ[0]);
    for (int i = 0; i < 4; i++) {
        int ind4 = ind * 4;
        vx[i] = GetSpline3(m[ind4 + 0], m[ind4 + 4], m[ind4 + 8], m[ind4 + 12], db);
        vy[i] = GetSpline3(m[ind4 + 1], m[ind4 + 5], m[ind4 + 9], m[ind4 + 13], db);
        vz[i] = GetSpline3(m[ind4 + 2], m[ind4 + 6], m[ind4 + 10], m[ind4 + 14], db);
        ind += fNB;
    }
    return {{GetSpline3(vx, da), GetSpline3(vy, da), GetSpline3(vz, da)}};
}

Point3V Spline::GetValue(const Point2V &ab) const  //{{{1
{
    index_v iA, iB;
    float_v da, db;
    std::tie(iA, iB, da, db) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);

    float_v vx[4];
    float_v vy[4];
    float_v vz[4];
    auto ind = iA * fNB + iB;
    const auto map = Vc::make_interleave_wrapper<float_v>(&fXYZ[0]);
    for (int i = 0; i < 4; i++) {
        float_v x[4], y[4], z[4];
        Vc::tie(x[0], y[0], z[0]) = map[ind];
        Vc::tie(x[1], y[1], z[1]) = map[ind + 1];
        Vc::tie(x[2], y[2], z[2]) = map[ind + 2];
        Vc::tie(x[3], y[3], z[3]) = map[ind + 3];
        vx[i] = GetSpline3<float_v>(x[0], x[1], x[2], x[3], db);
        vy[i] = GetSpline3<float_v>(y[0], y[1], y[2], y[3], db);
        vz[i] = GetSpline3<float_v>(z[0], z[1], z[2], z[3], db);
        ind += fNB;
    }
    Point3V XYZ;
    XYZ[0] = GetSpline3<float_v>(vx, da);
    XYZ[1] = GetSpline3<float_v>(vy, da);
    XYZ[2] = GetSpline3<float_v>(vz, da);
    return XYZ;
}

// Point3 Spline::GetValueAlice(Point2 ab) const {{{1
#pragma GCC diagnostic ignored "-Wold-style-cast"
#ifdef Vc_GCC
__attribute__((optimize("no-tree-vectorize")))
#endif
Point3 Spline::GetValueAlice(Point2 ab) const
{
    float lA = (ab[0] - fMinA) * fScaleA - 1.f;
    int iA = (int)lA;
    if (lA < 0) iA = 0;
    else if (iA > fNA - 4) iA = fNA - 4;

    float lB = (ab[1] - fMinB) * fScaleB - 1.f;
    int iB = (int)lB;
    if (lB < 0) iB = 0;
    else if (iB > fNB - 4) iB = fNB - 4;

    Point3 XYZ;
    if (Vc::float_v::Size == 4) {
        Vc::float_v da = lA - iA;
        Vc::float_v db = lB - iB;

        Vc::float_v v[4];
        int ind = iA * fNB + iB;
        const Vc::float_v *m = reinterpret_cast<const Vc::float_v *>(&fXYZ[0]);

        for (int i = 0; i < 4; i++) {
            v[i] = GetSpline3(m[ind + 0], m[ind + 1], m[ind + 2], m[ind + 3], db);
            ind += fNB;
        }
        Vc::float_v res = GetSpline3(v[0], v[1], v[2], v[3], da);
        XYZ[0] = res[0];
        XYZ[1] = res[1];
        XYZ[2] = res[2];
    } else {
        float da = lA - iA;
        float db = lB - iB;

        float vx[4];
        float vy[4];
        float vz[4];
        int ind = iA * fNB + iB;
        const float *m = reinterpret_cast<const float *>(&fXYZ[0]);
        for (int i = 0; i < 4; i++) {
            int ind4 = ind * 4;
            vx[i] = GetSpline3(m[ind4 + 0], m[ind4 + 4], m[ind4 + 8], m[ind4 + 12], db);
            vy[i] = GetSpline3(m[ind4 + 1], m[ind4 + 5], m[ind4 + 9], m[ind4 + 13], db);
            vz[i] = GetSpline3(m[ind4 + 2], m[ind4 + 6], m[ind4 + 10], m[ind4 + 14], db);
            ind += fNB;
        }
        XYZ[0] = GetSpline3(vx, da);
        XYZ[1] = GetSpline3(vy, da);
        XYZ[2] = GetSpline3(vz, da);
    }
    return XYZ;
}
// vim: foldmethod=marker
<commit_msg>Move GCC specific pragma into #ifdef<commit_after>/*{{{
    Copyright © 2015 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

This work is derived from a class in ALICE with the following copyright notice:
    **************************************************************************
    * This file is property of and copyright by the ALICE HLT Project        *
    * ALICE Experiment at CERN, All rights reserved.                         *
    *                                                                        *
    * Primary Authors: Sergey Gorbunov <sergey.gorbunov@cern.ch>             *
    *                  for The ALICE HLT Project.                            *
    *                                                                        *
    * Permission to use, copy, modify and distribute this software and its   *
    * documentation strictly for non-commercial purposes is hereby granted   *
    * without fee, provided that the above copyright notice appears in all   *
    * copies and that both the copyright notice and this permission notice   *
    * appear in the supporting documentation. The authors make no claims     *
    * about the suitability of this software for any purpose. It is          *
    * provided "as is" without express or implied warranty.                  *
    **************************************************************************
}}}*/

#include "spline.h"
#include <Vc/Vc>

#include <iostream>
#include <iomanip>

using namespace std;

Spline::Spline(float minA, float maxA, int nBinsA, float minB, float maxB,  //{{{1
               int nBinsB)
    : fNA(nBinsA < 4 ? 4 : nBinsA)
    , fNB(nBinsB < 4 ? 4 : nBinsB)
    , fN(fNA * fNB)
    , fMinA(minA)
    , fMinB(minB)
    , fStepA(((maxA <= minA ? minA + 1 : maxA) - minA) / (fNA - 1))
    , fStepB(((maxB <= minB ? minB + 1 : maxB) - minB) / (fNB - 1))
    , fScaleA(1.f / fStepA)
    , fScaleB(1.f / fStepB)
    , fXYZ(fN, DataPoint::Zero())
{
}

// spline 3-st order,  4 points, da = a - point 1 {{{1
template <typename T> static inline T GetSpline3(T v0, T v1, T v2, T v3, T x)
{
    const T dv = v2 - v1;
    const T z0 = 0.5f * (v2 - v0);
    const T z1 = 0.5f * (v3 - v1);
    return (x * x) * ((z1 - dv) * (x - 1) + (z0 - dv) * (x - 2)) + (z0 * x + v1);
    //return x * x * ((z1 - dv + z0 - dv) * (x - 1) - (z0 - dv)) + z0 * x + v1;
}

template <typename T> static inline T GetSpline3(const T *v, T x)
{
    return GetSpline3(v[0], v[1], v[2], v[3], x);
}

Point3 Spline::GetValue(Point2 ab) const  //{{{1
{
    float da1, db1;
    int iA, iB;
    std::tie(iA, iB, da1, db1) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);
    int ind = iA * fNB + iB;

    typedef Vc::SimdArray<float, 4> float4;
    const float4 da = da1;
    const float4 db = db1;

    float4 v[4];
    const float4 *m = &fXYZ[0];

    for (int i = 0; i < 4; i++) {
        v[i] = GetSpline3(m[ind + 0], m[ind + 1], m[ind + 2], m[ind + 3], db);
        ind += fNB;
    }
    float4 res = GetSpline3(v[0], v[1], v[2], v[3], da);
    return {{res[0], res[1], res[2]}};
}

Point3 Spline::GetValue16(Point2 ab) const  //{{{1
{
    float da1, db1;
    int iA, iB;
    std::tie(iA, iB, da1, db1) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);

    typedef Vc::SimdArray<float, 4> float4;
    typedef Vc::SimdArray<float, 16> float16;
    const float4 da = da1;
    const float16 db = db1;

    const float4 *m0 = &fXYZ[iA * fNB + iB];
    const float4 *m1 = m0 + fNB;
    const float4 *m2 = m1 + fNB;
    const float4 *m3 = m2 + fNB;
    const float16 v0123 =
        GetSpline3(Vc::simd_cast<float16>(m0[0], m1[0], m2[0], m3[0]),
                   Vc::simd_cast<float16>(m0[1], m1[1], m2[1], m3[1]),
                   Vc::simd_cast<float16>(m0[2], m1[2], m2[2], m3[2]),
                   Vc::simd_cast<float16>(m0[3], m1[3], m2[3], m3[3]), db);
    const float4 res =
        GetSpline3(Vc::simd_cast<float4, 0>(v0123), Vc::simd_cast<float4, 1>(v0123),
                   Vc::simd_cast<float4, 2>(v0123), Vc::simd_cast<float4, 3>(v0123), da);
    return {{res[0], res[1], res[2]}};
}

Point3 Spline::GetValueScalar(Point2 ab) const  //{{{1
{
    float da, db;
    int iA, iB;
    std::tie(iA, iB, da, db) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);
    int ind = iA * fNB + iB;

    float vx[4];
    float vy[4];
    float vz[4];
    for (int i = 0; i < 4; i++) {
        vx[i] = GetSpline3(fXYZ[ind][0], fXYZ[ind + 1][0], fXYZ[ind + 2][0],
                           fXYZ[ind + 3][0], db);
        vy[i] = GetSpline3(fXYZ[ind][1], fXYZ[ind + 1][1], fXYZ[ind + 2][1],
                           fXYZ[ind + 3][1], db);
        vz[i] = GetSpline3(fXYZ[ind][2], fXYZ[ind + 1][2], fXYZ[ind + 2][2],
                           fXYZ[ind + 3][2], db);
        ind += fNB;
    }
    return {{GetSpline3(vx, da), GetSpline3(vy, da), GetSpline3(vz, da)}};
}

Point3 Spline::GetValueAutovec(Point2 ab) const  //{{{1
{
    float da, db;
    int iA, iB;
    std::tie(iA, iB, da, db) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);
    int ind = iA * fNB + iB;

    float vx[4];
    float vy[4];
    float vz[4];
    const float *m = reinterpret_cast<const float *>(&fXYZ[0]);
    for (int i = 0; i < 4; i++) {
        int ind4 = ind * 4;
        vx[i] = GetSpline3(m[ind4 + 0], m[ind4 + 4], m[ind4 + 8], m[ind4 + 12], db);
        vy[i] = GetSpline3(m[ind4 + 1], m[ind4 + 5], m[ind4 + 9], m[ind4 + 13], db);
        vz[i] = GetSpline3(m[ind4 + 2], m[ind4 + 6], m[ind4 + 10], m[ind4 + 14], db);
        ind += fNB;
    }
    return {{GetSpline3(vx, da), GetSpline3(vy, da), GetSpline3(vz, da)}};
}

Point3V Spline::GetValue(const Point2V &ab) const  //{{{1
{
    index_v iA, iB;
    float_v da, db;
    std::tie(iA, iB, da, db) =
        evaluatePosition(ab, {{fMinA, fMinB}}, {{fScaleA, fScaleB}}, fNA, fNB);

    float_v vx[4];
    float_v vy[4];
    float_v vz[4];
    auto ind = iA * fNB + iB;
    const auto map = Vc::make_interleave_wrapper<float_v>(&fXYZ[0]);
    for (int i = 0; i < 4; i++) {
        float_v x[4], y[4], z[4];
        Vc::tie(x[0], y[0], z[0]) = map[ind];
        Vc::tie(x[1], y[1], z[1]) = map[ind + 1];
        Vc::tie(x[2], y[2], z[2]) = map[ind + 2];
        Vc::tie(x[3], y[3], z[3]) = map[ind + 3];
        vx[i] = GetSpline3<float_v>(x[0], x[1], x[2], x[3], db);
        vy[i] = GetSpline3<float_v>(y[0], y[1], y[2], y[3], db);
        vz[i] = GetSpline3<float_v>(z[0], z[1], z[2], z[3], db);
        ind += fNB;
    }
    Point3V XYZ;
    XYZ[0] = GetSpline3<float_v>(vx, da);
    XYZ[1] = GetSpline3<float_v>(vy, da);
    XYZ[2] = GetSpline3<float_v>(vz, da);
    return XYZ;
}

// Point3 Spline::GetValueAlice(Point2 ab) const {{{1
#ifdef Vc_GCC
#pragma GCC diagnostic ignored "-Wold-style-cast"
__attribute__((optimize("no-tree-vectorize")))
#endif
Point3 Spline::GetValueAlice(Point2 ab) const
{
    float lA = (ab[0] - fMinA) * fScaleA - 1.f;
    int iA = (int)lA;
    if (lA < 0) iA = 0;
    else if (iA > fNA - 4) iA = fNA - 4;

    float lB = (ab[1] - fMinB) * fScaleB - 1.f;
    int iB = (int)lB;
    if (lB < 0) iB = 0;
    else if (iB > fNB - 4) iB = fNB - 4;

    Point3 XYZ;
    if (Vc::float_v::Size == 4) {
        Vc::float_v da = lA - iA;
        Vc::float_v db = lB - iB;

        Vc::float_v v[4];
        int ind = iA * fNB + iB;
        const Vc::float_v *m = reinterpret_cast<const Vc::float_v *>(&fXYZ[0]);

        for (int i = 0; i < 4; i++) {
            v[i] = GetSpline3(m[ind + 0], m[ind + 1], m[ind + 2], m[ind + 3], db);
            ind += fNB;
        }
        Vc::float_v res = GetSpline3(v[0], v[1], v[2], v[3], da);
        XYZ[0] = res[0];
        XYZ[1] = res[1];
        XYZ[2] = res[2];
    } else {
        float da = lA - iA;
        float db = lB - iB;

        float vx[4];
        float vy[4];
        float vz[4];
        int ind = iA * fNB + iB;
        const float *m = reinterpret_cast<const float *>(&fXYZ[0]);
        for (int i = 0; i < 4; i++) {
            int ind4 = ind * 4;
            vx[i] = GetSpline3(m[ind4 + 0], m[ind4 + 4], m[ind4 + 8], m[ind4 + 12], db);
            vy[i] = GetSpline3(m[ind4 + 1], m[ind4 + 5], m[ind4 + 9], m[ind4 + 13], db);
            vz[i] = GetSpline3(m[ind4 + 2], m[ind4 + 6], m[ind4 + 10], m[ind4 + 14], db);
            ind += fNB;
        }
        XYZ[0] = GetSpline3(vx, da);
        XYZ[1] = GetSpline3(vy, da);
        XYZ[2] = GetSpline3(vz, da);
    }
    return XYZ;
}
// vim: foldmethod=marker
<|endoftext|>


<commit_before>/*
 * This program will simulate two protein molecules
 * in a dielectric solvent with explicit mobile ions.
 * The container is SPHERICAL w. hard walls.
 *
 * \author Mikael Lund
 * \date Prague 2007
 * \todo Maybe use a cylindrical cell?
 */

#include <iostream>
#include "analysis.h"
#include "mcloop.h"
typedef pot_coulomb T_pairpot;         // Specific pair interaction function
#include "markovmove.h"

using namespace std;

int main() {
  slump slump;                          // A random number generator
  inputfile in("twobody.conf");         // Read input file
  mcloop loop(in);                      // Set Markov chain loop lengths
  cell cell(in);                        // We want a spherical, hard cell
  canonical nvt;                        // Use the canonical ensemble
  pot_setup cfg(in);                    // Setup pair potential (default values)
  interaction<T_pairpot> pot(cfg);      // Functions for interactions
  ioxyz xyz(cell);                      // xyz output for VMD etc.
  distributions dst;                    // Distance dep. averages
  rdf saltrdf(particle::NA,particle::CL, .5, cell.r);

  vector<macromolecule> g;              // Group for proteins
  dualmove dm(nvt, cell, pot);          //   Class for 1D macromolecular translation
  dm.load( in, g, 40.);                 //   Load proteins and separate them
  dm.rmax=60;
  salt salt;                            // Group for mobile ions
  salt.add(cell, in);                   //   Add salt particles
  saltmove sm(nvt, cell, pot);          // Class for salt movements
  macrorot mr(nvt, cell, pot);          // Class for macromolecule rotation

  dm.dp=6;                              // Set displacement parameters
  sm.dp=90;                             // Set displacement parameters

  ioaam aam(cell);                      // Protein input file format is AAM
  if (aam.load(cell,"confout.aam")) {
    g[0].masscenter(cell);              // Load old config (if present)
    g[1].masscenter(cell);              // ...and recalc mass centers
  }
  chargereg tit(nvt,cell,pot,salt,4.0); // Prepare titration.
  systemenergy sys(pot.energy(cell.p)); // System energy analysis
  cout << cell.info() << pot.info()     // Print information to screen
    << tit.info();

  #ifdef GROMACS
  ioxtc xtc(cell, cell.r);              // Gromacs xtc output (if installed)
  #endif

  for (int macro=1; macro<=loop.macro; macro++) {//Markov chain
    for (int micro=1; micro<=loop.micro; micro++) {
      short i,n;
      switch (rand() % 4) {                     // Pick a random MC move
        case 0:                                 // Displace salt
          sys+=sm.move(salt);                   //   Do the move.
          break;
        case 1:                                 // Rotate proteins
          for (n=0; n<2; n++) {                 //   Loop over all proteins
            i = rand() % g.size();              //   and pick at random.
            sys+=mr.move(g[i]);                 //   Do the move.
          }
          break;
        case 2:                                 // Translate proteins
          sys+=dm.move(g[0], g[1]);             //   Do the move.
          break;
        case 3:                                 // Fluctuate charges
          sys+=tit.titrateall();                // Titrate sites on the protein
          if (tit.du!=0) {                      // Average charges and dipoles
            dst.add("Q1",dm.r, g[0].charge(cell.p));
            dst.add("Q2",dm.r, g[1].charge(cell.p));
            dst.add("MU1",dm.r,g[0].dipole(cell.p));
            dst.add("MU2",dm.r,g[1].dipole(cell.p));
          }
          break;
      }
      if (slump.random_one()>.8 && macro>1)
        saltrdf.update(cell);                   // Analyse salt g(r)

      #ifdef GROMACS
      if (slump.random_one()>.95 && macro>1)
        xtc.save("ignored-name.xtc", cell.p);   // Save trajectory
      #endif
    } // End of inner loop

    sys.update(pot.energy(cell.p));             // Update system energy averages
    cell.check_vector();                        // Check sanity of particle vector

    dm.gofr.write("rdfprot.dat");               // Write interprotein g(r)
    saltrdf.write("rdfsalt.dat");               // Write salt g(r)
    dst.write("distributions.dat");             // Write other distributions
    xyz.save("coord.xyz", cell.p);              // Write .xyz coordinate file
    aam.save("confout.aam", cell.p);            // Save config. for next run
    cout << loop.timing(macro);                 // Show progress
  } // End of outer loop

  cout << salt.info(cell)                       // Final information...
       << sm.info() << mr.info() << dm.info()
       << tit.info() << sys.info()
       << g[0].info() << g[1].info() << cell.info();

  #ifdef GROMACS
  xtc.close();
  #endif
}

<commit_msg>Some extentions for a isobaric/isothermal ensemble<commit_after>/*
 * This program will simulate two protein molecules
 * in a dielectric solvent with explicit mobile ions.
 * The container is SPHERICAL w. hard walls.
 *
 * \author Mikael Lund
 * \date Prague 2007
 * \todo Maybe use a cylindrical cell?
 */

#include <iostream>
#include "io.h"
#include "analysis.h"
#include "potentials.h"
#include "container.h"
#include "countdown.h"
#include "histogram.h"
#include "inputfile.h"
typedef pot_coulomb T_pairpot;         // Specific pair interaction function
#include "markovmove.h"

using namespace std;

int main() {
  enum dstkeys { Q1=0,Q2,MU1,MU2, LAST };
  slump slump;                          // A random number generator
  inputfile in("twobody.conf");         // Read input file
  cell cell(in);                        // We want a spherical, hard cell
  canonical nvt;                        // Use the canonical ensemble
  pot_setup cfg(in);                    // Setup pair potential (default values)
  interaction<T_pairpot> pot(cfg);      // Functions for interactions
  countdown<int> clock(10);             // Estimate simulation time
  ioxyz xyz(cell);                      // xyz output for VMD etc.
  distributions dst(LAST,0,180);
  rdf saltrdf(particle::NA,particle::SO4, .5, cell.r);

  vector<macromolecule> g;              // Group for proteins
  dualmove dm(nvt, cell, pot);          //   Class for 1D macromolecular translation
  dm.load( in, g, 40.);                 //   Load proteins and separate them
  salt salt;                            // Group for mobile ions
  salt.add(cell, in);                   //   Add salt particles
  saltmove sm(nvt, cell, pot);          // Class for salt movements
  macrorot mr(nvt, cell, pot);          // Class for macromolecule rotation

  ioaam aam(cell);                      // Protein input file format is AAM
  if (aam.load(cell,"confout.aam")) {
    g[0].masscenter(cell.p);            // Load old config (if present)
    g[1].masscenter(cell.p);            // ...and recalc mass centers
  }
  chargereg tit(nvt,cell,pot,salt,5.0); // Prepare titration.
  systemenergy sys(pot.energy(cell.p)); // System energy analysis
  cout << cell.info() << pot.info();    // Print information to screen

  #ifdef GROMACS
  ioxtc xtc(cell, cell.r);              // Gromacs xtc output (if installed)
  #endif

  for (int macro=1; macro<=10; macro++) {       // Markov chain
    for (int micro=1; micro<=2e5; micro++) {
      short i,n;
      switch (rand() % 4) {                     // Pick a random MC move
        case 0:                                 // Displace salt
          sys+=sm.move(salt);                   //   Do the move.
          break;
        case 1:                                 // Rotate proteins
          for (n=0; n<2; n++) {                 //   Loop over all proteins
            i = rand() % g.size();              //   and pick at random.
            sys+=mr.move(g[i]);                 //   Do the move.
          }
          break;
        case 2:                                 // Translate proteins
          sys+=dm.move(g[0], g[1]);             //   Do the move.
          break;
        case 3:                                 // Fluctuate charges
          sys+=tit.titrateall();                // Titrate sites on the protein
          dst.add(Q1,dm.r, g[0].charge(cell.p));// Re-calc. protein charges
          dst.add(Q2,dm.r, g[1].charge(cell.p));
          dst.add(MU1,dm.r,g[0].dipole(cell.p));// ..and dipole moments
          dst.add(MU2,dm.r,g[1].dipole(cell.p));
          break;
      }
      if (slump.random_one()>.8 && macro>1)
        saltrdf.update(cell);                   // Analyse salt g(r)

      #ifdef GROMACS
      if (slump.random_one()>.95 && macro>1)
        xtc.save("ignored-name.xtc", cell.p);   // Save trajectory
      #endif

    } // End of inner loop

    sys.update(pot.energy(cell.p));             // Update system energy averages
    cell.check_vector();                        // Check sanity of particle vector

    xyz.save("coord.xyz", cell.p);              // Write .xyz coordinate file
    aam.save("confout.aam", cell.p);            // Save config. for next run
    dm.gofr.write("rdfprot.dat");
    saltrdf.write("rdfsalt.dat");
    cout << "Macro step " << macro
         << " completed. ETA: " << clock.eta(macro);

  } // End of outer loop

  cout << salt.info(cell)                       // Final information...
       << sm.info() << mr.info() << dm.info()
       << tit.info() << sys.info()
       << g[0].info() << g[1].info() << cell.info();

  #ifdef GROMACS
  xtc.close();
  #endif
}

<|endoftext|>


<commit_before>#include <stdio.h>

#include "quick.hpp"
#include "swap.hpp"

void quick(int *data, const int size_of_data)
{
    return quick(data, 0, size_of_data - 1);
}

void quick(int *data, const int start, const int end)
{
    int size = end - start + 1;

#ifdef TESTLAYOUT
    printf("START %d : END %d : PIVOT %d\n", start, end, data[end]);
    for(int i = start; i <= end; ++i) printf(" %2d  ", data[i]);
    printf("\n");
#endif

    if(start >= end) return; /* Base case */

    /* Conquer */
    int pivot = end; /* Set pivot */

    int ps = start, pe = end - 1;
    while(ps < pe)
    {
        while(ps < pe && data[ps] < data[pivot]) ++ps;
        while(ps < pe && data[pe] >= data[pivot]) --pe;

#ifdef TESTLAYOUT
        for(int i = start; i <= end; ++i)
        {
            if(i == ps && i == pe)
                printf("(%2d) ", data[i]);
            else if(i == ps || i == pe)
                printf("[%2d] ", data[i]);
            else
                printf(" %2d  ", data[i]);
        }
        printf("  (%d, %d)\n", ps, pe);
#endif

        if(ps < pe) swap(data[ps], data[pe]);
    }

    if(data[pe] > data[pivot])
        swap(data[pe], data[pivot]);
    else if(pe == end - 1)
        ++pe;

#ifdef TESTLAYOUT
    for(int i = start; i <= end; ++i) printf(" %2d  ", data[i]);
    printf("\n");
#endif

    /* Divide */
    quick(data, start, pe - 1);
    quick(data, pe + 1, end);
}
<commit_msg>Remove test layout<commit_after>#include <stdio.h>

#include "quick.hpp"
#include "swap.hpp"

void quick(int *data, const int size_of_data)
{
    return quick(data, 0, size_of_data - 1);
}

void quick(int *data, const int start, const int end)
{
    int size = end - start + 1;

    if(start >= end) return; /* Base case */

    /* Conquer */
    int pivot = end; /* Set pivot */

    int ps = start, pe = end - 1;
    while(ps < pe)
    {
        while(ps < pe && data[ps] < data[pivot]) ++ps;
        while(ps < pe && data[pe] >= data[pivot]) --pe;

        if(ps < pe) swap(data[ps], data[pe]);
    }

    if(data[pe] > data[pivot])
        swap(data[pe], data[pivot]);
    else if(pe == end - 1)
        ++pe;

    /* Divide */
    quick(data, start, pe - 1);
    quick(data, pe + 1, end);
}
<|endoftext|>


<commit_before>
//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h>
#include <string>

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
#include <d3d9.h>
#include <XAudio2.h>
#pragma comment(lib, "d3d9.lib" )
#pragma comment(lib, "xaudio2.lib" )

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
#include <Effekseer.h>
#include <EffekseerRendererDX9.h>
#include <EffekseerSoundXAudio2.h>

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
static HWND g_window_handle = NULL;
static int g_window_width = 800;
static int g_window_height = 600;
static ::Effekseer::ManagerRef				g_manager;
static ::EffekseerRendererDX9::RendererRef	g_renderer;
static ::EffekseerSound::SoundRef			g_sound = NULL;
static ::Effekseer::Vector3D			g_position;
static ::Effekseer::EffectRef			g_effect;
static ::Effekseer::Handle				g_handle = -1;

static LPDIRECT3D9						g_d3d = NULL;
static LPDIRECT3DDEVICE9				g_d3d_device = NULL;
static IXAudio2*						g_xa2 = NULL;
static IXAudio2MasteringVoice*			g_xa2_master = NULL;

static int32_t							g_timer = 0;

static IDirect3DSurface9*				g_backgroundSurface = nullptr;
static IDirect3DTexture9*				g_backgroundTexture = nullptr;

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	switch( msg )
	{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
static bool CopyRenderTargetToBackground()
{
	bool ret = false;

	HRESULT hr;
	IDirect3DSurface9* tempRender = nullptr;
	IDirect3DSurface9* tempDepth = nullptr;

	hr = g_d3d_device->GetRenderTarget(0, &tempRender);
	if (FAILED(hr))
	{
		goto Exit;
	}

	hr = g_d3d_device->GetDepthStencilSurface(&tempDepth);
	if (FAILED(hr))
	{
		goto Exit;
	}

	g_d3d_device->SetRenderTarget(0, g_backgroundSurface);
	g_d3d_device->SetDepthStencilSurface(nullptr);

	D3DSURFACE_DESC desc;
	tempRender->GetDesc(&desc);

	g_d3d_device->StretchRect(
		tempRender,
		nullptr,
		g_backgroundSurface,
		nullptr,
		D3DTEXF_POINT
		);

	g_d3d_device->SetRenderTarget(0, tempRender);
	g_d3d_device->SetDepthStencilSurface(tempDepth);

	ret = true;

Exit:;
	ES_SAFE_RELEASE(tempRender);
	ES_SAFE_RELEASE(tempDepth);

	return ret;
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
class DistortingCallback
	: public EffekseerRenderer::DistortingCallback
{
public:
	DistortingCallback()
	{

	}

	virtual ~DistortingCallback()
	{

	}

	bool OnDistorting()
	{
		if (g_backgroundTexture == NULL)
		{
			g_renderer->SetBackground(NULL);
			return false;
		}

		CopyRenderTargetToBackground();
		g_renderer->SetBackground(g_backgroundTexture);
		return true;
	}
};

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
void InitWindow()
{
	WNDCLASS wndClass;
	wchar_t szClassNme[]      =  L"RuntimeSample";
	wndClass.style         = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc   = WndProc;
	wndClass.cbClsExtra    = 0;
	wndClass.cbWndExtra    = 0;
	wndClass.hInstance     = GetModuleHandle(0);
	wndClass.hIcon         = NULL;
	wndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName  = NULL;
	wndClass.lpszClassName = szClassNme;
	RegisterClass(&wndClass);
	g_window_handle = CreateWindow(
		szClassNme,
		L"RuntimeSample",
		WS_SYSMENU,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		g_window_width,
		g_window_height,
		NULL,
		NULL,
		GetModuleHandle(0),
		NULL);
	ShowWindow( g_window_handle, true );
	UpdateWindow( g_window_handle );

	// COMの初期化
	CoInitializeEx( NULL, NULL );

	// DirectX9の初期化を行う
	D3DPRESENT_PARAMETERS d3dp;
	ZeroMemory(&d3dp, sizeof(d3dp));
	d3dp.BackBufferWidth = g_window_width;
	d3dp.BackBufferHeight = g_window_height;
	d3dp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dp.BackBufferCount = 1;
	d3dp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dp.Windowed = TRUE;
	d3dp.hDeviceWindow = g_window_handle;
	d3dp.EnableAutoDepthStencil = TRUE;
    d3dp.AutoDepthStencilFormat = D3DFMT_D16;

	g_d3d = Direct3DCreate9(D3D_SDK_VERSION);

	g_d3d->CreateDevice(
		D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		g_window_handle,
		D3DCREATE_HARDWARE_VERTEXPROCESSING,
		&d3dp,
		&g_d3d_device );

	// XAudio2の初期化を行う
	XAudio2Create( &g_xa2 );

	g_xa2->CreateMasteringVoice( &g_xa2_master );
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
void MainLoop()
{
	for(;;)
	{
		MSG msg;
		if (PeekMessage (&msg,NULL,0,0,PM_NOREMOVE))
		{
			if( msg.message == WM_QUIT )
			{
				return ;
			}
			GetMessage (&msg,NULL,0,0);
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			// エフェクトの更新処理を行う。
			g_manager->Update();

			g_d3d_device->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
			g_d3d_device->BeginScene();

			// エフェクトの描画開始処理を行う。
			g_renderer->BeginRendering();

			// Render rear effects
			// 背面のエフェクトの描画を行う。
			g_manager->DrawBack();

			// Distort background and rear effects.
			// 背景と背面のエフェクトを歪ませる。
			DistortingCallback distoring;
			distoring.OnDistorting();

			// Render front effects
			// 前面のエフェクトの描画を行う。
			g_manager->DrawFront();

			// エフェクトの描画終了処理を行う。
			g_renderer->EndRendering();

			g_d3d_device->EndScene();

			g_timer++;

			{
				HRESULT hr;
				hr = g_d3d_device->Present( NULL, NULL, NULL, NULL );

				// デバイスロスト処理
				switch ( hr )
				{
					// デバイスロスト
					case D3DERR_DEVICELOST:
					while ( FAILED( hr = g_d3d_device->TestCooperativeLevel() ) )
					{
						switch ( hr )
						{
							// デバイスロスト
							case D3DERR_DEVICELOST:
								::SleepEx( 1000, true );
								break;

							// デバイスロスト：リセット可
							case D3DERR_DEVICENOTRESET:

								// デバイスロストの処理を行う前に実行する
								g_renderer->OnLostDevice();

								D3DPRESENT_PARAMETERS d3dp;
								ZeroMemory(&d3dp, sizeof(d3dp));
								d3dp.BackBufferWidth = g_window_width;
								d3dp.BackBufferHeight = g_window_height;
								d3dp.BackBufferFormat = D3DFMT_X8R8G8B8;
								d3dp.BackBufferCount = 1;
								d3dp.SwapEffect = D3DSWAPEFFECT_DISCARD;
								d3dp.Windowed = TRUE;
								d3dp.hDeviceWindow = g_window_handle;
								d3dp.EnableAutoDepthStencil = TRUE;
								d3dp.AutoDepthStencilFormat = D3DFMT_D16;

								g_d3d_device->Reset( &d3dp );

								// デバイスロストの処理の後に実行する
								g_renderer->OnResetDevice();

								break;
						}
					}
					break;
				}
			}
		}
	}
}

#if _WIN32
#include <windows.h>
std::wstring ToWide(const char* pText);
void GetDirectoryName(char* dst, char* src);
#endif

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
int main(int argc, char **argv)
{
#if _WIN32
	char current_path[MAX_PATH + 1];
	GetDirectoryName(current_path, argv[0]);
	SetCurrentDirectoryA(current_path);
#endif

	InitWindow();

	// 描画用インスタンスの生成
	g_renderer = ::EffekseerRendererDX9::Renderer::Create( g_d3d_device, 2000 );

	// Specify a distortion function
	// 歪み機能を設定

	// If you'd like to distort background and particles by rendering, it need to specify it.
	// It is a bit heavy
	// もし、描画するごとに背景とパーティクルを歪ませたい場合、設定する必要がある
	// やや重い
	g_renderer->SetDistortingCallback(new DistortingCallback());

	// 背景バッファの生成
	g_d3d_device->CreateTexture(
		640,
		480,
		1,
		D3DUSAGE_RENDERTARGET,
		D3DFMT_A8R8G8B8,
		D3DPOOL_DEFAULT,
		&g_backgroundTexture,
		NULL
		);

	g_backgroundTexture->GetSurfaceLevel(0, &g_backgroundSurface);

	// エフェクト管理用インスタンスの生成
	g_manager = ::Effekseer::Manager::Create( 2000 );

	// 描画用インスタンスから描画機能を設定
	g_manager->SetSpriteRenderer( g_renderer->CreateSpriteRenderer() );
	g_manager->SetRibbonRenderer( g_renderer->CreateRibbonRenderer() );
	g_manager->SetRingRenderer( g_renderer->CreateRingRenderer() );
	g_manager->SetTrackRenderer( g_renderer->CreateTrackRenderer() );
	g_manager->SetModelRenderer( g_renderer->CreateModelRenderer() );

	// 描画用インスタンスからテクスチャの読込機能を設定
	// 独自拡張可能、現在はファイルから読み込んでいる。
	g_manager->SetTextureLoader( g_renderer->CreateTextureLoader() );
	g_manager->SetModelLoader( g_renderer->CreateModelLoader() );

	// 音再生用インスタンスの生成
	g_sound = ::EffekseerSound::Sound::Create( g_xa2, 16, 16 );

	// 音再生用インスタンスから再生機能を指定
	g_manager->SetSoundPlayer( g_sound->CreateSoundPlayer() );

	// 音再生用インスタンスからサウンドデータの読込機能を設定
	// 独自拡張可能、現在はファイルから読み込んでいる。
	g_manager->SetSoundLoader( g_sound->CreateSoundLoader() );

	// 視点位置を確定
	g_position = ::Effekseer::Vector3D(10.0f, 5.0f, 20.0f) * 0.25;

	// 投影行列を設定
	g_renderer->SetProjectionMatrix(
		::Effekseer::Matrix44().PerspectiveFovRH(90.0f / 180.0f * 3.14f, (float)g_window_width / (float)g_window_height, 1.0f, 50.0f));

	// カメラ行列を設定
	g_renderer->SetCameraMatrix(
		::Effekseer::Matrix44().LookAtRH(g_position, ::Effekseer::Vector3D(0.0f, 0.0f, 0.0f), ::Effekseer::Vector3D(0.0f, 1.0f, 0.0f)));

	// エフェクトの読込
	g_effect = Effekseer::Effect::Create(g_manager, EFK_EXAMPLE_ASSETS_DIR_U16 u"distortion.efk");

	// エフェクトの再生
	g_handle = g_manager->Play(g_effect, 0, 0, 0);

	MainLoop();

	// エフェクトの停止
	g_manager->StopEffect(g_handle);

	// 先にエフェクト管理用インスタンスを破棄
	g_manager.Reset();

	// 次に音再生用インスタンスを破棄
	g_sound.Reset();

	// 次に描画用インスタンスを破棄
	g_renderer.Reset();

	// XAudio2の解放
	if( g_xa2_master != NULL )
	{
		g_xa2_master->DestroyVoice();
		g_xa2_master = NULL;
	}
	ES_SAFE_RELEASE( g_xa2 );

	// バックバッファの破棄
	ES_SAFE_RELEASE( g_backgroundTexture );
	ES_SAFE_RELEASE( g_backgroundSurface );

	// DirectXの解放
	ES_SAFE_RELEASE( g_d3d_device );
	ES_SAFE_RELEASE( g_d3d );

	// COMの終了処理
	CoUninitialize();

	return 0;
}
//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------

#if _WIN32
static std::wstring ToWide(const char* pText)
{
	int Len = ::MultiByteToWideChar(CP_ACP, 0, pText, -1, NULL, 0);

	wchar_t* pOut = new wchar_t[Len + 1];
	::MultiByteToWideChar(CP_ACP, 0, pText, -1, pOut, Len);
	std::wstring Out(pOut);
	delete[] pOut;

	return Out;
}

void GetDirectoryName(char* dst, char* src)
{
	auto Src = std::string(src);
	int pos = 0;
	int last = 0;
	while (Src.c_str()[pos] != 0)
	{
		dst[pos] = Src.c_str()[pos];

		if (Src.c_str()[pos] == L'\\' || Src.c_str()[pos] == L'/')
		{
			last = pos;
		}

		pos++;
	}

	dst[pos] = 0;
	dst[last] = 0;
}
#endif

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------<commit_msg>Refactor a distortion sample<commit_after>
#include <stdio.h>
#include <string>
#include <windows.h>

#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")

#include <Effekseer.h>
#include <EffekseerRendererDX9.h>

static HWND g_window_handle = NULL;
static int g_window_width = 800;
static int g_window_height = 600;
static ::Effekseer::ManagerRef g_manager;
static ::EffekseerRendererDX9::RendererRef g_renderer;
static ::Effekseer::Vector3D g_position;
static ::Effekseer::EffectRef g_effect;
static ::Effekseer::Handle g_handle = -1;

static LPDIRECT3D9 g_d3d = NULL;
static LPDIRECT3DDEVICE9 g_d3d_device = NULL;

static int32_t g_timer = 0;

static IDirect3DSurface9* g_backgroundSurface = nullptr;
static IDirect3DTexture9* g_backgroundTexture = nullptr;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

bool CopyRenderTargetToBackground()
{
	bool ret = false;

	HRESULT hr;
	IDirect3DSurface9* tempRender = nullptr;
	IDirect3DSurface9* tempDepth = nullptr;

	hr = g_d3d_device->GetRenderTarget(0, &tempRender);
	if (FAILED(hr))
	{
		goto Exit;
	}

	hr = g_d3d_device->GetDepthStencilSurface(&tempDepth);
	if (FAILED(hr))
	{
		goto Exit;
	}

	g_d3d_device->SetRenderTarget(0, g_backgroundSurface);
	g_d3d_device->SetDepthStencilSurface(nullptr);

	D3DSURFACE_DESC desc;
	tempRender->GetDesc(&desc);

	g_d3d_device->StretchRect(tempRender, nullptr, g_backgroundSurface, nullptr, D3DTEXF_POINT);

	g_d3d_device->SetRenderTarget(0, tempRender);
	g_d3d_device->SetDepthStencilSurface(tempDepth);

	ret = true;

Exit:;
	ES_SAFE_RELEASE(tempRender);
	ES_SAFE_RELEASE(tempDepth);

	return ret;
}

class DistortingCallback : public EffekseerRenderer::DistortingCallback
{
public:
	DistortingCallback() {}

	virtual ~DistortingCallback() {}

	bool OnDistorting()
	{
		if (g_backgroundTexture == NULL)
		{
			g_renderer->SetBackground(NULL);
			return false;
		}

		CopyRenderTargetToBackground();
		g_renderer->SetBackground(g_backgroundTexture);
		return true;
	}
};

void InitWindow()
{
	WNDCLASS wndClass;
	wchar_t szClassNme[] = L"RuntimeSample";
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = GetModuleHandle(0);
	wndClass.hIcon = NULL;
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = szClassNme;
	RegisterClass(&wndClass);
	g_window_handle = CreateWindow(szClassNme,
								   L"RuntimeSample",
								   WS_SYSMENU,
								   CW_USEDEFAULT,
								   CW_USEDEFAULT,
								   g_window_width,
								   g_window_height,
								   NULL,
								   NULL,
								   GetModuleHandle(0),
								   NULL);
	ShowWindow(g_window_handle, true);
	UpdateWindow(g_window_handle);

	D3DPRESENT_PARAMETERS d3dp;
	ZeroMemory(&d3dp, sizeof(d3dp));
	d3dp.BackBufferWidth = g_window_width;
	d3dp.BackBufferHeight = g_window_height;
	d3dp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dp.BackBufferCount = 1;
	d3dp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dp.Windowed = TRUE;
	d3dp.hDeviceWindow = g_window_handle;
	d3dp.EnableAutoDepthStencil = TRUE;
	d3dp.AutoDepthStencilFormat = D3DFMT_D16;

	g_d3d = Direct3DCreate9(D3D_SDK_VERSION);

	g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_window_handle, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dp, &g_d3d_device);
}

void MainLoop()
{
	for (;;)
	{
		MSG msg;
		if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				return;
			}
			GetMessage(&msg, NULL, 0, 0);
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			g_manager->Update();

			g_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
			g_d3d_device->BeginScene();

			g_renderer->BeginRendering();

			// Render rear effects
			// 背面のエフェクトの描画を行う。
			g_manager->DrawBack();

			g_renderer->EndRendering();

			// Distort background and rear effects.
			// 背景と背面のエフェクトを歪ませる。
			DistortingCallback distoring;
			distoring.OnDistorting();

			g_renderer->BeginRendering();

			// Render front effects
			// 前面のエフェクトの描画を行う。
			g_manager->DrawFront();

			g_renderer->EndRendering();

			g_d3d_device->EndScene();

			g_timer++;

			{
				HRESULT hr;
				hr = g_d3d_device->Present(NULL, NULL, NULL, NULL);

				switch (hr)
				{
				case D3DERR_DEVICELOST:
					while (FAILED(hr = g_d3d_device->TestCooperativeLevel()))
					{
						switch (hr)
						{
						case D3DERR_DEVICELOST:
							::SleepEx(1000, true);
							break;

						case D3DERR_DEVICENOTRESET:

							g_renderer->OnLostDevice();

							D3DPRESENT_PARAMETERS d3dp;
							ZeroMemory(&d3dp, sizeof(d3dp));
							d3dp.BackBufferWidth = g_window_width;
							d3dp.BackBufferHeight = g_window_height;
							d3dp.BackBufferFormat = D3DFMT_X8R8G8B8;
							d3dp.BackBufferCount = 1;
							d3dp.SwapEffect = D3DSWAPEFFECT_DISCARD;
							d3dp.Windowed = TRUE;
							d3dp.hDeviceWindow = g_window_handle;
							d3dp.EnableAutoDepthStencil = TRUE;
							d3dp.AutoDepthStencilFormat = D3DFMT_D16;

							g_d3d_device->Reset(&d3dp);

							g_renderer->OnResetDevice();

							break;
						}
					}
					break;
				}
			}
		}
	}
}

int main(int argc, char** argv)
{
	InitWindow();

	g_renderer = ::EffekseerRendererDX9::Renderer::Create(g_d3d_device, 2000);

	// Specify a distortion function
	// 歪み機能を設定

	// If you'd like to distort background and particles by rendering, it need to specify it.
	// It is a bit heavy
	// もし、描画するごとに背景とパーティクルを歪ませたい場合、設定する必要がある
	// やや重い
	// g_renderer->SetDistortingCallback(new DistortingCallback());

	// Create a background buffer
	g_d3d_device->CreateTexture(640, 480, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_backgroundTexture, NULL);

	g_backgroundTexture->GetSurfaceLevel(0, &g_backgroundSurface);

	g_manager = ::Effekseer::Manager::Create(2000);

	g_manager->SetSpriteRenderer(g_renderer->CreateSpriteRenderer());
	g_manager->SetRibbonRenderer(g_renderer->CreateRibbonRenderer());
	g_manager->SetRingRenderer(g_renderer->CreateRingRenderer());
	g_manager->SetTrackRenderer(g_renderer->CreateTrackRenderer());
	g_manager->SetModelRenderer(g_renderer->CreateModelRenderer());

	g_manager->SetTextureLoader(g_renderer->CreateTextureLoader());
	g_manager->SetModelLoader(g_renderer->CreateModelLoader());

	g_position = ::Effekseer::Vector3D(10.0f, 5.0f, 20.0f) * 0.25;

	g_renderer->SetProjectionMatrix(
		::Effekseer::Matrix44().PerspectiveFovRH(90.0f / 180.0f * 3.14f, (float)g_window_width / (float)g_window_height, 1.0f, 50.0f));

	g_renderer->SetCameraMatrix(
		::Effekseer::Matrix44().LookAtRH(g_position, ::Effekseer::Vector3D(0.0f, 0.0f, 0.0f), ::Effekseer::Vector3D(0.0f, 1.0f, 0.0f)));

	g_effect = Effekseer::Effect::Create(g_manager, EFK_EXAMPLE_ASSETS_DIR_U16 u"distortion.efk");

	g_handle = g_manager->Play(g_effect, 0, 0, 0);

	MainLoop();

	g_manager->StopEffect(g_handle);

	g_manager.Reset();

	g_renderer.Reset();

	ES_SAFE_RELEASE(g_backgroundTexture);
	ES_SAFE_RELEASE(g_backgroundSurface);

	ES_SAFE_RELEASE(g_d3d_device);
	ES_SAFE_RELEASE(g_d3d);

	return 0;
}
<|endoftext|>


<commit_before>#include "core/image.h"

#include "core/vfs.h"
#include "core/base64.h"
#include "core/rgb.h"
#include "core/image_draw.h"
#include "core/imageops.h"

#include "tests/approx_equal.h"
#include "tests/stringeq.h"
#include "core/fonts.h"

#include "catch.hpp"

namespace vfs  = euphoria::core::vfs;
namespace euco = euphoria::core;

using namespace euphoria::tests;

// 4x4 image without transperency
// white  / red
// green / blue
const char* const TEST_IMAGE
        = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAABmJLR0QA/wD/"
          "AP+"
          "gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QgdFSAdb6CP5AAAABVJREFUCNcFw"
          "QEBAAAAgBD/TxeqIDQz2gX7fv3PJgAAAABJRU5ErkJggg==";

TEST_CASE("image-load", "[img]")
{
    vfs::FileSystem fs;
    auto            catalog = vfs::FileSystemRootCatalog::AddRoot(&fs);
    catalog->RegisterFileData("white", euco::base64::Decode(TEST_IMAGE));

    auto loaded = euco::LoadImage(&fs, "white", euco::AlphaLoad::Remove);
    REQUIRE(loaded.error == "");
    REQUIRE_FALSE(loaded.image.HasAlpha());

    REQUIRE(loaded.image.GetHeight() == 2);
    REQUIRE(loaded.image.GetWidth() == 2);

    // upper left
    SECTION("load-white")
    {
        const auto pixel = loaded.image.GetPixel(0, 1);
        const auto white = euco::Rgbai {euco::Rgbi {255, 255, 255}, 255};
        REQUIRE(pixel == white);
    }

    // upper right
    SECTION("load-red")
    {
        const auto pixel = loaded.image.GetPixel(1, 1);
        const auto red   = euco::Rgbai {euco::Rgbi {255, 0, 0}, 255};
        REQUIRE(pixel == red);
    }

    // lower left
    SECTION("load-green")
    {
        const auto pixel = loaded.image.GetPixel(0, 0);
        const auto green = euco::Rgbai {euco::Rgbi {0, 255, 0}, 255};
        REQUIRE(pixel == green);
    }

    // lower right
    SECTION("load-blue")
    {
        const auto pixel = loaded.image.GetPixel(1, 0);
        const auto blue  = euco::Rgbai {euco::Rgbi {0, 0, 255}, 255};
        REQUIRE(pixel == blue);
    }
}

TEST_CASE("image solid", "[img]")
{
    euco::Image img;
    img.SetupNoAlphaSupport(3, 3);

    SECTION("default-is-black")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 255));
        REQUIRE(img.GetPixel(1, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 255));
    }

    SECTION("can set and get color")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 255));
        euco::Rgbai color {euco::Rgbi {255, 255, 255}, 255};
        img.SetPixel(0, 0, color);
        REQUIRE(img.GetPixel(0, 0) == color);
    }
}

TEST_CASE("image transparent", "[img]")
{
    euco::Image img;
    img.SetupWithAlphaSupport(4, 4);

    SECTION("default-is-black")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 0));
        REQUIRE(img.GetPixel(1, 1) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 0));
    }

    SECTION("can set and get color")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 0));
        euco::Rgbai color {euco::Rgbi {255, 255, 255}, 255};
        img.SetPixel(0, 0, color);
        REQUIRE(img.GetPixel(0, 0) == color);
    }
}

// todo: add paint test
TEST_CASE("image draw", "[img]")
{
    euco::Image img;
    const int   width  = 10;
    const int   height = 12;
    img.SetupNoAlphaSupport(width, height);

    SECTION("draw size is image size")
    {
        const auto size = euco::WholeImage(img);
        CHECK(size.bottom == 0);
        CHECK(size.left == 0);
        CHECK(size.GetWidth() == width);
        CHECK(size.GetHeight() == height);
    }

    euco::Rgbi  color {255, 255, 0};
    euco::Rgbai colora {color, 255};

    SECTION("fill")
    {
        CHECK_FALSE(img.GetPixel(0, 0) == colora);
        CHECK_FALSE(img.GetPixel(3, 3) == colora);
        CHECK_FALSE(img.GetPixel(width - 1, height - 1) == colora);

        euco::DrawRect(&img, color, euco::WholeImage(img));
        REQUIRE(img.GetPixel(0, 0) == colora);
        REQUIRE(img.GetPixel(3, 3) == colora);
        REQUIRE(img.GetPixel(width - 1, height - 1) == colora);
    }

    SECTION("circle")
    {
        CHECK_FALSE(img.GetPixel(5, 5) == colora);
        euco::DrawCircle(&img, rgb(color), euco::vec2i {5, 5}, 4);
        CHECK_FALSE(img.GetPixel(0, 0) == colora);
        REQUIRE(img.GetPixel(5, 5) == colora);
    }

    SECTION("circle with hole")
    {
        CHECK_FALSE(img.GetPixel(0, 0) == colora);
        CHECK_FALSE(img.GetPixel(5, 5) == colora);
        euco::DrawCircle(&img, rgb(color), euco::vec2i {5, 5}, 20, 0, 3);
        CHECK_FALSE(img.GetPixel(5, 5) == colora);
        REQUIRE(img.GetPixel(0, 0) == colora);
    }
}

TEST_CASE("image text")
{
    auto draw_text = [](const std::string& text, int width, int height) -> std::vector<std::string>
    {
        euco::Image image;
        image.SetupNoAlphaSupport(width, height);
        euco::DrawRect(&image, euco::Color::White, euco::WholeImage(image));
        euco::DrawText(&image, euco::vec2i(0,0), text, euco::Color::Black, euco::LoadCharactersFromBuiltin());
        const auto table = euco::ImageToStringTableExact(
            image,
            { {'#', euco::Color::Black}, {' ', euco::Color::White} }, '?');
        const auto strings = euco::ToStrings(table);
        return strings;
    };

    CHECK(StringEq(draw_text("dog !", 8*6, 8),
        {
    "   ###                             ##           ",
    "    ##                            ####          ",
    "    ##   ####    ### ##           ####          ",
    " #####  ##  ##  ##  ##             ##           ",
    "##  ##  ##  ##  ##  ##             ##           ",
    "##  ##  ##  ##   #####                          ",
    " ### ##  ####       ##             ##           ",
    "                #####                           "
        }));

    CHECK(StringEq(draw_text("CAT", 8, 8),
        {
            "  ####  ",
            " ##  ## ",
            "##      ",
            "##      ",
            "##      ",
            " ##  ## ",
            "  ####  ",
            "        "
        }));
}
<commit_msg>draw text at top-left of image<commit_after>#include "core/image.h"

#include "core/vfs.h"
#include "core/base64.h"
#include "core/rgb.h"
#include "core/image_draw.h"
#include "core/imageops.h"

#include "tests/approx_equal.h"
#include "tests/stringeq.h"
#include "core/fonts.h"

#include "catch.hpp"

namespace vfs  = euphoria::core::vfs;
namespace euco = euphoria::core;

using namespace euphoria::tests;

// 4x4 image without transperency
// white  / red
// green / blue
const char* const TEST_IMAGE
        = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAABmJLR0QA/wD/"
          "AP+"
          "gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QgdFSAdb6CP5AAAABVJREFUCNcFw"
          "QEBAAAAgBD/TxeqIDQz2gX7fv3PJgAAAABJRU5ErkJggg==";

TEST_CASE("image-load", "[img]")
{
    vfs::FileSystem fs;
    auto            catalog = vfs::FileSystemRootCatalog::AddRoot(&fs);
    catalog->RegisterFileData("white", euco::base64::Decode(TEST_IMAGE));

    auto loaded = euco::LoadImage(&fs, "white", euco::AlphaLoad::Remove);
    REQUIRE(loaded.error == "");
    REQUIRE_FALSE(loaded.image.HasAlpha());

    REQUIRE(loaded.image.GetHeight() == 2);
    REQUIRE(loaded.image.GetWidth() == 2);

    // upper left
    SECTION("load-white")
    {
        const auto pixel = loaded.image.GetPixel(0, 1);
        const auto white = euco::Rgbai {euco::Rgbi {255, 255, 255}, 255};
        REQUIRE(pixel == white);
    }

    // upper right
    SECTION("load-red")
    {
        const auto pixel = loaded.image.GetPixel(1, 1);
        const auto red   = euco::Rgbai {euco::Rgbi {255, 0, 0}, 255};
        REQUIRE(pixel == red);
    }

    // lower left
    SECTION("load-green")
    {
        const auto pixel = loaded.image.GetPixel(0, 0);
        const auto green = euco::Rgbai {euco::Rgbi {0, 255, 0}, 255};
        REQUIRE(pixel == green);
    }

    // lower right
    SECTION("load-blue")
    {
        const auto pixel = loaded.image.GetPixel(1, 0);
        const auto blue  = euco::Rgbai {euco::Rgbi {0, 0, 255}, 255};
        REQUIRE(pixel == blue);
    }
}

TEST_CASE("image solid", "[img]")
{
    euco::Image img;
    img.SetupNoAlphaSupport(3, 3);

    SECTION("default-is-black")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 255));
        REQUIRE(img.GetPixel(1, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 255));
    }

    SECTION("can set and get color")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 255));
        euco::Rgbai color {euco::Rgbi {255, 255, 255}, 255};
        img.SetPixel(0, 0, color);
        REQUIRE(img.GetPixel(0, 0) == color);
    }
}

TEST_CASE("image transparent", "[img]")
{
    euco::Image img;
    img.SetupWithAlphaSupport(4, 4);

    SECTION("default-is-black")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 0));
        REQUIRE(img.GetPixel(1, 1) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 0));
    }

    SECTION("can set and get color")
    {
        REQUIRE(img.GetPixel(0, 0) == euco::Rgbai(euco::Rgbi {0, 0, 0}, 0));
        euco::Rgbai color {euco::Rgbi {255, 255, 255}, 255};
        img.SetPixel(0, 0, color);
        REQUIRE(img.GetPixel(0, 0) == color);
    }
}

// todo: add paint test
TEST_CASE("image draw", "[img]")
{
    euco::Image img;
    const int   width  = 10;
    const int   height = 12;
    img.SetupNoAlphaSupport(width, height);

    SECTION("draw size is image size")
    {
        const auto size = euco::WholeImage(img);
        CHECK(size.bottom == 0);
        CHECK(size.left == 0);
        CHECK(size.GetWidth() == width);
        CHECK(size.GetHeight() == height);
    }

    euco::Rgbi  color {255, 255, 0};
    euco::Rgbai colora {color, 255};

    SECTION("fill")
    {
        CHECK_FALSE(img.GetPixel(0, 0) == colora);
        CHECK_FALSE(img.GetPixel(3, 3) == colora);
        CHECK_FALSE(img.GetPixel(width - 1, height - 1) == colora);

        euco::DrawRect(&img, color, euco::WholeImage(img));
        REQUIRE(img.GetPixel(0, 0) == colora);
        REQUIRE(img.GetPixel(3, 3) == colora);
        REQUIRE(img.GetPixel(width - 1, height - 1) == colora);
    }

    SECTION("circle")
    {
        CHECK_FALSE(img.GetPixel(5, 5) == colora);
        euco::DrawCircle(&img, rgb(color), euco::vec2i {5, 5}, 4);
        CHECK_FALSE(img.GetPixel(0, 0) == colora);
        REQUIRE(img.GetPixel(5, 5) == colora);
    }

    SECTION("circle with hole")
    {
        CHECK_FALSE(img.GetPixel(0, 0) == colora);
        CHECK_FALSE(img.GetPixel(5, 5) == colora);
        euco::DrawCircle(&img, rgb(color), euco::vec2i {5, 5}, 20, 0, 3);
        CHECK_FALSE(img.GetPixel(5, 5) == colora);
        REQUIRE(img.GetPixel(0, 0) == colora);
    }
}

TEST_CASE("image text")
{
    auto draw_text = [](const std::string& text, int width, int height) -> std::vector<std::string>
    {
        euco::Image image;
        image.SetupNoAlphaSupport(width, height);
        euco::DrawRect(&image, euco::Color::White, euco::WholeImage(image));
        euco::DrawText(&image, euco::vec2i(0,height-8), text, euco::Color::Black, euco::LoadCharactersFromBuiltin());
        const auto table = euco::ImageToStringTableExact(
            image,
            { {'#', euco::Color::Black}, {' ', euco::Color::White} }, '?');
        const auto strings = euco::ToStrings(table);
        return strings;
    };

    CHECK(StringEq(draw_text("dog !", 8*6, 8),
        {
    "   ###                             ##           ",
    "    ##                            ####          ",
    "    ##   ####    ### ##           ####          ",
    " #####  ##  ##  ##  ##             ##           ",
    "##  ##  ##  ##  ##  ##             ##           ",
    "##  ##  ##  ##   #####                          ",
    " ### ##  ####       ##             ##           ",
    "                #####                           "
        }));

    CHECK(StringEq(draw_text("CAT", 8, 8+1),
        {
            "  ####  ",
            " ##  ## ",
            "##      ",
            "##      ",
            "##      ",
            " ##  ## ",
            "  ####  ",
            "        ",
            "        "
        }));
}
<|endoftext|>