<commit_before>// Copyright (c) 2010 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.

// This file implements the ViewGLContext and PbufferGLContext classes.

#include <dlfcn.h>
#include <GL/glew.h>
#include <GL/glxew.h>
#include <GL/glx.h>
#include <GL/osmew.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "app/x11_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "app/gfx/gl/gl_context.h"
#include "app/gfx/gl/gl_context_osmesa.h"

namespace gfx {

typedef GLXContext GLContextHandle;
typedef GLXPbuffer PbufferHandle;

// This class is a wrapper around a GL context that renders directly to a
// window.
class ViewGLContext : public GLContext {
 public:
  explicit ViewGLContext(gfx::PluginWindowHandle window)
      : window_(window),
        context_(NULL) {
    DCHECK(window);
  }

  // Initializes the GL context.
  bool Initialize(bool multisampled);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  gfx::PluginWindowHandle window_;
  GLContextHandle context_;

  DISALLOW_COPY_AND_ASSIGN(ViewGLContext);
};

// This class is a wrapper around a GL context used for offscreen rendering.
// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
// rendering.
class PbufferGLContext : public GLContext {
 public:
  explicit PbufferGLContext()
      : context_(NULL),
        pbuffer_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  PbufferHandle pbuffer_;

  DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
};

// Backup context if Pbuffers (GLX 1.3) aren't supported. May run slower...
class PixmapGLContext : public GLContext {
 public:
  explicit PixmapGLContext()
      : context_(NULL),
        pixmap_(0),
        glx_pixmap_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  Pixmap pixmap_;
  GLXPixmap glx_pixmap_;

  DISALLOW_COPY_AND_ASSIGN(PixmapGLContext);
};

// scoped_ptr functor for XFree(). Use as follows:
//   scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
// where "XVisualInfo" is any X type that is freed with XFree.
class ScopedPtrXFree {
 public:
  void operator()(void* x) const {
    ::XFree(x);
  }
};

// Some versions of NVIDIA's GL libGL.so include a broken version of
// dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically
// load it, and use glew to dynamically resolve symbols.
// See http://code.google.com/p/chromium/issues/detail?id=16800

static bool InitializeOneOff() {
  static bool initialized = false;
  if (initialized)
    return true;

  osmewInit();
  if (!OSMesaCreateContext) {
    void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
    if (!handle) {
      LOG(ERROR) << "Could not find libGL.so.1";
      return false;
    }

    // Initializes context-independent parts of GLEW
    if (glxewInit() != GLEW_OK) {
      LOG(ERROR) << "glxewInit failed";
      return false;
    }
    // glxewContextInit really only needs a display connection to
    // complete, and we don't want to have to create an OpenGL context
    // just to get access to GLX 1.3 entry points to create pbuffers.
    // We therefore added a glxewContextInitWithDisplay entry point.
    Display* display = x11_util::GetXDisplay();
    if (glxewContextInitWithDisplay(display) != GLEW_OK) {
      LOG(ERROR) << "glxewContextInit failed";
      return false;
    }
  }

  initialized = true;
  return true;
}

bool ViewGLContext::Initialize(bool multisampled) {
  if (multisampled) {
    LOG(WARNING) << "Multisampling not implemented.";
  }

  Display* display = x11_util::GetXDisplay();
  XWindowAttributes attributes;
  XGetWindowAttributes(display, window_, &attributes);
  XVisualInfo visual_info_template;
  visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
  int visual_info_count = 0;
  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
      XGetVisualInfo(display, VisualIDMask,
                     &visual_info_template,
                     &visual_info_count));
  DCHECK(visual_info_list.get());
  DCHECK_GT(visual_info_count, 0);
  context_ = NULL;
  for (int i = 0; i < visual_info_count; ++i) {
    context_ = glXCreateContext(display, visual_info_list.get() + i, 0, True);
    if (context_)
      break;
  }
  if (!context_) {
    LOG(ERROR) << "Couldn't create GL context.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void ViewGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);

  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }
}

bool ViewGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }

  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, window_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = 0;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool ViewGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == window_ &&
      glXGetCurrentContext() == context_;
}

bool ViewGLContext::IsOffscreen() {
  return false;
}

void ViewGLContext::SwapBuffers() {
  Display* display = x11_util::GetXDisplay();
  glXSwapBuffers(display, window_);
}

gfx::Size ViewGLContext::GetSize() {
  XWindowAttributes attributes;
  Display* display = x11_util::GetXDisplay();
  XGetWindowAttributes(display, window_, &attributes);
  return gfx::Size(attributes.width, attributes.height);
}

void* ViewGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window,
                                          bool multisampled) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    // TODO(apatrick): Support OSMesa rendering to a window on Linux.
    NOTREACHED() << "OSMesa rendering to a window is not yet implemented.";
    return NULL;
  } else {
    scoped_ptr<ViewGLContext> context(new ViewGLContext(window));

    if (!context->Initialize(multisampled))
      return NULL;

    return context.release();
  }
}

bool PbufferGLContext::Initialize(void* shared_handle) {
  if (!glXChooseFBConfig ||
      !glXCreateNewContext ||
      !glXCreatePbuffer ||
      !glXDestroyPbuffer) {
    LOG(ERROR) << "Pbuffer support not available.";
    return false;
  }

  static const int config_attributes[] = {
    GLX_DRAWABLE_TYPE,
    GLX_PBUFFER_BIT,
    GLX_RENDER_TYPE,
    GLX_RGBA_BIT,
    GLX_DOUBLEBUFFER,
    0,
    0
  };

  Display* display = x11_util::GetXDisplay();

  int nelements = 0;
  // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient.
  scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
      glXChooseFBConfig(display, 0, config_attributes, &nelements));
  if (!config.get()) {
    LOG(ERROR) << "glXChooseFBConfig failed.";
    return false;
  }
  if (!nelements) {
    LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
    return false;
  }
  context_ = glXCreateNewContext(display,
                                 config.get()[0],
                                 GLX_RGBA_TYPE,
                                 static_cast<GLContextHandle>(shared_handle),
                                 True);
  if (!context_) {
    LOG(ERROR) << "glXCreateNewContext failed.";
    return false;
  }
  static const int pbuffer_attributes[] = {
    GLX_PBUFFER_WIDTH,
    1,
    GLX_PBUFFER_HEIGHT,
    1,
    0
  };
  pbuffer_ = glXCreatePbuffer(display,
                              config.get()[0], pbuffer_attributes);
  if (!pbuffer_) {
    Destroy();
    LOG(ERROR) << "glXCreatePbuffer failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PbufferGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (pbuffer_) {
    glXDestroyPbuffer(display, pbuffer_);
    pbuffer_ = 0;
  }
}

bool PbufferGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, pbuffer_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PbufferGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == pbuffer_ &&
      glXGetCurrentContext() == context_;
}

bool PbufferGLContext::IsOffscreen() {
  return true;
}

void PbufferGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
}

gfx::Size PbufferGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pbuffer.";
  return gfx::Size(1, 1);
}

void* PbufferGLContext::GetHandle() {
  return context_;
}

bool PixmapGLContext::Initialize(void* shared_handle) {
  LOG(INFO) << "GL context: using pixmaps.";
  if (!glXChooseVisual ||
      !glXCreateGLXPixmap ||
      !glXDestroyGLXPixmap) {
    LOG(ERROR) << "Pixmap support not available.";
    return false;
  }

  static int attributes[] = {
    GLX_RGBA,
    0
  };

  Display* display = x11_util::GetXDisplay();
  int screen = DefaultScreen(display);

  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info(
      glXChooseVisual(display, screen, attributes));

  if (!visual_info.get()) {
    LOG(ERROR) << "glXChooseVisual failed.";
    return false;
  }
  context_ = glXCreateContext(display, visual_info.get(),
                              static_cast<GLContextHandle>(shared_handle),
                              True);
  if (!context_) {
    LOG(ERROR) << "glXCreateContext failed.";
    return false;
  }

  pixmap_ = XCreatePixmap(display, RootWindow(display, screen), 1, 1,
                          visual_info->depth);
  if (!pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  glx_pixmap_ = glXCreateGLXPixmap(display, visual_info.get(), pixmap_);
  if (!glx_pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PixmapGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (glx_pixmap_) {
    glXDestroyGLXPixmap(display, glx_pixmap_);
    glx_pixmap_ = 0;
  }

  if (pixmap_) {
    XFreePixmap(display, pixmap_);
    pixmap_ = 0;
  }
}

bool PixmapGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, glx_pixmap_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PixmapGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == glx_pixmap_ &&
      glXGetCurrentContext() == context_;
}

bool PixmapGLContext::IsOffscreen() {
  return true;
}

void PixmapGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pixmap.";
}

gfx::Size PixmapGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pixmap.";
  return gfx::Size(1, 1);
}

void* PixmapGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateOffscreenGLContext(void* shared_handle) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    scoped_ptr<OSMesaGLContext> context(new OSMesaGLContext);

    if (!context->Initialize(shared_handle))
      return NULL;

    return context.release();
  } else {
    scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
    if (context->Initialize(shared_handle))
      return context.release();

    scoped_ptr<PixmapGLContext> context_pixmap(new PixmapGLContext);
    if (context_pixmap->Initialize(shared_handle))
      return context_pixmap.release();

    return NULL;
  }
}

}  // namespace gfx
<commit_msg>Added warning if GLX version is less than 1.3. Pbuffers need GLX 1.3 and the pixmap fallback for 1.2 does not work on all systems. TEST=try BUG=none<commit_after>// Copyright (c) 2010 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.

// This file implements the ViewGLContext and PbufferGLContext classes.

#include <dlfcn.h>
#include <GL/glew.h>
#include <GL/glxew.h>
#include <GL/glx.h>
#include <GL/osmew.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "app/x11_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "app/gfx/gl/gl_context.h"
#include "app/gfx/gl/gl_context_osmesa.h"

namespace gfx {

typedef GLXContext GLContextHandle;
typedef GLXPbuffer PbufferHandle;

// This class is a wrapper around a GL context that renders directly to a
// window.
class ViewGLContext : public GLContext {
 public:
  explicit ViewGLContext(gfx::PluginWindowHandle window)
      : window_(window),
        context_(NULL) {
    DCHECK(window);
  }

  // Initializes the GL context.
  bool Initialize(bool multisampled);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  gfx::PluginWindowHandle window_;
  GLContextHandle context_;

  DISALLOW_COPY_AND_ASSIGN(ViewGLContext);
};

// This class is a wrapper around a GL context used for offscreen rendering.
// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
// rendering.
class PbufferGLContext : public GLContext {
 public:
  explicit PbufferGLContext()
      : context_(NULL),
        pbuffer_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  PbufferHandle pbuffer_;

  DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
};

// Backup context if Pbuffers (GLX 1.3) aren't supported. May run slower...
class PixmapGLContext : public GLContext {
 public:
  explicit PixmapGLContext()
      : context_(NULL),
        pixmap_(0),
        glx_pixmap_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  Pixmap pixmap_;
  GLXPixmap glx_pixmap_;

  DISALLOW_COPY_AND_ASSIGN(PixmapGLContext);
};

// scoped_ptr functor for XFree(). Use as follows:
//   scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
// where "XVisualInfo" is any X type that is freed with XFree.
class ScopedPtrXFree {
 public:
  void operator()(void* x) const {
    ::XFree(x);
  }
};

// Some versions of NVIDIA's GL libGL.so include a broken version of
// dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically
// load it, and use glew to dynamically resolve symbols.
// See http://code.google.com/p/chromium/issues/detail?id=16800

static bool InitializeOneOff() {
  static bool initialized = false;
  if (initialized)
    return true;

  osmewInit();
  if (!OSMesaCreateContext) {
    void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
    if (!handle) {
      LOG(ERROR) << "Could not find libGL.so.1";
      return false;
    }

    // Initializes context-independent parts of GLEW
    if (glxewInit() != GLEW_OK) {
      LOG(ERROR) << "glxewInit failed";
      return false;
    }
    // glxewContextInit really only needs a display connection to
    // complete, and we don't want to have to create an OpenGL context
    // just to get access to GLX 1.3 entry points to create pbuffers.
    // We therefore added a glxewContextInitWithDisplay entry point.
    Display* display = x11_util::GetXDisplay();
    if (glxewContextInitWithDisplay(display) != GLEW_OK) {
      LOG(ERROR) << "glxewContextInit failed";
      return false;
    }

    int major, minor;
    if (!glXQueryVersion(display, &major, &minor)) {
      LOG(ERROR) << "glxQueryVersion failed";
      return false;
    }

    if (major == 1 && minor < 3) {
      LOG(WARNING) << "GLX 1.3 or later is recommended.";
    }
  }

  initialized = true;
  return true;
}

bool ViewGLContext::Initialize(bool multisampled) {
  if (multisampled) {
    LOG(WARNING) << "Multisampling not implemented.";
  }

  Display* display = x11_util::GetXDisplay();
  XWindowAttributes attributes;
  XGetWindowAttributes(display, window_, &attributes);
  XVisualInfo visual_info_template;
  visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
  int visual_info_count = 0;
  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
      XGetVisualInfo(display, VisualIDMask,
                     &visual_info_template,
                     &visual_info_count));
  DCHECK(visual_info_list.get());
  DCHECK_GT(visual_info_count, 0);
  context_ = NULL;
  for (int i = 0; i < visual_info_count; ++i) {
    context_ = glXCreateContext(display, visual_info_list.get() + i, 0, True);
    if (context_)
      break;
  }
  if (!context_) {
    LOG(ERROR) << "Couldn't create GL context.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void ViewGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);

  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }
}

bool ViewGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }

  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, window_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = 0;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool ViewGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == window_ &&
      glXGetCurrentContext() == context_;
}

bool ViewGLContext::IsOffscreen() {
  return false;
}

void ViewGLContext::SwapBuffers() {
  Display* display = x11_util::GetXDisplay();
  glXSwapBuffers(display, window_);
}

gfx::Size ViewGLContext::GetSize() {
  XWindowAttributes attributes;
  Display* display = x11_util::GetXDisplay();
  XGetWindowAttributes(display, window_, &attributes);
  return gfx::Size(attributes.width, attributes.height);
}

void* ViewGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window,
                                          bool multisampled) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    // TODO(apatrick): Support OSMesa rendering to a window on Linux.
    NOTREACHED() << "OSMesa rendering to a window is not yet implemented.";
    return NULL;
  } else {
    scoped_ptr<ViewGLContext> context(new ViewGLContext(window));

    if (!context->Initialize(multisampled))
      return NULL;

    return context.release();
  }
}

bool PbufferGLContext::Initialize(void* shared_handle) {
  if (!glXChooseFBConfig ||
      !glXCreateNewContext ||
      !glXCreatePbuffer ||
      !glXDestroyPbuffer) {
    LOG(ERROR) << "Pbuffer support not available.";
    return false;
  }

  static const int config_attributes[] = {
    GLX_DRAWABLE_TYPE,
    GLX_PBUFFER_BIT,
    GLX_RENDER_TYPE,
    GLX_RGBA_BIT,
    GLX_DOUBLEBUFFER,
    0,
    0
  };

  Display* display = x11_util::GetXDisplay();

  int nelements = 0;
  // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient.
  scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
      glXChooseFBConfig(display, 0, config_attributes, &nelements));
  if (!config.get()) {
    LOG(ERROR) << "glXChooseFBConfig failed.";
    return false;
  }
  if (!nelements) {
    LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
    return false;
  }
  context_ = glXCreateNewContext(display,
                                 config.get()[0],
                                 GLX_RGBA_TYPE,
                                 static_cast<GLContextHandle>(shared_handle),
                                 True);
  if (!context_) {
    LOG(ERROR) << "glXCreateNewContext failed.";
    return false;
  }
  static const int pbuffer_attributes[] = {
    GLX_PBUFFER_WIDTH,
    1,
    GLX_PBUFFER_HEIGHT,
    1,
    0
  };
  pbuffer_ = glXCreatePbuffer(display,
                              config.get()[0], pbuffer_attributes);
  if (!pbuffer_) {
    Destroy();
    LOG(ERROR) << "glXCreatePbuffer failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PbufferGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (pbuffer_) {
    glXDestroyPbuffer(display, pbuffer_);
    pbuffer_ = 0;
  }
}

bool PbufferGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, pbuffer_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PbufferGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == pbuffer_ &&
      glXGetCurrentContext() == context_;
}

bool PbufferGLContext::IsOffscreen() {
  return true;
}

void PbufferGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
}

gfx::Size PbufferGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pbuffer.";
  return gfx::Size(1, 1);
}

void* PbufferGLContext::GetHandle() {
  return context_;
}

bool PixmapGLContext::Initialize(void* shared_handle) {
  LOG(INFO) << "GL context: using pixmaps.";
  if (!glXChooseVisual ||
      !glXCreateGLXPixmap ||
      !glXDestroyGLXPixmap) {
    LOG(ERROR) << "Pixmap support not available.";
    return false;
  }

  static int attributes[] = {
    GLX_RGBA,
    0
  };

  Display* display = x11_util::GetXDisplay();
  int screen = DefaultScreen(display);

  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info(
      glXChooseVisual(display, screen, attributes));

  if (!visual_info.get()) {
    LOG(ERROR) << "glXChooseVisual failed.";
    return false;
  }
  context_ = glXCreateContext(display, visual_info.get(),
                              static_cast<GLContextHandle>(shared_handle),
                              True);
  if (!context_) {
    LOG(ERROR) << "glXCreateContext failed.";
    return false;
  }

  pixmap_ = XCreatePixmap(display, RootWindow(display, screen), 1, 1,
                          visual_info->depth);
  if (!pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  glx_pixmap_ = glXCreateGLXPixmap(display, visual_info.get(), pixmap_);
  if (!glx_pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PixmapGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (glx_pixmap_) {
    glXDestroyGLXPixmap(display, glx_pixmap_);
    glx_pixmap_ = 0;
  }

  if (pixmap_) {
    XFreePixmap(display, pixmap_);
    pixmap_ = 0;
  }
}

bool PixmapGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, glx_pixmap_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PixmapGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == glx_pixmap_ &&
      glXGetCurrentContext() == context_;
}

bool PixmapGLContext::IsOffscreen() {
  return true;
}

void PixmapGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pixmap.";
}

gfx::Size PixmapGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pixmap.";
  return gfx::Size(1, 1);
}

void* PixmapGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateOffscreenGLContext(void* shared_handle) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    scoped_ptr<OSMesaGLContext> context(new OSMesaGLContext);

    if (!context->Initialize(shared_handle))
      return NULL;

    return context.release();
  } else {
    scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
    if (context->Initialize(shared_handle))
      return context.release();

    scoped_ptr<PixmapGLContext> context_pixmap(new PixmapGLContext);
    if (context_pixmap->Initialize(shared_handle))
      return context_pixmap.release();

    return NULL;
  }
}

}  // namespace gfx
<|endoftext|>


<commit_before>// Copyright (c) 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 "media/midi/midi_manager_mac.h"

#include <algorithm>
#include <string>

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"

#include <CoreAudio/HostTime.h>

using base::IntToString;
using base::SysCFStringRefToUTF8;
using std::string;

// NB: System MIDI types are pointer types in 32-bit and integer types in
// 64-bit. Therefore, the initialization is the simplest one that satisfies both
// (if possible).

namespace media {

namespace {

MidiPortInfo GetPortInfoFromEndpoint(MIDIEndpointRef endpoint) {
  SInt32 id_number = 0;
  MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number);
  string id = IntToString(id_number);

  string manufacturer;
  CFStringRef manufacturer_ref = NULL;
  OSStatus result = MIDIObjectGetStringProperty(
      endpoint, kMIDIPropertyManufacturer, &manufacturer_ref);
  if (result == noErr) {
    manufacturer = SysCFStringRefToUTF8(manufacturer_ref);
  } else {
    // kMIDIPropertyManufacturer is not supported in IAC driver providing
    // endpoints, and the result will be kMIDIUnknownProperty (-10835).
    DLOG(WARNING) << "Failed to get kMIDIPropertyManufacturer with status "
                  << result;
  }

  string name;
  CFStringRef name_ref = NULL;
  result = MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref);
  if (result == noErr)
    name = SysCFStringRefToUTF8(name_ref);
  else
    DLOG(WARNING) << "Failed to get kMIDIPropertyName with status " << result;

  string version;
  SInt32 version_number = 0;
  result = MIDIObjectGetIntegerProperty(
      endpoint, kMIDIPropertyDriverVersion, &version_number);
  if (result == noErr) {
    version = IntToString(version_number);
  } else {
    // kMIDIPropertyDriverVersion is not supported in IAC driver providing
    // endpoints, and the result will be kMIDIUnknownProperty (-10835).
    DLOG(WARNING) << "Failed to get kMIDIPropertyDriverVersion with status "
                  << result;
  }

  const MidiPortState state = MIDI_PORT_OPENED;
  return MidiPortInfo(id, manufacturer, name, version, state);
}

double MIDITimeStampToSeconds(MIDITimeStamp timestamp) {
  UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp);
  return static_cast<double>(nanoseconds) / 1.0e9;
}

MIDITimeStamp SecondsToMIDITimeStamp(double seconds) {
  UInt64 nanos = UInt64(seconds * 1.0e9);
  return AudioConvertNanosToHostTime(nanos);
}

}  // namespace

MidiManager* MidiManager::Create() {
  return new MidiManagerMac();
}

MidiManagerMac::MidiManagerMac()
    : midi_client_(0),
      coremidi_input_(0),
      coremidi_output_(0),
      packet_list_(NULL),
      midi_packet_(NULL),
      client_thread_("MidiClientThread"),
      shutdown_(false) {
}

MidiManagerMac::~MidiManagerMac() {
  // Wait for the termination of |client_thread_| before disposing MIDI ports.
  shutdown_ = true;
  client_thread_.Stop();

  if (coremidi_input_)
    MIDIPortDispose(coremidi_input_);
  if (coremidi_output_)
    MIDIPortDispose(coremidi_output_);
  if (midi_client_)
    MIDIClientDispose(midi_client_);
}

void MidiManagerMac::StartInitialization() {
  // MIDIClient should be created on |client_thread_| to receive CoreMIDI event
  // notifications.
  RunOnClientThread(
      base::Bind(&MidiManagerMac::InitializeCoreMIDI, base::Unretained(this)));
}

void MidiManagerMac::DispatchSendMidiData(MidiManagerClient* client,
                                          uint32 port_index,
                                          const std::vector<uint8>& data,
                                          double timestamp) {
  RunOnClientThread(
      base::Bind(&MidiManagerMac::SendMidiData,
                 base::Unretained(this), client, port_index, data, timestamp));
}

void MidiManagerMac::RunOnClientThread(const base::Closure& closure) {
  if (shutdown_)
    return;

  if (!client_thread_.IsRunning())
    client_thread_.Start();

  client_thread_.message_loop()->PostTask(FROM_HERE, closure);
}

void MidiManagerMac::InitializeCoreMIDI() {
  DCHECK(client_thread_.message_loop_proxy()->BelongsToCurrentThread());

  // CoreMIDI registration.
  // TODO(toyoshim): Set MIDINotifyProc to receive CoreMIDI event notifications.
  midi_client_ = 0;
  OSStatus result =
      MIDIClientCreate(CFSTR("Chrome"), ReceiveMidiNotifyDispatch, this,
                       &midi_client_);

  if (result != noErr)
    return CompleteInitialization(MIDI_INITIALIZATION_ERROR);

  coremidi_input_ = 0;

  // Create input and output port.
  result = MIDIInputPortCreate(
      midi_client_,
      CFSTR("MIDI Input"),
      ReadMidiDispatch,
      this,
      &coremidi_input_);
  if (result != noErr)
    return CompleteInitialization(MIDI_INITIALIZATION_ERROR);

  result = MIDIOutputPortCreate(
      midi_client_,
      CFSTR("MIDI Output"),
      &coremidi_output_);
  if (result != noErr)
    return CompleteInitialization(MIDI_INITIALIZATION_ERROR);

  uint32 destination_count = MIDIGetNumberOfDestinations();
  destinations_.resize(destination_count);

  for (uint32 i = 0; i < destination_count ; i++) {
    MIDIEndpointRef destination = MIDIGetDestination(i);

    // Keep track of all destinations (known as outputs by the Web MIDI API).
    // Cache to avoid any possible overhead in calling MIDIGetDestination().
    destinations_[i] = destination;

    MidiPortInfo info = GetPortInfoFromEndpoint(destination);
    AddOutputPort(info);
  }

  // Open connections from all sources.
  uint32 source_count = MIDIGetNumberOfSources();

  for (uint32 i = 0; i < source_count; ++i)  {
    // Receive from all sources.
    MIDIEndpointRef src = MIDIGetSource(i);
    MIDIPortConnectSource(coremidi_input_, src, reinterpret_cast<void*>(src));

    // Keep track of all sources (known as inputs in Web MIDI API terminology).
    source_map_[src] = i;

    MidiPortInfo info = GetPortInfoFromEndpoint(src);
    AddInputPort(info);
  }

  packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_);
  midi_packet_ = MIDIPacketListInit(packet_list_);

  CompleteInitialization(MIDI_OK);
}

// static
void MidiManagerMac::ReceiveMidiNotifyDispatch(const MIDINotification* message,
                                               void* refcon) {
  MidiManagerMac* manager = static_cast<MidiManagerMac*>(refcon);
  manager->ReceiveMidiNotify(message);
}

void MidiManagerMac::ReceiveMidiNotify(const MIDINotification* message) {
  DCHECK(client_thread_.message_loop_proxy()->BelongsToCurrentThread());

  if (kMIDIMsgObjectAdded == message->messageID) {
    const MIDIObjectAddRemoveNotification* notification =
        reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
    MIDIEndpointRef endpoint =
        static_cast<MIDIEndpointRef>(notification->child);
    if (notification->childType == kMIDIObjectType_Source) {
      SourceMap::iterator it = source_map_.find(endpoint);
      if (it == source_map_.end()) {
        uint32 index = source_map_.size();
        source_map_[endpoint] = index;
        MidiPortInfo info = GetPortInfoFromEndpoint(endpoint);
        AddInputPort(info);
      } else {
        uint32 index = it->second;
        SetInputPortState(index, MIDI_PORT_OPENED);
      }
    } else if (notification->childType == kMIDIObjectType_Destination) {
      auto i = std::find(destinations_.begin(), destinations_.end(), endpoint);
      if (i != destinations_.end()) {
        SetOutputPortState(i - destinations_.begin(), MIDI_PORT_OPENED);
      } else {
        destinations_.push_back(endpoint);
        MidiPortInfo info = GetPortInfoFromEndpoint(endpoint);
        AddOutputPort(info);
      }
    }
  } else if (kMIDIMsgObjectRemoved == message->messageID) {
    const MIDIObjectAddRemoveNotification* notification =
        reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
    MIDIEndpointRef endpoint =
        static_cast<MIDIEndpointRef>(notification->child);
    if (notification->childType == kMIDIObjectType_Source) {
      SourceMap::iterator it = source_map_.find(endpoint);
      if (it != source_map_.end()) {
        uint32 index = it->second;
        SetInputPortState(index, MIDI_PORT_DISCONNECTED);
      }
    } else if (notification->childType == kMIDIObjectType_Destination) {
      auto i = std::find(destinations_.begin(), destinations_.end(), endpoint);
      if (i != destinations_.end())
        SetOutputPortState(i - destinations_.begin(), MIDI_PORT_DISCONNECTED);
    }
  }
}

// static
void MidiManagerMac::ReadMidiDispatch(const MIDIPacketList* packet_list,
                                      void* read_proc_refcon,
                                      void* src_conn_refcon) {
  // This method is called on a separate high-priority thread owned by CoreMIDI.

  MidiManagerMac* manager = static_cast<MidiManagerMac*>(read_proc_refcon);
#if __LP64__
  MIDIEndpointRef source = reinterpret_cast<uintptr_t>(src_conn_refcon);
#else
  MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon);
#endif

  // Dispatch to class method.
  manager->ReadMidi(source, packet_list);
}

void MidiManagerMac::ReadMidi(MIDIEndpointRef source,
                              const MIDIPacketList* packet_list) {
  // This method is called from ReadMidiDispatch() and runs on a separate
  // high-priority thread owned by CoreMIDI.

  // Lookup the port index based on the source.
  SourceMap::iterator j = source_map_.find(source);
  if (j == source_map_.end())
    return;
  // This is safe since MidiManagerMac does not remove any existing
  // MIDIEndpointRef, and the order is saved.
  uint32 port_index = source_map_[source];

  // Go through each packet and process separately.
  for (size_t i = 0; i < packet_list->numPackets; i++) {
    // Each packet contains MIDI data for one or more messages (like note-on).
    const MIDIPacket &packet = packet_list->packet[i];
    double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp);

    ReceiveMidiData(
        port_index,
        packet.data,
        packet.length,
        timestamp_seconds);
  }
}

void MidiManagerMac::SendMidiData(MidiManagerClient* client,
                                  uint32 port_index,
                                  const std::vector<uint8>& data,
                                  double timestamp) {
  DCHECK(client_thread_.message_loop_proxy()->BelongsToCurrentThread());

  // System Exclusive has already been filtered.
  MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp);

  midi_packet_ = MIDIPacketListAdd(
      packet_list_,
      kMaxPacketListSize,
      midi_packet_,
      coremidi_timestamp,
      data.size(),
      &data[0]);

  // Lookup the destination based on the port index.
  if (static_cast<size_t>(port_index) >= destinations_.size())
    return;

  MIDIEndpointRef destination = destinations_[port_index];

  MIDISend(coremidi_output_, destination, packet_list_);

  // Re-initialize for next time.
  midi_packet_ = MIDIPacketListInit(packet_list_);

  client->AccumulateMidiBytesSent(data.size());
}

}  // namespace media
<commit_msg>Web MIDI: remove a resolved TODO<commit_after>// Copyright (c) 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 "media/midi/midi_manager_mac.h"

#include <algorithm>
#include <string>

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"

#include <CoreAudio/HostTime.h>

using base::IntToString;
using base::SysCFStringRefToUTF8;
using std::string;

// NB: System MIDI types are pointer types in 32-bit and integer types in
// 64-bit. Therefore, the initialization is the simplest one that satisfies both
// (if possible).

namespace media {

namespace {

MidiPortInfo GetPortInfoFromEndpoint(MIDIEndpointRef endpoint) {
  SInt32 id_number = 0;
  MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number);
  string id = IntToString(id_number);

  string manufacturer;
  CFStringRef manufacturer_ref = NULL;
  OSStatus result = MIDIObjectGetStringProperty(
      endpoint, kMIDIPropertyManufacturer, &manufacturer_ref);
  if (result == noErr) {
    manufacturer = SysCFStringRefToUTF8(manufacturer_ref);
  } else {
    // kMIDIPropertyManufacturer is not supported in IAC driver providing
    // endpoints, and the result will be kMIDIUnknownProperty (-10835).
    DLOG(WARNING) << "Failed to get kMIDIPropertyManufacturer with status "
                  << result;
  }

  string name;
  CFStringRef name_ref = NULL;
  result = MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref);
  if (result == noErr)
    name = SysCFStringRefToUTF8(name_ref);
  else
    DLOG(WARNING) << "Failed to get kMIDIPropertyName with status " << result;

  string version;
  SInt32 version_number = 0;
  result = MIDIObjectGetIntegerProperty(
      endpoint, kMIDIPropertyDriverVersion, &version_number);
  if (result == noErr) {
    version = IntToString(version_number);
  } else {
    // kMIDIPropertyDriverVersion is not supported in IAC driver providing
    // endpoints, and the result will be kMIDIUnknownProperty (-10835).
    DLOG(WARNING) << "Failed to get kMIDIPropertyDriverVersion with status "
                  << result;
  }

  const MidiPortState state = MIDI_PORT_OPENED;
  return MidiPortInfo(id, manufacturer, name, version, state);
}

double MIDITimeStampToSeconds(MIDITimeStamp timestamp) {
  UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp);
  return static_cast<double>(nanoseconds) / 1.0e9;
}

MIDITimeStamp SecondsToMIDITimeStamp(double seconds) {
  UInt64 nanos = UInt64(seconds * 1.0e9);
  return AudioConvertNanosToHostTime(nanos);
}

}  // namespace

MidiManager* MidiManager::Create() {
  return new MidiManagerMac();
}

MidiManagerMac::MidiManagerMac()
    : midi_client_(0),
      coremidi_input_(0),
      coremidi_output_(0),
      packet_list_(NULL),
      midi_packet_(NULL),
      client_thread_("MidiClientThread"),
      shutdown_(false) {
}

MidiManagerMac::~MidiManagerMac() {
  // Wait for the termination of |client_thread_| before disposing MIDI ports.
  shutdown_ = true;
  client_thread_.Stop();

  if (coremidi_input_)
    MIDIPortDispose(coremidi_input_);
  if (coremidi_output_)
    MIDIPortDispose(coremidi_output_);
  if (midi_client_)
    MIDIClientDispose(midi_client_);
}

void MidiManagerMac::StartInitialization() {
  // MIDIClient should be created on |client_thread_| to receive CoreMIDI event
  // notifications.
  RunOnClientThread(
      base::Bind(&MidiManagerMac::InitializeCoreMIDI, base::Unretained(this)));
}

void MidiManagerMac::DispatchSendMidiData(MidiManagerClient* client,
                                          uint32 port_index,
                                          const std::vector<uint8>& data,
                                          double timestamp) {
  RunOnClientThread(
      base::Bind(&MidiManagerMac::SendMidiData,
                 base::Unretained(this), client, port_index, data, timestamp));
}

void MidiManagerMac::RunOnClientThread(const base::Closure& closure) {
  if (shutdown_)
    return;

  if (!client_thread_.IsRunning())
    client_thread_.Start();

  client_thread_.message_loop()->PostTask(FROM_HERE, closure);
}

void MidiManagerMac::InitializeCoreMIDI() {
  DCHECK(client_thread_.message_loop_proxy()->BelongsToCurrentThread());

  // CoreMIDI registration.
  midi_client_ = 0;
  OSStatus result =
      MIDIClientCreate(CFSTR("Chrome"), ReceiveMidiNotifyDispatch, this,
                       &midi_client_);

  if (result != noErr)
    return CompleteInitialization(MIDI_INITIALIZATION_ERROR);

  coremidi_input_ = 0;

  // Create input and output port.
  result = MIDIInputPortCreate(
      midi_client_,
      CFSTR("MIDI Input"),
      ReadMidiDispatch,
      this,
      &coremidi_input_);
  if (result != noErr)
    return CompleteInitialization(MIDI_INITIALIZATION_ERROR);

  result = MIDIOutputPortCreate(
      midi_client_,
      CFSTR("MIDI Output"),
      &coremidi_output_);
  if (result != noErr)
    return CompleteInitialization(MIDI_INITIALIZATION_ERROR);

  uint32 destination_count = MIDIGetNumberOfDestinations();
  destinations_.resize(destination_count);

  for (uint32 i = 0; i < destination_count ; i++) {
    MIDIEndpointRef destination = MIDIGetDestination(i);

    // Keep track of all destinations (known as outputs by the Web MIDI API).
    // Cache to avoid any possible overhead in calling MIDIGetDestination().
    destinations_[i] = destination;

    MidiPortInfo info = GetPortInfoFromEndpoint(destination);
    AddOutputPort(info);
  }

  // Open connections from all sources.
  uint32 source_count = MIDIGetNumberOfSources();

  for (uint32 i = 0; i < source_count; ++i)  {
    // Receive from all sources.
    MIDIEndpointRef src = MIDIGetSource(i);
    MIDIPortConnectSource(coremidi_input_, src, reinterpret_cast<void*>(src));

    // Keep track of all sources (known as inputs in Web MIDI API terminology).
    source_map_[src] = i;

    MidiPortInfo info = GetPortInfoFromEndpoint(src);
    AddInputPort(info);
  }

  packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_);
  midi_packet_ = MIDIPacketListInit(packet_list_);

  CompleteInitialization(MIDI_OK);
}

// static
void MidiManagerMac::ReceiveMidiNotifyDispatch(const MIDINotification* message,
                                               void* refcon) {
  MidiManagerMac* manager = static_cast<MidiManagerMac*>(refcon);
  manager->ReceiveMidiNotify(message);
}

void MidiManagerMac::ReceiveMidiNotify(const MIDINotification* message) {
  DCHECK(client_thread_.message_loop_proxy()->BelongsToCurrentThread());

  if (kMIDIMsgObjectAdded == message->messageID) {
    const MIDIObjectAddRemoveNotification* notification =
        reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
    MIDIEndpointRef endpoint =
        static_cast<MIDIEndpointRef>(notification->child);
    if (notification->childType == kMIDIObjectType_Source) {
      SourceMap::iterator it = source_map_.find(endpoint);
      if (it == source_map_.end()) {
        uint32 index = source_map_.size();
        source_map_[endpoint] = index;
        MidiPortInfo info = GetPortInfoFromEndpoint(endpoint);
        AddInputPort(info);
      } else {
        uint32 index = it->second;
        SetInputPortState(index, MIDI_PORT_OPENED);
      }
    } else if (notification->childType == kMIDIObjectType_Destination) {
      auto i = std::find(destinations_.begin(), destinations_.end(), endpoint);
      if (i != destinations_.end()) {
        SetOutputPortState(i - destinations_.begin(), MIDI_PORT_OPENED);
      } else {
        destinations_.push_back(endpoint);
        MidiPortInfo info = GetPortInfoFromEndpoint(endpoint);
        AddOutputPort(info);
      }
    }
  } else if (kMIDIMsgObjectRemoved == message->messageID) {
    const MIDIObjectAddRemoveNotification* notification =
        reinterpret_cast<const MIDIObjectAddRemoveNotification*>(message);
    MIDIEndpointRef endpoint =
        static_cast<MIDIEndpointRef>(notification->child);
    if (notification->childType == kMIDIObjectType_Source) {
      SourceMap::iterator it = source_map_.find(endpoint);
      if (it != source_map_.end()) {
        uint32 index = it->second;
        SetInputPortState(index, MIDI_PORT_DISCONNECTED);
      }
    } else if (notification->childType == kMIDIObjectType_Destination) {
      auto i = std::find(destinations_.begin(), destinations_.end(), endpoint);
      if (i != destinations_.end())
        SetOutputPortState(i - destinations_.begin(), MIDI_PORT_DISCONNECTED);
    }
  }
}

// static
void MidiManagerMac::ReadMidiDispatch(const MIDIPacketList* packet_list,
                                      void* read_proc_refcon,
                                      void* src_conn_refcon) {
  // This method is called on a separate high-priority thread owned by CoreMIDI.

  MidiManagerMac* manager = static_cast<MidiManagerMac*>(read_proc_refcon);
#if __LP64__
  MIDIEndpointRef source = reinterpret_cast<uintptr_t>(src_conn_refcon);
#else
  MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon);
#endif

  // Dispatch to class method.
  manager->ReadMidi(source, packet_list);
}

void MidiManagerMac::ReadMidi(MIDIEndpointRef source,
                              const MIDIPacketList* packet_list) {
  // This method is called from ReadMidiDispatch() and runs on a separate
  // high-priority thread owned by CoreMIDI.

  // Lookup the port index based on the source.
  SourceMap::iterator j = source_map_.find(source);
  if (j == source_map_.end())
    return;
  // This is safe since MidiManagerMac does not remove any existing
  // MIDIEndpointRef, and the order is saved.
  uint32 port_index = source_map_[source];

  // Go through each packet and process separately.
  for (size_t i = 0; i < packet_list->numPackets; i++) {
    // Each packet contains MIDI data for one or more messages (like note-on).
    const MIDIPacket &packet = packet_list->packet[i];
    double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp);

    ReceiveMidiData(
        port_index,
        packet.data,
        packet.length,
        timestamp_seconds);
  }
}

void MidiManagerMac::SendMidiData(MidiManagerClient* client,
                                  uint32 port_index,
                                  const std::vector<uint8>& data,
                                  double timestamp) {
  DCHECK(client_thread_.message_loop_proxy()->BelongsToCurrentThread());

  // System Exclusive has already been filtered.
  MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp);

  midi_packet_ = MIDIPacketListAdd(
      packet_list_,
      kMaxPacketListSize,
      midi_packet_,
      coremidi_timestamp,
      data.size(),
      &data[0]);

  // Lookup the destination based on the port index.
  if (static_cast<size_t>(port_index) >= destinations_.size())
    return;

  MIDIEndpointRef destination = destinations_[port_index];

  MIDISend(coremidi_output_, destination, packet_list_);

  // Re-initialize for next time.
  midi_packet_ = MIDIPacketListInit(packet_list_);

  client->AccumulateMidiBytesSent(data.size());
}

}  // namespace media
<|endoftext|>


<commit_before>/**
 * @file
 * @author Jason Lingle
 * @brief Implementation of src/editor/abstract_system_painter.hxx
 */

/*
 * abstract_system_painter.cxx
 *
 *  Created on: 08.02.2011
 *      Author: jason
 */

#include <cstring>
#include <cstdlib>
#include <typeinfo>
#include <string>

#include <libconfig.h++>

#include "abstract_system_painter.hxx"
#include "manipulator_mode.hxx"
#include "manipulator.hxx"
#include "src/ship/ship.hxx"
#include "src/ship/cell/cell.hxx"
#include "src/ship/cell/square_cell.hxx"
#include "src/ship/cell/circle_cell.hxx"
#include "src/ship/sys/ship_system.hxx"
#include "src/ship/sys/a/antimatter_power.hxx"
#include "src/ship/sys/a/cloaking_device.hxx"
#include "src/ship/sys/a/dispersion_shield.hxx"
#include "src/ship/sys/a/gatling_plasma_burst_launcher.hxx"
#include "src/ship/sys/a/missile_launcher.hxx"
#include "src/ship/sys/a/monophasic_energy_emitter.hxx"
#include "src/ship/sys/a/particle_beam_launcher.hxx"
#include "src/ship/sys/a/rel_ion_accelerator.hxx"
#include "src/ship/sys/b/bussard_ramjet.hxx"
#include "src/ship/sys/b/fusion_power.hxx"
#include "src/ship/sys/b/heatsink.hxx"
#include "src/ship/sys/b/mini_gravwave_drive_mkii.hxx"
#include "src/ship/sys/b/plasma_burst_launcher.hxx"
#include "src/ship/sys/b/semiguided_bomb_launcher.hxx"
#include "src/ship/sys/b/shield_generator.hxx"
#include "src/ship/sys/b/super_particle_accelerator.hxx"
#include "src/ship/sys/c/capacitor.hxx"
#include "src/ship/sys/c/energy_charge_launcher.hxx"
#include "src/ship/sys/c/fission_power.hxx"
#include "src/ship/sys/c/magneto_bomb_launcher.hxx"
#include "src/ship/sys/c/mini_gravwave_drive.hxx"
#include "src/ship/sys/c/particle_accelerator.hxx"
#include "src/ship/sys/c/power_cell.hxx"
#include "src/ship/sys/c/reinforcement_bulkhead.hxx"
#include "src/ship/sys/c/self_destruct_charge.hxx"
#include "src/globals.hxx"
#include "src/secondary/confreg.hxx"
#include "src/exit_conditions.hxx"
#include "src/core/lxn.hxx"

using namespace libconfig;
using namespace std;

AbstractSystemPainter::AbstractSystemPainter(Manipulator* m, Ship*const& s)
: ManipulatorMode(m,s)
{ }

void AbstractSystemPainter::deactivate() {
  if (pressed) release(0,0);
}

static ShipSystem* getSystem(const char* type, const string& prefix, Ship* ship) {
  string shstrength(prefix + "_shield_strength");
  string shradius(prefix + "_shield_radius");
  string capcap(prefix + "_capacitance");
  string gpblturbo(prefix + "_gatling_turbo");

  if (0 == strcmp(type, "delete"))
    return NULL;
  #define SYS(class, args) else if (0 == strcmp(type, #class)) return new class args
  SYS(AntimatterPower, (ship));
  SYS(CloakingDevice, (ship));
  SYS(DispersionShield, (ship));
  SYS(GatlingPlasmaBurstLauncher, (ship, conf["edit"][gpblturbo.c_str()]));
  SYS(MissileLauncher, (ship));
  SYS(MonophasicEnergyEmitter, (ship));
  SYS(ParticleBeamLauncher, (ship));
  SYS(RelIonAccelerator, (ship));
  SYS(BussardRamjet, (ship));
  SYS(FusionPower, (ship));
  SYS(Heatsink, (ship));
  SYS(MiniGravwaveDriveMKII, (ship));
  SYS(PlasmaBurstLauncher, (ship));
  SYS(SemiguidedBombLauncher, (ship));
  SYS(ShieldGenerator, (ship, conf["edit"][shstrength.c_str()], conf["edit"][shradius.c_str()]));
  SYS(SuperParticleAccelerator, (ship));
  SYS(Capacitor, (ship, conf["edit"][capcap.c_str()]));
  SYS(EnergyChargeLauncher, (ship));
  SYS(FissionPower, (ship));
  SYS(MagnetoBombLauncher, (ship));
  SYS(MiniGravwaveDrive, (ship));
  SYS(ParticleAccelerator, (ship));
  SYS(PowerCell, (ship));
  SYS(ReinforcementBulkhead, (ship));
  SYS(SelfDestructCharge, (ship));
  else {
    cerr << "FATAL: Unknown system type: " << type << endl;
    exit(EXIT_SCRIPTING_BUG);
  }
}

/* This function exists to pacify G++. If I try something like:
 *   if (x && e="foo")
 * I get "assignment requires lvalue". This expands to exactly
 * the same code, yet it works.
 */
static inline const char* asgn(const char*& l, const char* r) {
  l=r;
  return l;
}

const char* AbstractSystemPainter::paintSystems(Cell* cell) {
  if (cell->usage == CellBridge) return _(editor,cant_put_systems_in_bridge);

  const char* error=NULL;

  Setting& s(conf[(const char*)conf["edit"]["mountname"]]["cells"][cell->cellName.c_str()]);
  const char* ns0type = conf["edit"]["sys0_type"], *ns1type = conf["edit"]["sys1_type"];
  bool hasSys1 = (typeid(*cell) == typeid(SquareCell) || typeid(*cell) == typeid(CircleCell));

  bool sys0Mod=true, sys1Mod=true;

  //Begin by backing current systems up
  //Delete these if non-NULL at end of function
  ShipSystem* s0 = cell->systems[0], * s1 = cell->systems[1];

  if (0 == strcmp(ns0type, "none")) {
    //No change, don't delete current
    s0=NULL;
    sys0Mod=false;
  } else {
    cell->systems[0] = getSystem(ns0type, string("sys0"), ship);
    if (cell->systems[0]) cell->systems[0]->container = cell;
    const char* e=NULL;
    if (cell->systems[0]
    &&  (asgn(e,cell->systems[0]->autoOrient()) || asgn(e,cell->systems[0]->acceptShip()))) {
      if (!error) error=e;
      //Restore back-up
      delete cell->systems[0];
      cell->systems[0]=s0;
      s0=NULL;
      sys0Mod=false;
    }
  }

  if (!hasSys1 || 0 == strcmp(ns1type, "none")) {
    //No change
    s1=NULL;
    sys1Mod=false;
  } else {
    cell->systems[1] = getSystem(ns1type, string("sys1"), ship);
    if (cell->systems[1]) cell->systems[1]->container = cell;
    const char* e=NULL;
    if (cell->systems[1]
    && (asgn(e,cell->systems[1]->autoOrient()) || asgn(e,cell->systems[1]->acceptShip()))) {
      if (!error) error=e;
      delete cell->systems[1];
      cell->systems[1]=s1;
      s1=NULL;
      sys1Mod=false;
    }
  }

  /* If the ship still verifies, the result is still OK;
   * otherwise, we need to undo everything.
   */
  if (const char* e = verify(ship, false)) {
    if (!error) error=e;
    if (sys0Mod) {
      if (cell->systems[0]) delete cell->systems[0];
      cell->systems[0] = s0;
      s0=NULL;
      sys0Mod=false;
    }
    if (sys1Mod) {
      if (cell->systems[1]) delete cell->systems[1];
      cell->systems[1] = s1;
      s1=NULL;
      sys1Mod=false;
    }
  }

  //Apply changes to configuration
  if (sys0Mod) {
    if (s.exists("s0"))
      s.remove("s0");
    if (cell->systems[0]) {
      Setting& sys(s.add("s0", Setting::TypeGroup));
      sys.add("type", Setting::TypeString) = ns0type;
      if (cell->systems[0]->getOrientation() != -1)
        sys.add("orient", Setting::TypeInt) = cell->systems[0]->getOrientation();
      if (0 == strcmp(ns0type, "Capacitor"))
        sys.add("capacity", Setting::TypeInt) = (int)conf["edit"]["sys0_capacitance"];
      if (0 == strcmp(ns0type, "ShieldGenerator")) {
        sys.add("radius", Setting::TypeFloat) = (float)conf["edit"]["sys0_shield_radius"];
        sys.add("strength", Setting::TypeFloat) = (float)conf["edit"]["sys0_shield_strength"];
      }
      if (0 == strcmp(ns0type, "GatlingPlasmaBurstLauncher")) {
        sys.add("turbo", Setting::TypeBoolean) = (bool)conf["edit"]["sys0_gatling_turbo"];
      }
    }
  }

  if (sys1Mod) {
    if (s.exists("s1"))
      s.remove("s1");
    if (cell->systems[1]) {
      Setting& sys(s.add("s1", Setting::TypeGroup));
      sys.add("type", Setting::TypeString) = ns1type;
      if (cell->systems[1]->getOrientation() != -1)
        sys.add("orient", Setting::TypeInt) = cell->systems[1]->getOrientation();
      if (0 == strcmp(ns1type, "Capacitor"))
        sys.add("capacity", Setting::TypeInt) = (int)conf["edit"]["sys1_capacitance"];
      if (0 == strcmp(ns1type, "ShieldGenerator")) {
        sys.add("radius", Setting::TypeFloat) = (float)conf["edit"]["sys1_shield_radius"];
        sys.add("strength", Setting::TypeFloat) = (float)conf["edit"]["sys1_shield_strength"];
      }
      if (0 == strcmp(ns1type, "GatlingPlasmaBurstLauncher")) {
        sys.add("turbo", Setting::TypeBoolean) = (bool)conf["edit"]["sys1_gatling_turbo"];
      }
    }
  }

  if (sys0Mod || sys1Mod)
    conf["edit"]["modified"] = true;

  //Delete backups
  if (s0) delete s0;
  if (s1) delete s1;

  return error;
}
<commit_msg>Fix ship system painter causing crashes/misinformation.<commit_after>/**
 * @file
 * @author Jason Lingle
 * @brief Implementation of src/editor/abstract_system_painter.hxx
 */

/*
 * abstract_system_painter.cxx
 *
 *  Created on: 08.02.2011
 *      Author: jason
 */

#include <cstring>
#include <cstdlib>
#include <typeinfo>
#include <string>

#include <libconfig.h++>

#include "abstract_system_painter.hxx"
#include "manipulator_mode.hxx"
#include "manipulator.hxx"
#include "src/ship/ship.hxx"
#include "src/ship/cell/cell.hxx"
#include "src/ship/cell/square_cell.hxx"
#include "src/ship/cell/circle_cell.hxx"
#include "src/ship/sys/ship_system.hxx"
#include "src/ship/sys/a/antimatter_power.hxx"
#include "src/ship/sys/a/cloaking_device.hxx"
#include "src/ship/sys/a/dispersion_shield.hxx"
#include "src/ship/sys/a/gatling_plasma_burst_launcher.hxx"
#include "src/ship/sys/a/missile_launcher.hxx"
#include "src/ship/sys/a/monophasic_energy_emitter.hxx"
#include "src/ship/sys/a/particle_beam_launcher.hxx"
#include "src/ship/sys/a/rel_ion_accelerator.hxx"
#include "src/ship/sys/b/bussard_ramjet.hxx"
#include "src/ship/sys/b/fusion_power.hxx"
#include "src/ship/sys/b/heatsink.hxx"
#include "src/ship/sys/b/mini_gravwave_drive_mkii.hxx"
#include "src/ship/sys/b/plasma_burst_launcher.hxx"
#include "src/ship/sys/b/semiguided_bomb_launcher.hxx"
#include "src/ship/sys/b/shield_generator.hxx"
#include "src/ship/sys/b/super_particle_accelerator.hxx"
#include "src/ship/sys/c/capacitor.hxx"
#include "src/ship/sys/c/energy_charge_launcher.hxx"
#include "src/ship/sys/c/fission_power.hxx"
#include "src/ship/sys/c/magneto_bomb_launcher.hxx"
#include "src/ship/sys/c/mini_gravwave_drive.hxx"
#include "src/ship/sys/c/particle_accelerator.hxx"
#include "src/ship/sys/c/power_cell.hxx"
#include "src/ship/sys/c/reinforcement_bulkhead.hxx"
#include "src/ship/sys/c/self_destruct_charge.hxx"
#include "src/globals.hxx"
#include "src/secondary/confreg.hxx"
#include "src/exit_conditions.hxx"
#include "src/core/lxn.hxx"

using namespace libconfig;
using namespace std;

AbstractSystemPainter::AbstractSystemPainter(Manipulator* m, Ship*const& s)
: ManipulatorMode(m,s)
{ }

void AbstractSystemPainter::deactivate() {
  if (pressed) release(0,0);
}

static ShipSystem* getSystem(const char* type, const string& prefix, Ship* ship) {
  string shstrength(prefix + "_shield_strength");
  string shradius(prefix + "_shield_radius");
  string capcap(prefix + "_capacitance");
  string gpblturbo(prefix + "_gatling_turbo");

  if (0 == strcmp(type, "delete"))
    return NULL;
  #define SYS(class, args) else if (0 == strcmp(type, #class)) return new class args
  SYS(AntimatterPower, (ship));
  SYS(CloakingDevice, (ship));
  SYS(DispersionShield, (ship));
  SYS(GatlingPlasmaBurstLauncher, (ship, conf["edit"][gpblturbo.c_str()]));
  SYS(MissileLauncher, (ship));
  SYS(MonophasicEnergyEmitter, (ship));
  SYS(ParticleBeamLauncher, (ship));
  SYS(RelIonAccelerator, (ship));
  SYS(BussardRamjet, (ship));
  SYS(FusionPower, (ship));
  SYS(Heatsink, (ship));
  SYS(MiniGravwaveDriveMKII, (ship));
  SYS(PlasmaBurstLauncher, (ship));
  SYS(SemiguidedBombLauncher, (ship));
  SYS(ShieldGenerator, (ship, conf["edit"][shstrength.c_str()], conf["edit"][shradius.c_str()]));
  SYS(SuperParticleAccelerator, (ship));
  SYS(Capacitor, (ship, conf["edit"][capcap.c_str()]));
  SYS(EnergyChargeLauncher, (ship));
  SYS(FissionPower, (ship));
  SYS(MagnetoBombLauncher, (ship));
  SYS(MiniGravwaveDrive, (ship));
  SYS(ParticleAccelerator, (ship));
  SYS(PowerCell, (ship));
  SYS(ReinforcementBulkhead, (ship));
  SYS(SelfDestructCharge, (ship));
  else {
    cerr << "FATAL: Unknown system type: " << type << endl;
    exit(EXIT_SCRIPTING_BUG);
  }
}

/* This function exists to pacify G++. If I try something like:
 *   if (x && e="foo")
 * I get "assignment requires lvalue". This expands to exactly
 * the same code, yet it works.
 */
static inline const char* asgn(const char*& l, const char* r) {
  l=r;
  return l;
}

const char* AbstractSystemPainter::paintSystems(Cell* cell) {
  if (cell->usage == CellBridge) return _(editor,cant_put_systems_in_bridge);

  const char* error=NULL;

  Setting& s(conf[(const char*)conf["edit"]["mountname"]]["cells"][cell->cellName.c_str()]);
  const char* ns0type = conf["edit"]["sys0_type"], *ns1type = conf["edit"]["sys1_type"];
  bool hasSys1 = (typeid(*cell) == typeid(SquareCell) || typeid(*cell) == typeid(CircleCell));

  bool sys0Mod=true, sys1Mod=true;

  //Begin by backing current systems up
  //Delete these if non-NULL at end of function
  ShipSystem* s0 = cell->systems[0], * s1 = cell->systems[1];

  if (0 == strcmp(ns0type, "none")) {
    //No change, don't delete current
    s0=NULL;
    sys0Mod=false;
  } else {
    cell->systems[0] = getSystem(ns0type, string("sys0"), ship);
    if (cell->systems[0]) cell->systems[0]->container = cell;
    const char* e=NULL;
    if (cell->systems[0]
    &&  (asgn(e,cell->systems[0]->autoOrient()) || asgn(e,cell->systems[0]->acceptShip()))) {
      if (!error) error=e;
      //Restore back-up
      delete cell->systems[0];
      cell->systems[0]=s0;
      s0=NULL;
      sys0Mod=false;
    }
  }

  if (!hasSys1 || 0 == strcmp(ns1type, "none")) {
    //No change
    s1=NULL;
    sys1Mod=false;
  } else {
    cell->systems[1] = getSystem(ns1type, string("sys1"), ship);
    if (cell->systems[1]) cell->systems[1]->container = cell;
    const char* e=NULL;
    if (cell->systems[1]
    && (asgn(e,cell->systems[1]->autoOrient()) || asgn(e,cell->systems[1]->acceptShip()))) {
      if (!error) error=e;
      delete cell->systems[1];
      cell->systems[1]=s1;
      s1=NULL;
      sys1Mod=false;
    }
  }

  /* If the ship still verifies, the result is still OK;
   * otherwise, we need to undo everything.
   */
  if (const char* e = verify(ship, false)) {
    if (!error) error=e;
    if (sys0Mod) {
      if (cell->systems[0]) delete cell->systems[0];
      cell->systems[0] = s0;
      s0=NULL;
      sys0Mod=false;
    }
    if (sys1Mod) {
      if (cell->systems[1]) delete cell->systems[1];
      cell->systems[1] = s1;
      s1=NULL;
      sys1Mod=false;
    }
  }

  //Apply changes to configuration
  if (sys0Mod) {
    if (s.exists("s0"))
      s.remove("s0");
    if (cell->systems[0]) {
      Setting& sys(s.add("s0", Setting::TypeGroup));
      sys.add("type", Setting::TypeString) = ns0type;
      if (cell->systems[0]->getOrientation() != -1)
        sys.add("orient", Setting::TypeInt) = cell->systems[0]->getOrientation();
      if (0 == strcmp(ns0type, "Capacitor"))
        sys.add("capacity", Setting::TypeInt) = (int)conf["edit"]["sys0_capacitance"];
      if (0 == strcmp(ns0type, "ShieldGenerator")) {
        sys.add("radius", Setting::TypeFloat) = (float)conf["edit"]["sys0_shield_radius"];
        sys.add("strength", Setting::TypeFloat) = (float)conf["edit"]["sys0_shield_strength"];
      }
      if (0 == strcmp(ns0type, "GatlingPlasmaBurstLauncher")) {
        sys.add("turbo", Setting::TypeBoolean) = (bool)conf["edit"]["sys0_gatling_turbo"];
      }
    }
  }

  if (sys1Mod) {
    if (s.exists("s1"))
      s.remove("s1");
    if (cell->systems[1]) {
      Setting& sys(s.add("s1", Setting::TypeGroup));
      sys.add("type", Setting::TypeString) = ns1type;
      if (cell->systems[1]->getOrientation() != -1)
        sys.add("orient", Setting::TypeInt) = cell->systems[1]->getOrientation();
      if (0 == strcmp(ns1type, "Capacitor"))
        sys.add("capacity", Setting::TypeInt) = (int)conf["edit"]["sys1_capacitance"];
      if (0 == strcmp(ns1type, "ShieldGenerator")) {
        sys.add("radius", Setting::TypeFloat) = (float)conf["edit"]["sys1_shield_radius"];
        sys.add("strength", Setting::TypeFloat) = (float)conf["edit"]["sys1_shield_strength"];
      }
      if (0 == strcmp(ns1type, "GatlingPlasmaBurstLauncher")) {
        sys.add("turbo", Setting::TypeBoolean) = (bool)conf["edit"]["sys1_gatling_turbo"];
      }
    }
  }

  if (sys0Mod || sys1Mod)
    conf["edit"]["modified"] = true;

  //Delete backups
  if (s0) delete s0;
  if (s1) delete s1;
  //Forse re-inventory of ship shields (and other infos)
  ship->physicsClear(PHYS_SHIP_ALL | PHYS_CELL_ALL);

  return error;
}
<|endoftext|>


<commit_before>/*
 * CoreDecomposition.cpp
 *
 *  Created on: Oct 28, 2013
 *      Author: Lukas Barth, David Weiß, Christian Staudt
 *  Inplace change on Jun 26, 2015 by Henning Meyerhenke
 */

#include <set>

#include "CoreDecomposition.h"

namespace NetworKit {

CoreDecomposition::CoreDecomposition(const Graph& G) : Centrality(G, false), maxCore(0) {

}

void CoreDecomposition::run() {
	/* Main data structure: buckets of nodes indexed by their remaining degree. */
	typedef std::list<node> Bucket;
	index z = G.upperNodeIdBound();
	std::vector<Bucket> buckets(z);
	std::vector<Bucket::iterator> nodePtr(z);

	/* Current core and and computed scoreData values. */
	index core = std::numeric_limits<index>::max();
	scoreData.clear();
	scoreData.resize(z);

	std::vector<count> degree(z);       // tracks degree during algo
	std::vector<bool> alive(z, true);   // tracks if node is deleted (alive) or not
	count numAlive = G.numberOfNodes(); // tracks number of alive nodes

	/* Insert nodes into their initial buckets. */
	if (!G.isDirected()) {
		G.forNodes([&](node v) {
			count deg = G.degree(v);
			degree[v] = deg;
			buckets[deg].push_front(v);
			core = std::min(core, deg);
			nodePtr[v] = buckets[deg].begin();
		});
	} else {
		G.forNodes([&](node v) {
			count deg = G.degreeIn(v) + G.degreeOut(v); // TODO: Document this behavior for directed graph
			degree[v] = deg;
			buckets[deg].push_front(v);
			core = std::min(core, deg);
			nodePtr[v] = buckets[deg].begin();
		});

	}

	/* Main loop: Successively "remove" nodes by setting them not alive after processing them. */
	while (numAlive > 0) {
		Bucket& cur_bucket = buckets[core];

		/* Remove nodes with remaining degree <= core. */
		while (!cur_bucket.empty()) {
			/* scoreData for node u is current core value. */
			node u = cur_bucket.front();
			cur_bucket.pop_front();
			scoreData[u] = core;

			/* Remove u and its incident edges. */
			/* graph is undirected */
			if (!G.isDirected()) {
				G.forNeighborsOf(u, [&](node v) {
					count deg = degree[v];
					degree[v]--;

					/* Shift node v into new bucket.
					   Optimisation: Need not move to buckets < core. */
					if (deg > core) {
						buckets[deg].erase(nodePtr[v]);
						buckets[deg - 1].push_front(v);
						nodePtr[v] = buckets[deg - 1].begin();
					}
				});
			} else {
			/* graph is directed */
				G.forNeighborsOf(u, [&](node v) {
					count deg = degree[v];
					degree[v]--;

					/* Shift node v into new bucket.
					   Optimisation: Need not move to buckets < core. */
					if (deg > core) {
						buckets[deg].erase(nodePtr[v]);
						buckets[deg - 1].push_front(v);
						nodePtr[v] = buckets[deg - 1].begin();
					}
				});
				G.forInNeighborsOf(u, [&](node u, node v) {
					count deg = degree[v];
					degree[v]--;

					/* Shift node v into new bucket.
					   Optimisation: Need not move to buckets < core. */
					if (deg > core) {
						buckets[deg].erase(nodePtr[v]);
						buckets[deg - 1].push_front(v);
						nodePtr[v] = buckets[deg - 1].begin();
					}
				});
			}

			// "delete" current node
			alive[u] = false;
			--numAlive;
		}
		core++;
	}

	maxCore = core - 1;

	// TODO: shift the following to the respective getters

	// initialize Partition
	if (shellData.numberOfElements() != z) {
		shellData = Partition(z);
		shellData.allToSingletons();
	}
	// enter values from scoreData into shellData
	G.forNodes([&](node u){
		shellData.moveToSubset((index) scoreData[u], (index) u);
	});

	// initialize Cover
	if (coverData.numberOfElements() != z) {
		coverData = Cover(z);
		coverData.setUpperBound(z);
	}

	// enter values from scoreData into coverData
	G.forNodes([&](node u) {
		index k = 0;
		while (scoreData[u] >= k) {
			coverData.addToSubset((index) k, (index) u);
			++k;
		}
	});

	hasRun = true;
}

Cover CoreDecomposition::cores() const {
	if (! hasRun) throw std::runtime_error("call run method first");
	return coverData;
}

Partition CoreDecomposition::shells() const {
	if (! hasRun) throw std::runtime_error("call run method first");
	return shellData;
}

index CoreDecomposition::maxCoreNumber() const {
	if (! hasRun) throw std::runtime_error("call run method first");
	return maxCore;
}

} /* namespace NetworKit */
<commit_msg>k-core dec. without graph copies<commit_after>/*
 * CoreDecomposition.cpp
 *
 *  Created on: Oct 28, 2013
 *      Author: Lukas Barth, David Weiß, Christian Staudt
 *  Inplace change on Jun 26, 2015 by Henning Meyerhenke
 */

#include <set>

#include "CoreDecomposition.h"

namespace NetworKit {

CoreDecomposition::CoreDecomposition(const Graph& G) : Centrality(G, false), maxCore(0) {

}

void CoreDecomposition::run() {
	/* Main data structure: buckets of nodes indexed by their remaining degree. */
	typedef std::list<node> Bucket;
	index z = G.upperNodeIdBound();
	std::vector<Bucket> buckets(z);
	std::vector<Bucket::iterator> nodePtr(z);

	/* Current core and and computed scoreData values. */
	index core = std::numeric_limits<index>::max();
	scoreData.clear();
	scoreData.resize(z);

	std::vector<count> degree(z);       // tracks degree during algo
	std::vector<bool> alive(z, true);   // tracks if node is deleted (alive) or not
	count numAlive = G.numberOfNodes(); // tracks number of alive nodes

	/* Insert nodes into their initial buckets. */
	if (!G.isDirected()) {
		G.forNodes([&](node v) {
			count deg = G.degree(v);
			degree[v] = deg;
			buckets[deg].push_front(v);
			core = std::min(core, deg);
			nodePtr[v] = buckets[deg].begin();
		});
	} else {
		G.forNodes([&](node v) {
			count deg = G.degreeIn(v) + G.degreeOut(v); // TODO: Document this behavior for directed graph
			degree[v] = deg;
			buckets[deg].push_front(v);
			core = std::min(core, deg);
			nodePtr[v] = buckets[deg].begin();
		});

	}

	/* Main loop: Successively "remove" nodes by setting them not alive after processing them. */
	while (numAlive > 0) {
		Bucket& cur_bucket = buckets[core];

		/* Remove nodes with remaining degree <= core. */
		while (!cur_bucket.empty()) {
			/* scoreData for node u is current core value. */
			node u = cur_bucket.front();
			cur_bucket.pop_front();
			scoreData[u] = core;

			/* Remove u and its incident edges. */
			/* graph is undirected */
			if (!G.isDirected()) {
				G.forNeighborsOf(u, [&](node v) {
					if (alive[v]) {
						count deg = degree[v];
						degree[v]--;

						/* Shift node v into new bucket.
					   Optimisation: Need not move to buckets < core. */
						if (deg > core) {
							buckets[deg].erase(nodePtr[v]);
							buckets[deg - 1].push_front(v);
							nodePtr[v] = buckets[deg - 1].begin();
						}
					}
				});
			} else {
			/* graph is directed */
				G.forNeighborsOf(u, [&](node v) {
					if (alive[v]) {
						count deg = degree[v];
						degree[v]--;

						/* Shift node v into new bucket.
					   Optimisation: Need not move to buckets < core. */
						if (deg > core) {
							buckets[deg].erase(nodePtr[v]);
							buckets[deg - 1].push_front(v);
							nodePtr[v] = buckets[deg - 1].begin();
						}
					}
				});
				G.forInNeighborsOf(u, [&](node u, node v) {
					if (alive[v]) {
						count deg = degree[v];
						degree[v]--;

						/* Shift node v into new bucket.
					   Optimisation: Need not move to buckets < core. */
						if (deg > core) {
							buckets[deg].erase(nodePtr[v]);
							buckets[deg - 1].push_front(v);
							nodePtr[v] = buckets[deg - 1].begin();
						}
					}
				});
			}

			// "delete" current node
			alive[u] = false;
			--numAlive;
		}
		core++;
	}

	maxCore = core - 1;

	// TODO: shift the following to the respective getters

	// initialize Partition
	if (shellData.numberOfElements() != z) {
		shellData = Partition(z);
		shellData.allToSingletons();
	}
	// enter values from scoreData into shellData
	G.forNodes([&](node u){
		shellData.moveToSubset((index) scoreData[u], (index) u);
	});

	// initialize Cover
	if (coverData.numberOfElements() != z) {
		coverData = Cover(z);
		coverData.setUpperBound(z);
	}

	// enter values from scoreData into coverData
	G.forNodes([&](node u) {
		index k = 0;
		while (scoreData[u] >= k) {
			coverData.addToSubset((index) k, (index) u);
			++k;
		}
	});

	hasRun = true;
}

Cover CoreDecomposition::cores() const {
	if (! hasRun) throw std::runtime_error("call run method first");
	return coverData;
}

Partition CoreDecomposition::shells() const {
	if (! hasRun) throw std::runtime_error("call run method first");
	return shellData;
}

index CoreDecomposition::maxCoreNumber() const {
	if (! hasRun) throw std::runtime_error("call run method first");
	return maxCore;
}

} /* namespace NetworKit */
<|endoftext|>


<commit_before>// Copyright (c) 2016, LAAS-CNRS
// Authors: Pierre Fernbach (pierre.fernbach@laas.fr)
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

# include <hpp/core/steering-method/steering-kinodynamic.hh>

# include <hpp/model/device.hh>
# include <hpp/model/joint.hh>
# include <hpp/core/problem.hh>
# include <hpp/core/weighed-distance.hh>
# include <hpp/core/kinodynamic-path.hh>

namespace hpp {
  namespace core {
    namespace steeringMethod {
      PathPtr_t Kinodynamic::impl_compute (ConfigurationIn_t q1,
                                           ConfigurationIn_t q2) const
      {
        double Tmax = 0;
        double T = 0;
        double t1,tv,t2,a1;
        int sigma;

        size_type configSize = problem_->robot()->configSize() - problem_->robot()->extraConfigSpace().dimension ();
        // looking for Tmax
        hppDout(notice,"## Looking for Tmax :");
        /*const JointVector_t& jv (problem_->robot()->getJointVector ());
        for (model::JointVector_t::const_iterator itJoint = jv.begin (); itJoint != jv.end (); itJoint++) {
          size_type indexConfig = (*itJoint)->rankInConfiguration ();
          size_type indexVel = (*itJoint)->rankInVelocity() + configSize;
          hppDout(notice,"For joint "<<(*itJoint)->name());
          if((*itJoint)->configSize() >= 1){
            T = computeMinTime(q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&sigma,&t1,&tv,&t2);
            if(T > Tmax)
              Tmax = T;
          }

        }// for all joints*/

        for(int indexConfig = 0 ; indexConfig < configSize ; indexConfig++){
          size_type indexVel = indexConfig + configSize;
          hppDout(notice,"For joint :"<<problem_->robot()->getJointAtConfigRank(indexConfig)->name());
          if(problem_->robot()->getJointAtConfigRank(indexConfig)->name() != "base_joint_SO3"){
            T = computeMinTime(q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&sigma,&t1,&tv,&t2);
            if(T > Tmax)
              Tmax = T;
          }else{
            hppDout(notice,"!! Steering method for quaternion not implemented yet.");
          }

        }
        value_type length = Tmax;
        // create array of times intervals and acceleration values:
        Configuration_t a1_t(configSize);
        Configuration_t t1_t(configSize);
        Configuration_t t2_t(configSize);
        Configuration_t tv_t(configSize);

        // compute trajectory with fixed time T found
        /*for (model::JointVector_t::const_iterator itJoint = jv.begin (); itJoint != jv.end (); itJoint++) {
          size_type indexConfig = (*itJoint)->rankInConfiguration ();
          size_type indexVel = (*itJoint)->rankInVelocity() + configSize;
          hppDout(notice,"For joint "<<(*itJoint)->name());
          if((*itJoint)->configSize() >= 1){
            fixedTimeTrajectory(Tmax,q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&a1,&t1,&tv,&t2);
            a1_t[indexConfig]=a1;
            t1_t[indexConfig]=t1;
            tv_t[indexConfig]=tv;
            t2_t[indexConfig]=t2;
          }

        }// for all joints
        */
        for(int indexConfig = 0 ; indexConfig < configSize ; indexConfig++){
          size_type indexVel = indexConfig + configSize;
          hppDout(notice,"For joint :"<<problem_->robot()->getJointAtConfigRank(indexConfig)->name());
          if(problem_->robot()->getJointAtConfigRank(indexConfig)->name() != "base_joint_SO3"){
            fixedTimeTrajectory(Tmax,q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&a1,&t1,&tv,&t2);
            a1_t[indexConfig]=a1;
            t1_t[indexConfig]=t1;
            tv_t[indexConfig]=tv;
            t2_t[indexConfig]=t2;
          }else{
            hppDout(notice,"!! Steering method for quaternion not implemented yet.");
            a1_t[indexConfig]=0;
            t1_t[indexConfig]=0;
            tv_t[indexConfig]=0;
            t2_t[indexConfig]=0;
          }
        }

        KinodynamicPathPtr_t path = KinodynamicPath::create (device_.lock (), q1, q2,length,a1_t,t1_t,tv_t,t2_t,vMax_);
        return path;
      }

      Kinodynamic::Kinodynamic (const Problem& problem) :
        SteeringMethod (problem), device_ (problem.robot ()), weak_ ()
      {
        if((2*(problem.robot()->extraConfigSpace().dimension())) < problem.robot()->configSize()){
          std::cout<<"Error : you need at least "<<problem.robot()->configSize()-problem.robot()->extraConfigSpace().dimension()<<" extra DOF"<<std::endl;
          hppDout(error,"Error : you need at least "<<problem.robot()->configSize() - problem.robot()->extraConfigSpace().dimension()<<" extra DOF");
        }
        aMax_ = 0.5;
        vMax_ = 2;
      }

      /// Copy constructor
      Kinodynamic::Kinodynamic (const Kinodynamic& other) :
        SteeringMethod (other), device_ (other.device_)
      {
      }

      double Kinodynamic::computeMinTime(double p1, double p2, double v1, double v2, int *sigma, double *t1, double *tv, double *t2) const{
        hppDout(info,"p1 = "<<p1<<"  p2 = "<<p2<<"   ; v1 = "<<v1<<"    v2 = "<<v2);
        // compute the sign of each acceleration
        double deltaPacc = 0.5*(v1+v2)*(fabs(v2-v1)/aMax_);
        *sigma = sgn(p2-p1-deltaPacc);
        hppDout(info,"sigma = "<<*sigma);
        double a1 = (*sigma)*aMax_;
        double a2 = -a1;
        double vLim = (*sigma) * vMax_;
        hppDout(info,"Vlim = "<<vLim<<"   ;  aMax = "<<aMax_);
        if(*sigma == 0 ){
          hppDout(notice,"No movement in this joints, abort.");
          return 0.;
        }
        // test if two segment trajectory is valid :
        bool twoSegment = false;
        hppDout(info,"inf bound on t1 (from t2 > 0) "<<-((v2-v1)/a2));
        double minT1 = std::max(0.,-((v2-v1)/a2));  //lower bound for valid t1 value
        // solve quadratic equation
        const double a = a1;
        const double b = 2. * v1;
        const double c = (0.5*(v1+v2)*(v2-v1)/a2) - (p2-p1);
        const double delta = b*b - 4*a*c;
        if(delta < 0 )
          std::cout<<"Error : determinant of quadratic function negative"<<std::endl;
        double x1 = (-b + sqrt(delta))/(2*a);
        double x2 = (-b - sqrt(delta))/(2*a);
        double x = std::max(x1,x2);
        hppDout(info,"t1 before vel limit = "<<x);
        if(x > minT1){
          twoSegment = true;
          *t1 = x;
        }

        if(twoSegment){ // check if max velocity is respected
          if(std::abs(v1+(*t1)*a1) > vMax_)
            twoSegment = false;
        }

        if(twoSegment){ // compute t2 for two segment trajectory
          *tv = 0.;
          *t2 = ((v2-v1)/a2) + (*t1);
        }else{// compute 3 segment trajectory, with constant velocity phase :
          *t1 = (vLim - v1)/a1;
          *tv = ((v1*v1+v2*v2 - 2*vLim*vLim)/(2*vLim*a1)) + (p2-p1)/vLim ;
          *t2 = (v2-vLim)/a2;
          hppDout(info,"test 1 "<<(v1*v1+v2*v2 - 2*vLim*vLim));
          hppDout(info,"test 2 "<<((v1*v1+v2*v2 - 2*vLim*vLim)/(2*vLim*a1)));
          hppDout(info,"test 3 "<<((p2-p1)/vLim));

        }
        if(twoSegment){
          hppDout(notice,"Trajectory with 2 segments");
        }else{
          hppDout(notice,"Trajectory with 3 segments");
        }
        hppDout(notice,"a1 = "<<a1<<"  ;  a2 ="<<a2);
        hppDout(notice,"t = "<<(*t1)<<"   ;   "<<(*tv)<<"   ;   "<<(*t2));
        double T = (*t1)+(*tv)+(*t2);
        hppDout(notice,"T = "<<T);
        return T;
      }

      void Kinodynamic::fixedTimeTrajectory(double T, double p1, double p2, double v1, double v2, double *a1, double *t1, double *tv, double *t2) const{
        hppDout(info,"p1 = "<<p1<<"  p2 = "<<p2<<"   ; v1 = "<<v1<<"    v2 = "<<v2);
        double v12 = v1+v2;
        double v2_1 = v2-v1;
        double p2_1 = p2-p1;
        hppDout(info,"v12 = "<<v12<<"   ; v21 = "<<v2_1<<"   ; p21 = "<<p2_1);

        if(v2_1 == 0 && p2_1 == 0){
          *a1 = 0;
          *t1 = 0;
          *tv = 0;
          *t2 = 0;
          return;
        }
        double a2;
        double delta;
        delta = 4*T*T*(v12*v12+v2_1*v2_1) - 16*T*v12*p2_1 + 16*p2_1*p2_1;
        if(delta < 0 )
          std::cout<<"Error : determinant of quadratic function negative"<<std::endl;
        double b = 2*T*v12-4*p2_1;
        double a_2 = 2*T*T;

        double x1= (-b-sqrt(delta))/a_2;
        double x2= (-b+sqrt(delta))/a_2;
        hppDout(info,"b = "<<b<<"   ;  2*a = "<<a_2);
        hppDout(info,"delta = "<<delta<<"    ; x1 = "<<x1 << "   ;  x2 = "<<x2);
        if(std::abs(x1)>std::abs(x2)){
          *a1 = x1;
        }else{
          *a1 = x2;
        }
        a2 = -(*a1);

        *t1 = 0.5*((v2_1/(*a1))+T);
        double vLim = sgn((*a1))*vMax_;
        if(std::abs(v1+(*t1)*(*a1)) <= vMax_){  // two segment trajectory
          hppDout(notice,"Trajectory with 2 segments");
          *t2 = T - (*t1);
          *tv = 0.;
        }else{ // three segment trajectory
          hppDout(notice,"Trajectory with 3 segments");
          // adjust acceleration :
          *a1 = ((vLim - v1)*(vLim - v1) + (vLim - v2)*(vLim - v2))/(2*(vLim*T- p2_1));
          a2 = -(*a1);
          // compute new time intervals :
          *t1 = (vLim - v1)/(*a1);
          *tv = (v1*v1+v2*v2-2*vLim*vLim)/(2*vLim*(*a1)) + (p2-p1)/vLim ;
          *t2 = (v2-vLim)/(a2);
        }

        hppDout(notice,"a1 = "<<*a1<<"  ;  a2 ="<<a2);
        hppDout(notice,"t = "<<(*t1)<<"   ;   "<<(*tv)<<"   ;   "<<(*t2));

      }

    } // namespace steeringMethod
  } // namespace core
} // namespace hpp

<commit_msg>need fix : when sigma == 0<commit_after>// Copyright (c) 2016, LAAS-CNRS
// Authors: Pierre Fernbach (pierre.fernbach@laas.fr)
//
// This file is part of hpp-core.
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core. If not, see <http://www.gnu.org/licenses/>.

# include <hpp/core/steering-method/steering-kinodynamic.hh>

# include <hpp/model/device.hh>
# include <hpp/model/joint.hh>
# include <hpp/core/problem.hh>
# include <hpp/core/weighed-distance.hh>
# include <hpp/core/kinodynamic-path.hh>

namespace hpp {
  namespace core {
    namespace steeringMethod {
      PathPtr_t Kinodynamic::impl_compute (ConfigurationIn_t q1,
                                           ConfigurationIn_t q2) const
      {
        double Tmax = 0;
        double T = 0;
        double t1,tv,t2,a1;
        int sigma;

        size_type configSize = problem_->robot()->configSize() - problem_->robot()->extraConfigSpace().dimension ();
        // looking for Tmax
        hppDout(notice,"## Looking for Tmax :");
        /*const JointVector_t& jv (problem_->robot()->getJointVector ());
        for (model::JointVector_t::const_iterator itJoint = jv.begin (); itJoint != jv.end (); itJoint++) {
          size_type indexConfig = (*itJoint)->rankInConfiguration ();
          size_type indexVel = (*itJoint)->rankInVelocity() + configSize;
          hppDout(notice,"For joint "<<(*itJoint)->name());
          if((*itJoint)->configSize() >= 1){
            T = computeMinTime(q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&sigma,&t1,&tv,&t2);
            if(T > Tmax)
              Tmax = T;
          }

        }// for all joints*/

        for(int indexConfig = 0 ; indexConfig < configSize ; indexConfig++){
          size_type indexVel = indexConfig + configSize;
          hppDout(notice,"For joint :"<<problem_->robot()->getJointAtConfigRank(indexConfig)->name());
          if(problem_->robot()->getJointAtConfigRank(indexConfig)->name() != "base_joint_SO3"){
            T = computeMinTime(q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&sigma,&t1,&tv,&t2);
            if(T > Tmax)
              Tmax = T;
          }else{
            hppDout(notice,"!! Steering method for quaternion not implemented yet.");
          }

        }
        value_type length = Tmax;
        // create array of times intervals and acceleration values:
        Configuration_t a1_t(configSize);
        Configuration_t t1_t(configSize);
        Configuration_t t2_t(configSize);
        Configuration_t tv_t(configSize);

        // compute trajectory with fixed time T found
        /*for (model::JointVector_t::const_iterator itJoint = jv.begin (); itJoint != jv.end (); itJoint++) {
          size_type indexConfig = (*itJoint)->rankInConfiguration ();
          size_type indexVel = (*itJoint)->rankInVelocity() + configSize;
          hppDout(notice,"For joint "<<(*itJoint)->name());
          if((*itJoint)->configSize() >= 1){
            fixedTimeTrajectory(Tmax,q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&a1,&t1,&tv,&t2);
            a1_t[indexConfig]=a1;
            t1_t[indexConfig]=t1;
            tv_t[indexConfig]=tv;
            t2_t[indexConfig]=t2;
          }

        }// for all joints
        */
        for(int indexConfig = 0 ; indexConfig < configSize ; indexConfig++){
          size_type indexVel = indexConfig + configSize;
          hppDout(notice,"For joint :"<<problem_->robot()->getJointAtConfigRank(indexConfig)->name());
          if(problem_->robot()->getJointAtConfigRank(indexConfig)->name() != "base_joint_SO3"){
            fixedTimeTrajectory(Tmax,q1[indexConfig],q2[indexConfig],q1[indexVel],q2[indexVel],&a1,&t1,&tv,&t2);
            a1_t[indexConfig]=a1;
            t1_t[indexConfig]=t1;
            tv_t[indexConfig]=tv;
            t2_t[indexConfig]=t2;
          }else{
            hppDout(notice,"!! Steering method for quaternion not implemented yet.");
            a1_t[indexConfig]=0;
            t1_t[indexConfig]=0;
            tv_t[indexConfig]=0;
            t2_t[indexConfig]=0;
          }
        }

        KinodynamicPathPtr_t path = KinodynamicPath::create (device_.lock (), q1, q2,length,a1_t,t1_t,tv_t,t2_t,vMax_);
        return path;
      }

      Kinodynamic::Kinodynamic (const Problem& problem) :
        SteeringMethod (problem), device_ (problem.robot ()), weak_ ()
      {
        if((2*(problem.robot()->extraConfigSpace().dimension())) < problem.robot()->configSize()){
          std::cout<<"Error : you need at least "<<problem.robot()->configSize()-problem.robot()->extraConfigSpace().dimension()<<" extra DOF"<<std::endl;
          hppDout(error,"Error : you need at least "<<problem.robot()->configSize() - problem.robot()->extraConfigSpace().dimension()<<" extra DOF");
        }
        aMax_ = 0.5;
        vMax_ = 2;
      }

      /// Copy constructor
      Kinodynamic::Kinodynamic (const Kinodynamic& other) :
        SteeringMethod (other), device_ (other.device_)
      {
      }

      double Kinodynamic::computeMinTime(double p1, double p2, double v1, double v2, int *sigma, double *t1, double *tv, double *t2) const{
        hppDout(info,"p1 = "<<p1<<"  p2 = "<<p2<<"   ; v1 = "<<v1<<"    v2 = "<<v2);
        // compute the sign of each acceleration
        double deltaPacc = 0.5*(v1+v2)*(fabs(v2-v1)/aMax_);
        *sigma = sgn(p2-p1-deltaPacc);  //TODO bug sigma == 0
        hppDout(info,"sigma = "<<*sigma);
        double a1 = (*sigma)*aMax_;
        double a2 = -a1;
        double vLim = (*sigma) * vMax_;
        hppDout(info,"Vlim = "<<vLim<<"   ;  aMax = "<<aMax_);
        if((p2-p1) == 0. && (v2-v1)==0. ){
          hppDout(notice,"No movement in this joints, abort.");
          return 0.;
        }
        // test if two segment trajectory is valid :
        bool twoSegment = false;
        hppDout(info,"inf bound on t1 (from t2 > 0) "<<-((v2-v1)/a2));
        double minT1 = std::max(0.,-((v2-v1)/a2));  //lower bound for valid t1 value
        // solve quadratic equation
        const double a = a1;
        const double b = 2. * v1;
        const double c = (0.5*(v1+v2)*(v2-v1)/a2) - (p2-p1);
        const double delta = b*b - 4*a*c;
        if(delta < 0 )
          std::cout<<"Error : determinant of quadratic function negative"<<std::endl;
        double x1 = (-b + sqrt(delta))/(2*a);
        double x2 = (-b - sqrt(delta))/(2*a);
        double x = std::max(x1,x2);
        hppDout(info,"t1 before vel limit = "<<x);
        if(x > minT1){
          twoSegment = true;
          *t1 = x;
        }

        if(twoSegment){ // check if max velocity is respected
          if(std::abs(v1+(*t1)*a1) > vMax_)
            twoSegment = false;
        }

        if(twoSegment){ // compute t2 for two segment trajectory
          *tv = 0.;
          *t2 = ((v2-v1)/a2) + (*t1);
        }else{// compute 3 segment trajectory, with constant velocity phase :
          *t1 = (vLim - v1)/a1;
          *tv = ((v1*v1+v2*v2 - 2*vLim*vLim)/(2*vLim*a1)) + (p2-p1)/vLim ;
          *t2 = (v2-vLim)/a2;
          hppDout(info,"test 1 "<<(v1*v1+v2*v2 - 2*vLim*vLim));
          hppDout(info,"test 2 "<<((v1*v1+v2*v2 - 2*vLim*vLim)/(2*vLim*a1)));
          hppDout(info,"test 3 "<<((p2-p1)/vLim));

        }
        if(twoSegment){
          hppDout(notice,"Trajectory with 2 segments");
        }else{
          hppDout(notice,"Trajectory with 3 segments");
        }
        hppDout(notice,"a1 = "<<a1<<"  ;  a2 ="<<a2);
        hppDout(notice,"t = "<<(*t1)<<"   ;   "<<(*tv)<<"   ;   "<<(*t2));
        double T = (*t1)+(*tv)+(*t2);
        hppDout(notice,"T = "<<T);
        return T;
      }

      void Kinodynamic::fixedTimeTrajectory(double T, double p1, double p2, double v1, double v2, double *a1, double *t1, double *tv, double *t2) const{
        hppDout(info,"p1 = "<<p1<<"  p2 = "<<p2<<"   ; v1 = "<<v1<<"    v2 = "<<v2);
        double v12 = v1+v2;
        double v2_1 = v2-v1;
        double p2_1 = p2-p1;
        hppDout(info,"v12 = "<<v12<<"   ; v21 = "<<v2_1<<"   ; p21 = "<<p2_1);

        if(v2_1 == 0 && p2_1 == 0){
          *a1 = 0;
          *t1 = 0;
          *tv = 0;
          *t2 = 0;
          return;
        }
        double a2;
        double delta;
        delta = 4*T*T*(v12*v12+v2_1*v2_1) - 16*T*v12*p2_1 + 16*p2_1*p2_1;
        if(delta < 0 )
          std::cout<<"Error : determinant of quadratic function negative"<<std::endl;
        double b = 2*T*v12-4*p2_1;
        double a_2 = 2*T*T;

        double x1= (-b-sqrt(delta))/a_2;
        double x2= (-b+sqrt(delta))/a_2;
        hppDout(info,"b = "<<b<<"   ;  2*a = "<<a_2);
        hppDout(info,"delta = "<<delta<<"    ; x1 = "<<x1 << "   ;  x2 = "<<x2);
        if(std::abs(x1)>std::abs(x2)){
          *a1 = x1;
        }else{
          *a1 = x2;
        }
        a2 = -(*a1);

        *t1 = 0.5*((v2_1/(*a1))+T);
        double vLim = sgn((*a1))*vMax_;
        if(std::abs(v1+(*t1)*(*a1)) <= vMax_){  // two segment trajectory
          hppDout(notice,"Trajectory with 2 segments");
          *t2 = T - (*t1);
          *tv = 0.;
        }else{ // three segment trajectory
          hppDout(notice,"Trajectory with 3 segments");
          // adjust acceleration :
          *a1 = ((vLim - v1)*(vLim - v1) + (vLim - v2)*(vLim - v2))/(2*(vLim*T- p2_1));
          a2 = -(*a1);
          // compute new time intervals :
          *t1 = (vLim - v1)/(*a1);
          *tv = (v1*v1+v2*v2-2*vLim*vLim)/(2*vLim*(*a1)) + (p2-p1)/vLim ;
          *t2 = (v2-vLim)/(a2);
        }

        hppDout(notice,"a1 = "<<*a1<<"  ;  a2 ="<<a2);
        hppDout(notice,"t = "<<(*t1)<<"   ;   "<<(*tv)<<"   ;   "<<(*t2));

      }

    } // namespace steeringMethod
  } // namespace core
} // namespace hpp

<|endoftext|>


<commit_before><commit_msg>Changes CellIDEncoder syntax in ../src/modules/LCIOWriter/LCIOWriterModule.cpp<commit_after><|endoftext|>