<commit_before>// Copyright 2013 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 "content/renderer/media/renderer_gpu_video_accelerator_factories.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include "base/bind.h"
#include "content/child/child_thread.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"

namespace content {

// static
scoped_refptr<RendererGpuVideoAcceleratorFactories>
RendererGpuVideoAcceleratorFactories::Create(
    GpuChannelHost* gpu_channel_host,
    const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
    const scoped_refptr<ContextProviderCommandBuffer>& context_provider) {
  scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
      new RendererGpuVideoAcceleratorFactories(
          gpu_channel_host, message_loop_proxy, context_provider);
  // Post task from outside constructor, since AddRef()/Release() is unsafe from
  // within.
  message_loop_proxy->PostTask(
      FROM_HERE,
      base::Bind(&RendererGpuVideoAcceleratorFactories::BindContext,
                 factories));
  return factories;
}

RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
    GpuChannelHost* gpu_channel_host,
    const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
    const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
    : task_runner_(message_loop_proxy),
      gpu_channel_host_(gpu_channel_host),
      context_provider_(context_provider),
      thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}

RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}

void RendererGpuVideoAcceleratorFactories::BindContext() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  if (!context_provider_->BindToCurrentThread())
    context_provider_ = NULL;
}

WebGraphicsContext3DCommandBufferImpl*
RendererGpuVideoAcceleratorFactories::GetContext3d() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  if (!context_provider_)
    return NULL;
  if (context_provider_->IsContextLost()) {
    context_provider_->VerifyContexts();
    context_provider_ = NULL;
    return NULL;
  }
  return context_provider_->WebContext3D();
}

scoped_ptr<media::VideoDecodeAccelerator>
RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (context && context->GetCommandBufferProxy()) {
    return gpu_channel_host_->CreateVideoDecoder(
        context->GetCommandBufferProxy()->GetRouteID());
  }

  return scoped_ptr<media::VideoDecodeAccelerator>();
}

scoped_ptr<media::VideoEncodeAccelerator>
RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (context && context->GetCommandBufferProxy()) {
    return gpu_channel_host_->CreateVideoEncoder(
        context->GetCommandBufferProxy()->GetRouteID());
  }

  return scoped_ptr<media::VideoEncodeAccelerator>();
}

bool RendererGpuVideoAcceleratorFactories::CreateTextures(
    int32 count,
    const gfx::Size& size,
    std::vector<uint32>* texture_ids,
    std::vector<gpu::Mailbox>* texture_mailboxes,
    uint32 texture_target) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  DCHECK(texture_target);

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return false;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
  texture_ids->resize(count);
  texture_mailboxes->resize(count);
  gles2->GenTextures(count, &texture_ids->at(0));
  for (int i = 0; i < count; ++i) {
    gles2->ActiveTexture(GL_TEXTURE0);
    uint32 texture_id = texture_ids->at(i);
    gles2->BindTexture(texture_target, texture_id);
    gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    if (texture_target == GL_TEXTURE_2D) {
      gles2->TexImage2D(texture_target,
                        0,
                        GL_RGBA,
                        size.width(),
                        size.height(),
                        0,
                        GL_RGBA,
                        GL_UNSIGNED_BYTE,
                        NULL);
    }
    gles2->GenMailboxCHROMIUM(texture_mailboxes->at(i).name);
    gles2->ProduceTextureCHROMIUM(texture_target,
                                  texture_mailboxes->at(i).name);
  }

  // We need ShallowFlushCHROMIUM() here to order the command buffer commands
  // with respect to IPC to the GPU process, to guarantee that the decoder in
  // the GPU process can use these textures as soon as it receives IPC
  // notification of them.
  gles2->ShallowFlushCHROMIUM();
  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
  return true;
}

void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
  gles2->DeleteTextures(1, &texture_id);
  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
}

void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
  gles2->WaitSyncPointCHROMIUM(sync_point);

  // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
  // flush the command buffers to ensure that.
  gles2->ShallowFlushCHROMIUM();
}

void RendererGpuVideoAcceleratorFactories::ReadPixels(
    uint32 texture_id,
    const gfx::Rect& visible_rect,
    const SkBitmap& pixels) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();

  GLuint tmp_texture;
  gles2->GenTextures(1, &tmp_texture);
  gles2->BindTexture(GL_TEXTURE_2D, tmp_texture);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  context->copyTextureCHROMIUM(
      GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);

  GLuint fb;
  gles2->GenFramebuffers(1, &fb);
  gles2->BindFramebuffer(GL_FRAMEBUFFER, fb);
  gles2->FramebufferTexture2D(
      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0);
  gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
#if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
    SK_A32_SHIFT == 24
  GLenum skia_format = GL_BGRA_EXT;
#elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
    SK_A32_SHIFT == 24
  GLenum skia_format = GL_RGBA;
#else
#error Unexpected Skia ARGB_8888 layout!
#endif
  gles2->ReadPixels(visible_rect.x(),
                    visible_rect.y(),
                    visible_rect.width(),
                    visible_rect.height(),
                    skia_format,
                    GL_UNSIGNED_BYTE,
                    pixels.pixelRef()->pixels());
  gles2->DeleteFramebuffers(1, &fb);
  gles2->DeleteTextures(1, &tmp_texture);
  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
}

base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
    size_t size) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
}

scoped_refptr<base::SingleThreadTaskRunner>
RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
  return task_runner_;
}

}  // namespace content
<commit_msg>Convert format of pixels read from GL to BGRA on CPU if necessary<commit_after>// Copyright 2013 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 "content/renderer/media/renderer_gpu_video_accelerator_factories.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include "base/bind.h"
#include "content/child/child_thread.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"

namespace content {

// static
scoped_refptr<RendererGpuVideoAcceleratorFactories>
RendererGpuVideoAcceleratorFactories::Create(
    GpuChannelHost* gpu_channel_host,
    const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
    const scoped_refptr<ContextProviderCommandBuffer>& context_provider) {
  scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
      new RendererGpuVideoAcceleratorFactories(
          gpu_channel_host, message_loop_proxy, context_provider);
  // Post task from outside constructor, since AddRef()/Release() is unsafe from
  // within.
  message_loop_proxy->PostTask(
      FROM_HERE,
      base::Bind(&RendererGpuVideoAcceleratorFactories::BindContext,
                 factories));
  return factories;
}

RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
    GpuChannelHost* gpu_channel_host,
    const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
    const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
    : task_runner_(message_loop_proxy),
      gpu_channel_host_(gpu_channel_host),
      context_provider_(context_provider),
      thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}

RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}

void RendererGpuVideoAcceleratorFactories::BindContext() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  if (!context_provider_->BindToCurrentThread())
    context_provider_ = NULL;
}

WebGraphicsContext3DCommandBufferImpl*
RendererGpuVideoAcceleratorFactories::GetContext3d() {
  DCHECK(task_runner_->BelongsToCurrentThread());
  if (!context_provider_)
    return NULL;
  if (context_provider_->IsContextLost()) {
    context_provider_->VerifyContexts();
    context_provider_ = NULL;
    return NULL;
  }
  return context_provider_->WebContext3D();
}

scoped_ptr<media::VideoDecodeAccelerator>
RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (context && context->GetCommandBufferProxy()) {
    return gpu_channel_host_->CreateVideoDecoder(
        context->GetCommandBufferProxy()->GetRouteID());
  }

  return scoped_ptr<media::VideoDecodeAccelerator>();
}

scoped_ptr<media::VideoEncodeAccelerator>
RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (context && context->GetCommandBufferProxy()) {
    return gpu_channel_host_->CreateVideoEncoder(
        context->GetCommandBufferProxy()->GetRouteID());
  }

  return scoped_ptr<media::VideoEncodeAccelerator>();
}

bool RendererGpuVideoAcceleratorFactories::CreateTextures(
    int32 count,
    const gfx::Size& size,
    std::vector<uint32>* texture_ids,
    std::vector<gpu::Mailbox>* texture_mailboxes,
    uint32 texture_target) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  DCHECK(texture_target);

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return false;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
  texture_ids->resize(count);
  texture_mailboxes->resize(count);
  gles2->GenTextures(count, &texture_ids->at(0));
  for (int i = 0; i < count; ++i) {
    gles2->ActiveTexture(GL_TEXTURE0);
    uint32 texture_id = texture_ids->at(i);
    gles2->BindTexture(texture_target, texture_id);
    gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    if (texture_target == GL_TEXTURE_2D) {
      gles2->TexImage2D(texture_target,
                        0,
                        GL_RGBA,
                        size.width(),
                        size.height(),
                        0,
                        GL_RGBA,
                        GL_UNSIGNED_BYTE,
                        NULL);
    }
    gles2->GenMailboxCHROMIUM(texture_mailboxes->at(i).name);
    gles2->ProduceTextureCHROMIUM(texture_target,
                                  texture_mailboxes->at(i).name);
  }

  // We need ShallowFlushCHROMIUM() here to order the command buffer commands
  // with respect to IPC to the GPU process, to guarantee that the decoder in
  // the GPU process can use these textures as soon as it receives IPC
  // notification of them.
  gles2->ShallowFlushCHROMIUM();
  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
  return true;
}

void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
  gles2->DeleteTextures(1, &texture_id);
  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
}

void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
  gles2->WaitSyncPointCHROMIUM(sync_point);

  // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
  // flush the command buffers to ensure that.
  gles2->ShallowFlushCHROMIUM();
}

void RendererGpuVideoAcceleratorFactories::ReadPixels(
    uint32 texture_id,
    const gfx::Rect& visible_rect,
    const SkBitmap& pixels) {
  DCHECK(task_runner_->BelongsToCurrentThread());

  WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
  if (!context)
    return;

  gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();

  GLuint tmp_texture;
  gles2->GenTextures(1, &tmp_texture);
  gles2->BindTexture(GL_TEXTURE_2D, tmp_texture);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  context->copyTextureCHROMIUM(
      GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);

  GLuint fb;
  gles2->GenFramebuffers(1, &fb);
  gles2->BindFramebuffer(GL_FRAMEBUFFER, fb);
  gles2->FramebufferTexture2D(
      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0);
  gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);

#if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
    SK_A32_SHIFT == 24
  GLenum skia_format = GL_BGRA_EXT;
  GLenum read_format = GL_BGRA_EXT;
  GLint supported_format = 0;
  GLint supported_type = 0;
  gles2->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &supported_format);
  gles2->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &supported_type);
  if (supported_format != GL_BGRA_EXT || supported_type != GL_UNSIGNED_BYTE) {
    read_format = GL_RGBA;
  }
#elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
    SK_A32_SHIFT == 24
  GLenum skia_format = GL_RGBA;
  GLenum read_format = GL_RGBA;
#else
#error Unexpected Skia ARGB_8888 layout!
#endif
  gles2->ReadPixels(visible_rect.x(),
                    visible_rect.y(),
                    visible_rect.width(),
                    visible_rect.height(),
                    read_format,
                    GL_UNSIGNED_BYTE,
                    pixels.pixelRef()->pixels());
  gles2->DeleteFramebuffers(1, &fb);
  gles2->DeleteTextures(1, &tmp_texture);

  if (skia_format != read_format) {
    DCHECK(read_format == GL_RGBA);
    int pixel_count = visible_rect.width() * visible_rect.height();
    uint32_t* pixels_ptr = static_cast<uint32_t*>(pixels.pixelRef()->pixels());
    for (int i = 0; i < pixel_count; ++i) {
        uint32_t r = pixels_ptr[i] & 0xFF;
        uint32_t g = (pixels_ptr[i] >> 8) & 0xFF;
        uint32_t b = (pixels_ptr[i] >> 16) & 0xFF;
        uint32_t a = (pixels_ptr[i] >> 24) & 0xFF;
        pixels_ptr[i] = (r << SK_R32_SHIFT) |
                        (g << SK_G32_SHIFT) |
                        (b << SK_B32_SHIFT) |
                        (a << SK_A32_SHIFT);
    }
  }

  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
}

base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
    size_t size) {
  DCHECK(task_runner_->BelongsToCurrentThread());
  return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
}

scoped_refptr<base::SingleThreadTaskRunner>
RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
  return task_runner_;
}

}  // namespace content
<|endoftext|>


<commit_before>/*
 * An istream filter that escapes the data.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_escape.hxx"
#include "istream/FacadeIstream.hxx"
#include "escape_class.h"
#include "util/Cast.hxx"
#include "util/ConstBuffer.hxx"

#include <assert.h>
#include <string.h>

class EscapeIstream final : public FacadeIstream {
    const struct escape_class &cls;

    ConstBuffer<char> escaped;

public:
    EscapeIstream(struct pool &pool, struct istream &_input,
                  const struct escape_class &_cls)
        :FacadeIstream(pool, _input,
                       MakeIstreamHandler<EscapeIstream>::handler, this),
         cls(_cls) {
        escaped.size = 0;
    }

    bool SendEscaped();

    /* virtual methods from class Istream */

    off_t GetAvailable(bool partial) override {
        return partial
            ? input.GetAvailable(partial)
            : -1;
    }

    off_t Skip(gcc_unused off_t length) override {
        return -1;
    }

    void Read() override;

    int AsFd() override {
        return -1;
    }

    void Close() override;

    /* handler */

    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        gcc_unreachable();
    }

    void OnEof() {
        DestroyEof();
    }

    void OnError(GError *error) {
        DestroyError(error);
    }
};

bool
EscapeIstream::SendEscaped()
{
    assert(!escaped.IsEmpty());

    size_t nbytes = InvokeData(escaped.data, escaped.size);
    if (nbytes == 0)
        return false;

    escaped.skip_front(nbytes);
    if (!escaped.IsEmpty())
        return false;

    if (!HasInput()) {
        DestroyEof();
        return false;
    }

    return true;
}

/*
 * istream handler
 *
 */

size_t
EscapeIstream::OnData(const void *data0, size_t length)
{
    const char *data = (const char *)data0;

    if (!escaped.IsEmpty() && !SendEscaped())
        return 0;

    size_t total = 0;

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    do {
        /* find the next control character */
        const char *control = escape_find(&cls, data, length);
        if (control == nullptr) {
            /* none found - just forward the data block to our sink */
            size_t nbytes = InvokeData(data, length);
            if (nbytes == 0 && !HasInput())
                total = 0;
            else
                total += nbytes;
            break;
        }

        if (control > data) {
            /* forward the portion before the control character */
            const size_t n = control - data;
            size_t nbytes = InvokeData(data, n);
            if (nbytes == 0 && !HasInput()) {
                total = 0;
                break;
            }

            total += nbytes;
            if (nbytes < n)
                break;
        }

        /* consume everything until after the control character */

        length -= control - data + 1;
        data = control + 1;
        ++total;

        /* insert the entity into the stream */

        escaped.data = escape_char(&cls, *control);
        escaped.size = strlen(escaped.data);

        if (!SendEscaped()) {
            if (!HasInput())
                total = 0;
            break;
        }
    } while (length > 0);

    return total;
}

/*
 * istream implementation
 *
 */

void
EscapeIstream::Read()
{
    if (!escaped.IsEmpty() && !SendEscaped())
        return;

    input.Read();
}

void
EscapeIstream::Close()
{
    if (HasInput())
        input.Close();

    Destroy();
}

/*
 * constructor
 *
 */

struct istream *
istream_escape_new(struct pool *pool, struct istream *input,
                   const struct escape_class *cls)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));
    assert(cls != nullptr);
    assert(cls->escape_find != nullptr);
    assert(cls->escape_char != nullptr);

    return NewIstream<EscapeIstream>(*pool, *input, *cls);
}
<commit_msg>istream_escape: consider escaped data in GetAvailable()<commit_after>/*
 * An istream filter that escapes the data.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_escape.hxx"
#include "istream/FacadeIstream.hxx"
#include "escape_class.h"
#include "util/Cast.hxx"
#include "util/ConstBuffer.hxx"

#include <assert.h>
#include <string.h>

class EscapeIstream final : public FacadeIstream {
    const struct escape_class &cls;

    ConstBuffer<char> escaped;

public:
    EscapeIstream(struct pool &pool, struct istream &_input,
                  const struct escape_class &_cls)
        :FacadeIstream(pool, _input,
                       MakeIstreamHandler<EscapeIstream>::handler, this),
         cls(_cls) {
        escaped.size = 0;
    }

    bool SendEscaped();

    /* virtual methods from class Istream */

    off_t GetAvailable(bool partial) override {
        return partial
            ? escaped.size + input.GetAvailable(partial)
            : -1;
    }

    off_t Skip(gcc_unused off_t length) override {
        return -1;
    }

    void Read() override;

    int AsFd() override {
        return -1;
    }

    void Close() override;

    /* handler */

    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        gcc_unreachable();
    }

    void OnEof() {
        DestroyEof();
    }

    void OnError(GError *error) {
        DestroyError(error);
    }
};

bool
EscapeIstream::SendEscaped()
{
    assert(!escaped.IsEmpty());

    size_t nbytes = InvokeData(escaped.data, escaped.size);
    if (nbytes == 0)
        return false;

    escaped.skip_front(nbytes);
    if (!escaped.IsEmpty())
        return false;

    if (!HasInput()) {
        DestroyEof();
        return false;
    }

    return true;
}

/*
 * istream handler
 *
 */

size_t
EscapeIstream::OnData(const void *data0, size_t length)
{
    const char *data = (const char *)data0;

    if (!escaped.IsEmpty() && !SendEscaped())
        return 0;

    size_t total = 0;

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    do {
        /* find the next control character */
        const char *control = escape_find(&cls, data, length);
        if (control == nullptr) {
            /* none found - just forward the data block to our sink */
            size_t nbytes = InvokeData(data, length);
            if (nbytes == 0 && !HasInput())
                total = 0;
            else
                total += nbytes;
            break;
        }

        if (control > data) {
            /* forward the portion before the control character */
            const size_t n = control - data;
            size_t nbytes = InvokeData(data, n);
            if (nbytes == 0 && !HasInput()) {
                total = 0;
                break;
            }

            total += nbytes;
            if (nbytes < n)
                break;
        }

        /* consume everything until after the control character */

        length -= control - data + 1;
        data = control + 1;
        ++total;

        /* insert the entity into the stream */

        escaped.data = escape_char(&cls, *control);
        escaped.size = strlen(escaped.data);

        if (!SendEscaped()) {
            if (!HasInput())
                total = 0;
            break;
        }
    } while (length > 0);

    return total;
}

/*
 * istream implementation
 *
 */

void
EscapeIstream::Read()
{
    if (!escaped.IsEmpty() && !SendEscaped())
        return;

    input.Read();
}

void
EscapeIstream::Close()
{
    if (HasInput())
        input.Close();

    Destroy();
}

/*
 * constructor
 *
 */

struct istream *
istream_escape_new(struct pool *pool, struct istream *input,
                   const struct escape_class *cls)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));
    assert(cls != nullptr);
    assert(cls->escape_find != nullptr);
    assert(cls->escape_char != nullptr);

    return NewIstream<EscapeIstream>(*pool, *input, *cls);
}
<|endoftext|>


<commit_before>/**********************************************************\

  Auto-generated KSenseJSAPI.cpp

\**********************************************************/

#include "JSObject.h"
#include "variant_list.h"
#include "DOM/Document.h"
#include "global/config.h"

#include "KSenseJSAPI.h"

///////////////////////////////////////////////////////////////////////////////
/// @fn KSenseJSPtr KSenseJSAPI::getPlugin()
///
/// @brief  Gets a reference to the plugin that was passed in when the object
///         was created.  If the plugin has already been released then this
///         will throw a FB::script_error that will be translated into a
///         javascript exception in the page.
///////////////////////////////////////////////////////////////////////////////
KSenseJSPtr KSenseJSAPI::getPlugin()
{
    KSenseJSPtr plugin(m_plugin.lock());
    if (!plugin) {
        throw FB::script_error("The plugin is invalid");
    }
    return plugin;
}

/*	Get the number of skeletons tracked by the Kinect. */
int KSenseJSAPI::get_tracked_skeletons_count()
{
	int tracked_skeleton_count = 0;
	KSenseJSPtr plugin = getPlugin();
	SkeletonDataPtr skeleton_data = plugin->getSkeletonDataPtr();

	for ( int i = 0; i < NUI_SKELETON_COUNT; i++ ) {
		if ( skeleton_data->SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) {
			tracked_skeleton_count++;
		}
	}

	return tracked_skeleton_count;
}

/*	Get a list of tracking IDs for the currently tracked skeletons. */
FB::VariantList KSenseJSAPI::get_valid_tracking_ids()
{
	KSenseJSPtr plugin = getPlugin();
	SkeletonDataPtr skeleton_data = plugin->getSkeletonDataPtr();
	FB::VariantList tracking_ids;

	for ( int i = 0; i < NUI_SKELETON_COUNT; i++ ) {
		if ( skeleton_data->SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) {
			tracking_ids.push_back(skeleton_data->SkeletonData[i].dwTrackingID);
		}
	}

	return tracking_ids;
}

/*	Get the skeleton data that corresponds to the given tracking ID.  If the tracking
	ID is invalid, throw an error. */
FB::VariantList KSenseJSAPI::get_skeleton_data(int tracking_id)
{
	KSenseJSPtr plugin = getPlugin();
	SkeletonDataPtr skeleton_data = plugin->getSkeletonDataPtr();
	FB::VariantList skeleton_data_output (NUI_SKELETON_POSITION_COUNT, 0);
	bool found_data = false;

	for ( int i = 0; i < NUI_SKELETON_COUNT; i++ ) {
		if ( skeleton_data->SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED &&
			 skeleton_data->SkeletonData[i].dwTrackingID ) {
			found_data = true;
			for ( int j = 0; j < NUI_SKELETON_POSITION_COUNT; j++ ) {
				FB::VariantList position (3,0);
				position[0] = skeleton_data->SkeletonData[i].SkeletonPositions[j].x;
				position[1] = skeleton_data->SkeletonData[i].SkeletonPositions[j].y;
				position[2] = skeleton_data->SkeletonData[i].SkeletonPositions[j].z;
				skeleton_data_output[j] = position;
			}
		}
	}

	if ( found_data ) {
		return skeleton_data_output;
	} else {
		throw FB::script_error("Invalid tracking ID");
	}
}

void KSenseJSAPI::new_skeleton_data_event()
{
	fire_newskeletondata();
}<commit_msg>Handle void skeleton_data pointer in KinectJSAPI.<commit_after>/**********************************************************\

  Auto-generated KSenseJSAPI.cpp

\**********************************************************/

#include "JSObject.h"
#include "variant_list.h"
#include "DOM/Document.h"
#include "global/config.h"

#include "KSenseJSAPI.h"

///////////////////////////////////////////////////////////////////////////////
/// @fn KSenseJSPtr KSenseJSAPI::getPlugin()
///
/// @brief  Gets a reference to the plugin that was passed in when the object
///         was created.  If the plugin has already been released then this
///         will throw a FB::script_error that will be translated into a
///         javascript exception in the page.
///////////////////////////////////////////////////////////////////////////////
KSenseJSPtr KSenseJSAPI::getPlugin()
{
    KSenseJSPtr plugin(m_plugin.lock());
    if (!plugin) {
        throw FB::script_error("The plugin is invalid");
    }
    return plugin;
}

/*	Get the number of skeletons tracked by the Kinect. */
int KSenseJSAPI::get_tracked_skeletons_count()
{
	int tracked_skeleton_count = 0;
	KSenseJSPtr plugin = getPlugin();
	SkeletonDataPtr skeleton_data = plugin->getSkeletonDataPtr();

	if ( !skeleton_data ) {
		return 0;
	}

	for ( int i = 0; i < NUI_SKELETON_COUNT; i++ ) {
		if ( skeleton_data->SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) {
			tracked_skeleton_count++;
		}
	}

	return tracked_skeleton_count;
}

/*	Get a list of tracking IDs for the currently tracked skeletons. */
FB::VariantList KSenseJSAPI::get_valid_tracking_ids()
{
	KSenseJSPtr plugin = getPlugin();
	SkeletonDataPtr skeleton_data = plugin->getSkeletonDataPtr();
	FB::VariantList tracking_ids;

	if ( !skeleton_data ) {
		return tracking_ids;
	}

	for ( int i = 0; i < NUI_SKELETON_COUNT; i++ ) {
		if ( skeleton_data->SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) {
			tracking_ids.push_back(skeleton_data->SkeletonData[i].dwTrackingID);
		}
	}

	return tracking_ids;
}

/*	Get the skeleton data that corresponds to the given tracking ID.  If the tracking
	ID is invalid, throw an error. */
FB::VariantList KSenseJSAPI::get_skeleton_data(int tracking_id)
{
	KSenseJSPtr plugin = getPlugin();
	SkeletonDataPtr skeleton_data = plugin->getSkeletonDataPtr();
	FB::VariantList skeleton_data_output (NUI_SKELETON_POSITION_COUNT, 0);
	bool found_data = false;

	if ( !skeleton_data ) {
		throw FB::script_error("No skeleton data.");
	}

	for ( int i = 0; i < NUI_SKELETON_COUNT; i++ ) {
		if ( skeleton_data->SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED &&
			 skeleton_data->SkeletonData[i].dwTrackingID ) {
			found_data = true;
			for ( int j = 0; j < NUI_SKELETON_POSITION_COUNT; j++ ) {
				FB::VariantList position (3,0);
				position[0] = skeleton_data->SkeletonData[i].SkeletonPositions[j].x;
				position[1] = skeleton_data->SkeletonData[i].SkeletonPositions[j].y;
				position[2] = skeleton_data->SkeletonData[i].SkeletonPositions[j].z;
				skeleton_data_output[j] = position;
			}
		}
	}

	if ( found_data ) {
		return skeleton_data_output;
	} else {
		throw FB::script_error("Invalid tracking ID");
	}
}

void KSenseJSAPI::new_skeleton_data_event()
{
	fire_newskeletondata();
}<|endoftext|>


<commit_before>#include "pch.h"
#include "Servo.h"

namespace winrt::servo {

void on_load_started() { sServo->Delegate().OnServoLoadStarted(); }

void on_load_ended() { sServo->Delegate().OnServoLoadEnded(); }

void on_history_changed(bool back, bool forward) {
  sServo->Delegate().OnServoHistoryChanged(back, forward);
}

void on_shutdown_complete() { sServo->Delegate().OnServoShutdownComplete(); }

void on_title_changed(const char *title) {
  sServo->Delegate().OnServoTitleChanged(char2hstring(title));
}

void on_url_changed(const char *url) {
  sServo->Delegate().OnServoURLChanged(char2hstring(url));
}

void flush() { sServo->Delegate().Flush(); }

void make_current() { sServo->Delegate().MakeCurrent(); }

void wakeup() { sServo->Delegate().WakeUp(); }

bool on_allow_navigation(const char *url) {
  return sServo->Delegate().OnServoAllowNavigation(char2hstring(url));
};

void on_animating_changed(bool aAnimating) {
  sServo->Delegate().OnServoAnimatingChanged(aAnimating);
}

void on_panic(const char *backtrace) {
  throw hresult_error(E_FAIL, char2hstring(backtrace));
}

void on_ime_state_changed(bool aShow) {
  sServo->Delegate().OnServoIMEStateChanged(aShow);
}

void set_clipboard_contents(const char *content) {
  // FIXME
}

const char *get_clipboard_contents() {
  // FIXME
  return nullptr;
}

void on_media_session_metadata(const char *title, const char *album,
                               const char *artist) {
  return sServo->Delegate().OnServoMediaSessionMetadata(
      char2hstring(title), char2hstring(album), char2hstring(artist));
}

void on_media_session_playback_state_change(
    const capi::CMediaSessionPlaybackState state) {
  return sServo->Delegate().OnServoMediaSessionPlaybackStateChange(state);
}

void prompt_alert(const char *message, bool trusted) {
  sServo->Delegate().OnServoPromptAlert(char2hstring(message), trusted);
}

Servo::PromptResult prompt_ok_cancel(const char *message, bool trusted) {
  return sServo->Delegate().OnServoPromptOkCancel(char2hstring(message),
                                                  trusted);
}

Servo::PromptResult prompt_yes_no(const char *message, bool trusted) {
  return sServo->Delegate().OnServoPromptYesNo(char2hstring(message), trusted);
}

const char *prompt_input(const char *message, const char *default,
                         bool trusted) {
  auto input = sServo->Delegate().OnServoPromptInput(
      char2hstring(message), char2hstring(default), trusted);
  if (input.has_value()) {
    return *hstring2char(*input);
  } else {
    return nullptr;
  }
}

Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height,
             float dpi, ServoDelegate &aDelegate)
    : mWindowHeight(height), mWindowWidth(width), mDelegate(aDelegate) {

  capi::CInitOptions o;
  hstring defaultPrefs = L" --pref dom.webxr.enabled  --devtools=6000";
  o.args = *hstring2char(args + defaultPrefs);
  o.url = *hstring2char(url);
  o.width = mWindowWidth;
  o.height = mWindowHeight;
  o.density = dpi;
  o.enable_subpixel_text_antialiasing = false;
  o.vr_pointer = NULL;

  // 7 filter modules.
  /* Sample list of servo modules to filter.
  static char *pfilters[] = {
          "servo",
          "simpleservo",
          "simpleservo::jniapi",
          "simpleservo::gl_glue::egl",
          // Show JS errors by default.
          "script::dom::bindings::error",
          // Show GL errors by default.
          "canvas::webgl_thread",
          "compositing::compositor",
          "constellation::constellation",
  };
  */

  // Example Call when *pfilters[] is used:
  // o.vslogger_mod_list = pfilters; // servo log modules
  // o.vslogger_mod_size = sizeof(pfilters) / sizeof(pfilters[0]); //
  // Important: Number of modules in pfilters
  o.vslogger_mod_list = NULL;
  o.vslogger_mod_size = 0;

  sServo = this; // FIXME;

  capi::CHostCallbacks c;
  c.flush = &flush;
  c.make_current = &make_current;
  c.on_load_started = &on_load_started;
  c.on_load_ended = &on_load_ended;
  c.on_title_changed = &on_title_changed;
  c.on_url_changed = &on_url_changed;
  c.on_history_changed = &on_history_changed;
  c.on_animating_changed = &on_animating_changed;
  c.on_shutdown_complete = &on_shutdown_complete;
  c.on_allow_navigation = &on_allow_navigation;
  c.on_ime_state_changed = &on_ime_state_changed;
  c.get_clipboard_contents = &get_clipboard_contents;
  c.set_clipboard_contents = &set_clipboard_contents;
  c.on_media_session_metadata = &on_media_session_metadata;
  c.on_media_session_playback_state_change =
      &on_media_session_playback_state_change;
  c.prompt_alert = &prompt_alert;
  c.prompt_ok_cancel = &prompt_ok_cancel;
  c.prompt_yes_no = &prompt_yes_no;
  c.prompt_input = &prompt_input;

  capi::register_panic_handler(&on_panic);

  capi::init_with_egl(o, &wakeup, c);
}

Servo::~Servo() { sServo = nullptr; }

winrt::hstring char2hstring(const char *c_str) {
  // FIXME: any better way of doing this?
  auto str = std::string(c_str);
  int size_needed =
      MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
  std::wstring str2(size_needed, 0);
  MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &str2[0],
                      size_needed);
  winrt::hstring str3{str2};
  return str3;
}

std::unique_ptr<char *> hstring2char(hstring hstr) {
  const wchar_t *wc = hstr.c_str();
  size_t size = hstr.size() + 1;
  char *str = new char[size];
  size_t converted = 0;
  wcstombs_s(&converted, str, size, wc, hstr.size());
  return std::make_unique<char *>(str);
}

} // namespace winrt::servo
<commit_msg>Auto merge of #25899 - servo:jdm-patch-41, r=paulrouget<commit_after>#include "pch.h"
#include "Servo.h"

namespace winrt::servo {

void on_load_started() { sServo->Delegate().OnServoLoadStarted(); }

void on_load_ended() { sServo->Delegate().OnServoLoadEnded(); }

void on_history_changed(bool back, bool forward) {
  sServo->Delegate().OnServoHistoryChanged(back, forward);
}

void on_shutdown_complete() { sServo->Delegate().OnServoShutdownComplete(); }

void on_title_changed(const char *title) {
  sServo->Delegate().OnServoTitleChanged(char2hstring(title));
}

void on_url_changed(const char *url) {
  sServo->Delegate().OnServoURLChanged(char2hstring(url));
}

void flush() { sServo->Delegate().Flush(); }

void make_current() { sServo->Delegate().MakeCurrent(); }

void wakeup() { sServo->Delegate().WakeUp(); }

bool on_allow_navigation(const char *url) {
  return sServo->Delegate().OnServoAllowNavigation(char2hstring(url));
};

void on_animating_changed(bool aAnimating) {
  sServo->Delegate().OnServoAnimatingChanged(aAnimating);
}

void on_panic(const char *backtrace) {
  throw hresult_error(E_FAIL, char2hstring(backtrace));
}

void on_ime_state_changed(bool aShow) {
  sServo->Delegate().OnServoIMEStateChanged(aShow);
}

void set_clipboard_contents(const char *content) {
  // FIXME
}

const char *get_clipboard_contents() {
  // FIXME
  return nullptr;
}

void on_media_session_metadata(const char *title, const char *album,
                               const char *artist) {
  return sServo->Delegate().OnServoMediaSessionMetadata(
      char2hstring(title), char2hstring(album), char2hstring(artist));
}

void on_media_session_playback_state_change(
    const capi::CMediaSessionPlaybackState state) {
  return sServo->Delegate().OnServoMediaSessionPlaybackStateChange(state);
}

void prompt_alert(const char *message, bool trusted) {
  sServo->Delegate().OnServoPromptAlert(char2hstring(message), trusted);
}

Servo::PromptResult prompt_ok_cancel(const char *message, bool trusted) {
  return sServo->Delegate().OnServoPromptOkCancel(char2hstring(message),
                                                  trusted);
}

Servo::PromptResult prompt_yes_no(const char *message, bool trusted) {
  return sServo->Delegate().OnServoPromptYesNo(char2hstring(message), trusted);
}

const char *prompt_input(const char *message, const char *default,
                         bool trusted) {
  auto input = sServo->Delegate().OnServoPromptInput(
      char2hstring(message), char2hstring(default), trusted);
  if (input.has_value()) {
    return *hstring2char(*input);
  } else {
    return nullptr;
  }
}

Servo::Servo(hstring url, hstring args, GLsizei width, GLsizei height,
             float dpi, ServoDelegate &aDelegate)
    : mWindowHeight(height), mWindowWidth(width), mDelegate(aDelegate) {

  capi::CInitOptions o;
  hstring defaultPrefs = L" --pref dom.webxr.enabled";
  o.args = *hstring2char(args + defaultPrefs);
  o.url = *hstring2char(url);
  o.width = mWindowWidth;
  o.height = mWindowHeight;
  o.density = dpi;
  o.enable_subpixel_text_antialiasing = false;
  o.vr_pointer = NULL;

  // 7 filter modules.
  /* Sample list of servo modules to filter.
  static char *pfilters[] = {
          "servo",
          "simpleservo",
          "simpleservo::jniapi",
          "simpleservo::gl_glue::egl",
          // Show JS errors by default.
          "script::dom::bindings::error",
          // Show GL errors by default.
          "canvas::webgl_thread",
          "compositing::compositor",
          "constellation::constellation",
  };
  */

  // Example Call when *pfilters[] is used:
  // o.vslogger_mod_list = pfilters; // servo log modules
  // o.vslogger_mod_size = sizeof(pfilters) / sizeof(pfilters[0]); //
  // Important: Number of modules in pfilters
  o.vslogger_mod_list = NULL;
  o.vslogger_mod_size = 0;

  sServo = this; // FIXME;

  capi::CHostCallbacks c;
  c.flush = &flush;
  c.make_current = &make_current;
  c.on_load_started = &on_load_started;
  c.on_load_ended = &on_load_ended;
  c.on_title_changed = &on_title_changed;
  c.on_url_changed = &on_url_changed;
  c.on_history_changed = &on_history_changed;
  c.on_animating_changed = &on_animating_changed;
  c.on_shutdown_complete = &on_shutdown_complete;
  c.on_allow_navigation = &on_allow_navigation;
  c.on_ime_state_changed = &on_ime_state_changed;
  c.get_clipboard_contents = &get_clipboard_contents;
  c.set_clipboard_contents = &set_clipboard_contents;
  c.on_media_session_metadata = &on_media_session_metadata;
  c.on_media_session_playback_state_change =
      &on_media_session_playback_state_change;
  c.prompt_alert = &prompt_alert;
  c.prompt_ok_cancel = &prompt_ok_cancel;
  c.prompt_yes_no = &prompt_yes_no;
  c.prompt_input = &prompt_input;

  capi::register_panic_handler(&on_panic);

  capi::init_with_egl(o, &wakeup, c);
}

Servo::~Servo() { sServo = nullptr; }

winrt::hstring char2hstring(const char *c_str) {
  // FIXME: any better way of doing this?
  auto str = std::string(c_str);
  int size_needed =
      MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
  std::wstring str2(size_needed, 0);
  MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &str2[0],
                      size_needed);
  winrt::hstring str3{str2};
  return str3;
}

std::unique_ptr<char *> hstring2char(hstring hstr) {
  const wchar_t *wc = hstr.c_str();
  size_t size = hstr.size() + 1;
  char *str = new char[size];
  size_t converted = 0;
  wcstombs_s(&converted, str, size, wc, hstr.size());
  return std::make_unique<char *>(str);
}

} // namespace winrt::servo
<|endoftext|>


<commit_before>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD-style license contained in the LICENSE.txt file.

#include "../include/Image.h"

#include <ImfChannelList.h>
#include <ImfInputFile.h>

#include <stb_image.h>

#include <array>
#include <iostream>

using namespace std;

namespace {
    bool endsWith(const string& a, const string& b) {
        return a.find_last_of(b) == a.size() - 1;
    }
}

Image::Image(const string& filename)
    : mName(filename) {
    if (endsWith(filename, ".exr")) {
        readExr(filename);
    } else {
        readStbi(filename);
    }
}

const GlTexture* Image::texture(const std::string& channelName) {
    auto iter = mTextures.find(channelName);
    if (iter != end(mTextures)) {
        return &iter->second;
    }

    const auto* chan = channel(channelName);
    if (!chan) {
        return nullptr;
    }

    mTextures.emplace(channelName, GlTexture{});
    auto& texture = mTextures.at(channelName);
    texture.setData(chan->data(), mSize, 1);

    return &texture;
}

void Image::readStbi(const std::string& filename) {
    // No exr image? Try our best using stbi
    cout << "Loading "s + filename + " via STB." << endl;

    int numChannels;
    auto data = stbi_load(filename.c_str(), &mSize.x(), &mSize.y(), &numChannels, 0);
    if (!data) {
        throw invalid_argument("Could not load texture data from file " + filename);
    }

    mNumChannels = static_cast<size_t>(numChannels);

    vector<string> channelNames = {"R", "G", "B", "A"};

    vector<Channel> channels;
    for (size_t c = 0; c < mNumChannels; ++c) {
        string name = c < channelNames.size() ? channelNames[c] : to_string(c - channelNames.size());
        channels.emplace_back(name);
    }

    size_t numPixels = mSize.prod();
    for (size_t i = 0; i < numPixels; ++i) {
        size_t baseIdx = i * mNumChannels;
        for (size_t c = 0; c < mNumChannels; ++c) {
            // Assume LDR images were sRGB tonemapped and apply inverse.
            // For now, approximate sRGB curve by 2.2 gamma.
            // TODO: Proper sRGB curve.
            float value = data[baseIdx + c];
            channels[c].data().push_back(pow(value / 255.0f, 2.2f));
        }
    }

    stbi_image_free(data);

    for (auto& channel : channels) {
        string name = channel.name();
        mChannels.emplace(move(name), move(channel));
    }
}

void Image::readExr(const std::string& filename) {
    // OpenEXR for reading exr images
    cout << "Loading "s + filename + " via OpenEXR." << endl;

    Imf::InputFile file(filename.c_str());
    Imath::Box2i dw = file.header().dataWindow();
    mSize.x() = dw.max.x - dw.min.x + 1;
    mSize.y() = dw.max.y - dw.min.y + 1;

    // Inline helper class for dealing with the raw channels loaded from an exr file.
    class RawChannel {
    public:
        RawChannel(string name, Imf::PixelType type, size_t size)
            : mName(name), mType(type) {
            mData.resize(size * bytesPerPixel());
        }

        void registerWith(Imf::FrameBuffer& frameBuffer, const Imath::Box2i& dw) {
            int width = dw.max.x - dw.min.x + 1;
            frameBuffer.insert(mName.c_str(), Imf::Slice(
                mType,
                mData.data() - (dw.min.x - dw.min.y * width) * bytesPerPixel(),
                bytesPerPixel(), bytesPerPixel() * width, // stride in x and y
                1, 1, 0
            ));
        }

        void copyTo(Channel& channel) const {
            int bpp = bytesPerPixel();
            auto& dstData = channel.data();
            dstData.resize(mData.size() / bpp);

            for (size_t i = 0; i < dstData.size(); ++i) {
                size_t rawIdx = i * bpp;
                switch (mType) {
                    case Imf::HALF:  dstData[i] = *reinterpret_cast<const half*>(&mData[rawIdx]);     break;
                    case Imf::FLOAT: dstData[i] = *reinterpret_cast<const float*>(&mData[rawIdx]);    break;
                    case Imf::UINT:  dstData[i] = *reinterpret_cast<const uint32_t*>(&mData[rawIdx]); break;
                    default:
                        throw runtime_error("Invalid pixel type encountered.");
                }
            }
        }

        const auto& name() const {
            return mName;
        }

    private:
        int bytesPerPixel() const {
            return mType == Imf::HALF ? 2 : 4;
        }

        string mName;
        Imf::PixelType mType;
        vector<char> mData;
    };

    vector<RawChannel> rawChannels;
    Imf::FrameBuffer frameBuffer;

    const Imf::ChannelList& imfChannels = file.header().channels();
    for (Imf::ChannelList::ConstIterator i = imfChannels.begin(); i != imfChannels.end(); ++i) {
        rawChannels.emplace_back(i.name(), i.channel().type, mSize.prod());
        rawChannels.back().registerWith(frameBuffer, dw);
    }

    file.setFrameBuffer(frameBuffer);
    file.readPixels(dw.min.y, dw.max.y);

    for (const auto& rawChannel : rawChannels) {
        mChannels.emplace(rawChannel.name(), Channel{rawChannel.name()});
        rawChannel.copyTo(mChannels.at(rawChannel.name()));
    }
}
<commit_msg>Fix OpenEXR images being incorrectly loaded for some file formats<commit_after>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD-style license contained in the LICENSE.txt file.

#include "../include/Image.h"

#include <ImfChannelList.h>
#include <ImfInputFile.h>

#include <stb_image.h>

#include <array>
#include <iostream>

using namespace std;

namespace {
    bool endsWith(const string& a, const string& b) {
        return a.length() >= b.length() && a.compare(a.length() - b.length(), b.length(), b) == 0;
    }
}

Image::Image(const string& filename)
    : mName(filename) {
    if (endsWith(filename, ".exr")) {
        readExr(filename);
    } else {
        readStbi(filename);
    }
}

const GlTexture* Image::texture(const std::string& channelName) {
    auto iter = mTextures.find(channelName);
    if (iter != end(mTextures)) {
        return &iter->second;
    }

    const auto* chan = channel(channelName);
    if (!chan) {
        return nullptr;
    }

    mTextures.emplace(channelName, GlTexture{});
    auto& texture = mTextures.at(channelName);
    texture.setData(chan->data(), mSize, 1);

    return &texture;
}

void Image::readStbi(const std::string& filename) {
    // No exr image? Try our best using stbi
    cout << "Loading "s + filename + " via STB." << endl;

    int numChannels;
    auto data = stbi_load(filename.c_str(), &mSize.x(), &mSize.y(), &numChannels, 0);
    if (!data) {
        throw invalid_argument("Could not load texture data from file " + filename);
    }

    mNumChannels = static_cast<size_t>(numChannels);

    vector<string> channelNames = {"R", "G", "B", "A"};

    vector<Channel> channels;
    for (size_t c = 0; c < mNumChannels; ++c) {
        string name = c < channelNames.size() ? channelNames[c] : to_string(c - channelNames.size());
        channels.emplace_back(name);
    }

    size_t numPixels = mSize.prod();
    for (size_t i = 0; i < numPixels; ++i) {
        size_t baseIdx = i * mNumChannels;
        for (size_t c = 0; c < mNumChannels; ++c) {
            // Assume LDR images were sRGB tonemapped and apply inverse.
            // For now, approximate sRGB curve by 2.2 gamma.
            // TODO: Proper sRGB curve.
            float value = data[baseIdx + c];
            channels[c].data().push_back(pow(value / 255.0f, 2.2f));
        }
    }

    stbi_image_free(data);

    for (auto& channel : channels) {
        string name = channel.name();
        mChannels.emplace(move(name), move(channel));
    }
}

void Image::readExr(const std::string& filename) {
    // OpenEXR for reading exr images
    cout << "Loading "s + filename + " via OpenEXR." << endl;

    Imf::InputFile file(filename.c_str());
    Imath::Box2i dw = file.header().dataWindow();
    mSize.x() = dw.max.x - dw.min.x + 1;
    mSize.y() = dw.max.y - dw.min.y + 1;

    // Inline helper class for dealing with the raw channels loaded from an exr file.
    class RawChannel {
    public:
        RawChannel(string name, Imf::PixelType type, size_t size)
            : mName(name), mType(type) {
            mData.resize(size * bytesPerPixel());
        }

        void registerWith(Imf::FrameBuffer& frameBuffer, const Imath::Box2i& dw) {
            int width = dw.max.x - dw.min.x + 1;
            frameBuffer.insert(mName.c_str(), Imf::Slice(
                mType,
                mData.data() - (dw.min.x - dw.min.y * width) * bytesPerPixel(),
                bytesPerPixel(), bytesPerPixel() * width, // stride in x and y
                1, 1, 0
            ));
        }

        void copyTo(Channel& channel) const {
            int bpp = bytesPerPixel();
            auto& dstData = channel.data();
            dstData.resize(mData.size() / bpp);

            for (size_t i = 0; i < dstData.size(); ++i) {
                size_t rawIdx = i * bpp;
                switch (mType) {
                    case Imf::HALF:  dstData[i] = *reinterpret_cast<const half*>(&mData[rawIdx]);     break;
                    case Imf::FLOAT: dstData[i] = *reinterpret_cast<const float*>(&mData[rawIdx]);    break;
                    case Imf::UINT:  dstData[i] = *reinterpret_cast<const uint32_t*>(&mData[rawIdx]); break;
                    default:
                        throw runtime_error("Invalid pixel type encountered.");
                }
            }
        }

        const auto& name() const {
            return mName;
        }

    private:
        int bytesPerPixel() const {
            return mType == Imf::HALF ? 2 : 4;
        }

        string mName;
        Imf::PixelType mType;
        vector<char> mData;
    };

    vector<RawChannel> rawChannels;
    Imf::FrameBuffer frameBuffer;

    const Imf::ChannelList& imfChannels = file.header().channels();
    for (Imf::ChannelList::ConstIterator i = imfChannels.begin(); i != imfChannels.end(); ++i) {
        rawChannels.emplace_back(i.name(), i.channel().type, mSize.prod());
        rawChannels.back().registerWith(frameBuffer, dw);
    }

    file.setFrameBuffer(frameBuffer);
    file.readPixels(dw.min.y, dw.max.y);

    for (const auto& rawChannel : rawChannels) {
        mChannels.emplace(rawChannel.name(), Channel{rawChannel.name()});
        rawChannel.copyTo(mChannels.at(rawChannel.name()));
    }
}
<|endoftext|>


<commit_before>// RenderScene.cpp

#include <Engine/SystemFrame.h>
#include <Engine/Util/VectorUtils.h>
#include <Engine/Components/CTransform3D.h>
#include <Engine/Components/Display/CStaticMesh.h>
#include <Engine/Components/Display/CLightMaskObstructor.h>
#include <Engine/Components/Display/CLightMaskReceiver.h>
#include "../private/RenderScene.h"
#include "../private/GLRenderSystemState.h"

namespace sge
{
    namespace gl_render
    {
        static void render_prepare(
            const GLStaticMesh& mesh,
            const GLMaterial& mat,
            const Mat4& model,
            const Mat4& view,
            const Mat4& proj)
        {
            // Bind the mesh and material
            mesh.bind();
            GLuint texIndex = GL_TEXTURE0;
            mat.bind(texIndex);

            // Upload transformation matrices
            mat.set_model_matrix(model);
            mat.set_view_matrix(view);
            mat.set_projection_matrix(proj);
        }

        void init_render_scene(GLRenderSystem::State& state, SystemFrame& frame)
        {
            auto& render_scene = state.render_scene;
            render_scene.ord_render_entities.clear();
            render_scene.ord_render_entities_matrices.clear();

            // Get all entities with a transform
            frame.process_entities(
                [&render_scene] (
                    ProcessingFrame& pframe,
                    const CTransform3D& transform)
            {
                render_scene.ord_render_entities.push_back(pframe.entity());
                render_scene.ord_render_entities_matrices.push_back(transform.get_world_matrix());
            });

            render_scene.ord_mesh_entities.clear();
            render_scene.ord_mesh_entity_meshes.clear();
            render_scene.ord_mesh_entity_materials.clear();

            // Get all entities with a static mesh component
            frame.process_entities(
                [&render_scene, &state] (
                    ProcessingFrame& pframe,
                    const CStaticMesh& static_mesh)
            {
                render_scene.ord_mesh_entities.push_back(pframe.entity());
                render_scene.ord_mesh_entity_meshes.push_back(state.get_static_mesh_resource(static_mesh.mesh()));
                render_scene.ord_mesh_entity_materials.push_back(state.get_material_resource(static_mesh.material()));
            });

            render_scene.ord_lightmask_obstructors.clear();

            // Get all entities the 'CLightMaskObstructor' component
            frame.process_entities(
                [&render_scene, &state] (
                    ProcessingFrame& pframe,
                    const CLightMaskObstructor& /*obstructor*/)
            {
                render_scene.ord_lightmask_obstructors.push_back(pframe.entity());
            });

            render_scene.ord_lightmask_receivers.clear();

            // Get all entities with the 'CLightMaskReceiver' component
            frame.process_entities(
                [&render_scene, &state] (
                    ProcessingFrame& pframe,
                    const CLightMaskReceiver& /*receiver*/)
            {
                render_scene.ord_lightmask_receivers.push_back(pframe.entity());
            });
        }

        void render_scene_render_normal(GLRenderSystem::State& state, Mat4 view, Mat4 proj)
        {
            const auto& render_scene = state.render_scene;

            std::size_t iters[] = { 0, 0, 0, 0 };
            auto& obj_iter = iters[0], &mesh_iter = iters[1], &recv_iter = iters[2], &obst_iter = iters[3];

            const EntityId* const ord_arrays[] = {
                render_scene.ord_render_entities.data(),
                render_scene.ord_mesh_entities.data(),
                render_scene.ord_lightmask_receivers.data(),
                render_scene.ord_lightmask_obstructors.data(),
            };

            const std::size_t ord_array_lens[] = {
                render_scene.ord_render_entities.size(),
                render_scene.ord_mesh_entities.size(),
                render_scene.ord_lightmask_receivers.size(),
                render_scene.ord_lightmask_obstructors.size(),
            };

            // Set stencil function
            glStencilFunc(GL_ALWAYS, 0, 0xFF);

            // Draw all normal objects
            while (const auto entity = ord_entities_match(ord_arrays, ord_array_lens, iters, 2, 4))
            {
                // Make sure we didn't hit a lightmask receiver object
                if (recv_iter != render_scene.ord_lightmask_receivers.size() && entity == render_scene.ord_lightmask_receivers[recv_iter])
                {
                    ++obj_iter;
                    continue;
                }

                // Make sure we didn't hit a lightmask obstructor object
                if (obst_iter != render_scene.ord_lightmask_obstructors.size() && entity == render_scene.ord_lightmask_obstructors[obst_iter])
                {
                    ++obj_iter;
                    continue;
                }

                // Get the object properties
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }
        }

        void render_scene_render_lightmasks(GLRenderSystem::State& state, Mat4 view, Mat4 proj)
        {
            auto& render_scene = state.render_scene;

            std::size_t iters[] = { 0, 0, 0 };
            auto& obj_iter = iters[0], &mesh_iter = iters[1];

            const EntityId* const recv_pass_ord_arrays[] = {
                render_scene.ord_render_entities.data(),
                render_scene.ord_mesh_entities.data(),
                render_scene.ord_lightmask_receivers.data() };

            const EntityId* const obst_pass_ord_arrays[] = {
                render_scene.ord_render_entities.data(),
                render_scene.ord_mesh_entities.data(),
                render_scene.ord_lightmask_obstructors.data()
            };

            const std::size_t recv_pass_ord_array_lens[] = {
                render_scene.ord_render_entities.size(),
                render_scene.ord_mesh_entities.size(),
                render_scene.ord_lightmask_receivers.size()
            };

            const std::size_t obst_pass_ord_array_lens[] = {
                render_scene.ord_render_entities.size(),
                render_scene.ord_mesh_entities.size(),
                render_scene.ord_lightmask_obstructors.size()
            };

            // DRAW BACKFACE OF RECEIVERS
            while (const auto entity = ord_entities_match(recv_pass_ord_arrays, recv_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Disable face culling
                glDisable(GL_CULL_FACE);

                // Disable color output
                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

                // Set stencil
                glStencilFunc(GL_ALWAYS, 1, 0xFF);
                glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Disable stencil writing
                glStencilFunc(GL_EQUAL, 1, 0xFF);
                glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

                // Set depth function to greater than
                glDepthFunc(GL_GREATER);

                // Draw
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- DRAW BACKFACE OF OBSTRUCTORS ---*/

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(obst_pass_ord_arrays, obst_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Set depth function back to normal (less than)
                glDepthFunc(GL_LESS);

                // Draw backfaces only
                glEnable(GL_CULL_FACE);
                glCullFace(GL_FRONT);

                // Enable color output
                glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

                // Set to replace stencil buffer with '3' wherever drawn (within backface)
                glStencilFunc(GL_EQUAL, 0x03, 0x01);
                glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- OVERWRITE DEPTH WITH FRONT FACES OF LIGHTMASK RECEIVERS ---*/

            // Draw front faces only
            glCullFace(GL_BACK);

            // Set depth function to normal
            glDepthFunc(GL_LESS);

            // Set stencil to always pass within backface area, allow drawing where depth fails
            glStencilFunc(GL_LEQUAL, 1, 0xFF);
            glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);

            // Disable color output
            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(recv_pass_ord_arrays, recv_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- DRAW FRONT FACES OF LIGHTMASK OBSTRUCTORS ---*/

            // Set to allow drawing where depth test fails
            glStencilFunc(GL_LEQUAL, 1, 0xFF);
            glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(obst_pass_ord_arrays, obst_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- DRAW FRONT FACES OF LIGTHMASK RECEIVERS ---*/

            // Set depth function to always pass
            glDepthFunc(GL_ALWAYS);

            // Set stencil to always pass within backface area
            glStencilFunc(GL_EQUAL, 1, 0xFF);
            glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

            // Enable color output
            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(recv_pass_ord_arrays, recv_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }
        }
    }
}
<commit_msg>Should have made this part of the previous commit<commit_after>// RenderScene.cpp

#include <Engine/SystemFrame.h>
#include <Engine/Util/VectorUtils.h>
#include <Engine/Components/CTransform3D.h>
#include <Engine/Components/Display/CStaticMesh.h>
#include <Engine/Components/Display/CLightMaskObstructor.h>
#include <Engine/Components/Display/CLightMaskReceiver.h>
#include "../private/RenderScene.h"
#include "../private/GLRenderSystemState.h"

namespace sge
{
    namespace gl_render
    {
        static void render_prepare(
            const GLStaticMesh& mesh,
            const GLMaterial& mat,
            const Mat4& model,
            const Mat4& view,
            const Mat4& proj)
        {
            // Bind the mesh and material
            mesh.bind();
            GLuint texIndex = GL_TEXTURE0;
            mat.bind(texIndex);

            // Upload transformation matrices
            mat.set_model_matrix(model);
            mat.set_view_matrix(view);
            mat.set_projection_matrix(proj);
        }

        void init_render_scene(GLRenderSystem::State& state, SystemFrame& frame)
        {
            auto& render_scene = state.render_scene;
            render_scene.ord_render_entities.clear();
            render_scene.ord_render_entities_matrices.clear();

            // Get all entities with a transform
            frame.process_entities(
                [&render_scene] (
                    ProcessingFrame& pframe,
                    const CTransform3D& transform)
            {
                render_scene.ord_render_entities.push_back(pframe.entity());
                render_scene.ord_render_entities_matrices.push_back(transform.get_world_matrix());
            });

            render_scene.ord_mesh_entities.clear();
            render_scene.ord_mesh_entity_meshes.clear();
            render_scene.ord_mesh_entity_materials.clear();

            // Get all entities with a static mesh component
            frame.process_entities(
                [&render_scene, &state] (
                    ProcessingFrame& pframe,
                    const CStaticMesh& static_mesh)
            {
                render_scene.ord_mesh_entities.push_back(pframe.entity());
                render_scene.ord_mesh_entity_meshes.push_back(state.get_static_mesh_resource(static_mesh.mesh()));
                render_scene.ord_mesh_entity_materials.push_back(state.get_material_resource(static_mesh.material()));
            });

            render_scene.ord_lightmask_obstructors.clear();

            // Get all entities the 'CLightMaskObstructor' component
            frame.process_entities(
                [&render_scene, &state] (
                    ProcessingFrame& pframe,
                    const CLightMaskObstructor& /*obstructor*/)
            {
                render_scene.ord_lightmask_obstructors.push_back(pframe.entity());
            });

            render_scene.ord_lightmask_receivers.clear();

            // Get all entities with the 'CLightMaskReceiver' component
            frame.process_entities(
                [&render_scene, &state] (
                    ProcessingFrame& pframe,
                    const CLightMaskReceiver& /*receiver*/)
            {
                render_scene.ord_lightmask_receivers.push_back(pframe.entity());
            });
        }

        void render_scene_render_normal(GLRenderSystem::State& state, Mat4 view, Mat4 proj)
        {
            const auto& render_scene = state.render_scene;

            std::size_t iters[] = { 0, 0, 0, 0 };
            auto& obj_iter = iters[0], &mesh_iter = iters[1], &recv_iter = iters[2], &obst_iter = iters[3];

            const EntityId* const ord_arrays[] = {
                render_scene.ord_render_entities.data(),
                render_scene.ord_mesh_entities.data(),
                render_scene.ord_lightmask_receivers.data(),
                render_scene.ord_lightmask_obstructors.data(),
            };

            const std::size_t ord_array_lens[] = {
                render_scene.ord_render_entities.size(),
                render_scene.ord_mesh_entities.size(),
                render_scene.ord_lightmask_receivers.size(),
                render_scene.ord_lightmask_obstructors.size(),
            };

            // Disable stencil testing
            glDisable(GL_STENCIL_TEST);

            // Cull back faces
            glEnable(GL_CULL_FACE);
            glCullFace(GL_BACK);

            // User normal depth testing
            glEnable(GL_DEPTH_TEST);
            glDepthFunc(GL_LEQUAL);

            // Draw all normal objects
            while (const auto entity = ord_entities_match(ord_arrays, ord_array_lens, iters, 2, 4))
            {
                // Make sure we didn't hit a lightmask receiver object
                if (recv_iter != render_scene.ord_lightmask_receivers.size() && entity == render_scene.ord_lightmask_receivers[recv_iter])
                {
                    ++obj_iter;
                    continue;
                }

                // Make sure we didn't hit a lightmask obstructor object
                if (obst_iter != render_scene.ord_lightmask_obstructors.size() && entity == render_scene.ord_lightmask_obstructors[obst_iter])
                {
                    ++obj_iter;
                    continue;
                }

                // Get the object properties
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }
        }

        void render_scene_render_lightmasks(GLRenderSystem::State& state, Mat4 view, Mat4 proj)
        {
            auto& render_scene = state.render_scene;

            std::size_t iters[] = { 0, 0, 0 };
            auto& obj_iter = iters[0], &mesh_iter = iters[1];

            const EntityId* const recv_pass_ord_arrays[] = {
                render_scene.ord_render_entities.data(),
                render_scene.ord_mesh_entities.data(),
                render_scene.ord_lightmask_receivers.data() };

            const EntityId* const obst_pass_ord_arrays[] = {
                render_scene.ord_render_entities.data(),
                render_scene.ord_mesh_entities.data(),
                render_scene.ord_lightmask_obstructors.data()
            };

            const std::size_t recv_pass_ord_array_lens[] = {
                render_scene.ord_render_entities.size(),
                render_scene.ord_mesh_entities.size(),
                render_scene.ord_lightmask_receivers.size()
            };

            const std::size_t obst_pass_ord_array_lens[] = {
                render_scene.ord_render_entities.size(),
                render_scene.ord_mesh_entities.size(),
                render_scene.ord_lightmask_obstructors.size()
            };

            // Enable stencil testing
            glEnable(GL_STENCIL_TEST);

            /*--- DRAW BACKFACES OF LIGHTMASK RECEIVERS ---*/

            // Draw back faces only
            glCullFace(GL_FRONT);

            // Disable color output
            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

            // Set stencil
            glStencilFunc(GL_ALWAYS, 1, 0xFF);
            glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

            while (const auto entity = ord_entities_match(recv_pass_ord_arrays, recv_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- DRAW BACKFACE OF LIGHTMASK OBSTRUCTORS ---*/

            // Enable color output
            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

            // Set to replace stencil buffer with '3' wherever drawn (within backface)
            glStencilFunc(GL_EQUAL, 0x03, 0x01);
            glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(obst_pass_ord_arrays, obst_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- OVERWRITE DEPTH WITH FRONT FACES OF LIGHTMASK RECEIVERS ---*/

            // Draw front faces only
            glCullFace(GL_BACK);

            // Set stencil to always pass within backface area, allow drawing where depth fails
            glStencilFunc(GL_LEQUAL, 1, 0xFF);
            glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);

            // Disable color output
            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(recv_pass_ord_arrays, recv_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- DRAW FRONT FACES OF LIGHTMASK OBSTRUCTORS ---*/

            // Set to allow drawing where depth test fails
            glStencilFunc(GL_LEQUAL, 1, 0xFF);
            glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(obst_pass_ord_arrays, obst_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }

            /*--- DRAW FRONT FACES OF LIGTHMASK RECEIVERS ---*/

            // Set depth function to always pass
            glDepthFunc(GL_ALWAYS);

            // Set stencil to always pass within backface area
            glStencilFunc(GL_EQUAL, 1, 0xFF);
            glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

            // Enable color output
            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

            // Reset iterators
            std::memset(iters, 0, sizeof(iters));
            while (const auto entity = ord_entities_match(recv_pass_ord_arrays, recv_pass_ord_array_lens, iters, 3, 3))
            {
                const auto& model = render_scene.ord_render_entities_matrices[obj_iter];
                const auto& mesh = state.static_meshes.find(render_scene.ord_mesh_entity_meshes[mesh_iter])->second;
                const auto& material = state.materials.find(render_scene.ord_mesh_entity_materials[mesh_iter])->second;

                // Prepare for rendering
                render_prepare(mesh, material, model, view, proj);

                // Draw the mesh
                glDrawArrays(GL_TRIANGLES, 0, mesh.num_vertices());

                // Increment iter
                ++obj_iter;
            }
        }
    }
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
/**
 *
 *  This program illustrates the use of Geometric objects
 *
 */

#include "itkMath.h"
#include "itkPoint.h"
#include "itkVectorContainer.h"
#include <iostream>

//-------------------------
//
//   Main code
//
//-------------------------
int
itkPointGeometryTest(int, char *[])
{

  // Dimension & Type
  constexpr unsigned int N = 3;
  using ValueType = double;

  //  Vector & Point Classes
  using VectorType = itk::Vector<ValueType, N>;
  using PointType = itk::Point<ValueType, N>;

  VectorType va;

  va[0] = 1.0;
  va[1] = 3.0;
  va[2] = 5.0;

  std::cout << "initial vector va = ";
  std::cout << va << std::endl;

  // Tests for Point Type

  PointType pa;
  pa[0] = 1.0;
  pa[1] = 5.0;
  pa[2] = 11.0;

  std::cout << "initial point pa = ";
  std::cout << pa << std::endl;

  PointType pb(pa);
  std::cout << "copy constructor pb(pa) = ";
  std::cout << pb << std::endl;

  PointType pc = pa;
  std::cout << "copy constructor pc=pa  = ";
  std::cout << pc << std::endl;

  PointType pd = pa + va;
  std::cout << "vector sum pd = pa + va = ";
  std::cout << pd << std::endl;

  pb = pd + va;
  std::cout << "vector sum pb = pd + va = ";
  std::cout << pb << std::endl;

  VectorType diff = pa - pb;
  std::cout << "diff = pa - pb = ";
  std::cout << diff << std::endl;

  pc -= va;
  std::cout << "pc -= va = ";
  std::cout << pc << std::endl;

  pc += va;
  std::cout << "pc += va = ";
  std::cout << pc << std::endl;

  ValueType distance = pc.EuclideanDistanceTo(pb);
  std::cout << "Euclidean distance between pc and pb = ";
  std::cout << distance << std::endl;

  ValueType distance2 = pc.SquaredEuclideanDistanceTo(pb);
  std::cout << "Squared Euclidean distance between pc and pb = ";
  std::cout << distance2 << std::endl;

  vnl_vector_ref<ValueType> vnlVector = pa.GetVnlVector();
  std::cout << "vnl_vector = ";
  {
    for (unsigned int i = 0; i < N; i++)
    {
      std::cout << vnlVector[i] << ", ";
    }
    std::cout << std::endl;
  }

  // Test for CastFrom() method
  {
    std::cout << "Test for CastFrom() method... ";

    const float tolerance = 1e-7;

    //  Point Classes
    using DoublePointType = itk::Point<double, N>;
    using FloatPointType = itk::Point<float, N>;

    DoublePointType dp;
    dp[0] = 1.0;
    dp[1] = 1.7;
    dp[2] = 1.9;

    FloatPointType fp;
    fp[0] = 0.0;
    fp[1] = 0.0;
    fp[2] = 0.0;

    fp.CastFrom(dp); // Here is the call !

    // Verification...
    for (unsigned int i = 0; i < N; i++)
    {
      auto val = static_cast<FloatPointType::ValueType>(dp[i]);
      if (std::fabs(val - fp[i]) > tolerance)
      {
        std::cout << "Failed at component " << i << std::endl;
        return EXIT_FAILURE;
      }
    }

    std::cout << " PASSED ! " << std::endl;
  }

  // Test the MeanPoint
  {
    PointType            midpoint;
    PointType::ValueType aInit[3] = { 2.0, 4.0, 7.0 };
    PointType::ValueType bInit[3] = { 6.0, 2.0, 9.0 };
    PointType            A = aInit;
    PointType            B = bInit;
    midpoint.SetToMidPoint(A, B);
    std::cout << "Test for MidPoint " << std::endl;
    std::cout << "PA = " << A << std::endl;
    std::cout << "PB = " << B << std::endl;
    std::cout << "MidPoint = " << midpoint << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      if (itk::Math::NotAlmostEquals(midpoint[i], (A[i] + B[i]) / 2.0))
      {
        std::cerr << "Failure to compute MidPoint " << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for MidPoint point PASSED" << std::endl;
  }

  // Test the Barycentric combination
  {
    const double         tolerance = 1e-10;
    PointType            combination;
    PointType::ValueType aInit[3] = { 2.0, 4.0, 7.0 };
    PointType::ValueType bInit[3] = { 6.0, 2.0, 9.0 };
    PointType            A = aInit;
    PointType            B = bInit;
    double               alpha = 0.5;
    combination.SetToBarycentricCombination(A, B, alpha);
    std::cout << "Test for Barycentric combination" << std::endl;
    std::cout << "PA = " << A << std::endl;
    std::cout << "PB = " << B << std::endl;
    std::cout << "Alpha = " << alpha << std::endl;
    std::cout << "Combination = " << combination << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      const double value = (alpha * A[i] + (1.0 - alpha) * B[i]);
      if (std::fabs(combination[i] - value) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination PASSED" << std::endl;
  }

  // Test the Barycentric combination
  {
    const double         tolerance = 1e-10;
    PointType            combination;
    PointType::ValueType aInit[3] = { 12.0, 0.0, 0.0 };
    PointType::ValueType bInit[3] = { 0.0, 0.0, 12.0 };
    PointType::ValueType cInit[3] = { 0.0, 12.0, 0.0 };
    PointType            A = aInit;
    PointType            B = bInit;
    PointType            C = cInit;
    double               alpha = 1.0 / 3.0;
    double               beta = 1.0 / 3.0;
    combination.SetToBarycentricCombination(A, B, C, alpha, beta);
    std::cout << "Test for Barycentric combination" << std::endl;
    std::cout << "PA = " << A << std::endl;
    std::cout << "PB = " << B << std::endl;
    std::cout << "PC = " << C << std::endl;
    std::cout << "Alpha = " << alpha << std::endl;
    std::cout << "Beta  = " << beta << std::endl;
    std::cout << "Combination = " << combination << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      const double value = alpha * A[i] + beta * B[i] + (1.0 - alpha - beta) * C[i];
      if (std::fabs(combination[i] - value) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination PASSED" << std::endl;
  }

  // Test the Barycentric combination for an array
  {
    const double           tolerance = 1e-10;
    PointType              combination;
    constexpr unsigned int NP = 3;
    PointType              A[NP];
    double                 w[NP - 1];
    constexpr double       K = 12.0;
    PointType::ValueType   aInit0[3] = { K, 0.0, 0.0 };
    PointType::ValueType   aInit1[3] = { 0.0, K, 0.0 };
    PointType::ValueType   aInit2[3] = { 0.0, 0.0, K };
    A[0] = aInit0;
    A[1] = aInit1;
    A[2] = aInit2;
    w[0] = 1 / 3.0;
    w[1] = 1 / 3.0;
    combination.SetToBarycentricCombination(A, w, N);
    std::cout << "Test for Barycentric combination of an array of Points" << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      if (std::fabs(combination[i] - (K / 3.0)) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination of an array of Points PASSED" << std::endl;
  }

  // Test the Barycentric combination for an VectorContainer of Points
  {
    const double           tolerance = 1e-10;
    PointType              combination;
    constexpr unsigned int NP = 3;
    using VectorOfPoints = itk::VectorContainer<unsigned long, PointType>;
    VectorOfPoints::Pointer points = VectorOfPoints::New();
    points->Reserve(NP);
    constexpr double K = 12.0;

    VectorOfPoints::Iterator point = points->Begin();
    PointType::ValueType     vInit0[3] = { K, 0.0, 0.0 };
    PointType::ValueType     vInit1[3] = { 0.0, K, 0.0 };
    PointType::ValueType     vInit2[3] = { 0.0, 0.0, K };
    point->Value() = vInit0;
    point++;
    point->Value() = vInit1;
    point++;
    point->Value() = vInit2;

    double w[NP - 1];
    w[0] = 1 / 3.0;
    w[1] = 1 / 3.0;

    using BarycentricCalculatorType = itk::BarycentricCombination<VectorOfPoints, double *>;
    combination = BarycentricCalculatorType::Evaluate(points, w);
    std::cout << "Test for Barycentric combination of a VectorContainer of Points" << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      if (std::fabs(combination[i] - (K / 3.0)) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination of a VectorContainer of Points PASSED" << std::endl;
  }

  return EXIT_SUCCESS;
}
<commit_msg>COMP: fixing a couple of VNL related linking errors<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
/**
 *
 *  This program illustrates the use of Geometric objects
 *
 */

#include "itkMath.h"
#include "itkPoint.h"
#include "itkVectorContainer.h"
#include <iostream>

//-------------------------
//
//   Main code
//
//-------------------------
int
itkPointGeometryTest(int, char *[])
{

  // Dimension & Type
  constexpr unsigned int N = 3;
  using ValueType = double;

  //  Vector & Point Classes
  using VectorType = itk::Vector<ValueType, N>;
  using PointType = itk::Point<ValueType, N>;

  VectorType va;

  va[0] = 1.0;
  va[1] = 3.0;
  va[2] = 5.0;

  std::cout << "initial vector va = ";
  std::cout << va << std::endl;

  // Tests for Point Type

  PointType pa;
  pa[0] = 1.0;
  pa[1] = 5.0;
  pa[2] = 11.0;

  std::cout << "initial point pa = ";
  std::cout << pa << std::endl;

  PointType pb(pa);
  std::cout << "copy constructor pb(pa) = ";
  std::cout << pb << std::endl;

  PointType pc = pa;
  std::cout << "copy constructor pc=pa  = ";
  std::cout << pc << std::endl;

  PointType pd = pa + va;
  std::cout << "vector sum pd = pa + va = ";
  std::cout << pd << std::endl;

  pb = pd + va;
  std::cout << "vector sum pb = pd + va = ";
  std::cout << pb << std::endl;

  VectorType diff = pa - pb;
  std::cout << "diff = pa - pb = ";
  std::cout << diff << std::endl;

  pc -= va;
  std::cout << "pc -= va = ";
  std::cout << pc << std::endl;

  pc += va;
  std::cout << "pc += va = ";
  std::cout << pc << std::endl;

  ValueType distance = pc.EuclideanDistanceTo(pb);
  std::cout << "Euclidean distance between pc and pb = ";
  std::cout << distance << std::endl;

  ValueType distance2 = pc.SquaredEuclideanDistanceTo(pb);
  std::cout << "Squared Euclidean distance between pc and pb = ";
  std::cout << distance2 << std::endl;

  auto vnlVector = pa.GetVnlVector();
  std::cout << "vnl_vector = ";
  {
    for (unsigned int i = 0; i < N; i++)
    {
      std::cout << vnlVector[i] << ", ";
    }
    std::cout << std::endl;
  }

  // Test for CastFrom() method
  {
    std::cout << "Test for CastFrom() method... ";

    const float tolerance = 1e-7;

    //  Point Classes
    using DoublePointType = itk::Point<double, N>;
    using FloatPointType = itk::Point<float, N>;

    DoublePointType dp;
    dp[0] = 1.0;
    dp[1] = 1.7;
    dp[2] = 1.9;

    FloatPointType fp;
    fp[0] = 0.0;
    fp[1] = 0.0;
    fp[2] = 0.0;

    fp.CastFrom(dp); // Here is the call !

    // Verification...
    for (unsigned int i = 0; i < N; i++)
    {
      auto val = static_cast<FloatPointType::ValueType>(dp[i]);
      if (std::fabs(val - fp[i]) > tolerance)
      {
        std::cout << "Failed at component " << i << std::endl;
        return EXIT_FAILURE;
      }
    }

    std::cout << " PASSED ! " << std::endl;
  }

  // Test the MeanPoint
  {
    PointType            midpoint;
    PointType::ValueType aInit[3] = { 2.0, 4.0, 7.0 };
    PointType::ValueType bInit[3] = { 6.0, 2.0, 9.0 };
    PointType            A = aInit;
    PointType            B = bInit;
    midpoint.SetToMidPoint(A, B);
    std::cout << "Test for MidPoint " << std::endl;
    std::cout << "PA = " << A << std::endl;
    std::cout << "PB = " << B << std::endl;
    std::cout << "MidPoint = " << midpoint << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      if (itk::Math::NotAlmostEquals(midpoint[i], (A[i] + B[i]) / 2.0))
      {
        std::cerr << "Failure to compute MidPoint " << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for MidPoint point PASSED" << std::endl;
  }

  // Test the Barycentric combination
  {
    const double         tolerance = 1e-10;
    PointType            combination;
    PointType::ValueType aInit[3] = { 2.0, 4.0, 7.0 };
    PointType::ValueType bInit[3] = { 6.0, 2.0, 9.0 };
    PointType            A = aInit;
    PointType            B = bInit;
    double               alpha = 0.5;
    combination.SetToBarycentricCombination(A, B, alpha);
    std::cout << "Test for Barycentric combination" << std::endl;
    std::cout << "PA = " << A << std::endl;
    std::cout << "PB = " << B << std::endl;
    std::cout << "Alpha = " << alpha << std::endl;
    std::cout << "Combination = " << combination << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      const double value = (alpha * A[i] + (1.0 - alpha) * B[i]);
      if (std::fabs(combination[i] - value) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination PASSED" << std::endl;
  }

  // Test the Barycentric combination
  {
    const double         tolerance = 1e-10;
    PointType            combination;
    PointType::ValueType aInit[3] = { 12.0, 0.0, 0.0 };
    PointType::ValueType bInit[3] = { 0.0, 0.0, 12.0 };
    PointType::ValueType cInit[3] = { 0.0, 12.0, 0.0 };
    PointType            A = aInit;
    PointType            B = bInit;
    PointType            C = cInit;
    double               alpha = 1.0 / 3.0;
    double               beta = 1.0 / 3.0;
    combination.SetToBarycentricCombination(A, B, C, alpha, beta);
    std::cout << "Test for Barycentric combination" << std::endl;
    std::cout << "PA = " << A << std::endl;
    std::cout << "PB = " << B << std::endl;
    std::cout << "PC = " << C << std::endl;
    std::cout << "Alpha = " << alpha << std::endl;
    std::cout << "Beta  = " << beta << std::endl;
    std::cout << "Combination = " << combination << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      const double value = alpha * A[i] + beta * B[i] + (1.0 - alpha - beta) * C[i];
      if (std::fabs(combination[i] - value) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination PASSED" << std::endl;
  }

  // Test the Barycentric combination for an array
  {
    const double           tolerance = 1e-10;
    PointType              combination;
    constexpr unsigned int NP = 3;
    PointType              A[NP];
    double                 w[NP - 1];
    constexpr double       K = 12.0;
    PointType::ValueType   aInit0[3] = { K, 0.0, 0.0 };
    PointType::ValueType   aInit1[3] = { 0.0, K, 0.0 };
    PointType::ValueType   aInit2[3] = { 0.0, 0.0, K };
    A[0] = aInit0;
    A[1] = aInit1;
    A[2] = aInit2;
    w[0] = 1 / 3.0;
    w[1] = 1 / 3.0;
    combination.SetToBarycentricCombination(A, w, N);
    std::cout << "Test for Barycentric combination of an array of Points" << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      if (std::fabs(combination[i] - (K / 3.0)) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination of an array of Points PASSED" << std::endl;
  }

  // Test the Barycentric combination for an VectorContainer of Points
  {
    const double           tolerance = 1e-10;
    PointType              combination;
    constexpr unsigned int NP = 3;
    using VectorOfPoints = itk::VectorContainer<unsigned long, PointType>;
    VectorOfPoints::Pointer points = VectorOfPoints::New();
    points->Reserve(NP);
    constexpr double K = 12.0;

    VectorOfPoints::Iterator point = points->Begin();
    PointType::ValueType     vInit0[3] = { K, 0.0, 0.0 };
    PointType::ValueType     vInit1[3] = { 0.0, K, 0.0 };
    PointType::ValueType     vInit2[3] = { 0.0, 0.0, K };
    point->Value() = vInit0;
    point++;
    point->Value() = vInit1;
    point++;
    point->Value() = vInit2;

    double w[NP - 1];
    w[0] = 1 / 3.0;
    w[1] = 1 / 3.0;

    using BarycentricCalculatorType = itk::BarycentricCombination<VectorOfPoints, double *>;
    combination = BarycentricCalculatorType::Evaluate(points, w);
    std::cout << "Test for Barycentric combination of a VectorContainer of Points" << std::endl;
    for (unsigned int i = 0; i < N; i++)
    {
      if (std::fabs(combination[i] - (K / 3.0)) > tolerance)
      {
        std::cerr << "Failure to compute Barycentric combination" << std::endl;
        return EXIT_FAILURE;
      }
    }
    std::cout << "Test for Barycentric combination of a VectorContainer of Points PASSED" << std::endl;
  }

  return EXIT_SUCCESS;
}
<|endoftext|>