<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/browser/android/in_process/synchronous_compositor_impl.h"

#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "cc/input/input_handler.h"
#include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
#include "content/browser/android/in_process/synchronous_compositor_registry.h"
#include "content/browser/android/in_process/synchronous_input_event_filter.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/common/input/did_overscroll_params.h"
#include "content/common/input_messages.h"
#include "content/public/browser/android/synchronous_compositor_client.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "ui/gl/gl_surface.h"

namespace content {

namespace {

int GetInProcessRendererId() {
  content::RenderProcessHost::iterator it =
      content::RenderProcessHost::AllHostsIterator();
  if (it.IsAtEnd()) {
    // There should always be one RPH in single process mode.
    NOTREACHED();
    return 0;
  }

  int id = it.GetCurrentValue()->GetID();
  it.Advance();
  DCHECK(it.IsAtEnd());  // Not multiprocess compatible.
  return id;
}

base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
    LAZY_INSTANCE_INITIALIZER;

}  // namespace

DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);

// static
SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
                                                             int routing_id) {
  if (g_factory == nullptr)
    return nullptr;
  RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
  if (!rvh)
    return nullptr;
  WebContents* contents = WebContents::FromRenderViewHost(rvh);
  if (!contents)
    return nullptr;
  return FromWebContents(contents);
}

SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
    int routing_id) {
  return FromID(GetInProcessRendererId(), routing_id);
}

SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
    : compositor_client_(nullptr),
      output_surface_(nullptr),
      begin_frame_source_(nullptr),
      contents_(contents),
      routing_id_(contents->GetRoutingID()),
      input_handler_(nullptr),
      registered_with_client_(false),
      is_active_(true),
      renderer_needs_begin_frames_(false),
      weak_ptr_factory_(this) {
  DCHECK(contents);
  DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
}

SynchronousCompositorImpl::~SynchronousCompositorImpl() {
  DCHECK(!output_surface_);
  DCHECK(!begin_frame_source_);
  DCHECK(!input_handler_);
}

void SynchronousCompositorImpl::SetClient(
    SynchronousCompositorClient* compositor_client) {
  DCHECK(CalledOnValidThread());
  DCHECK_IMPLIES(compositor_client, !compositor_client_);
  DCHECK_IMPLIES(!compositor_client, compositor_client_);

  if (!compositor_client) {
    SynchronousCompositorRegistry::GetInstance()->UnregisterCompositor(
        routing_id_, this);
  }

  compositor_client_ = compositor_client;

  // SetClient is essentially the constructor and destructor of
  // SynchronousCompositorImpl.
  if (compositor_client_) {
    SynchronousCompositorRegistry::GetInstance()->RegisterCompositor(
        routing_id_, this);
  }
}

void SynchronousCompositorImpl::RegisterWithClient() {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  DCHECK(output_surface_);
  DCHECK(input_handler_);
  DCHECK(!registered_with_client_);
  registered_with_client_ = true;

  compositor_client_->DidInitializeCompositor(this);

  output_surface_->SetTreeActivationCallback(
    base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree,
               weak_ptr_factory_.GetWeakPtr()));

  // Setting the delegate causes UpdateRootLayerState immediately so do it
  // after setting the client.
  input_handler_->SetRootLayerScrollOffsetDelegate(this);
}

// static
void SynchronousCompositor::SetGpuService(
    scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
  g_factory.Get().SetDeferredGpuService(service);
}

// static
void SynchronousCompositor::SetRecordFullDocument(bool record_full_document) {
  g_factory.Get().SetRecordFullDocument(record_full_document);
}

void SynchronousCompositorImpl::DidInitializeRendererObjects(
    SynchronousCompositorOutputSurface* output_surface,
    SynchronousCompositorExternalBeginFrameSource* begin_frame_source,
    cc::InputHandler* input_handler) {
  DCHECK(!output_surface_);
  DCHECK(!begin_frame_source_);
  DCHECK(output_surface);
  DCHECK(begin_frame_source);
  DCHECK(compositor_client_);
  DCHECK(input_handler);

  output_surface_ = output_surface;
  begin_frame_source_ = begin_frame_source;
  input_handler_ = input_handler;

  output_surface_->SetCompositor(this);
  begin_frame_source_->SetCompositor(this);
}

void SynchronousCompositorImpl::DidDestroyRendererObjects() {
  DCHECK(output_surface_);
  DCHECK(begin_frame_source_);
  DCHECK(compositor_client_);

  if (registered_with_client_) {
    input_handler_->SetRootLayerScrollOffsetDelegate(nullptr);
    output_surface_->SetTreeActivationCallback(base::Closure());
    compositor_client_->DidDestroyCompositor(this);
    registered_with_client_ = false;
  }

  begin_frame_source_->SetCompositor(nullptr);
  output_surface_->SetCompositor(nullptr);

  input_handler_ = nullptr;
  begin_frame_source_ = nullptr;
  output_surface_ = nullptr;
}

scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
    gfx::Size surface_size,
    const gfx::Transform& transform,
    gfx::Rect viewport,
    gfx::Rect clip,
    gfx::Rect viewport_rect_for_tile_priority,
    const gfx::Transform& transform_for_tile_priority) {
  DCHECK(CalledOnValidThread());
  DCHECK(output_surface_);
  DCHECK(compositor_client_);
  DCHECK(begin_frame_source_);

  scoped_ptr<cc::CompositorFrame> frame =
      output_surface_->DemandDrawHw(surface_size,
                                    transform,
                                    viewport,
                                    clip,
                                    viewport_rect_for_tile_priority,
                                    transform_for_tile_priority);

  if (frame.get())
    UpdateFrameMetaData(frame->metadata);

  return frame.Pass();
}

void SynchronousCompositorImpl::ReturnResources(
    const cc::CompositorFrameAck& frame_ack) {
  DCHECK(CalledOnValidThread());
  output_surface_->ReturnResources(frame_ack);
}

bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
  DCHECK(CalledOnValidThread());
  DCHECK(output_surface_);
  DCHECK(compositor_client_);
  DCHECK(begin_frame_source_);

  scoped_ptr<cc::CompositorFrame> frame =
      output_surface_->DemandDrawSw(canvas);

  if (frame.get())
    UpdateFrameMetaData(frame->metadata);

  return !!frame.get();
}

void SynchronousCompositorImpl::UpdateFrameMetaData(
    const cc::CompositorFrameMetadata& frame_metadata) {
  RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
      contents_->GetRenderWidgetHostView());
  if (rwhv)
    rwhv->SynchronousFrameMetadata(frame_metadata);
  DeliverMessages();
}

void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) {
  DCHECK(CalledOnValidThread());
  DCHECK(output_surface_);

  size_t current_bytes_limit = output_surface_->GetMemoryPolicy();
  output_surface_->SetMemoryPolicy(bytes_limit);

  if (bytes_limit && !current_bytes_limit) {
    g_factory.Get().CompositorInitializedHardwareDraw();
  } else if (!bytes_limit && current_bytes_limit) {
    g_factory.Get().CompositorReleasedHardwareDraw();
  }
}

void SynchronousCompositorImpl::PostInvalidate() {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  if (registered_with_client_)
    compositor_client_->PostInvalidate();
}

void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
  if (input_handler_)
    input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
}

void SynchronousCompositorImpl::SetIsActive(bool is_active) {
  TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
               is_active);
  is_active_ = is_active;
  UpdateNeedsBeginFrames();
}

void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
    bool needs_begin_frames) {
  renderer_needs_begin_frames_ = needs_begin_frames;
  UpdateNeedsBeginFrames();
}

void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs& args) {
  if (!registered_with_client_) {
    RegisterWithClient();
    DCHECK(registered_with_client_);
  }
  if (begin_frame_source_)
    begin_frame_source_->BeginFrame(args);
}

void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
  RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
      contents_->GetRenderWidgetHostView());
  if (rwhv)
    rwhv->OnSetNeedsBeginFrames(is_active_ && renderer_needs_begin_frames_);
}

void SynchronousCompositorImpl::DidOverscroll(
    const DidOverscrollParams& params) {
  DCHECK(compositor_client_);
  if (registered_with_client_) {
    compositor_client_->DidOverscroll(params.accumulated_overscroll,
                                      params.latest_overscroll_delta,
                                      params.current_fling_velocity);
  }
}

void SynchronousCompositorImpl::DidStopFlinging() {
  // It's important that the fling-end notification follow the same path as it
  // takes on other platforms (using an IPC). This ensures consistent
  // bookkeeping at all stages of the input pipeline.
  contents_->GetRenderProcessHost()->OnMessageReceived(
      InputHostMsg_DidStopFlinging(routing_id_));
}

InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
    const blink::WebInputEvent& input_event) {
  DCHECK(CalledOnValidThread());
  return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
      contents_->GetRoutingID(), input_event);
}

void SynchronousCompositorImpl::DeliverMessages() {
  ScopedVector<IPC::Message> messages;
  output_surface_->GetMessagesToDeliver(&messages);
  RenderProcessHost* rph = contents_->GetRenderProcessHost();
  for (ScopedVector<IPC::Message>::const_iterator i = messages.begin();
       i != messages.end();
       ++i) {
    rph->OnMessageReceived(**i);
  }
}

void SynchronousCompositorImpl::DidActivatePendingTree() {
  DCHECK(compositor_client_);
  if (registered_with_client_)
    compositor_client_->DidUpdateContent();
  DeliverMessages();
}

gfx::ScrollOffset SynchronousCompositorImpl::GetTotalScrollOffset() {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  if (!registered_with_client_)
    return gfx::ScrollOffset();
  // TODO(miletus): Make GetTotalRootLayerScrollOffset return
  // ScrollOffset. crbug.com/414283.
  return gfx::ScrollOffset(
      compositor_client_->GetTotalRootLayerScrollOffset());
}

bool SynchronousCompositorImpl::IsExternalFlingActive() const {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  if (!registered_with_client_)
    return false;
  return compositor_client_->IsExternalFlingActive();
}

void SynchronousCompositorImpl::UpdateRootLayerState(
    const gfx::ScrollOffset& total_scroll_offset,
    const gfx::ScrollOffset& max_scroll_offset,
    const gfx::SizeF& scrollable_size,
    float page_scale_factor,
    float min_page_scale_factor,
    float max_page_scale_factor) {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);

  if (registered_with_client_) {
    // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
    compositor_client_->UpdateRootLayerState(
        gfx::ScrollOffsetToVector2dF(total_scroll_offset),
        gfx::ScrollOffsetToVector2dF(max_scroll_offset),
        scrollable_size,
        page_scale_factor,
        min_page_scale_factor,
        max_page_scale_factor);
  }
}

// Not using base::NonThreadSafe as we want to enforce a more exacting threading
// requirement: SynchronousCompositorImpl() must only be used on the UI thread.
bool SynchronousCompositorImpl::CalledOnValidThread() const {
  return BrowserThread::CurrentlyOn(BrowserThread::UI);
}

// static
void SynchronousCompositor::SetClientForWebContents(
    WebContents* contents,
    SynchronousCompositorClient* client) {
  DCHECK(contents);
  if (client) {
    g_factory.Get();  // Ensure it's initialized.
    SynchronousCompositorImpl::CreateForWebContents(contents);
  }
  SynchronousCompositorImpl* instance =
      SynchronousCompositorImpl::FromWebContents(contents);
  DCHECK(instance);
  instance->SetClient(client);
}

}  // namespace content
<commit_msg>Fix crash in sync compositor registration<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/browser/android/in_process/synchronous_compositor_impl.h"

#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "cc/input/input_handler.h"
#include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
#include "content/browser/android/in_process/synchronous_compositor_registry.h"
#include "content/browser/android/in_process/synchronous_input_event_filter.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/common/input/did_overscroll_params.h"
#include "content/common/input_messages.h"
#include "content/public/browser/android/synchronous_compositor_client.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "ui/gl/gl_surface.h"

namespace content {

namespace {

int GetInProcessRendererId() {
  content::RenderProcessHost::iterator it =
      content::RenderProcessHost::AllHostsIterator();
  if (it.IsAtEnd()) {
    // There should always be one RPH in single process mode.
    NOTREACHED();
    return 0;
  }

  int id = it.GetCurrentValue()->GetID();
  it.Advance();
  DCHECK(it.IsAtEnd());  // Not multiprocess compatible.
  return id;
}

base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
    LAZY_INSTANCE_INITIALIZER;

}  // namespace

DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl);

// static
SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
                                                             int routing_id) {
  if (g_factory == nullptr)
    return nullptr;
  RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
  if (!rvh)
    return nullptr;
  WebContents* contents = WebContents::FromRenderViewHost(rvh);
  if (!contents)
    return nullptr;
  return FromWebContents(contents);
}

SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
    int routing_id) {
  return FromID(GetInProcessRendererId(), routing_id);
}

SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents)
    : compositor_client_(nullptr),
      output_surface_(nullptr),
      begin_frame_source_(nullptr),
      contents_(contents),
      routing_id_(contents->GetRoutingID()),
      input_handler_(nullptr),
      registered_with_client_(false),
      is_active_(true),
      renderer_needs_begin_frames_(false),
      weak_ptr_factory_(this) {
  DCHECK(contents);
  DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
}

SynchronousCompositorImpl::~SynchronousCompositorImpl() {
  DCHECK(!output_surface_);
  DCHECK(!begin_frame_source_);
  DCHECK(!input_handler_);
}

void SynchronousCompositorImpl::SetClient(
    SynchronousCompositorClient* compositor_client) {
  DCHECK(CalledOnValidThread());
  DCHECK_IMPLIES(compositor_client, !compositor_client_);
  DCHECK_IMPLIES(!compositor_client, compositor_client_);

  if (!compositor_client) {
    SynchronousCompositorRegistry::GetInstance()->UnregisterCompositor(
        routing_id_, this);
  }

  compositor_client_ = compositor_client;

  // SetClient is essentially the constructor and destructor of
  // SynchronousCompositorImpl.
  if (compositor_client_) {
    SynchronousCompositorRegistry::GetInstance()->RegisterCompositor(
        routing_id_, this);
  }
}

void SynchronousCompositorImpl::RegisterWithClient() {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  DCHECK(output_surface_);
  DCHECK(input_handler_);
  DCHECK(!registered_with_client_);
  registered_with_client_ = true;

  compositor_client_->DidInitializeCompositor(this);

  output_surface_->SetTreeActivationCallback(
    base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree,
               weak_ptr_factory_.GetWeakPtr()));

  // Setting the delegate causes UpdateRootLayerState immediately so do it
  // after setting the client.
  input_handler_->SetRootLayerScrollOffsetDelegate(this);
}

// static
void SynchronousCompositor::SetGpuService(
    scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
  g_factory.Get().SetDeferredGpuService(service);
}

// static
void SynchronousCompositor::SetRecordFullDocument(bool record_full_document) {
  g_factory.Get().SetRecordFullDocument(record_full_document);
}

void SynchronousCompositorImpl::DidInitializeRendererObjects(
    SynchronousCompositorOutputSurface* output_surface,
    SynchronousCompositorExternalBeginFrameSource* begin_frame_source,
    cc::InputHandler* input_handler) {
  DCHECK(!output_surface_);
  DCHECK(!begin_frame_source_);
  DCHECK(output_surface);
  DCHECK(begin_frame_source);
  DCHECK(compositor_client_);
  DCHECK(input_handler);

  output_surface_ = output_surface;
  begin_frame_source_ = begin_frame_source;
  input_handler_ = input_handler;

  output_surface_->SetCompositor(this);
  begin_frame_source_->SetCompositor(this);
}

void SynchronousCompositorImpl::DidDestroyRendererObjects() {
  DCHECK(output_surface_);
  DCHECK(begin_frame_source_);
  DCHECK(compositor_client_);

  if (registered_with_client_) {
    input_handler_->SetRootLayerScrollOffsetDelegate(nullptr);
    output_surface_->SetTreeActivationCallback(base::Closure());
    compositor_client_->DidDestroyCompositor(this);
    registered_with_client_ = false;
  }

  begin_frame_source_->SetCompositor(nullptr);
  output_surface_->SetCompositor(nullptr);

  input_handler_ = nullptr;
  begin_frame_source_ = nullptr;
  output_surface_ = nullptr;
}

scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
    gfx::Size surface_size,
    const gfx::Transform& transform,
    gfx::Rect viewport,
    gfx::Rect clip,
    gfx::Rect viewport_rect_for_tile_priority,
    const gfx::Transform& transform_for_tile_priority) {
  DCHECK(CalledOnValidThread());
  DCHECK(output_surface_);
  DCHECK(compositor_client_);
  DCHECK(begin_frame_source_);

  scoped_ptr<cc::CompositorFrame> frame =
      output_surface_->DemandDrawHw(surface_size,
                                    transform,
                                    viewport,
                                    clip,
                                    viewport_rect_for_tile_priority,
                                    transform_for_tile_priority);

  if (frame.get())
    UpdateFrameMetaData(frame->metadata);

  return frame.Pass();
}

void SynchronousCompositorImpl::ReturnResources(
    const cc::CompositorFrameAck& frame_ack) {
  DCHECK(CalledOnValidThread());
  output_surface_->ReturnResources(frame_ack);
}

bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
  DCHECK(CalledOnValidThread());
  DCHECK(output_surface_);
  DCHECK(compositor_client_);
  DCHECK(begin_frame_source_);

  scoped_ptr<cc::CompositorFrame> frame =
      output_surface_->DemandDrawSw(canvas);

  if (frame.get())
    UpdateFrameMetaData(frame->metadata);

  return !!frame.get();
}

void SynchronousCompositorImpl::UpdateFrameMetaData(
    const cc::CompositorFrameMetadata& frame_metadata) {
  RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
      contents_->GetRenderWidgetHostView());
  if (rwhv)
    rwhv->SynchronousFrameMetadata(frame_metadata);
  DeliverMessages();
}

void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) {
  DCHECK(CalledOnValidThread());
  DCHECK(output_surface_);

  size_t current_bytes_limit = output_surface_->GetMemoryPolicy();
  output_surface_->SetMemoryPolicy(bytes_limit);

  if (bytes_limit && !current_bytes_limit) {
    g_factory.Get().CompositorInitializedHardwareDraw();
  } else if (!bytes_limit && current_bytes_limit) {
    g_factory.Get().CompositorReleasedHardwareDraw();
  }
}

void SynchronousCompositorImpl::PostInvalidate() {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  if (registered_with_client_)
    compositor_client_->PostInvalidate();
}

void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
  if (input_handler_)
    input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
}

void SynchronousCompositorImpl::SetIsActive(bool is_active) {
  TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
               is_active);
  is_active_ = is_active;
  UpdateNeedsBeginFrames();
}

void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
    bool needs_begin_frames) {
  renderer_needs_begin_frames_ = needs_begin_frames;
  UpdateNeedsBeginFrames();
}

void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs& args) {
  if (!registered_with_client_ && is_active_ && renderer_needs_begin_frames_) {
    // Make sure this is a BeginFrame that renderer side explicitly requested.
    // Otherwise it is possible renderer objects not initialized.
    RegisterWithClient();
    DCHECK(registered_with_client_);
  }
  if (begin_frame_source_)
    begin_frame_source_->BeginFrame(args);
}

void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
  RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
      contents_->GetRenderWidgetHostView());
  if (rwhv)
    rwhv->OnSetNeedsBeginFrames(is_active_ && renderer_needs_begin_frames_);
}

void SynchronousCompositorImpl::DidOverscroll(
    const DidOverscrollParams& params) {
  DCHECK(compositor_client_);
  if (registered_with_client_) {
    compositor_client_->DidOverscroll(params.accumulated_overscroll,
                                      params.latest_overscroll_delta,
                                      params.current_fling_velocity);
  }
}

void SynchronousCompositorImpl::DidStopFlinging() {
  // It's important that the fling-end notification follow the same path as it
  // takes on other platforms (using an IPC). This ensures consistent
  // bookkeeping at all stages of the input pipeline.
  contents_->GetRenderProcessHost()->OnMessageReceived(
      InputHostMsg_DidStopFlinging(routing_id_));
}

InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
    const blink::WebInputEvent& input_event) {
  DCHECK(CalledOnValidThread());
  return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
      contents_->GetRoutingID(), input_event);
}

void SynchronousCompositorImpl::DeliverMessages() {
  ScopedVector<IPC::Message> messages;
  output_surface_->GetMessagesToDeliver(&messages);
  RenderProcessHost* rph = contents_->GetRenderProcessHost();
  for (ScopedVector<IPC::Message>::const_iterator i = messages.begin();
       i != messages.end();
       ++i) {
    rph->OnMessageReceived(**i);
  }
}

void SynchronousCompositorImpl::DidActivatePendingTree() {
  DCHECK(compositor_client_);
  if (registered_with_client_)
    compositor_client_->DidUpdateContent();
  DeliverMessages();
}

gfx::ScrollOffset SynchronousCompositorImpl::GetTotalScrollOffset() {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  if (!registered_with_client_)
    return gfx::ScrollOffset();
  // TODO(miletus): Make GetTotalRootLayerScrollOffset return
  // ScrollOffset. crbug.com/414283.
  return gfx::ScrollOffset(
      compositor_client_->GetTotalRootLayerScrollOffset());
}

bool SynchronousCompositorImpl::IsExternalFlingActive() const {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);
  if (!registered_with_client_)
    return false;
  return compositor_client_->IsExternalFlingActive();
}

void SynchronousCompositorImpl::UpdateRootLayerState(
    const gfx::ScrollOffset& total_scroll_offset,
    const gfx::ScrollOffset& max_scroll_offset,
    const gfx::SizeF& scrollable_size,
    float page_scale_factor,
    float min_page_scale_factor,
    float max_page_scale_factor) {
  DCHECK(CalledOnValidThread());
  DCHECK(compositor_client_);

  if (registered_with_client_) {
    // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
    compositor_client_->UpdateRootLayerState(
        gfx::ScrollOffsetToVector2dF(total_scroll_offset),
        gfx::ScrollOffsetToVector2dF(max_scroll_offset),
        scrollable_size,
        page_scale_factor,
        min_page_scale_factor,
        max_page_scale_factor);
  }
}

// Not using base::NonThreadSafe as we want to enforce a more exacting threading
// requirement: SynchronousCompositorImpl() must only be used on the UI thread.
bool SynchronousCompositorImpl::CalledOnValidThread() const {
  return BrowserThread::CurrentlyOn(BrowserThread::UI);
}

// static
void SynchronousCompositor::SetClientForWebContents(
    WebContents* contents,
    SynchronousCompositorClient* client) {
  DCHECK(contents);
  if (client) {
    g_factory.Get();  // Ensure it's initialized.
    SynchronousCompositorImpl::CreateForWebContents(contents);
  }
  SynchronousCompositorImpl* instance =
      SynchronousCompositorImpl::FromWebContents(contents);
  DCHECK(instance);
  instance->SetClient(client);
}

}  // namespace content
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of object with set of particles at pixel
 * @copyright Copyright (c) 2017-2019 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "PixelCharge.hpp"

#include <set>
#include "exceptions.h"

using namespace allpix;

PixelCharge::PixelCharge(Pixel pixel, unsigned int charge, std::vector<const PropagatedCharge*> propagated_charges)
    : pixel_(std::move(pixel)), charge_(charge) {
    // Unique set of MC particles
    std::set<TRef> unique_particles;
    // Store all propagated charges and their MC particles
    for(auto& propagated_charge : propagated_charges) {
        propagated_charges_.push_back(const_cast<PropagatedCharge*>(propagated_charge)); // NOLINT
        unique_particles.insert(propagated_charge->mc_particle_);
    }
    // Store the MC particle references
    for(auto& mc_particle : unique_particles) {
        mc_particles_.push_back(mc_particle);
    }

    // No pulse provided, set full charge in first bin:
    pulse_.addCharge(charge, 0);
}

// WARNING PixelCharge always returns a positive "collected" charge...
PixelCharge::PixelCharge(Pixel pixel, Pulse pulse, std::vector<const PropagatedCharge*> propagated_charges)
    : PixelCharge(std::move(pixel), static_cast<unsigned int>(std::abs(pulse.getCharge())), std::move(propagated_charges)) {
    pulse_ = std::move(pulse);
}

const Pixel& PixelCharge::getPixel() const {
    return pixel_;
}

Pixel::Index PixelCharge::getIndex() const {
    return getPixel().getIndex();
}

unsigned int PixelCharge::getCharge() const {
    return charge_;
}

const Pulse& PixelCharge::getPulse() const {
    return pulse_;
}

/**
 * @throws MissingReferenceException If the pointed object is not in scope
 *
 * Objects are stored as vector of TRef and can only be accessed if pointed objects are in scope
 */
std::vector<const PropagatedCharge*> PixelCharge::getPropagatedCharges() const {
    // FIXME: This is not very efficient unfortunately
    std::vector<const PropagatedCharge*> propagated_charges;
    for(auto& propagated_charge : propagated_charges_) {
        if(!propagated_charge.IsValid() || propagated_charge.GetObject() == nullptr) {
            throw MissingReferenceException(typeid(*this), typeid(PropagatedCharge));
        }
        propagated_charges.emplace_back(dynamic_cast<PropagatedCharge*>(propagated_charge.GetObject()));
    }
    return propagated_charges;
}

/**
 * @throws MissingReferenceException If the pointed object is not in scope
 *
 * MCParticles can only be fetched if the full history of objects are in scope and stored
 */
std::vector<const MCParticle*> PixelCharge::getMCParticles() const {

    std::vector<const MCParticle*> mc_particles;
    for(auto& mc_particle : mc_particles_) {
        if(!mc_particle.IsValid() || mc_particle.GetObject() == nullptr) {
            throw MissingReferenceException(typeid(*this), typeid(MCParticle));
        }
        mc_particles.emplace_back(dynamic_cast<MCParticle*>(mc_particle.GetObject()));
    }

    // Return as a vector of mc particles
    return mc_particles;
}

void PixelCharge::print(std::ostream& out) const {
    auto local_center_location = pixel_.getLocalCenter();
    auto global_center_location = pixel_.getGlobalCenter();
    auto pixel_size = pixel_.getSize();

    out << "--- Pixel charge information\n";
    out << "Local Position: (" << local_center_location.X() << ", " << local_center_location.Y() << ", "
        << local_center_location.Z() << ") mm\n"
        << "Global Position: (" << global_center_location.X() << ", " << global_center_location.Y() << ", "
        << global_center_location.Z() << ") mm\n"
        << "\nCharge: " << charge_ << " ke"
        << "\nSize: " << pixel_size.X() << ' ' << pixel_size.Y() << '\n';
}
<commit_msg>Remove the empty line between PixelCharge printed data<commit_after>/**
 * @file
 * @brief Implementation of object with set of particles at pixel
 * @copyright Copyright (c) 2017-2019 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "PixelCharge.hpp"

#include <set>
#include "exceptions.h"

using namespace allpix;

PixelCharge::PixelCharge(Pixel pixel, unsigned int charge, std::vector<const PropagatedCharge*> propagated_charges)
    : pixel_(std::move(pixel)), charge_(charge) {
    // Unique set of MC particles
    std::set<TRef> unique_particles;
    // Store all propagated charges and their MC particles
    for(auto& propagated_charge : propagated_charges) {
        propagated_charges_.push_back(const_cast<PropagatedCharge*>(propagated_charge)); // NOLINT
        unique_particles.insert(propagated_charge->mc_particle_);
    }
    // Store the MC particle references
    for(auto& mc_particle : unique_particles) {
        mc_particles_.push_back(mc_particle);
    }

    // No pulse provided, set full charge in first bin:
    pulse_.addCharge(charge, 0);
}

// WARNING PixelCharge always returns a positive "collected" charge...
PixelCharge::PixelCharge(Pixel pixel, Pulse pulse, std::vector<const PropagatedCharge*> propagated_charges)
    : PixelCharge(std::move(pixel), static_cast<unsigned int>(std::abs(pulse.getCharge())), std::move(propagated_charges)) {
    pulse_ = std::move(pulse);
}

const Pixel& PixelCharge::getPixel() const {
    return pixel_;
}

Pixel::Index PixelCharge::getIndex() const {
    return getPixel().getIndex();
}

unsigned int PixelCharge::getCharge() const {
    return charge_;
}

const Pulse& PixelCharge::getPulse() const {
    return pulse_;
}

/**
 * @throws MissingReferenceException If the pointed object is not in scope
 *
 * Objects are stored as vector of TRef and can only be accessed if pointed objects are in scope
 */
std::vector<const PropagatedCharge*> PixelCharge::getPropagatedCharges() const {
    // FIXME: This is not very efficient unfortunately
    std::vector<const PropagatedCharge*> propagated_charges;
    for(auto& propagated_charge : propagated_charges_) {
        if(!propagated_charge.IsValid() || propagated_charge.GetObject() == nullptr) {
            throw MissingReferenceException(typeid(*this), typeid(PropagatedCharge));
        }
        propagated_charges.emplace_back(dynamic_cast<PropagatedCharge*>(propagated_charge.GetObject()));
    }
    return propagated_charges;
}

/**
 * @throws MissingReferenceException If the pointed object is not in scope
 *
 * MCParticles can only be fetched if the full history of objects are in scope and stored
 */
std::vector<const MCParticle*> PixelCharge::getMCParticles() const {

    std::vector<const MCParticle*> mc_particles;
    for(auto& mc_particle : mc_particles_) {
        if(!mc_particle.IsValid() || mc_particle.GetObject() == nullptr) {
            throw MissingReferenceException(typeid(*this), typeid(MCParticle));
        }
        mc_particles.emplace_back(dynamic_cast<MCParticle*>(mc_particle.GetObject()));
    }

    // Return as a vector of mc particles
    return mc_particles;
}

void PixelCharge::print(std::ostream& out) const {
    auto local_center_location = pixel_.getLocalCenter();
    auto global_center_location = pixel_.getGlobalCenter();
    auto pixel_size = pixel_.getSize();

    out << "--- Pixel charge information\n";
    out << "Local Position: (" << local_center_location.X() << ", " << local_center_location.Y() << ", "
        << local_center_location.Z() << ") mm\n"
        << "Global Position: (" << global_center_location.X() << ", " << global_center_location.Y() << ", "
        << global_center_location.Z() << ") mm\n"
        << "Charge: " << charge_ << " ke\n"
        << "Size: " << pixel_size.X() << ' ' << pixel_size.Y() << '\n';
}
<|endoftext|>


<commit_before>/** \brief  Utility for finding referenced PPN's that we should have, but that are missing.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include "FileUtil.h"
#include "MARC.h"
#include "util.h"

int Main(int argc, char *argv[]) {
    if (argc != 3)
        ::Usage("marc_input missing_references");

    const auto marc_reader(MARC::Reader::Factory(argv[1]));
    std::unique_ptr<MARC::Writer> marc_writer(nullptr);
    const auto missing_references_log(FileUtil::OpenOutputFileOrDie(argv[2]));

    std::unordered_set<std::string> all_ppns;
    while (const auto record = marc_reader->read())
        all_ppns.emplace(record.getControlNumber());
    marc_reader->rewind();

    std::unordered_map<std::string, std::set<std::string>> missing_ppns_to_referers_map;
    while (const auto record = marc_reader->read()) {
        for (const auto _787_field : record.getTagRange("787")) {
            if (not StringUtil::StartsWith(_787_field.getFirstSubfieldWithCode('i'), "Rezension"))
                continue;

            for (const auto &subfield : _787_field.getSubfields()) {
                if (subfield.code_ == 'w' and StringUtil::StartsWith(subfield.value_, "(DE-627)")) {
                    const auto referenced_ppn(subfield.value_.substr(__builtin_strlen("(DE-627)")));
                    if (all_ppns.find(referenced_ppn) == all_ppns.end()) {
                        auto missing_ppn_and_referers(missing_ppns_to_referers_map.find(referenced_ppn));
                        if (missing_ppn_and_referers != missing_ppns_to_referers_map.end())
                            missing_ppn_and_referers->second.emplace(record.getControlNumber());
                        else
                            missing_ppns_to_referers_map.emplace(referenced_ppn, std::set<std::string>{ record.getControlNumber() });
                    }
                    break;
                }
            }
        }
    }

    for (const auto &[missing_ppn, referers] : missing_ppns_to_referers_map)
        (*missing_references_log) << missing_ppn << " <- " << StringUtil::Join(referers, ", ") << '\n';

    LOG_INFO("Found " + std::to_string(missing_ppns_to_referers_map.size()) + " missing reference(s).");

    return EXIT_FAILURE;
}
<commit_msg>Now we send notification emails.<commit_after>/** \brief  Utility for finding referenced PPN's that we should have, but that are missing.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include "DbConnection.h"
#include "EmailSender.h"
#include "FileUtil.h"
#include "MARC.h"
#include "UBTools.h"
#include "util.h"

namespace {

DbConnection *OpenOrCreateDatabase() {
    const std::string DATABASE_PATH(UBTools::GetTuelibPath() + "previously_reported_missing_ppns.sq3");
    if (FileUtil::Exists(DATABASE_PATH))
        return new DbConnection(DATABASE_PATH, DbConnection::READWRITE);

    DbConnection *db_connection(new DbConnection(DATABASE_PATH, DbConnection::CREATE));
    db_connection->queryOrDie("CREATE TABLE missing_references (ppn PRIMARY TEXT KEY) WITHOUT ROWID");
    return db_connection;
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc != 3)
        ::Usage("marc_input email_address");

    const auto marc_reader(MARC::Reader::Factory(argv[1]));
    std::unique_ptr<MARC::Writer> marc_writer(nullptr);
    const auto missing_references_log(FileUtil::OpenOutputFileOrDie(argv[2]));

    const std::string email_address(argv[2]);
    if (not EmailSender::IsValidEmailAddress(email_address))
        LOG_ERROR("\"" + email_address + "\" is not a valid email address!");

    DbConnection *db_connection(OpenOrCreateDatabase());

    std::unordered_set<std::string> all_ppns;
    while (const auto record = marc_reader->read())
        all_ppns.emplace(record.getControlNumber());
    marc_reader->rewind();

    std::unordered_map<std::string, std::set<std::string>> missing_ppns_to_referers_map;
    while (const auto record = marc_reader->read()) {
        for (const auto _787_field : record.getTagRange("787")) {
            if (not StringUtil::StartsWith(_787_field.getFirstSubfieldWithCode('i'), "Rezension"))
                continue;

            for (const auto &subfield : _787_field.getSubfields()) {
                if (subfield.code_ == 'w' and StringUtil::StartsWith(subfield.value_, "(DE-627)")) {
                    const auto referenced_ppn(subfield.value_.substr(__builtin_strlen("(DE-627)")));
                    if (all_ppns.find(referenced_ppn) == all_ppns.end()) {
                        auto missing_ppn_and_referers(missing_ppns_to_referers_map.find(referenced_ppn));
                        if (missing_ppn_and_referers != missing_ppns_to_referers_map.end())
                            missing_ppn_and_referers->second.emplace(record.getControlNumber());
                        else
                            missing_ppns_to_referers_map.emplace(referenced_ppn, std::set<std::string>{ record.getControlNumber() });
                    }
                    break;
                }
            }
        }
    }

    std::string email_attachement;
    unsigned new_missing_count(0);
    for (const auto &[missing_ppn, referers] : missing_ppns_to_referers_map) {
        db_connection->queryOrDie("SELECT ppn FROM missing_references WHERE ppn='" + missing_ppn + "'");
        const DbResultSet result_set(db_connection->getLastResultSet());
        if (result_set.empty()) {
            ++new_missing_count;
            email_attachement +=  missing_ppn + " <- " + StringUtil::Join(referers, ", ") + "\n";
            db_connection->queryOrDie("INSERT INTO missing_references (ppn) VALUES ('" + missing_ppn + "')");
        }
    }

    LOG_INFO("Found " + std::to_string(missing_ppns_to_referers_map.size()) + " new missing reference(s).");

    if (not email_attachement.empty()) {
        const auto status_code(EmailSender::SendEmail("nobody@nowhere.com", email_address, "Missing PPN's",
                                                      "Attached is the new list of " + std::to_string(new_missing_count) + " missing PPN('s).",
                                                      EmailSender::DO_NOT_SET_PRIORITY, EmailSender::PLAIN_TEXT, /* reply_to = */"",
                                                      /* use_ssl = */true, /* use_authentication = */true, { email_attachement }));
        if (status_code > 299)
            LOG_ERROR("Failed to send an email to \"" + email_address + "\"!  The server returned "
                      + std::to_string(status_code) + ".");
    }

    return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wakeupthread.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 01:28:08 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

//_______________________________________________
// include files of own module

#ifndef __FRAMEWORK_HELPER_WAKEUPTHREAD_HXX_
#include <helper/wakeupthread.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_READGUARD_HXX_
#include <threadhelp/readguard.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_
#include <threadhelp/writeguard.hxx>
#endif

//_______________________________________________
// namespace

namespace framework{

//_______________________________________________
// declarations

//***********************************************
WakeUpThread::WakeUpThread(const css::uno::Reference< css::util::XUpdatable >& xListener)
    : ThreadHelpBase(         )
    , m_xListener   (xListener)
{
}

//***********************************************
void SAL_CALL WakeUpThread::run()
{
    ::osl::Condition aSleeper;

    TimeValue aTime;
    aTime.Seconds = 0;
    aTime.Nanosec = 25000000; // 25 msec

    while(schedule())
    {
        aSleeper.reset();
        aSleeper.wait(&aTime);

        // SAFE ->
        ReadGuard aReadLock(m_aLock);
        css::uno::Reference< css::util::XUpdatable > xListener(m_xListener.get(), css::uno::UNO_QUERY);
        aReadLock.unlock();
        // <- SAFE

        if (xListener.is())
            xListener->update();
    }
}

//***********************************************
void SAL_CALL WakeUpThread::onTerminated()
{
    delete this;
}

} // namespace framework
<commit_msg>INTEGRATION: CWS pchfix02 (1.4.202); FILE MERGED 2006/09/01 17:29:12 kaib 1.4.202.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wakeupthread.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 14:01:54 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_framework.hxx"

//_______________________________________________
// include files of own module

#ifndef __FRAMEWORK_HELPER_WAKEUPTHREAD_HXX_
#include <helper/wakeupthread.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_READGUARD_HXX_
#include <threadhelp/readguard.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_
#include <threadhelp/writeguard.hxx>
#endif

//_______________________________________________
// namespace

namespace framework{

//_______________________________________________
// declarations

//***********************************************
WakeUpThread::WakeUpThread(const css::uno::Reference< css::util::XUpdatable >& xListener)
    : ThreadHelpBase(         )
    , m_xListener   (xListener)
{
}

//***********************************************
void SAL_CALL WakeUpThread::run()
{
    ::osl::Condition aSleeper;

    TimeValue aTime;
    aTime.Seconds = 0;
    aTime.Nanosec = 25000000; // 25 msec

    while(schedule())
    {
        aSleeper.reset();
        aSleeper.wait(&aTime);

        // SAFE ->
        ReadGuard aReadLock(m_aLock);
        css::uno::Reference< css::util::XUpdatable > xListener(m_xListener.get(), css::uno::UNO_QUERY);
        aReadLock.unlock();
        // <- SAFE

        if (xListener.is())
            xListener->update();
    }
}

//***********************************************
void SAL_CALL WakeUpThread::onTerminated()
{
    delete this;
}

} // namespace framework
<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <unordered_set>
#include <string>
#include <vector>

using namespace std;

constexpr bool debug = true;

using UChar = unsigned char;
using ULInt = unsigned long int;

template <typename Container>
void printContainer(const Container& c, const string& name) {
    cout << "Printing container - " << name << " of size = " << c.size() << " : [";
    for (auto i = c.begin(); i != c.end(); ++i) {
        cout << *i << ",";
    }
	cout << "]" << endl;
}

void findChange(ULInt change, const vector<ULInt>& coins, string& solution, ULInt& nSolutions,
		unordered_set<string>& solutions, vector<ULInt>::const_iterator& fromStart, unordered_set<string>& unsortedSolutions) {
	if (change != 0) {
		for (auto it = fromStart; it != coins.cend(); ++it) {
			auto coin = *it;
			auto coinStr = to_string(coin);
			if (debug) {
				cout << "current coin is : " << coinStr << endl;
				cout << "current change is : " << change << endl;
			}
			if (change > coin) {
				findChange(change - coin, coins, solution.append(coinStr), nSolutions, solutions, fromStart, unsortedSolutions);
				solution.pop_back();
			} else if (change == coin) {
				solution.append(coinStr);
				auto sortedSolution = solution;
				sort(sortedSolution.begin(), sortedSolution.end());
				auto checkInsert = solutions.insert(sortedSolution);
				unsortedSolutions.insert(solution);
				if (checkInsert.second == true) {
					++nSolutions;
					cout << "solution found! : " << solution << endl;
				}
				if (debug) printContainer(solutions, "solutions so far");
				if (debug) printContainer(unsortedSolutions, "unsortedSolutions so far");
				solution.pop_back();
			} else {
				if (debug) {
					cout << "overshooting, try with next coin " << coinStr << endl;
				}
				++fromStart;
			}
		}
	}
}

int main() {
    auto change = static_cast<ULInt>(0);
    cin >> change;

	auto nCoins = static_cast<ULInt>(0);
	cin >> nCoins;

	vector<ULInt> coins;
    for (auto i = 0; i < nCoins; ++i) {
        auto coin = static_cast<ULInt>(0);
 	   	cin >> coin;
        coins.push_back(coin);
	}

	sort(coins.begin(), coins.end());
	reverse(coins.begin(), coins.end());

	if (debug) printContainer(coins, "coins (sorted)");

	ULInt nSolutions = 0;
	unordered_set<string> solutions;
	unordered_set<string> unsortedSolutions;
	auto fromStart = coins.cbegin();
	// for (auto coin : coins) {
		string solution;
		findChange(change, coins, solution, nSolutions, solutions, fromStart, unsortedSolutions);
	// }

	cout << nSolutions << endl;

	return 0;
}<commit_msg>on the right path, to be continued<commit_after>#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <unordered_set>
#include <string>
#include <vector>

using namespace std;

constexpr bool debug = true;

using UChar = unsigned char;
using ULInt = unsigned long int;
using UInt = unsigned int;

template <typename Container>
void printContainer(const Container& c, const string& name) {
    cout << "Printing container - " << name << " of size = " << c.size() << " : [";
    for (auto i = c.begin(); i != c.end(); ++i) {
        cout << *i << ",";
    }
	cout << "]" << endl;
}

// void printContainerInsideContainer(const vector<vector<UInt>>& c, const string& name) {
//     cout << "Printing container - " << name << " of size = " << c.size() << " : {" << endl;
//     for (auto i = c.begin(); i != c.end(); ++i) {
//         cout << "[";
//         for (auto j = (*i).cbegin(); j != (*i).cend(); ++j) {
//             cout << *j << ",";
//         }
//         cout << "]," << endl;
//     }
//     cout << endl << "}" << endl;
// }

// void findChange(ULInt change, const vector<ULInt>& coins, string& solution, ULInt& nSolutions,
//         unordered_set<string>& solutions, vector<ULInt>::const_iterator& fromStart, unordered_set<string>& unsortedSolutions) {
//     if (change != 0) {
//         for (auto it = fromStart; it != coins.cend(); ++it) {
//             auto coin = *it;
//             auto coinStr = to_string(coin);
//             if (debug) {
//                 cout << "current coin is : " << coinStr << endl;
//                 cout << "current change is : " << change << endl;
//             }
//             if (change > coin) {
//                 findChange(change - coin, coins, solution.append(coinStr), nSolutions, solutions, fromStart, unsortedSolutions);
//                 solution.pop_back();
//             } else if (change == coin) {
//                 solution.append(coinStr);
//                 auto sortedSolution = solution;
//                 sort(sortedSolution.begin(), sortedSolution.end());
//                 auto checkInsert = solutions.insert(sortedSolution);
//                 unsortedSolutions.insert(solution);
//                 if (checkInsert.second == true) {
//                     ++nSolutions;
//                     cout << "solution found! : " << solution << endl;
//                 }
//                 if (next(it) == coins.cend()) {
//                     ++fromStart;
//                 }
//                 solution.pop_back();
//                 if (debug) printContainer(solutions, "solutions so far");
//                 if (debug) printContainer(unsortedSolutions, "unsortedSolutions so far");
//             } else {
//                 if (debug) {
//                     cout << "overshooting, try with next coin " << coinStr << endl;
//                 }
//                 // ++fromStart;
//             }
//         }
//     }
// }

class Solution {
public:
    Solution(vector<UInt> s, UInt i, UInt c);
    Solution(const Solution& a);
    Solution(Solution&& a);
    Solution& operator=(const Solution& a);
    Solution& operator=(Solution&& a);

    vector<UInt>& getSequence();
    UInt getIndex();
    UInt getChange();
    void setChange(UInt c);

    friend ostream& operator<<(ostream& outstream, const Solution& a);
    friend void printCompleteSolution(const Solution& a);

private:
    vector<UInt> sequence;
    UInt index;
    UInt change;
};

Solution::Solution(vector<UInt> s, UInt i, UInt c)
    : sequence(s), index(i), change(c)
{}

Solution::Solution(const Solution& a)
    : sequence(a.sequence), index(a.index), change(a.change)
{}

Solution::Solution(Solution&& a)
    : sequence(move(a.sequence)), index(move(a.index)), change(move(a.change))
{}

Solution& Solution::operator=(const Solution& a) {
    sequence = a.sequence;
    index = a.index;
    change = a.change;

    return *this;
}

Solution& Solution::operator=(Solution&& a) {
    sequence = move(a.sequence);
    index = move(a.index);
    change = move(a.change);

    return *this;
}

vector<UInt>& Solution::getSequence() {
    return sequence;
}

UInt Solution::getIndex() {
    return index;
}

UInt Solution::getChange() {
    return change;
}

void Solution::setChange(UInt c) {
    change = c;
}

ostream& operator<<(ostream& outstream, const Solution& a) {
    if (a.sequence.size() > 0) {
        outstream << "[";
        for (auto i = 0; i < a.sequence.size()-1; ++i) {
            outstream << a.sequence[i] << ",";
        }
        outstream << a.sequence[a.sequence.size()-1] << "]" << endl;
    }

    return outstream;
}

void printCompleteSolution(const Solution& a) {
    cout << "---------------------------------" << endl;
    cout << "Solution index : " << a.index << endl;
    cout << "Solution change : " << a.change << endl;
    cout << "Solution sequence : " << endl << a;
    cout << "---------------------------------" << endl;
}

ULInt findChange(UInt change, const vector<UInt>& coins) {
    auto i = 0;
    auto prevIndex = 0;
    vector<Solution> solutions;
    vector<Solution> partialSolutions;
    Solution solution(vector<UInt>(), i, change);
    auto remainingChange = solution.getChange();
    while (i < coins.size()) {
        auto coin = coins[i];
        if (remainingChange >= coin) {
            vector<UInt>& seq = solution.getSequence();
            seq.insert(seq.end(), remainingChange / coin, coin);
            solution.setChange(remainingChange % coin);
            if (i < coins.size()-1) {
                partialSolutions.push_back(Solution(seq, i, remainingChange));
                if (debug) {
                    cout << "storing partial solution" << endl;
                    printCompleteSolution(solution);
                }
            }
        }
        if (remainingChange == 0) {
            solutions.push_back(solution);
            if (debug) {
                printContainer(solution.getSequence(), "solution found");
            }
            if (!partialSolutions.empty()) {
                auto solution = partialSolutions.back();
                partialSolutions.pop_back();
                i = solution.getIndex();
                remainingChange = solution.getChange();
            }
        }
        if (i == coins.size()-1) {
            if (debug) cout << "resetting change" << endl;
            remainingChange = change;
            i = prevIndex + 1;
            ++prevIndex;
            vector<UInt>& seq = solution.getSequence();
            seq.clear();
            if (debug) cout << "increasing prevIndex to : " << prevIndex << endl;
        } else {
            ++i;
        }
        if (debug) printContainer(solutions, "solutions so far");
        if (debug) printContainer(partialSolutions, "partial solutions");
    }

    return solutions.size();
}

int main() {
    auto change = static_cast<UInt>(0);
    cin >> change;

	auto nCoins = static_cast<UInt>(0);
	cin >> nCoins;

	vector<UInt> coins;
    for (auto i = 0; i < nCoins; ++i) {
        auto coin = static_cast<UInt>(0);
 	   	cin >> coin;
        coins.push_back(coin);
	}

	sort(coins.begin(), coins.end());
	reverse(coins.begin(), coins.end());

	if (debug) printContainer(coins, "coins (sorted)");

	cout << findChange(change, coins) << endl;

	return 0;
}<|endoftext|>


<commit_before>#ifndef STACKTRANSFORMS_HPP_
#define STACKTRANSFORMS_HPP_

#include "boost/filesystem.hpp"

#include "itkTranslationTransform.h"
#include "itkCenteredRigid2DTransform.h"
#include "itkCenteredAffineTransform.h"
#include "itkSingleValuedNonLinearOptimizer.h"
#include "itkBSplineDeformableTransform.h"
#include "itkBSplineDeformableTransformInitializer.h"
#include "itkLBFGSBOptimizer.h"

#include "Stack.hpp"
#include "Dirs.hpp"
#include "Parameters.hpp"
#include "StdOutIterationUpdate.hpp"

using namespace std;

namespace StackTransforms {
  typedef itk::MatrixOffsetTransformBase< double, 2, 2 > LinearTransformType;
  typedef itk::TranslationTransform< double, 2 > TranslationTransformType;

  itk::Vector< double, 2 > GetLoResTranslation(const string& roi) {
    itk::Vector< double, 2 > LoResTranslation;
    boost::shared_ptr< YAML::Node > roiNode = config("ROIs/" + roi + ".yml");
    for(unsigned int i=0; i<2; i++) {
      (*roiNode)["Translation"][i] >> LoResTranslation[i];
    }
    return LoResTranslation;
  }

  template <typename StackType>
  void InitializeToIdentity(StackType& stack) {
    typedef itk::TranslationTransform< double, 2 > TransformType;

    typename StackType::TransformVectorType newTransforms;

    for(unsigned int i=0; i<stack.GetSize(); i++)
		{
      typename StackType::TransformType::Pointer transform( TransformType::New() );
      transform->SetIdentity();
      newTransforms.push_back( transform );
		}

    stack.SetTransforms(newTransforms);

  }

  template <typename StackType>
  void InitializeWithTranslation(StackType& stack, const itk::Vector< double, 2 > &translation) {
    typedef itk::TranslationTransform< double, 2 > TransformType;
    typename StackType::TransformVectorType newTransforms;
    TransformType::ParametersType parameters(2);

    parameters[0] = translation[0];
    parameters[1] = translation[1];

    for(unsigned int i=0; i<stack.GetSize(); i++)
		{
      typename StackType::TransformType::Pointer transform( TransformType::New() );
      transform->SetParametersByValue( parameters );
      newTransforms.push_back( transform );
		}

    stack.SetTransforms(newTransforms);

  }

  template <typename StackType>
  void InitializeToCommonCentre(StackType& stack) {
    typedef itk::CenteredRigid2DTransform< double > TransformType;
    typename StackType::TransformVectorType newTransforms;
    TransformType::ParametersType parameters(5);

    for(unsigned int i=0; i<stack.GetSize(); i++)
		{
			const typename StackType::SliceType::SizeType &originalSize( stack.GetOriginalImage(i)->GetLargestPossibleRegion().GetSize() ),
                                       &resamplerSize( stack.GetResamplerSize() );
      const typename StackType::SliceType::SpacingType &originalSpacings( stack.GetOriginalSpacings() );
      const typename StackType::VolumeType::SpacingType &spacings( stack.GetSpacings() );

			// rotation in radians
			parameters[0] = 0;
			// translation, applied after rotation.
			parameters[3] = ( originalSpacings[0] * (double)originalSize[0] - spacings[0] * (double)resamplerSize[0] ) / 2.0;
			parameters[4] = ( originalSpacings[1] * (double)originalSize[1] - spacings[1] * (double)resamplerSize[1] ) / 2.0;

			// set them to new transform
      typename StackType::TransformType::Pointer transform( TransformType::New() );
      transform->SetParametersByValue( parameters );
      newTransforms.push_back( transform );
		}

    stack.SetTransforms(newTransforms);
  }

  // Moves centre of rotation without changing the transform
  void MoveCenter(LinearTransformType * transform, const LinearTransformType::CenterType& newCenter)
  {
    LinearTransformType::OffsetType offset = transform->GetOffset();
    transform->SetCenter(newCenter);
    transform->SetOffset(offset);
  }

  template <typename StackType>
  void SetMovingStackCenterWithFixedStack( StackType& fixedStack, StackType& movingStack )
  {
    const typename StackType::TransformVectorType& movingTransforms = movingStack.GetTransforms();

    // set the moving slices' centre of rotation to the centre of the fixed image
    for(unsigned int i=0; i<movingStack.GetSize(); ++i)
    {
      LinearTransformType::Pointer transform = dynamic_cast< LinearTransformType* >( movingTransforms[i].GetPointer() );
      if(transform)
      {
        const typename StackType::SliceType::SizeType &resamplerSize( fixedStack.GetResamplerSize() );
        const typename StackType::VolumeType::SpacingType &spacings( fixedStack.GetSpacings() );
        LinearTransformType::CenterType center;

        center[0] = spacings[0] * (double)resamplerSize[0] / 2.0;
        center[1] = spacings[1] * (double)resamplerSize[1] / 2.0;

        MoveCenter(transform, center);
      }
      else
      {
        cerr << "slice " << slice_number << " isn't a MatrixOffsetTransformBase :-(\n";
        cerr << "stack.GetTransform(slice_number): " << stack.GetTransform(slice_number) << endl;
        std::abort();
      }

    }

  }

  template <typename StackType, typename NewTransformType>
  void InitializeFromCurrentTransforms(StackType& stack)
  {
    typename StackType::TransformVectorType newTransforms;

    for(unsigned int i=0; i<stack.GetSize(); i++)
    {
      typename NewTransformType::Pointer newTransform = NewTransformType::New();
      newTransform->SetIdentity();
      // specialize from vanilla Transform to lowest common denominator in order to call GetCenter()
      LinearTransformType::Pointer oldTransform( dynamic_cast< LinearTransformType* >( stack.GetTransform(i).GetPointer() ) );
      newTransform->SetCenter( oldTransform->GetCenter() );
      newTransform->Compose( oldTransform );
      typename StackType::TransformType::Pointer baseTransform( newTransform );
      newTransforms.push_back( baseTransform );
    }

    // set stack's transforms to newTransforms
    stack.SetTransforms(newTransforms);

  }

  template <typename StackType>
  void InitializeBSplineDeformableFromBulk(StackType& LoResStack, StackType& HiResStack)
  {
    // Perform non-rigid registration
    typedef double CoordinateRepType;
    const unsigned int SpaceDimension = 2;
    const unsigned int SplineOrder = 3;
    typedef itk::BSplineDeformableTransform< CoordinateRepType, SpaceDimension, SplineOrder > TransformType;
    typedef itk::BSplineDeformableTransformInitializer< TransformType, typename StackType::SliceType > InitializerType;
    typename StackType::TransformVectorType newTransforms;

    for(unsigned int slice_number=0; slice_number<HiResStack.GetSize(); slice_number++)
    {
      // instantiate transform
      TransformType::Pointer transform( TransformType::New() );

      // initialise transform
      typename InitializerType::Pointer initializer = InitializerType::New();
      initializer->SetTransform( transform );
      initializer->SetImage( LoResStack.GetResampledSlice(slice_number) );
      unsigned int gridSize;
      boost::shared_ptr<YAML::Node> deformableParameters = config("deformable_parameters.yml");
      (*deformableParameters)["bsplineTransform"]["gridSize"] >> gridSize;
      TransformType::RegionType::SizeType gridSizeInsideTheImage;
      gridSizeInsideTheImage.Fill(gridSize);
      initializer->SetGridSizeInsideTheImage( gridSizeInsideTheImage );

      initializer->InitializeTransform();

      transform->SetBulkTransform( HiResStack.GetTransform(slice_number) );

      // set initial parameters to zero
      TransformType::ParametersType initialDeformableTransformParameters( transform->GetNumberOfParameters() );
      initialDeformableTransformParameters.Fill( 0.0 );
      transform->SetParametersByValue( initialDeformableTransformParameters );

      // add transform to vector
      typename StackType::TransformType::Pointer baseTransform( transform );
      newTransforms.push_back( baseTransform );
    }
    HiResStack.SetTransforms(newTransforms);
  }

  // Translate a single slice
  template <typename StackType>
  void Translate(StackType& stack, const itk::Vector< double, 2 > translation, unsigned int slice_number)
  {
    // attempt to cast stack transform and apply translation
    LinearTransformType::Pointer linearTransform
      = dynamic_cast< LinearTransformType* >( stack.GetTransform(slice_number).GetPointer() );
    TranslationTransformType::Pointer translationTransform
      = dynamic_cast< TranslationTransformType* >( stack.GetTransform(slice_number).GetPointer() );
    if(linearTransform)
    {
      // construct transform to represent translation
      LinearTransformType::Pointer translationTransform = LinearTransformType::New();
      translationTransform->SetIdentity();
      translationTransform->SetTranslation(translation);
      // if second argument is true, translationTransform is applied first,
      // then linearTransform
      linearTransform->Compose(translationTransform, true);
    }
    else if(translationTransform)
    {
      translationTransform->Translate(translation);
    }
    else
    {
      cerr << "slice " << slice_number << " isn't a MatrixOffsetTransformBase or a TranslationTransform :-(\n";
      cerr << "stack.GetTransform(slice_number): " << stack.GetTransform(slice_number) << endl;
      std::abort();
    }
  }

  // Translate the entire stack
  template <typename StackType>
  void Translate(StackType& stack, const itk::Vector< double, 2 > translation)
  {
    // attempt to cast stack transforms and apply translation
    for(unsigned int slice_number=0; slice_number<stack.GetSize(); ++slice_number)
    {
      Translate(stack, translation, slice_number);
    }
  }

}

#endif
<commit_msg>Oops, fixed type and error message bugs.<commit_after>#ifndef STACKTRANSFORMS_HPP_
#define STACKTRANSFORMS_HPP_

#include "boost/filesystem.hpp"

#include "itkTranslationTransform.h"
#include "itkCenteredRigid2DTransform.h"
#include "itkCenteredAffineTransform.h"
#include "itkSingleValuedNonLinearOptimizer.h"
#include "itkBSplineDeformableTransform.h"
#include "itkBSplineDeformableTransformInitializer.h"
#include "itkLBFGSBOptimizer.h"

#include "Stack.hpp"
#include "Dirs.hpp"
#include "Parameters.hpp"
#include "StdOutIterationUpdate.hpp"

using namespace std;

namespace StackTransforms {
  typedef itk::MatrixOffsetTransformBase< double, 2, 2 > LinearTransformType;
  typedef itk::TranslationTransform< double, 2 > TranslationTransformType;

  itk::Vector< double, 2 > GetLoResTranslation(const string& roi) {
    itk::Vector< double, 2 > LoResTranslation;
    boost::shared_ptr< YAML::Node > roiNode = config("ROIs/" + roi + ".yml");
    for(unsigned int i=0; i<2; i++) {
      (*roiNode)["Translation"][i] >> LoResTranslation[i];
    }
    return LoResTranslation;
  }

  template <typename StackType>
  void InitializeToIdentity(StackType& stack) {
    typedef itk::TranslationTransform< double, 2 > TransformType;

    typename StackType::TransformVectorType newTransforms;

    for(unsigned int i=0; i<stack.GetSize(); i++)
		{
      TransformType::Pointer transform = TransformType::New();
      transform->SetIdentity();
      typename StackType::TransformType::Pointer baseTransform( transform );
      newTransforms.push_back( baseTransform );
		}

    stack.SetTransforms(newTransforms);

  }

  template <typename StackType>
  void InitializeWithTranslation(StackType& stack, const itk::Vector< double, 2 > &translation) {
    typedef itk::TranslationTransform< double, 2 > TransformType;
    typename StackType::TransformVectorType newTransforms;
    TransformType::ParametersType parameters(2);

    parameters[0] = translation[0];
    parameters[1] = translation[1];

    for(unsigned int i=0; i<stack.GetSize(); i++)
		{
      typename StackType::TransformType::Pointer transform( TransformType::New() );
      transform->SetParametersByValue( parameters );
      newTransforms.push_back( transform );
		}

    stack.SetTransforms(newTransforms);

  }

  template <typename StackType>
  void InitializeToCommonCentre(StackType& stack) {
    typedef itk::CenteredRigid2DTransform< double > TransformType;
    typename StackType::TransformVectorType newTransforms;
    TransformType::ParametersType parameters(5);

    for(unsigned int i=0; i<stack.GetSize(); i++)
		{
			const typename StackType::SliceType::SizeType &originalSize( stack.GetOriginalImage(i)->GetLargestPossibleRegion().GetSize() ),
                                       &resamplerSize( stack.GetResamplerSize() );
      const typename StackType::SliceType::SpacingType &originalSpacings( stack.GetOriginalSpacings() );
      const typename StackType::VolumeType::SpacingType &spacings( stack.GetSpacings() );

			// rotation in radians
			parameters[0] = 0;
			// translation, applied after rotation.
			parameters[3] = ( originalSpacings[0] * (double)originalSize[0] - spacings[0] * (double)resamplerSize[0] ) / 2.0;
			parameters[4] = ( originalSpacings[1] * (double)originalSize[1] - spacings[1] * (double)resamplerSize[1] ) / 2.0;

			// set them to new transform
      typename StackType::TransformType::Pointer transform( TransformType::New() );
      transform->SetParametersByValue( parameters );
      newTransforms.push_back( transform );
		}

    stack.SetTransforms(newTransforms);
  }

  // Moves centre of rotation without changing the transform
  void MoveCenter(LinearTransformType * transform, const LinearTransformType::CenterType& newCenter)
  {
    LinearTransformType::OffsetType offset = transform->GetOffset();
    transform->SetCenter(newCenter);
    transform->SetOffset(offset);
  }

  template <typename StackType>
  void SetMovingStackCenterWithFixedStack( StackType& fixedStack, StackType& movingStack )
  {
    const typename StackType::TransformVectorType& movingTransforms = movingStack.GetTransforms();

    // set the moving slices' centre of rotation to the centre of the fixed image
    for(unsigned int slice_number=0; slice_number<movingStack.GetSize(); ++slice_number)
    {
      LinearTransformType::Pointer transform = dynamic_cast< LinearTransformType* >( movingTransforms[slice_number].GetPointer() );
      if(transform)
      {
        const typename StackType::SliceType::SizeType &resamplerSize( fixedStack.GetResamplerSize() );
        const typename StackType::VolumeType::SpacingType &spacings( fixedStack.GetSpacings() );
        LinearTransformType::CenterType center;

        center[0] = spacings[0] * (double)resamplerSize[0] / 2.0;
        center[1] = spacings[1] * (double)resamplerSize[1] / 2.0;

        MoveCenter(transform, center);
      }
      else
      {
        cerr << "transform " << slice_number << " isn't a MatrixOffsetTransformBase :-(\n";
        cerr << "transform: " << transform << endl;
        std::abort();
      }

    }

  }

  template <typename StackType, typename NewTransformType>
  void InitializeFromCurrentTransforms(StackType& stack)
  {
    typename StackType::TransformVectorType newTransforms;

    for(unsigned int i=0; i<stack.GetSize(); i++)
    {
      typename NewTransformType::Pointer newTransform = NewTransformType::New();
      newTransform->SetIdentity();
      // specialize from vanilla Transform to lowest common denominator in order to call GetCenter()
      LinearTransformType::Pointer oldTransform( dynamic_cast< LinearTransformType* >( stack.GetTransform(i).GetPointer() ) );
      newTransform->SetCenter( oldTransform->GetCenter() );
      newTransform->Compose( oldTransform );
      typename StackType::TransformType::Pointer baseTransform( newTransform );
      newTransforms.push_back( baseTransform );
    }

    // set stack's transforms to newTransforms
    stack.SetTransforms(newTransforms);

  }

  template <typename StackType>
  void InitializeBSplineDeformableFromBulk(StackType& LoResStack, StackType& HiResStack)
  {
    // Perform non-rigid registration
    typedef double CoordinateRepType;
    const unsigned int SpaceDimension = 2;
    const unsigned int SplineOrder = 3;
    typedef itk::BSplineDeformableTransform< CoordinateRepType, SpaceDimension, SplineOrder > TransformType;
    typedef itk::BSplineDeformableTransformInitializer< TransformType, typename StackType::SliceType > InitializerType;
    typename StackType::TransformVectorType newTransforms;

    for(unsigned int slice_number=0; slice_number<HiResStack.GetSize(); slice_number++)
    {
      // instantiate transform
      TransformType::Pointer transform( TransformType::New() );

      // initialise transform
      typename InitializerType::Pointer initializer = InitializerType::New();
      initializer->SetTransform( transform );
      initializer->SetImage( LoResStack.GetResampledSlice(slice_number) );
      unsigned int gridSize;
      boost::shared_ptr<YAML::Node> deformableParameters = config("deformable_parameters.yml");
      (*deformableParameters)["bsplineTransform"]["gridSize"] >> gridSize;
      TransformType::RegionType::SizeType gridSizeInsideTheImage;
      gridSizeInsideTheImage.Fill(gridSize);
      initializer->SetGridSizeInsideTheImage( gridSizeInsideTheImage );

      initializer->InitializeTransform();

      transform->SetBulkTransform( HiResStack.GetTransform(slice_number) );

      // set initial parameters to zero
      TransformType::ParametersType initialDeformableTransformParameters( transform->GetNumberOfParameters() );
      initialDeformableTransformParameters.Fill( 0.0 );
      transform->SetParametersByValue( initialDeformableTransformParameters );

      // add transform to vector
      typename StackType::TransformType::Pointer baseTransform( transform );
      newTransforms.push_back( baseTransform );
    }
    HiResStack.SetTransforms(newTransforms);
  }

  // Translate a single slice
  template <typename StackType>
  void Translate(StackType& stack, const itk::Vector< double, 2 > translation, unsigned int slice_number)
  {
    // attempt to cast stack transform and apply translation
    LinearTransformType::Pointer linearTransform
      = dynamic_cast< LinearTransformType* >( stack.GetTransform(slice_number).GetPointer() );
    TranslationTransformType::Pointer translationTransform
      = dynamic_cast< TranslationTransformType* >( stack.GetTransform(slice_number).GetPointer() );
    if(linearTransform)
    {
      // construct transform to represent translation
      LinearTransformType::Pointer translationTransform = LinearTransformType::New();
      translationTransform->SetIdentity();
      translationTransform->SetTranslation(translation);
      // if second argument is true, translationTransform is applied first,
      // then linearTransform
      linearTransform->Compose(translationTransform, true);
    }
    else if(translationTransform)
    {
      translationTransform->Translate(translation);
    }
    else
    {
      cerr << "slice " << slice_number << " isn't a MatrixOffsetTransformBase or a TranslationTransform :-(\n";
      cerr << "stack.GetTransform(slice_number): " << stack.GetTransform(slice_number) << endl;
      std::abort();
    }
  }

  // Translate the entire stack
  template <typename StackType>
  void Translate(StackType& stack, const itk::Vector< double, 2 > translation)
  {
    // attempt to cast stack transforms and apply translation
    for(unsigned int slice_number=0; slice_number<stack.GetSize(); ++slice_number)
    {
      Translate(stack, translation, slice_number);
    }
  }

}

#endif
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   CEGUIOpenGLGeometryBuffer.cpp
    created:    Wed, 8th Feb 2012
    author:     Lukas E Meindl (based on code by Paul D Turner)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include <GL/glew.h>

#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "CEGUI/RendererModules/OpenGL/GL3GeometryBuffer.h"
#include "CEGUI/RendererModules/OpenGL/GL3Renderer.h"
#include "CEGUI/RenderEffect.h"
#include "CEGUI/RendererModules/OpenGL/Texture.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/ShaderParameterBindings.h"
#include "CEGUI/RendererModules/OpenGL/ShaderManager.h"
#include "CEGUI/RendererModules/OpenGL/Shader.h"
#include "CEGUI/RendererModules/OpenGL/StateChangeWrapper.h"
#include "CEGUI/RendererModules/OpenGL/GlmPimpl.h"
#include "CEGUI/RendererModules/OpenGL/GL3ShaderWrapper.h"

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
OpenGL3GeometryBuffer::OpenGL3GeometryBuffer(OpenGL3Renderer& owner, CEGUI::RefCounted<RenderMaterial> renderMaterial) :
    OpenGLGeometryBufferBase(owner, renderMaterial),
    d_glStateChanger(owner.getOpenGLStateChanger()),
    d_bufferSize(0)
{
    initialiseOpenGLBuffers();
}

//----------------------------------------------------------------------------//
OpenGL3GeometryBuffer::~OpenGL3GeometryBuffer()
{
    deinitialiseOpenGLBuffers();
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::draw() const
{
    CEGUI::Rectf viewPort = d_owner->getActiveViewPort();

    d_glStateChanger->scissor(static_cast<GLint>(d_clipRect.left()),
              static_cast<GLint>(viewPort.getHeight() - d_clipRect.bottom()),
              static_cast<GLint>(d_clipRect.getWidth()),
              static_cast<GLint>(d_clipRect.getHeight()));

    // apply the transformations we need to use.
    if (!d_matrixValid)
        updateMatrix();

    CEGUI::ShaderParameterBindings* shaderParameterBindings = (*d_renderMaterial).getShaderParamBindings();
    // Set the ModelViewProjection matrix in the bindings
    glm::mat4 modelViewProjectionMatrix = d_owner->getViewProjectionMatrix()->d_matrix * d_matrix->d_matrix;
    shaderParameterBindings->setParameter("modelViewPerspMatrix", modelViewProjectionMatrix);

    // activate desired blending mode
    d_owner->setupRenderingBlendMode(d_blendMode);

    // Bind our vao
    d_glStateChanger->bindVertexArray(d_verticesVAO);

    const int pass_count = d_effect ? d_effect->getPassCount() : 1;
     size_t pos = 0;
    for (int pass = 0; pass < pass_count; ++pass)
    {
        // set up RenderEffect
        if (d_effect)
            d_effect->performPreRenderFunctions(pass);

        // draw the batches

        BatchList::const_iterator i = d_batches.begin();
        for ( ; i != d_batches.end(); ++i)
        {
            const BatchInfo& currentBatch = *i;

            if (currentBatch.clip)
                glEnable(GL_SCISSOR_TEST);
            else
                glDisable(GL_SCISSOR_TEST);

            if(currentBatch.texture != 0)
                shaderParameterBindings->setParameter("texture0", currentBatch.texture);

            d_renderMaterial->prepareForRendering();

            // draw the geometry
            const unsigned int numVertices = currentBatch.vertexCount;
            glDrawArrays(GL_TRIANGLES, pos, numVertices);

            pos += numVertices;
        }
    }

    // clean up RenderEffect
    if (d_effect)
        d_effect->performPostRenderFunctions();
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::reset()
{
    OpenGLGeometryBufferBase::reset();
    updateOpenGLBuffers();
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::initialiseOpenGLBuffers()
{
    glGenVertexArrays(1, &d_verticesVAO);
    d_glStateChanger->bindVertexArray(d_verticesVAO);

    // Generate and bind position vbo
    glGenBuffers(1, &d_verticesVBO);
    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, d_verticesVBO);

    glBufferData(GL_ARRAY_BUFFER, 0, 0, GL_DYNAMIC_DRAW);

    // Unbind Vertex Attribute Array (VAO)
    d_glStateChanger->bindVertexArray(0);

    // Unbind array and element array buffers
    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, 0);
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::finaliseVertexAttributes()
{
    d_glStateChanger->bindVertexArray(d_verticesVAO);
    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, d_verticesVBO);

    GLsizei stride = getVertexAttributeElementCount() * sizeof(GL_FLOAT);

    CEGUI::OpenGL3ShaderWrapper* gl3_shader_wrapper = static_cast<CEGUI::OpenGL3ShaderWrapper*>(d_renderMaterial->getShaderWrapper());

    //Update the vertex attrib pointers of the vertex array object depending on the saved attributes
    int dataOffset = 0;
    const unsigned int attribute_count = d_vertexAttributes.size();
    for (unsigned int i = 0; i < attribute_count; ++i)
    {
        switch(d_vertexAttributes.at(i))
        {
        case VAT_POSITION0:
            {
                GLint shader_pos_loc = gl3_shader_wrapper->getAttributeLocation("inPosition");
                glVertexAttribPointer(shader_pos_loc, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(dataOffset * sizeof(GL_FLOAT)));
                glEnableVertexAttribArray(shader_pos_loc);
                dataOffset += 3;
            }
            break;
        case VAT_COLOUR0:
            {
                GLint shader_colour_loc = gl3_shader_wrapper->getAttributeLocation("inColour");
                glVertexAttribPointer(shader_colour_loc, 4, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(dataOffset * sizeof(GL_FLOAT)));
                glEnableVertexAttribArray(shader_colour_loc);
                dataOffset += 4;
            }
            break;
        case VAT_TEXCOORD0:
            {
                GLint texture_coord_loc = gl3_shader_wrapper->getAttributeLocation("inTexCoord");
                glVertexAttribPointer(texture_coord_loc, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(dataOffset * sizeof(GL_FLOAT)));
                glEnableVertexAttribArray(texture_coord_loc);
                dataOffset += 2;
            }
            break;
        default:
            break;
        }
    }
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::deinitialiseOpenGLBuffers()
{
    glDeleteVertexArrays(1, &d_verticesVAO);
    glDeleteBuffers(1, &d_verticesVBO);
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::updateOpenGLBuffers()
{
    bool needNewBuffer = false;
    unsigned int vertexCount = d_vertexData.size();

    if(d_bufferSize < vertexCount)
    {
        needNewBuffer = true;
        d_bufferSize = vertexCount;
    }

    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, d_verticesVBO);

    float* vertexData;
    if(d_vertexData.empty())
        vertexData = 0;
    else
        vertexData = &d_vertexData[0];

    GLsizei dataSize = d_bufferSize * sizeof(float);

    if(needNewBuffer)
    {
        glBufferData(GL_ARRAY_BUFFER, dataSize, vertexData, GL_DYNAMIC_DRAW);
    }
    else
    {
        glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, vertexData);
    }
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::appendGeometry(const std::vector<float>& vertex_data)
{
    OpenGLGeometryBufferBase::appendGeometry(vertex_data);
    updateOpenGLBuffers();
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section

<commit_msg>MOD: Should be static draw because we assume we don't change it every frame<commit_after>/***********************************************************************
    filename:   CEGUIOpenGLGeometryBuffer.cpp
    created:    Wed, 8th Feb 2012
    author:     Lukas E Meindl (based on code by Paul D Turner)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include <GL/glew.h>

#include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "CEGUI/RendererModules/OpenGL/GL3GeometryBuffer.h"
#include "CEGUI/RendererModules/OpenGL/GL3Renderer.h"
#include "CEGUI/RenderEffect.h"
#include "CEGUI/RendererModules/OpenGL/Texture.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/ShaderParameterBindings.h"
#include "CEGUI/RendererModules/OpenGL/ShaderManager.h"
#include "CEGUI/RendererModules/OpenGL/Shader.h"
#include "CEGUI/RendererModules/OpenGL/StateChangeWrapper.h"
#include "CEGUI/RendererModules/OpenGL/GlmPimpl.h"
#include "CEGUI/RendererModules/OpenGL/GL3ShaderWrapper.h"

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
OpenGL3GeometryBuffer::OpenGL3GeometryBuffer(OpenGL3Renderer& owner, CEGUI::RefCounted<RenderMaterial> renderMaterial) :
    OpenGLGeometryBufferBase(owner, renderMaterial),
    d_glStateChanger(owner.getOpenGLStateChanger()),
    d_bufferSize(0)
{
    initialiseOpenGLBuffers();
}

//----------------------------------------------------------------------------//
OpenGL3GeometryBuffer::~OpenGL3GeometryBuffer()
{
    deinitialiseOpenGLBuffers();
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::draw() const
{
    CEGUI::Rectf viewPort = d_owner->getActiveViewPort();

    d_glStateChanger->scissor(static_cast<GLint>(d_clipRect.left()),
              static_cast<GLint>(viewPort.getHeight() - d_clipRect.bottom()),
              static_cast<GLint>(d_clipRect.getWidth()),
              static_cast<GLint>(d_clipRect.getHeight()));

    // apply the transformations we need to use.
    if (!d_matrixValid)
        updateMatrix();

    CEGUI::ShaderParameterBindings* shaderParameterBindings = (*d_renderMaterial).getShaderParamBindings();
    // Set the ModelViewProjection matrix in the bindings
    glm::mat4 modelViewProjectionMatrix = d_owner->getViewProjectionMatrix()->d_matrix * d_matrix->d_matrix;
    shaderParameterBindings->setParameter("modelViewPerspMatrix", modelViewProjectionMatrix);

    // activate desired blending mode
    d_owner->setupRenderingBlendMode(d_blendMode);

    // Bind our vao
    d_glStateChanger->bindVertexArray(d_verticesVAO);

    const int pass_count = d_effect ? d_effect->getPassCount() : 1;
     size_t pos = 0;
    for (int pass = 0; pass < pass_count; ++pass)
    {
        // set up RenderEffect
        if (d_effect)
            d_effect->performPreRenderFunctions(pass);

        // draw the batches

        BatchList::const_iterator i = d_batches.begin();
        for ( ; i != d_batches.end(); ++i)
        {
            const BatchInfo& currentBatch = *i;

            if (currentBatch.clip)
                glEnable(GL_SCISSOR_TEST);
            else
                glDisable(GL_SCISSOR_TEST);

            if(currentBatch.texture != 0)
                shaderParameterBindings->setParameter("texture0", currentBatch.texture);

            d_renderMaterial->prepareForRendering();

            // draw the geometry
            const unsigned int numVertices = currentBatch.vertexCount;
            glDrawArrays(GL_TRIANGLES, pos, numVertices);

            pos += numVertices;
        }
    }

    // clean up RenderEffect
    if (d_effect)
        d_effect->performPostRenderFunctions();
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::reset()
{
    OpenGLGeometryBufferBase::reset();
    updateOpenGLBuffers();
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::initialiseOpenGLBuffers()
{
    glGenVertexArrays(1, &d_verticesVAO);
    d_glStateChanger->bindVertexArray(d_verticesVAO);

    // Generate and bind position vbo
    glGenBuffers(1, &d_verticesVBO);
    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, d_verticesVBO);

    glBufferData(GL_ARRAY_BUFFER, 0, 0, GL_STATIC_DRAW);

    // Unbind Vertex Attribute Array (VAO)
    d_glStateChanger->bindVertexArray(0);

    // Unbind array and element array buffers
    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, 0);
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::finaliseVertexAttributes()
{
    d_glStateChanger->bindVertexArray(d_verticesVAO);
    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, d_verticesVBO);

    GLsizei stride = getVertexAttributeElementCount() * sizeof(GL_FLOAT);

    CEGUI::OpenGL3ShaderWrapper* gl3_shader_wrapper = static_cast<CEGUI::OpenGL3ShaderWrapper*>(d_renderMaterial->getShaderWrapper());

    //Update the vertex attrib pointers of the vertex array object depending on the saved attributes
    int dataOffset = 0;
    const unsigned int attribute_count = d_vertexAttributes.size();
    for (unsigned int i = 0; i < attribute_count; ++i)
    {
        switch(d_vertexAttributes.at(i))
        {
        case VAT_POSITION0:
            {
                GLint shader_pos_loc = gl3_shader_wrapper->getAttributeLocation("inPosition");
                glVertexAttribPointer(shader_pos_loc, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(dataOffset * sizeof(GL_FLOAT)));
                glEnableVertexAttribArray(shader_pos_loc);
                dataOffset += 3;
            }
            break;
        case VAT_COLOUR0:
            {
                GLint shader_colour_loc = gl3_shader_wrapper->getAttributeLocation("inColour");
                glVertexAttribPointer(shader_colour_loc, 4, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(dataOffset * sizeof(GL_FLOAT)));
                glEnableVertexAttribArray(shader_colour_loc);
                dataOffset += 4;
            }
            break;
        case VAT_TEXCOORD0:
            {
                GLint texture_coord_loc = gl3_shader_wrapper->getAttributeLocation("inTexCoord");
                glVertexAttribPointer(texture_coord_loc, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(dataOffset * sizeof(GL_FLOAT)));
                glEnableVertexAttribArray(texture_coord_loc);
                dataOffset += 2;
            }
            break;
        default:
            break;
        }
    }
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::deinitialiseOpenGLBuffers()
{
    glDeleteVertexArrays(1, &d_verticesVAO);
    glDeleteBuffers(1, &d_verticesVBO);
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::updateOpenGLBuffers()
{
    bool needNewBuffer = false;
    unsigned int vertexCount = d_vertexData.size();

    if(d_bufferSize < vertexCount)
    {
        needNewBuffer = true;
        d_bufferSize = vertexCount;
    }

    d_glStateChanger->bindBuffer(GL_ARRAY_BUFFER, d_verticesVBO);

    float* vertexData;
    if(d_vertexData.empty())
        vertexData = 0;
    else
        vertexData = &d_vertexData[0];

    GLsizei dataSize = d_bufferSize * sizeof(float);

    if(needNewBuffer)
    {
        glBufferData(GL_ARRAY_BUFFER, dataSize, vertexData, GL_STATIC_DRAW);
    }
    else
    {
        glBufferSubData(GL_ARRAY_BUFFER, 0, dataSize, vertexData);
    }
}

//----------------------------------------------------------------------------//
void OpenGL3GeometryBuffer::appendGeometry(const std::vector<float>& vertex_data)
{
    OpenGLGeometryBufferBase::appendGeometry(vertex_data);
    updateOpenGLBuffers();
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section

<|endoftext|>