<commit_before>// Copyright (c) 2009 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 <string.h>
#include <iostream>

#include "chrome/browser/thumbnail_store.h"

#include "base/time.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/gfx/jpeg_codec.h"
#include "base/path_service.h"
#include "base/ref_counted.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/ref_counted_util.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"

inline unsigned int diff(unsigned int a, unsigned int b) {
  return a>b ? a-b : b-a;
}

class ThumbnailStoreTest : public testing::Test {
 public:
  ThumbnailStoreTest() : score1_(.5, true, false),
    url1_("http://www.google.com"), url2_("http://www.elgoog.com") {
  }
  ~ThumbnailStoreTest() {
  }

 protected:
  void SetUp();

  void TearDown() {
    file_util::Delete(file_path_.AppendASCII(url1_.host()), false);
    file_util::Delete(file_path_.AppendASCII(url2_.host()), false);
  }

  // Compute the max difference over all pixels for each RGBA component.
  void PrintPixelDiff(SkBitmap* image_a, SkBitmap* image_b);

  // The directory where ThumbnailStore will store data.
  FilePath file_path_;

  SkBitmap image_;
  scoped_refptr<RefCountedBytes> jpeg_image_;
  ThumbnailScore score1_, score2_;
  GURL url1_, url2_;
  base::Time time_;
};

void ThumbnailStoreTest::SetUp() {
  if (!file_util::GetTempDir(&file_path_))
    FAIL();

  // Delete any old thumbnail files if they exist.
  file_util::Delete(file_path_.AppendASCII(url1_.host()), false);
  file_util::Delete(file_path_.AppendASCII(url2_.host()), false);

  // image is the original SkBitmap representing the thumbnail
  image_ = *(JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));

  SkAutoLockPixels thumbnail_lock(image_);
  jpeg_image_ = new RefCountedBytes;
  JPEGCodec::Encode(
      reinterpret_cast<unsigned char*>(image_.getAddr32(0, 0)),
      JPEGCodec::FORMAT_BGRA, image_.width(),
      image_.height(),
      static_cast<int>(image_.rowBytes()), 90,
      &(jpeg_image_->data));
}

void ThumbnailStoreTest::PrintPixelDiff(SkBitmap* image_a, SkBitmap* image_b) {
  // Compute the maximum difference in each of the RGBA components across all
  // pixels between the retrieved SkBitmap and the original.  These
  // differences should be small since encoding was done at 90% before
  // writing to disk.

  if (image_a->height() != image_b->height() ||
      image_b->width() != image_b->width() ||
      image_a->rowBytes() != image_b->rowBytes())
    return;

  SkAutoLockPixels lock_a(*image_a);
  SkAutoLockPixels lock_b(*image_b);

  int ppr = image_a->rowBytesAsPixels();
  unsigned int *a, *b;
  unsigned int maxv[4];
  memset(maxv, 0, sizeof(maxv));

  for (int nrows = image_a->height()-1; nrows >= 0; nrows--) {
    a = image_a->getAddr32(0, nrows);
    b = image_b->getAddr32(0, nrows);
    for (int i = 0; i < ppr; i += 4) {
      for (int j = 0; j < 4; j++) {
        maxv[j] = std::max(diff(*(a+i) >> (j<<3) & 0xff,
                                *(b+i) >> (j<<3) & 0xff),
                           maxv[j]);
      }
    }
  }

  std::cout << "Max diff btwn original and encoded image (b,g,r,a) = ("
            << maxv[0] << ","
            << maxv[1] << ","
            << maxv[2] << ","
            << maxv[3] << ")" << std::endl;
}

// TODO(meelapshah) fix the leak in these tests and re-enable.
#if 0

TEST_F(ThumbnailStoreTest, RetrieveFromCache) {
  RefCountedBytes* read_image = NULL;
  scoped_refptr<ThumbnailStore> store = new ThumbnailStore;

  store->file_path_ = file_path_;
  store->cache_.reset(new ThumbnailStore::Cache);
  store->cache_initialized_ = true;

  // Retrieve a thumbnail/score for a nonexistent page.

  EXPECT_FALSE(store->GetPageThumbnail(url2_, &read_image));

  // Store a thumbnail into the cache and retrieve it.

  EXPECT_TRUE(store->SetPageThumbnail(url1_, image_, score1_, false));
  EXPECT_TRUE(store->GetPageThumbnail(url1_, &read_image));
  EXPECT_TRUE(score1_.Equals((*store->cache_)[url1_].second));
  EXPECT_TRUE(read_image->data.size() == jpeg_image_->data.size());
  EXPECT_EQ(0, memcmp(&read_image->data[0], &jpeg_image_->data[0],
                      jpeg_image_->data.size()));

  read_image->Release();
}

TEST_F(ThumbnailStoreTest, RetrieveFromDisk) {
  scoped_refptr<RefCountedBytes> read_image = new RefCountedBytes;
  scoped_refptr<ThumbnailStore> store = new ThumbnailStore;

  store->file_path_ = file_path_;
  store->cache_.reset(new ThumbnailStore::Cache);
  store->cache_initialized_ = true;

  // Store a thumbnail onto the disk and retrieve it.

  EXPECT_TRUE(store->SetPageThumbnail(url1_, image_, score1_, false));
  EXPECT_TRUE(store->WriteThumbnailToDisk(url1_));
  EXPECT_TRUE(store->GetPageThumbnailFromDisk(
      file_path_.AppendASCII(url1_.host()), &url2_, read_image, &score2_));
  read_image->AddRef();
  EXPECT_TRUE(url1_ == url2_);
  EXPECT_TRUE(score1_.Equals(score2_));
  EXPECT_TRUE(read_image->data.size() == jpeg_image_->data.size());
  EXPECT_EQ(0, memcmp(&read_image->data[0], &jpeg_image_->data[0],
                      jpeg_image_->data.size()));
}
#endif
<commit_msg>Fix memory leak in unit_tests<commit_after>// Copyright (c) 2009 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 <string.h>
#include <iostream>

#include "chrome/browser/thumbnail_store.h"

#include "base/time.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/gfx/jpeg_codec.h"
#include "base/path_service.h"
#include "base/ref_counted.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/ref_counted_util.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixelRef.h"

inline unsigned int diff(unsigned int a, unsigned int b) {
  return a>b ? a-b : b-a;
}

class ThumbnailStoreTest : public testing::Test {
 public:
  ThumbnailStoreTest() : score1_(.5, true, false),
    url1_("http://www.google.com"), url2_("http://www.elgoog.com") {
  }
  ~ThumbnailStoreTest() {
  }

 protected:
  void SetUp();

  void TearDown() {
    file_util::Delete(file_path_.AppendASCII(url1_.host()), false);
    file_util::Delete(file_path_.AppendASCII(url2_.host()), false);
  }

  // Compute the max difference over all pixels for each RGBA component.
  void PrintPixelDiff(SkBitmap* image_a, SkBitmap* image_b);

  // The directory where ThumbnailStore will store data.
  FilePath file_path_;

  scoped_ptr<SkBitmap> image_;
  scoped_refptr<RefCountedBytes> jpeg_image_;
  ThumbnailScore score1_, score2_;
  GURL url1_, url2_;
  base::Time time_;
};

void ThumbnailStoreTest::SetUp() {
  if (!file_util::GetTempDir(&file_path_))
    FAIL();

  // Delete any old thumbnail files if they exist.
  file_util::Delete(file_path_.AppendASCII(url1_.host()), false);
  file_util::Delete(file_path_.AppendASCII(url2_.host()), false);

  // image is the original SkBitmap representing the thumbnail
  image_.reset(JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));

  SkAutoLockPixels thumbnail_lock(*image_);
  jpeg_image_ = new RefCountedBytes;
  JPEGCodec::Encode(
      reinterpret_cast<unsigned char*>(image_->getAddr32(0, 0)),
      JPEGCodec::FORMAT_BGRA, image_->width(),
      image_->height(),
      static_cast<int>(image_->rowBytes()), 90,
      &(jpeg_image_->data));
}

void ThumbnailStoreTest::PrintPixelDiff(SkBitmap* image_a, SkBitmap* image_b) {
  // Compute the maximum difference in each of the RGBA components across all
  // pixels between the retrieved SkBitmap and the original.  These
  // differences should be small since encoding was done at 90% before
  // writing to disk.

  if (image_a->height() != image_b->height() ||
      image_b->width() != image_b->width() ||
      image_a->rowBytes() != image_b->rowBytes())
    return;

  SkAutoLockPixels lock_a(*image_a);
  SkAutoLockPixels lock_b(*image_b);

  int ppr = image_a->rowBytesAsPixels();
  unsigned int *a, *b;
  unsigned int maxv[4];
  memset(maxv, 0, sizeof(maxv));

  for (int nrows = image_a->height()-1; nrows >= 0; nrows--) {
    a = image_a->getAddr32(0, nrows);
    b = image_b->getAddr32(0, nrows);
    for (int i = 0; i < ppr; i += 4) {
      for (int j = 0; j < 4; j++) {
        maxv[j] = std::max(diff(*(a+i) >> (j<<3) & 0xff,
                                *(b+i) >> (j<<3) & 0xff),
                           maxv[j]);
      }
    }
  }

  std::cout << "Max diff btwn original and encoded image (b,g,r,a) = ("
            << maxv[0] << ","
            << maxv[1] << ","
            << maxv[2] << ","
            << maxv[3] << ")" << std::endl;
}

TEST_F(ThumbnailStoreTest, RetrieveFromCache) {
  RefCountedBytes* read_image = NULL;
  scoped_refptr<ThumbnailStore> store = new ThumbnailStore;

  store->file_path_ = file_path_;
  store->cache_.reset(new ThumbnailStore::Cache);
  store->cache_initialized_ = true;

  // Retrieve a thumbnail/score for a nonexistent page.

  EXPECT_FALSE(store->GetPageThumbnail(url2_, &read_image));

  // Store a thumbnail into the cache and retrieve it.

  EXPECT_TRUE(store->SetPageThumbnail(url1_, *image_, score1_, false));
  EXPECT_TRUE(store->GetPageThumbnail(url1_, &read_image));
  EXPECT_TRUE(score1_.Equals((*store->cache_)[url1_].second));
  EXPECT_TRUE(read_image->data.size() == jpeg_image_->data.size());
  EXPECT_EQ(0, memcmp(&read_image->data[0], &jpeg_image_->data[0],
                      jpeg_image_->data.size()));

  read_image->Release();
}

TEST_F(ThumbnailStoreTest, RetrieveFromDisk) {
  scoped_refptr<RefCountedBytes> read_image = new RefCountedBytes;
  scoped_refptr<ThumbnailStore> store = new ThumbnailStore;

  store->file_path_ = file_path_;
  store->cache_.reset(new ThumbnailStore::Cache);
  store->cache_initialized_ = true;

  // Store a thumbnail onto the disk and retrieve it.

  EXPECT_TRUE(store->SetPageThumbnail(url1_, *image_, score1_, false));
  EXPECT_TRUE(store->WriteThumbnailToDisk(url1_));
  EXPECT_TRUE(store->GetPageThumbnailFromDisk(
      file_path_.AppendASCII(url1_.host()), &url2_, read_image, &score2_));
  EXPECT_TRUE(url1_ == url2_);
  EXPECT_TRUE(score1_.Equals(score2_));
  EXPECT_TRUE(read_image->data.size() == jpeg_image_->data.size());
  EXPECT_EQ(0, memcmp(&read_image->data[0], &jpeg_image_->data[0],
                      jpeg_image_->data.size()));
}
<|endoftext|>


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

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/test/trace_event_analyzer.h"
#include "base/version.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/tracing.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/gpu/gpu_blacklist.h"
#include "content/browser/gpu/gpu_data_manager.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_switches.h"

namespace {

typedef uint32 GpuResultFlags;
#define EXPECT_NO_GPU_PROCESS         GpuResultFlags(0)
// Expect GPU process to be created.
#define EXPECT_GPU_PROCESS            GpuResultFlags(1<<0)
// Expect num_contexts_ to be created (onscreen or offscreen).
#define EXPECT_GPU_CONTEXTS           GpuResultFlags(1<<1)
// Expect a SwapBuffers to occur (see gles2_cmd_decoder.cc).
#define EXPECT_GPU_SWAP_BUFFERS       GpuResultFlags(1<<2)

class GpuFeatureTest : public InProcessBrowserTest {
 public:
  GpuFeatureTest()
      : num_contexts_(0),
        num_offscreen_contexts_(0) {}

  virtual void SetUpCommandLine(CommandLine* command_line) {
    // This enables DOM automation for tab contents.
    EnableDOMAutomation();
#if !defined(OS_MACOSX)
    CHECK(!command_line->HasSwitch(switches::kUseGL)) <<
        "kUseGL must not be set by test framework code!";
    command_line->AppendSwitchASCII(switches::kUseGL, "osmesa");
#endif
  }

  void SetupBlacklist(const std::string& json_blacklist) {
    scoped_ptr<Version> os_version(Version::GetVersionFromString("1.0"));
    GpuBlacklist* blacklist = new GpuBlacklist("1.0");

    ASSERT_TRUE(blacklist->LoadGpuBlacklist(
        json_blacklist, GpuBlacklist::kAllOs));
    GpuDataManager::GetInstance()->SetBuiltInGpuBlacklist(blacklist);
  }

  void RunTest(const FilePath& url, GpuResultFlags expectations) {
    using namespace trace_analyzer;

    FilePath test_path;
    PathService::Get(chrome::DIR_TEST_DATA, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("gpu"));
    test_path = test_path.Append(url);

    ASSERT_TRUE(file_util::PathExists(test_path))
        << "Missing test file: " << test_path.value();

    ASSERT_TRUE(tracing::BeginTracing("test_gpu"));

    ui_test_utils::DOMMessageQueue message_queue;
    // Have to use a new tab for the blacklist to work.
    ui_test_utils::NavigateToURLWithDisposition(
        browser(), net::FilePathToFileURL(test_path), NEW_FOREGROUND_TAB,
        ui_test_utils::BROWSER_TEST_NONE);
    // Wait for message indicating the test has finished running.
    ASSERT_TRUE(message_queue.WaitForMessage(NULL));

    std::string json_events;
    ASSERT_TRUE(tracing::EndTracing(&json_events));

    scoped_ptr<TraceAnalyzer> analyzer(TraceAnalyzer::Create(json_events));
    analyzer->AssociateBeginEndEvents();
    TraceAnalyzer::TraceEventVector events;

    size_t num_gpu_processes = (expectations & EXPECT_GPU_PROCESS) ? 1 : 0;
    analyzer->FindEvents(Query::MatchBeginName("OnGraphicsInfoCollected"),
                         &events);
    EXPECT_EQ(num_gpu_processes, events.size());

    // Check for context creation if expected:
    if (expectations & EXPECT_GPU_CONTEXTS) {
      analyzer->FindEvents(
          Query(EVENT_NAME) == Query::String("TryCreateGLContext"),
          &events);
      EXPECT_EQ(num_contexts_, events.size());
      analyzer->FindEvents(
          Query(EVENT_NAME) == Query::String("CreateGLContextSuccess"),
          &events);
      EXPECT_EQ(num_contexts_, events.size());
    }

    // Check for swap buffers if expected:
    if (expectations & EXPECT_GPU_SWAP_BUFFERS) {
      analyzer->FindEvents(
          Query(EVENT_NAME) == Query::String("SwapBuffers"),
          &events);
      EXPECT_GT(events.size(), size_t(0));
    }
  }

 protected:
  size_t num_contexts_;
  size_t num_offscreen_contexts_;
};

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, AcceleratedCompositingAllowed) {
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(flags.flags(), 0u);

  num_contexts_ = 1;
  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_GPU_PROCESS | EXPECT_GPU_SWAP_BUFFERS |
          EXPECT_GPU_CONTEXTS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, AcceleratedCompositingBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_compositing\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(
      flags.flags(),
      static_cast<uint32>(GpuFeatureFlags::kGpuFeatureAcceleratedCompositing));

  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, FLAKY_WebGLAllowed) {
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(flags.flags(), 0u);

  num_contexts_ = 2;
  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_GPU_PROCESS | EXPECT_GPU_SWAP_BUFFERS |
          EXPECT_GPU_CONTEXTS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"webgl\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(
      flags.flags(),
      static_cast<uint32>(GpuFeatureFlags::kGpuFeatureWebgl));

  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

#if defined(OS_LINUX)
// http://crbug.com/104142
#define Canvas2DAllowed FLAKY_Canvas2DAllowed
#endif
IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DAllowed) {
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(flags.flags(), 0u);

#if defined(OS_MACOSX)
  // TODO(zmo): enabling Mac when skia backend is enabled.
  const GpuResultFlags expectations = EXPECT_NO_GPU_PROCESS;
#else
  num_contexts_ = 2;
  const GpuResultFlags expectations = EXPECT_GPU_PROCESS |
                                      EXPECT_GPU_SWAP_BUFFERS |
                                      EXPECT_GPU_CONTEXTS;
#endif
  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, expectations);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_2d_canvas\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(
      flags.flags(),
      static_cast<uint32>(GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas));

  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

}  // namespace anonymous

<commit_msg>Disable AcceleratedCompositingAllowed.AcceleratedCompositingAllowed on Chrome OS for now.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/test/trace_event_analyzer.h"
#include "base/version.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/tracing.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/gpu/gpu_blacklist.h"
#include "content/browser/gpu/gpu_data_manager.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_switches.h"

namespace {

typedef uint32 GpuResultFlags;
#define EXPECT_NO_GPU_PROCESS         GpuResultFlags(0)
// Expect GPU process to be created.
#define EXPECT_GPU_PROCESS            GpuResultFlags(1<<0)
// Expect num_contexts_ to be created (onscreen or offscreen).
#define EXPECT_GPU_CONTEXTS           GpuResultFlags(1<<1)
// Expect a SwapBuffers to occur (see gles2_cmd_decoder.cc).
#define EXPECT_GPU_SWAP_BUFFERS       GpuResultFlags(1<<2)

class GpuFeatureTest : public InProcessBrowserTest {
 public:
  GpuFeatureTest()
      : num_contexts_(0),
        num_offscreen_contexts_(0) {}

  virtual void SetUpCommandLine(CommandLine* command_line) {
    // This enables DOM automation for tab contents.
    EnableDOMAutomation();
#if !defined(OS_MACOSX)
    CHECK(!command_line->HasSwitch(switches::kUseGL)) <<
        "kUseGL must not be set by test framework code!";
    command_line->AppendSwitchASCII(switches::kUseGL, "osmesa");
#endif
  }

  void SetupBlacklist(const std::string& json_blacklist) {
    scoped_ptr<Version> os_version(Version::GetVersionFromString("1.0"));
    GpuBlacklist* blacklist = new GpuBlacklist("1.0");

    ASSERT_TRUE(blacklist->LoadGpuBlacklist(
        json_blacklist, GpuBlacklist::kAllOs));
    GpuDataManager::GetInstance()->SetBuiltInGpuBlacklist(blacklist);
  }

  void RunTest(const FilePath& url, GpuResultFlags expectations) {
    using namespace trace_analyzer;

    FilePath test_path;
    PathService::Get(chrome::DIR_TEST_DATA, &test_path);
    test_path = test_path.Append(FILE_PATH_LITERAL("gpu"));
    test_path = test_path.Append(url);

    ASSERT_TRUE(file_util::PathExists(test_path))
        << "Missing test file: " << test_path.value();

    ASSERT_TRUE(tracing::BeginTracing("test_gpu"));

    ui_test_utils::DOMMessageQueue message_queue;
    // Have to use a new tab for the blacklist to work.
    ui_test_utils::NavigateToURLWithDisposition(
        browser(), net::FilePathToFileURL(test_path), NEW_FOREGROUND_TAB,
        ui_test_utils::BROWSER_TEST_NONE);
    // Wait for message indicating the test has finished running.
    ASSERT_TRUE(message_queue.WaitForMessage(NULL));

    std::string json_events;
    ASSERT_TRUE(tracing::EndTracing(&json_events));

    scoped_ptr<TraceAnalyzer> analyzer(TraceAnalyzer::Create(json_events));
    analyzer->AssociateBeginEndEvents();
    TraceAnalyzer::TraceEventVector events;

    size_t num_gpu_processes = (expectations & EXPECT_GPU_PROCESS) ? 1 : 0;
    analyzer->FindEvents(Query::MatchBeginName("OnGraphicsInfoCollected"),
                         &events);
    EXPECT_EQ(num_gpu_processes, events.size());

    // Check for context creation if expected:
    if (expectations & EXPECT_GPU_CONTEXTS) {
      analyzer->FindEvents(
          Query(EVENT_NAME) == Query::String("TryCreateGLContext"),
          &events);
      EXPECT_EQ(num_contexts_, events.size());
      analyzer->FindEvents(
          Query(EVENT_NAME) == Query::String("CreateGLContextSuccess"),
          &events);
      EXPECT_EQ(num_contexts_, events.size());
    }

    // Check for swap buffers if expected:
    if (expectations & EXPECT_GPU_SWAP_BUFFERS) {
      analyzer->FindEvents(
          Query(EVENT_NAME) == Query::String("SwapBuffers"),
          &events);
      EXPECT_GT(events.size(), size_t(0));
    }
  }

 protected:
  size_t num_contexts_;
  size_t num_offscreen_contexts_;
};

#if defined(OS_CHROMEOS)
// http://crbug.com/106259
#define MAYBE_AcceleratedCompositingAllowed DISABLED_testSetBooleanPrefTriggers
#else
#define MAYBE_AcceleratedCompositingAllowed AcceleratedCompositingAllowed
#endif
IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MAYBE_AcceleratedCompositingAllowed) {
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(flags.flags(), 0u);

  num_contexts_ = 1;
  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_GPU_PROCESS | EXPECT_GPU_SWAP_BUFFERS |
          EXPECT_GPU_CONTEXTS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, AcceleratedCompositingBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_compositing\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(
      flags.flags(),
      static_cast<uint32>(GpuFeatureFlags::kGpuFeatureAcceleratedCompositing));

  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, FLAKY_WebGLAllowed) {
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(flags.flags(), 0u);

  num_contexts_ = 2;
  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_GPU_PROCESS | EXPECT_GPU_SWAP_BUFFERS |
          EXPECT_GPU_CONTEXTS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"webgl\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(
      flags.flags(),
      static_cast<uint32>(GpuFeatureFlags::kGpuFeatureWebgl));

  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

#if defined(OS_LINUX)
// http://crbug.com/104142
#define Canvas2DAllowed FLAKY_Canvas2DAllowed
#endif
IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DAllowed) {
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(flags.flags(), 0u);

#if defined(OS_MACOSX)
  // TODO(zmo): enabling Mac when skia backend is enabled.
  const GpuResultFlags expectations = EXPECT_NO_GPU_PROCESS;
#else
  num_contexts_ = 2;
  const GpuResultFlags expectations = EXPECT_GPU_PROCESS |
                                      EXPECT_GPU_SWAP_BUFFERS |
                                      EXPECT_GPU_CONTEXTS;
#endif
  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, expectations);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_2d_canvas\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureFlags flags = GpuDataManager::GetInstance()->GetGpuFeatureFlags();
  EXPECT_EQ(
      flags.flags(),
      static_cast<uint32>(GpuFeatureFlags::kGpuFeatureAccelerated2dCanvas));

  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

}  // namespace anonymous

<|endoftext|>


<commit_before>class Solution {
    public:
        void merge(int A[], int m, int B[], int n) {
            if(n == 0) return;
            for(unsigned int i = 0; i != m; ++i)
            {
                A[m + n - 1 - i] = A[m - 1 - i];
            }
            unsigned int startA = n, startB = 0, index = 0;
            while(startA != (m + n) && startB != n){
                if(A[startA] <= B[startB]){
                    A[index] = A[startA]; ++ startA; ++ index;
                }else{
                    A[index] = B[startB]; ++ startB; ++ index;
                }
            }
            while(startA != (m + n)){
                A[index] = A[startA]; ++ startA; ++index;
            }
            while(startB != n){
                A[index] = B[startB]; ++ startB; ++ index;
            }
        }
};
<commit_msg>simplify - merge-sort-array<commit_after>class Solution {
    public:
        void merge(int A[], int m, int B[], int n) {
            for(int i = m + n - 1; i != -1; --i){
                if(m <= 0)A[i] = B[--n];
                else if(n <= 0)break;
                else if(A[m-1] > B[n-1]) A[i] = A[--m];
                else A[i] = B[--n];
            }
        }
};
<|endoftext|>


<commit_before>// compare numerical result to analytic calculation for a 1D planar detector
using namespace GeFiCa;
void compare2analytic()
{
   // configure detector
   Planar1D *num = new Planar1D;
   num->V0=0*volt;
   num->V1=800*volt;
   num->Thickness=1*cm;
   num->SetAverageImpurity(1e10/cm3);

   // make a copy of the detector configuration
   Planar1D *ana = (Planar1D*) num->Clone("ana");

   // calculate potential using SOR method
   num->CalculatePotential(kSOR2);

   // fill grid with analytic result
   ana->CalculatePotential(kAnalytic);

   // prepare drawing style
   gROOT->SetStyle("Plain"); // pick up a good drawing style to modify
   gStyle->SetLegendBorderSize(0);
   gStyle->SetLegendFont(132);
   gStyle->SetLabelFont(132,"XY");
   gStyle->SetTitleFont(132,"XY");
   gStyle->SetLabelSize(0.05,"XY");
   gStyle->SetTitleSize(0.05,"XY");
   gStyle->SetPadRightMargin(0.01);
   gStyle->SetPadLeftMargin(0.12);
   gStyle->SetPadTopMargin(0.02);

   // generate graphics
   TTree *tn = num->GetTree();
   tn->Draw("v:c1");
   TGraph *gn = new TGraph(tn->GetSelectedRows(), tn->GetV2(), tn->GetV1());
   TTree *ta = ana->GetTree();
   ta->Draw("v:c1");
   TGraph *ga = new TGraph(ta->GetSelectedRows(), ta->GetV2(), ta->GetV1());

   // compare numerical result to analytic calculation
   gn->SetMarkerColor(kBlue);
   gn->SetMarkerStyle(kCircle);
   gn->SetMarkerSize(0.8);
   gn->SetTitle(";Thickness [cm];Potential [V]");
   gn->GetXaxis()->SetRangeUser(0,1);
   gn->GetYaxis()->SetRangeUser(0,800);
   //gn->GetYaxis()->SetTitleOffset(1.2);
   gn->Draw("ap");

   ga->SetLineColor(kRed);
   ga->Draw("l");

   TLegend *l = new TLegend(0.2,0.6,0.4,0.8);
   l->AddEntry(ga,"Analytic","l");
   l->AddEntry(gn,"SOR2","p");
   l->Draw();

   gPad->Print("planar1d.png");
}
<commit_msg>SOR2 -> SOR<commit_after>// compare numerical result to analytic calculation for a 1D planar detector
using namespace GeFiCa;
void compare2analytic()
{
   // configure detector
   Planar1D *num = new Planar1D;
   num->V0=0*volt;
   num->V1=800*volt;
   num->Thickness=1*cm;
   num->SetAverageImpurity(1e10/cm3);

   // make a copy of the detector configuration
   Planar1D *ana = (Planar1D*) num->Clone("ana");

   // calculate potential using SOR method
   num->CalculatePotential(kSOR2);

   // fill grid with analytic result
   ana->CalculatePotential(kAnalytic);

   // prepare drawing style
   gROOT->SetStyle("Plain"); // pick up a good drawing style to modify
   gStyle->SetLegendBorderSize(0);
   gStyle->SetLegendFont(132);
   gStyle->SetLabelFont(132,"XY");
   gStyle->SetTitleFont(132,"XY");
   gStyle->SetLabelSize(0.05,"XY");
   gStyle->SetTitleSize(0.05,"XY");
   gStyle->SetPadRightMargin(0.01);
   gStyle->SetPadLeftMargin(0.12);
   gStyle->SetPadTopMargin(0.02);

   // generate graphics
   TTree *tn = num->GetTree();
   tn->Draw("v:c1");
   TGraph *gn = new TGraph(tn->GetSelectedRows(), tn->GetV2(), tn->GetV1());
   TTree *ta = ana->GetTree();
   ta->Draw("v:c1");
   TGraph *ga = new TGraph(ta->GetSelectedRows(), ta->GetV2(), ta->GetV1());

   // compare numerical result to analytic calculation
   gn->SetMarkerColor(kBlue);
   gn->SetMarkerStyle(kCircle);
   gn->SetMarkerSize(0.8);
   gn->SetTitle(";Thickness [cm];Potential [V]");
   gn->GetXaxis()->SetRangeUser(0,1);
   gn->GetYaxis()->SetRangeUser(0,800);
   //gn->GetYaxis()->SetTitleOffset(1.2);
   gn->Draw("ap");

   ga->SetLineColor(kRed);
   ga->Draw("l");

   TLegend *l = new TLegend(0.2,0.6,0.4,0.8);
   l->AddEntry(ga,"Analytic","l");
   l->AddEntry(gn,"SOR","p");
   l->Draw();

   gPad->Print("planar1d.png");
}
<|endoftext|>


<commit_before>// Denoising using Fields of Experts [1]. This example problem also comes
// with Ceres Solver, a solver for nonlinear least squares problems and
// can be used for comparing the two solvers.
//
// [1] S. Roth and M.J. Black. “Fields of Experts.” International Journal of
//     Computer Vision, 82(2):205–229, 2009.

#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <sstream>
#include <string>

#include <spii/color.h>
#include <spii/solver.h>

// pgm_image uses Google Glog, specifically the
// CHECK macro.
#define CHECK(arg) spii_assert(arg)
#include "pgm_image.h"
using ceres::examples::PGMImage;

#include "fields_of_experts.h"

const double sigma = 20.0;

// This Term is used to build the data term.
//
//   f_i(x) = a · (x_i - b)^2
//
class QuadraticTerm
	: public spii::SizedTerm<1>
{
public:
	QuadraticTerm(double a_, double b_)
		  // 0.5 to agree with Ceres.
		: a{0.5 * a_}, b{b_}
	{ }

	double evaluate(double * const * const x) const override
	{
		return a * (x[0][0] - b) * (x[0][0] - b);
	}

	double evaluate(double * const * const x,
	                std::vector<Eigen::VectorXd>* gradient) const override
	{
		(*gradient)[0][0] = 2.0 * a * x[0][0] - 2.0 * a * b;
		return evaluate(x);
	}

	double evaluate(double * const * const x,
	                std::vector<Eigen::VectorXd>* gradient,
	                std::vector< std::vector<Eigen::MatrixXd> >* hessian) const override
	{
		(*hessian)[0][0](0, 0) = 2.0 * a;
		return evaluate(x, gradient);
	}

private:
	double a, b;
};

// Creates a Fields of Experts MAP function.
void create_functions(const FieldsOfExperts& foe,
                      const PGMImage<double>& image,
                      spii::Function* function,
                      PGMImage<double>* solution)
{
	// Create the data term
	const double coefficient = 1 / (2.0 * sigma * sigma);
	for (int index = 0; index < image.NumPixels(); ++index)
	{
		auto term =
			std::make_shared<QuadraticTerm>(coefficient,
			                                image.PixelFromLinearIndex(index));
		function->add_term(term, solution->MutablePixelFromLinearIndex(index));
	}

	// Create terms for regularization. One is needed for each filter.
	std::vector<std::shared_ptr<spii::Term>> foe_terms(foe.num_filters());
	for (int alpha_index = 0; alpha_index < foe.num_filters(); ++alpha_index) {
		foe_terms[alpha_index] = foe.new_term(alpha_index);
	}

	// Add FoE regularization for each patch in the image.
	for (int x = 0; x < image.width() - (foe.size() - 1); ++x) {
		for (int y = 0; y < image.height() - (foe.size() - 1); ++y) {
			// Build a vector with the pixel indices of this patch.
			std::vector<double*> pixels;
			const std::vector<int>& x_delta_indices = foe.get_x_delta_indices();
			const std::vector<int>& y_delta_indices = foe.get_y_delta_indices();
			for (int i = 0; i < foe.num_variables(); ++i) {
				double* pixel = solution->MutablePixel(x + x_delta_indices[i],
				                                       y + y_delta_indices[i]);
				pixels.push_back(pixel);
			}
			// For this patch with coordinates (x, y), we will add foe.NumFilters()
			// terms to the objective function.
			for (int alpha_index = 0; alpha_index < foe.num_filters(); ++alpha_index) {
				function->add_term(foe_terms[alpha_index],
				                   pixels);
			}
		}
	}
}

void minimize_function(const spii::Function& function, PGMImage<double>* solution)
{
	spii::LBFGSSolver solver;
	solver.function_improvement_tolerance = 1e-3;

	solver.maximum_iterations = 16;

	int iteration = 0;
	solver.callback_function =
		[&](const spii::CallbackInformation& info) -> bool
		{
			if (++iteration % 10 == 0) {
			// Uncomment to save solution every 10 iterations.
				//function.copy_global_to_user(*info.x);
				//std::stringstream sout;
				//sout << "output-" << iteration << ".pgm";
				//spii::check(solution->WriteToFile(sout.str()), "Writing failed.");
			}
			return true;
		};

	solver.log_function =
		[](const std::string& str)
		{
			std::cout << str << std::endl;
		};

	spii::SolverResults results;
	solver.solve(function, &results);

	function.print_timing_information(std::cout);
    std::cout << results << std::endl;

	// Make the solution stay in [0, 255].
	for (int x = 0; x < solution->width(); ++x) {
		for (int y = 0; y < solution->height(); ++y) {
			*solution->MutablePixel(x, y) =
				std::min(255.0, std::max(0.0, solution->Pixel(x, y)));
		}
	}
}

int main_function(int argc, char** argv)
{
	using namespace spii;
	using namespace std;

	auto foe_file_name = "2x2.foe";
	if (argc > 1) {
		foe_file_name = argv[1];
	}

	auto input_file_name = "ceres_noisy.pgm";
	if (argc > 2) {
		input_file_name = argv[2];
	}

	// Load the Fields of Experts filters from file.
	Timer foe_timer("Loading FoE file");
		FieldsOfExperts foe(foe_file_name);
	foe_timer.OK();

	// Read the images
	Timer image_timer("Loading images");
		PGMImage<double> image(input_file_name);
		check(image.width() > 0, "Reading input image failed.");
		PGMImage<double> solution(image.width(), image.height());
		solution.Set(0.0);
		solution += image;
	image_timer.OK();

	Timer function_timer("Creating function");
		spii::Function function;
		function.hessian_is_enabled = false;
		create_functions(foe, image, &function, &solution);
	function_timer.OK();

	cout << "Number of variables  : " << function.get_number_of_variables() << endl;
	cout << "Number of terms      : " << function.get_number_of_terms() << endl;
	cout << "Function value       : " << function.evaluate() << endl;

	minimize_function(function, &solution);

	cout << "Final function value : " << function.evaluate() << endl;

	Timer save_timer("Saving image");
		check(solution.WriteToFile("output-final.pgm"), "Writing failed.");
	save_timer.OK();

	return 0;
}

int main(int argc, char** argv)
{
	try {
		return main_function(argc, argv);
	}
	catch (std::exception& e) {
		std::cerr << "\nException: " << e.what() << std::endl;
	}
}
<commit_msg>More iterations in denoising example.<commit_after>// Denoising using Fields of Experts [1]. This example problem also comes
// with Ceres Solver, a solver for nonlinear least squares problems and
// can be used for comparing the two solvers.
//
// [1] S. Roth and M.J. Black. “Fields of Experts.” International Journal of
//     Computer Vision, 82(2):205–229, 2009.

#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <sstream>
#include <string>

#include <spii/color.h>
#include <spii/solver.h>

// pgm_image uses Google Glog, specifically the
// CHECK macro.
#define CHECK(arg) spii_assert(arg)
#include "pgm_image.h"
using ceres::examples::PGMImage;

#include "fields_of_experts.h"

const double sigma = 20.0;

// This Term is used to build the data term.
//
//   f_i(x) = a · (x_i - b)^2
//
class QuadraticTerm
	: public spii::SizedTerm<1>
{
public:
	QuadraticTerm(double a_, double b_)
		  // 0.5 to agree with Ceres.
		: a{0.5 * a_}, b{b_}
	{ }

	double evaluate(double * const * const x) const override
	{
		return a * (x[0][0] - b) * (x[0][0] - b);
	}

	double evaluate(double * const * const x,
	                std::vector<Eigen::VectorXd>* gradient) const override
	{
		(*gradient)[0][0] = 2.0 * a * x[0][0] - 2.0 * a * b;
		return evaluate(x);
	}

	double evaluate(double * const * const x,
	                std::vector<Eigen::VectorXd>* gradient,
	                std::vector< std::vector<Eigen::MatrixXd> >* hessian) const override
	{
		(*hessian)[0][0](0, 0) = 2.0 * a;
		return evaluate(x, gradient);
	}

private:
	double a, b;
};

// Creates a Fields of Experts MAP function.
void create_functions(const FieldsOfExperts& foe,
                      const PGMImage<double>& image,
                      spii::Function* function,
                      PGMImage<double>* solution)
{
	// Create the data term
	const double coefficient = 1 / (2.0 * sigma * sigma);
	for (int index = 0; index < image.NumPixels(); ++index)
	{
		auto term =
			std::make_shared<QuadraticTerm>(coefficient,
			                                image.PixelFromLinearIndex(index));
		function->add_term(term, solution->MutablePixelFromLinearIndex(index));
	}

	// Create terms for regularization. One is needed for each filter.
	std::vector<std::shared_ptr<spii::Term>> foe_terms(foe.num_filters());
	for (int alpha_index = 0; alpha_index < foe.num_filters(); ++alpha_index) {
		foe_terms[alpha_index] = foe.new_term(alpha_index);
	}

	// Add FoE regularization for each patch in the image.
	for (int x = 0; x < image.width() - (foe.size() - 1); ++x) {
		for (int y = 0; y < image.height() - (foe.size() - 1); ++y) {
			// Build a vector with the pixel indices of this patch.
			std::vector<double*> pixels;
			const std::vector<int>& x_delta_indices = foe.get_x_delta_indices();
			const std::vector<int>& y_delta_indices = foe.get_y_delta_indices();
			for (int i = 0; i < foe.num_variables(); ++i) {
				double* pixel = solution->MutablePixel(x + x_delta_indices[i],
				                                       y + y_delta_indices[i]);
				pixels.push_back(pixel);
			}
			// For this patch with coordinates (x, y), we will add foe.NumFilters()
			// terms to the objective function.
			for (int alpha_index = 0; alpha_index < foe.num_filters(); ++alpha_index) {
				function->add_term(foe_terms[alpha_index],
				                   pixels);
			}
		}
	}
}

void minimize_function(const spii::Function& function, PGMImage<double>* solution)
{
	spii::LBFGSSolver solver;
	solver.function_improvement_tolerance = 1e-3;

	solver.maximum_iterations = 1000;

	int iteration = 0;
	solver.callback_function =
		[&](const spii::CallbackInformation& info) -> bool
		{
			if (++iteration % 10 == 0) {
			// Uncomment to save solution every 10 iterations.
				//function.copy_global_to_user(*info.x);
				//std::stringstream sout;
				//sout << "output-" << iteration << ".pgm";
				//spii::check(solution->WriteToFile(sout.str()), "Writing failed.");
			}
			return true;
		};

	solver.log_function =
		[](const std::string& str)
		{
			std::cout << str << std::endl;
		};

	spii::SolverResults results;
	solver.solve(function, &results);

	function.print_timing_information(std::cout);
    std::cout << results << std::endl;

	// Make the solution stay in [0, 255].
	for (int x = 0; x < solution->width(); ++x) {
		for (int y = 0; y < solution->height(); ++y) {
			*solution->MutablePixel(x, y) =
				std::min(255.0, std::max(0.0, solution->Pixel(x, y)));
		}
	}
}

int main_function(int argc, char** argv)
{
	using namespace spii;
	using namespace std;

	auto foe_file_name = "2x2.foe";
	if (argc > 1) {
		foe_file_name = argv[1];
	}

	auto input_file_name = "ceres_noisy.pgm";
	if (argc > 2) {
		input_file_name = argv[2];
	}

	// Load the Fields of Experts filters from file.
	Timer foe_timer("Loading FoE file");
		FieldsOfExperts foe(foe_file_name);
	foe_timer.OK();

	// Read the images
	Timer image_timer("Loading images");
		PGMImage<double> image(input_file_name);
		check(image.width() > 0, "Reading input image failed.");
		PGMImage<double> solution(image.width(), image.height());
		solution.Set(0.0);
		solution += image;
	image_timer.OK();

	Timer function_timer("Creating function");
		spii::Function function;
		function.hessian_is_enabled = false;
		create_functions(foe, image, &function, &solution);
	function_timer.OK();

	cout << "Number of variables  : " << function.get_number_of_variables() << endl;
	cout << "Number of terms      : " << function.get_number_of_terms() << endl;
	cout << "Function value       : " << function.evaluate() << endl;

	minimize_function(function, &solution);

	cout << "Final function value : " << function.evaluate() << endl;

	Timer save_timer("Saving image");
		check(solution.WriteToFile("output-final.pgm"), "Writing failed.");
	save_timer.OK();

	return 0;
}

int main(int argc, char** argv)
{
	try {
		return main_function(argc, argv);
	}
	catch (std::exception& e) {
		std::cerr << "\nException: " << e.what() << std::endl;
	}
}
<|endoftext|>


<commit_before>//                       MFEM Example normal-bc - Parallel Version
//

/*
  higher order seems to work fine?
  3D also looks fine
  curved mesh does *not* seem to be working
  (not even for the mesh itself, but this may be VisIt and not MFEM)
  solver obviously still needs some serious work

  square-disc attributes (not indices):

  1: south external
  2: east external
  3: north external
  4: west external
  5: southeast internal
  6: northeast internal
  7: northwest internal
  8: southwest internal

  icf attributes (not indices):

  1: west side
  2: south side
  3: ???
  4: outer edge (circle constraint)
  5: some internal boundaries??

  sphere_hex27.mesh

  1: external boundary
*/

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

SparseMatrix * BuildConstraints(FiniteElementSpace& fespace, Array<int> constrained_att)
{
   int dim = fespace.GetVDim();

   std::set<int> constrained_dofs;
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         for (auto k : dofs)
         {
            constrained_dofs.insert(k);
         }
      }
   }

   std::map<int, int> dof_constraint;
   int n_constraints = 0;
   for (auto k : constrained_dofs)
   {
      dof_constraint[k] = n_constraints++;
   }
   SparseMatrix * out = new SparseMatrix(n_constraints, fespace.GetVSize());

   Vector nor(dim);
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         ElementTransformation * Tr = fespace.GetBdrElementTransformation(i);
         const FiniteElement * fe = fespace.GetBE(i);
         const IntegrationRule& nodes = fe->GetNodes();

         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         MFEM_VERIFY(dofs.Size() == nodes.Size(),
                     "Something wrong in finite element space!");

         for (int j = 0; j < dofs.Size(); ++j)
         {
            Tr->SetIntPoint(&nodes[j]);
            CalcOrtho(Tr->Jacobian(), nor); // this normal is scaled by h or something

            int k = dofs[j]; // are we sure nodes and dofs are ordered the same?
            int constraint = dof_constraint[k];
            for (int d = 0; d < dim; ++d)
            {
               int vdof = fespace.DofToVDof(k, d);
               out->Set(constraint, vdof, nor[d]);
            }
         }
      }
   }

   out->Finalize();
   return out;
}

class ConstrainedSolver : public Solver
{
public:
   ConstrainedSolver(HypreParMatrix& A, SparseMatrix& B);
   ~ConstrainedSolver();

   void SetOperator(const Operator& op) { }

   void Mult(const Vector& b, Vector& x) const;

private:
   Array<int> offsets;
   BlockOperator * block_op;
   GMRESSolver gmres;
   TransposeOperator * tr_B;

   mutable Vector workb;
   mutable Vector workx;
};

ConstrainedSolver::ConstrainedSolver(HypreParMatrix& A, SparseMatrix& B)
   :
   // Solver(A.Height() + B.Height()),
   Solver(A.Height()),  // not sure conceptually what the size should be!
   offsets(3),
   gmres(A.GetComm())
{
   offsets[0] = 0;
   offsets[1] = A.Height();
   offsets[2] = A.Height() + B.Height();

   block_op = new BlockOperator(offsets);
   block_op->SetBlock(0, 0, &A);
   block_op->SetBlock(1, 0, &B);
   tr_B = new TransposeOperator(&B);
   block_op->SetBlock(0, 1, tr_B);

   gmres.SetOperator(*block_op);
   gmres.SetRelTol(1.e-6);
   gmres.SetAbsTol(1.e-12);
   gmres.SetMaxIter(500);
   gmres.SetPrintLevel(1);

   workb.SetSize(A.Height() + B.Height());
   workx.SetSize(A.Height() + B.Height());
}

ConstrainedSolver::~ConstrainedSolver()
{
   delete block_op;
   delete tr_B;
}

void ConstrainedSolver::Mult(const Vector& b, Vector& x) const
{
   workb = 0.0;
   workx = 0.0;
   for (int i = 0; i < b.Size(); ++i)
   {
      workb(i) = b(i);
      workx(i) = x(i);
   }

   gmres.Mult(workb, workx);

   for (int i = 0; i < b.Size(); ++i)
   {
      x(i) = workx(i);
   }
}

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/square-disc-p3.mesh";
   int order = 1;
   bool static_cond = false;
   bool pa = false;
   const char *device_config = "cpu";
   bool visualization = true;
   int boundary_attribute = 0;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree) or -1 for"
                  " isoparametric space.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
                  "--no-partial-assembly", "Enable Partial Assembly.");
   args.AddOption(&device_config, "-d", "--device",
                  "Device configuration string, see Device::Configure().");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption(&boundary_attribute, "--boundary-attribute", "--boundary-attribute",
                  "Which attribute to apply essential conditions on.");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }

   Device device(device_config);
   if (myid == 0) { device.Print(); }

   Mesh mesh(mesh_file, 1, 1);
   // mesh.EnsureNodes(); // ???
   int dim = mesh.Dimension();

   {
      int ref_levels =
         (int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh.UniformRefinement();
      }
   }
   mesh.SetCurvature(order); // ??? try to get curved mesh

   ParMesh pmesh(MPI_COMM_WORLD, mesh);
   mesh.Clear();
   {
      // int par_ref_levels = 2;
      int par_ref_levels = 0;
      for (int l = 0; l < par_ref_levels; l++)
      {
         pmesh.UniformRefinement();
      }
   }

   // 7. Define a parallel finite element space on the parallel mesh. Here we
   //    use continuous Lagrange finite elements of the specified order. If
   //    order < 1, we instead use an isoparametric/isogeometric space.
   FiniteElementCollection *fec;
   bool delete_fec;
   if (order > 0)
   {
      fec = new H1_FECollection(order, dim);
      delete_fec = true;
   }
   else if (pmesh.GetNodes())
   {
      fec = pmesh.GetNodes()->OwnFEC();
      delete_fec = false;
      if (myid == 0)
      {
         cout << "Using isoparametric FEs: " << fec->Name() << endl;
      }
   }
   else
   {
      fec = new H1_FECollection(order = 1, dim);
      delete_fec = true;
   }
   ParFiniteElementSpace fespace(&pmesh, fec, dim); // vector space
   HYPRE_Int size = fespace.GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   Array<int> ess_tdof_list;
   if (pmesh.bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh.bdr_attributes.Max());
      // ess_bdr = 1;
      ess_bdr = 0;
      if (boundary_attribute > 0)
      {
         ess_bdr[boundary_attribute - 1] = 1;
      }
      fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

/*
   Array<int> circle_atts(4);
   circle_atts[0] = 5;
   circle_atts[1] = 6;
   circle_atts[2] = 7;
   circle_atts[3] = 8;
   SparseMatrix * constraint_mat = BuildConstraints(fespace, circle_atts);
*/

/*
   Array<int> icf_atts(1);
   icf_atts[0] = 4;
   SparseMatrix * constraint_mat = BuildConstraints(fespace, icf_atts);
*/

   Array<int> sphere_atts(1);
   sphere_atts[0] = 1;
   SparseMatrix * constraint_mat = BuildConstraints(fespace, sphere_atts);

   {
      std::ofstream out("constraint.sparsematrix");
      constraint_mat->Print(out, 1);
   }

   ParLinearForm b(&fespace);
   // ConstantCoefficient one(1.0);
   Vector rhs_direction(dim);
   rhs_direction = 0.0;
   rhs_direction[0] = 1.0;
   VectorConstantCoefficient rhs_coeff(rhs_direction);
   b.AddDomainIntegrator(new VectorDomainLFIntegrator(rhs_coeff));
   b.Assemble();

   // 10. Define the solution vector x as a parallel finite element grid function
   //     corresponding to fespace. Initialize x with initial guess of zero,
   //     which satisfies the boundary conditions.
   ParGridFunction x(&fespace);
   x = 0.0;

   // 11. Set up the parallel bilinear form a(.,.) on the finite element space
   //     corresponding to the Laplacian operator -Delta, by adding the Diffusion
   //     domain integrator.
   ParBilinearForm a(&fespace);
   if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
   // a.AddDomainIntegrator(new DiffusionIntegrator(one));
   Vector ones(dim);
   ones = 1.0;
   VectorConstantCoefficient coeff(ones);
   a.AddDomainIntegrator(new VectorMassIntegrator(coeff));

   // 12. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a.EnableStaticCondensation(); }
   a.Assemble();

   OperatorPtr A;
   Vector B, X;
   a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);

   ConstrainedSolver constrained(*A.As<HypreParMatrix>(), *constraint_mat);
   constrained.Mult(B, X);

   // 14. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a.RecoverFEMSolution(X, b, x);

   // 15. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      // todo: might make more sense to .SetCycle() than to append boundary_attribute to name
      std::stringstream visitname;
      visitname << "normal" << boundary_attribute;
      // visitname << "icf";
      VisItDataCollection visit_dc(MPI_COMM_WORLD, visitname.str(), &pmesh);
      visit_dc.SetLevelsOfDetail(4);
      visit_dc.RegisterField("sol", &x);
      // visit_dc.SetCycle(boundary_attribute);
      visit_dc.Save();
   }

   // 16. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << pmesh << x << flush;
   }

   // 17. Free the used memory.
   if (delete_fec)
   {
      delete fec;
   }
   delete constraint_mat;
   MPI_Finalize();

   return 0;
}
<commit_msg>ex-norml: add primal preconditioner interface?<commit_after>//                       MFEM Example normal-bc - Parallel Version
//

/*
  higher order seems to work fine?
  3D also looks fine
  curved mesh does *not* seem to be working
  (not even for the mesh itself, but this may be VisIt and not MFEM)
  solver obviously still needs some serious work

  square-disc attributes (not indices):

  1: south external
  2: east external
  3: north external
  4: west external
  5: southeast internal
  6: northeast internal
  7: northwest internal
  8: southwest internal

  icf attributes (not indices):

  1: west side
  2: south side
  3: ???
  4: outer edge (circle constraint)
  5: some internal boundaries??

  sphere_hex27.mesh

  1: external boundary
*/

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

SparseMatrix * BuildConstraints(FiniteElementSpace& fespace, Array<int> constrained_att)
{
   int dim = fespace.GetVDim();

   std::set<int> constrained_dofs;
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         for (auto k : dofs)
         {
            constrained_dofs.insert(k);
         }
      }
   }

   std::map<int, int> dof_constraint;
   int n_constraints = 0;
   for (auto k : constrained_dofs)
   {
      dof_constraint[k] = n_constraints++;
   }
   SparseMatrix * out = new SparseMatrix(n_constraints, fespace.GetVSize());

   Vector nor(dim);
   for (int i = 0; i < fespace.GetNBE(); ++i)
   {
      int att = fespace.GetBdrAttribute(i);
      if (constrained_att.FindSorted(att) != -1)
      {
         ElementTransformation * Tr = fespace.GetBdrElementTransformation(i);
         const FiniteElement * fe = fespace.GetBE(i);
         const IntegrationRule& nodes = fe->GetNodes();

         Array<int> dofs;
         fespace.GetBdrElementDofs(i, dofs);
         MFEM_VERIFY(dofs.Size() == nodes.Size(),
                     "Something wrong in finite element space!");

         for (int j = 0; j < dofs.Size(); ++j)
         {
            Tr->SetIntPoint(&nodes[j]);
            CalcOrtho(Tr->Jacobian(), nor); // this normal is scaled by h or something

            int k = dofs[j]; // are we sure nodes and dofs are ordered the same?
            int constraint = dof_constraint[k];
            for (int d = 0; d < dim; ++d)
            {
               int vdof = fespace.DofToVDof(k, d);
               out->Set(constraint, vdof, nor[d]);
            }
         }
      }
   }

   out->Finalize();
   return out;
}

/// because IdentityOperator isn't a Solver
class IdentitySolver : public Solver
{
public:
   IdentitySolver(int size) : Solver(size) { }
   void Mult(const Vector& x, Vector& y) const { y = x; }
   void SetOperator(const Operator& op) { }
};

/**
   A class to solve the constrained system

     A x = f

   subject to the constraint

     B x = r

   abstractly.
*/
class ConstrainedSolver : public Solver
{
public:
   ConstrainedSolver(Operator& A, SparseMatrix& B);
   ~ConstrainedSolver();

   void SetOperator(const Operator& op) { }

   /**
      This is a preconditioner that is expected to be effective
      for the unconstrained system A. Internally, this object
      may use the preconditioner for related or modified
      systems.
   */
   void SetPrimalPreconditioner(Solver& pc);

   void Mult(const Vector& b, Vector& x) const;

private:
   Array<int> offsets;
   BlockOperator * block_op;
   GMRESSolver gmres;
   TransposeOperator * tr_B;

   Solver * primal_pc;  // not owned
   Solver * dual_pc;  // owned
   BlockDiagonalPreconditioner * block_pc;  // owned

   mutable Vector workb;
   mutable Vector workx;
};

ConstrainedSolver::ConstrainedSolver(Operator& A, SparseMatrix& B)
   :
   // Solver(A.Height() + B.Height()),
   Solver(A.Height()),  // not sure conceptually what the size should be!
   offsets(3),
   gmres(MPI_COMM_WORLD),
   primal_pc(NULL),
   dual_pc(NULL),
   block_pc(NULL)
{
   offsets[0] = 0;
   offsets[1] = A.Height();
   offsets[2] = A.Height() + B.Height();

   block_op = new BlockOperator(offsets);
   block_op->SetBlock(0, 0, &A);
   block_op->SetBlock(1, 0, &B);
   tr_B = new TransposeOperator(&B);
   block_op->SetBlock(0, 1, tr_B);

   gmres.SetOperator(*block_op);
   gmres.SetRelTol(1.e-6);
   gmres.SetAbsTol(1.e-12);
   gmres.SetMaxIter(500);
   gmres.SetPrintLevel(1);

   workb.SetSize(A.Height() + B.Height());
   workx.SetSize(A.Height() + B.Height());
}

ConstrainedSolver::~ConstrainedSolver()
{
   delete block_op;
   delete tr_B;
   delete dual_pc;
   delete block_pc;
}

void ConstrainedSolver::SetPrimalPreconditioner(Solver& pc)
{
   primal_pc = &pc;
   block_pc = new BlockDiagonalPreconditioner(offsets);
   primal_pc->SetOperator(block_op->GetBlock(0, 0));
   block_pc->SetDiagonalBlock(0, primal_pc);
   dual_pc = new IdentitySolver(offsets[2] - offsets[1]);
   block_pc->SetDiagonalBlock(1, dual_pc);
   gmres.SetPreconditioner(*block_pc);
}

void ConstrainedSolver::Mult(const Vector& b, Vector& x) const
{
   workb = 0.0;
   workx = 0.0;
   for (int i = 0; i < b.Size(); ++i)
   {
      workb(i) = b(i);
      workx(i) = x(i);
   }

   gmres.Mult(workb, workx);

   for (int i = 0; i < b.Size(); ++i)
   {
      x(i) = workx(i);
   }
}

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/square-disc-p3.mesh";
   int order = 1;
   bool static_cond = false;
   bool pa = false;
   const char *device_config = "cpu";
   bool visualization = true;
   int boundary_attribute = 0;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree) or -1 for"
                  " isoparametric space.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
                  "--no-partial-assembly", "Enable Partial Assembly.");
   args.AddOption(&device_config, "-d", "--device",
                  "Device configuration string, see Device::Configure().");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption(&boundary_attribute, "--boundary-attribute", "--boundary-attribute",
                  "Which attribute to apply essential conditions on.");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }

   Device device(device_config);
   if (myid == 0) { device.Print(); }

   Mesh mesh(mesh_file, 1, 1);
   // mesh.EnsureNodes(); // ???
   int dim = mesh.Dimension();

   {
      int ref_levels =
         (int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh.UniformRefinement();
      }
   }
   mesh.SetCurvature(order); // ??? try to get curved mesh

   ParMesh pmesh(MPI_COMM_WORLD, mesh);
   mesh.Clear();
   {
      // int par_ref_levels = 2;
      int par_ref_levels = 0;
      for (int l = 0; l < par_ref_levels; l++)
      {
         pmesh.UniformRefinement();
      }
   }

   // 7. Define a parallel finite element space on the parallel mesh. Here we
   //    use continuous Lagrange finite elements of the specified order. If
   //    order < 1, we instead use an isoparametric/isogeometric space.
   FiniteElementCollection *fec;
   bool delete_fec;
   if (order > 0)
   {
      fec = new H1_FECollection(order, dim);
      delete_fec = true;
   }
   else if (pmesh.GetNodes())
   {
      fec = pmesh.GetNodes()->OwnFEC();
      delete_fec = false;
      if (myid == 0)
      {
         cout << "Using isoparametric FEs: " << fec->Name() << endl;
      }
   }
   else
   {
      fec = new H1_FECollection(order = 1, dim);
      delete_fec = true;
   }
   ParFiniteElementSpace fespace(&pmesh, fec, dim); // vector space
   HYPRE_Int size = fespace.GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   Array<int> ess_tdof_list;
   if (pmesh.bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh.bdr_attributes.Max());
      // ess_bdr = 1;
      ess_bdr = 0;
      if (boundary_attribute > 0)
      {
         ess_bdr[boundary_attribute - 1] = 1;
      }
      fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   Array<int> constraint_atts;
   if (!strcmp(mesh_file, "../data/square-disc-p3.mesh"))
   {
      constraint_atts.SetSize(4);
      constraint_atts[0] = 5;
      constraint_atts[1] = 6;
      constraint_atts[2] = 7;
      constraint_atts[3] = 8;
   }
   else if (!strcmp(mesh_file, "icf.mesh"))
   {
      constraint_atts.SetSize(1);
      constraint_atts[0] = 4;
   }
   else if (!strcmp(mesh_file, "sphere_hex27.mesh"))
   {
      constraint_atts.SetSize(1);
      constraint_atts[0] = 1;
   }
   SparseMatrix * constraint_mat = BuildConstraints(fespace, constraint_atts);
   {
      std::ofstream out("constraint.sparsematrix");
      constraint_mat->Print(out, 1);
   }

   ParLinearForm b(&fespace);
   // ConstantCoefficient one(1.0);
   Vector rhs_direction(dim);
   rhs_direction = 0.0;
   rhs_direction[0] = 1.0;
   VectorConstantCoefficient rhs_coeff(rhs_direction);
   b.AddDomainIntegrator(new VectorDomainLFIntegrator(rhs_coeff));
   b.Assemble();

   // 10. Define the solution vector x as a parallel finite element grid function
   //     corresponding to fespace. Initialize x with initial guess of zero,
   //     which satisfies the boundary conditions.
   ParGridFunction x(&fespace);
   x = 0.0;

   // 11. Set up the parallel bilinear form a(.,.) on the finite element space
   //     corresponding to the Laplacian operator -Delta, by adding the Diffusion
   //     domain integrator.
   ParBilinearForm a(&fespace);
   if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
   // a.AddDomainIntegrator(new DiffusionIntegrator(one));
   Vector ones(dim);
   ones = 1.0;
   VectorConstantCoefficient coeff(ones);
   a.AddDomainIntegrator(new VectorMassIntegrator(coeff));

   // 12. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a.EnableStaticCondensation(); }
   a.Assemble();

   OperatorPtr A;
   Vector B, X;
   a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);

   ConstrainedSolver constrained(*A, *constraint_mat);
   HypreBoomerAMG prec;
   prec.SetPrintLevel(0);
   constrained.SetPrimalPreconditioner(prec);
   constrained.Mult(B, X);

   // 14. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a.RecoverFEMSolution(X, b, x);

   // 15. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      // todo: might make more sense to .SetCycle() than to append boundary_attribute to name
      std::stringstream visitname;
      visitname << "normal" << boundary_attribute;
      // visitname << "icf";
      VisItDataCollection visit_dc(MPI_COMM_WORLD, visitname.str(), &pmesh);
      visit_dc.SetLevelsOfDetail(4);
      visit_dc.RegisterField("sol", &x);
      // visit_dc.SetCycle(boundary_attribute);
      visit_dc.Save();
   }

   // 16. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << pmesh << x << flush;
   }

   // 17. Free the used memory.
   if (delete_fec)
   {
      delete fec;
   }
   delete constraint_mat;
   MPI_Finalize();

   return 0;
}
<|endoftext|>


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

#include <OgreRenderSystem.h>
#include <OgreQuaternion.h>
#include <OgreHardwareBufferManager.h>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_colourBlendMode =
{
    Ogre::LBT_COLOUR,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE
};

//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_alphaBlendMode =
{
    Ogre::LBT_ALPHA,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE
};

//----------------------------------------------------------------------------//
static const Ogre::TextureUnitState::UVWAddressingMode S_textureAddressMode =
{
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP
};

//----------------------------------------------------------------------------//
// Helper to allocate a vertex buffer and initialse a Ogre::RenderOperation
static void initialiseRenderOp(Ogre::RenderOperation& rop,
                               Ogre::HardwareVertexBufferSharedPtr& vb,
                               size_t count)
{
    using namespace Ogre;

    // basic initialisation of render op
    rop.vertexData = new VertexData;
    rop.operationType = RenderOperation::OT_TRIANGLE_LIST;
    rop.useIndexes = false;

    // setup vertex declaration for format we will use
    VertexDeclaration* vd = rop.vertexData->vertexDeclaration;
    size_t vd_offset = 0;
    vd->addElement(0, vd_offset, VET_FLOAT3, VES_POSITION);
    vd_offset += VertexElement::getTypeSize(VET_FLOAT3);
    vd->addElement(0, vd_offset, VET_COLOUR, VES_DIFFUSE);
    vd_offset += VertexElement::getTypeSize(VET_COLOUR);
    vd->addElement(0, vd_offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);

    // create hardware vertex buffer
    vb = HardwareBufferManager::getSingleton().createVertexBuffer(
            vd->getVertexSize(0), count,
            HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
            false);

    // bind vertex buffer
    rop.vertexData->vertexBufferBinding->setBinding(0, vb);
}

//----------------------------------------------------------------------------//
// Helper to cleanup what initialiseRenderOp did.
static void cleanupRenderOp(Ogre::RenderOperation& rop,
                            Ogre::HardwareVertexBufferSharedPtr& vb)
{
    delete rop.vertexData;
    rop.vertexData = 0;
    vb.setNull();
}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::OgreGeometryBuffer(OgreRenderer& owner,
                                       Ogre::RenderSystem& rs) :
    d_owner(owner),
    d_renderSystem(rs),
    d_activeTexture(0),
    d_translation(0, 0, 0),
    d_rotation(0, 0, 0),
    d_pivot(0, 0, 0),
    d_effect(0),
    d_texelOffset(rs.getHorizontalTexelOffset(), -rs.getVerticalTexelOffset()),
    d_matrixValid(false),
    d_sync(false)
{
    initialiseRenderOp(d_renderOp, d_hwBuffer, 64);
}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::~OgreGeometryBuffer()
{
    cleanupRenderOp(d_renderOp, d_hwBuffer);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::draw() const
{
    // Set up clipping for this buffer
    d_renderSystem.setScissorTest(true, d_clipRect.d_left, d_clipRect.d_top,
                                  d_clipRect.d_right, d_clipRect.d_bottom);

    if (!d_sync)
        syncHardwareBuffer();

    if (!d_matrixValid)
        updateMatrix();

    d_renderSystem._setWorldMatrix(d_matrix);

    d_owner.setupRenderingBlendMode(d_blendMode);

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

        // draw the batches
        size_t pos = 0;
        BatchList::const_iterator i = d_batches.begin();
        for ( ; i != d_batches.end(); ++i)
        {
            d_renderOp.vertexData->vertexStart = pos;
            d_renderOp.vertexData->vertexCount = (*i).second;
            d_renderSystem._setTexture(0, true, (*i).first);
            initialiseTextureStates();
            d_renderSystem._render(d_renderOp);
            pos += (*i).second;
        }
    }

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

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setTranslation(const Vector3& v)
{
    d_translation = v;
    d_matrixValid = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setRotation(const Vector3& r)
{
    d_rotation = r;
    d_matrixValid = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setPivot(const Vector3& p)
{
    d_pivot = p;
    d_matrixValid = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setClippingRegion(const Rect& region)
{
    d_clipRect.d_top    = PixelAligned(region.d_top);
    d_clipRect.d_bottom = PixelAligned(region.d_bottom);
    d_clipRect.d_left   = PixelAligned(region.d_left);
    d_clipRect.d_right  = PixelAligned(region.d_right);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendVertex(const Vertex& vertex)
{
    appendGeometry(&vertex, 1);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendGeometry(const Vertex* const vbuff,
                                        uint vertex_count)
{
    // see if we should start a new batch
    Ogre::TexturePtr t;
    if (d_activeTexture)
        t = d_activeTexture->getOgreTexture();

    if (d_batches.empty() || d_batches.back().first != t)
        d_batches.push_back(BatchInfo(t, 0));

    // update size of current batch
    d_batches.back().second += vertex_count;

    // buffer these vertices
    OgreVertex v;
    for (uint i = 0; i < vertex_count; ++i)
    {
        const Vertex& vs = vbuff[i];
        // convert from CEGUI::Vertex to something directly usable by Ogre.
        v.x       = vs.position.d_x + d_texelOffset.d_x;
        v.y       = vs.position.d_y + d_texelOffset.d_y;
        v.z       = vs.position.d_z;
        v.diffuse = colourToOgre(vs.colour_val);
        v.u       = vs.tex_coords.d_x;
        v.v       = vs.tex_coords.d_y;

        d_vertices.push_back(v);
    }

    d_sync = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setActiveTexture(Texture* texture)
{
    d_activeTexture = static_cast<OgreTexture*>(texture);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::reset()
{
    d_vertices.clear();
    d_batches.clear();
    d_activeTexture = 0;
    d_sync = false;
}

//----------------------------------------------------------------------------//
Texture* OgreGeometryBuffer::getActiveTexture() const
{
    return d_activeTexture;
}

//----------------------------------------------------------------------------//
uint OgreGeometryBuffer::getVertexCount() const
{
    return d_vertices.size();
}

//----------------------------------------------------------------------------//
uint OgreGeometryBuffer::getBatchCount() const
{
    return d_batches.size();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setRenderEffect(RenderEffect* effect)
{
    d_effect = effect;
}

//----------------------------------------------------------------------------//
RenderEffect* OgreGeometryBuffer::getRenderEffect()
{
    return d_effect;
}

//----------------------------------------------------------------------------//
Ogre::RGBA OgreGeometryBuffer::colourToOgre(const colour& col) const
{
    Ogre::ColourValue ocv(col.getRed(),
                          col.getGreen(),
                          col.getBlue(),
                          col.getAlpha());

    uint32 final;
    d_renderSystem.convertColourValue(ocv, &final);

    return final;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::updateMatrix() const
{
    // translation to position geometry and offset to pivot point
    Ogre::Matrix4 trans;
    trans.makeTrans(d_translation.d_x + d_pivot.d_x,
                    d_translation.d_y + d_pivot.d_y,
                    d_translation.d_z + d_pivot.d_z);

    // rotation
    Ogre::Quaternion qz(Ogre::Degree(d_rotation.d_z),
                        Ogre::Vector3::UNIT_Z);
    Ogre::Quaternion qy(Ogre::Degree(d_rotation.d_y),
                        Ogre::Vector3::UNIT_Y);
    Ogre::Quaternion qx(Ogre::Degree(d_rotation.d_x),
                        Ogre::Vector3::UNIT_X);
    Ogre::Matrix4 rot(qz * qy * qx);

    // translation to remove rotation pivot offset
    Ogre::Matrix4 inv_pivot_trans;
    inv_pivot_trans.makeTrans(-d_pivot.d_x, -d_pivot.d_y, -d_pivot.d_z);

    // calculate final matrix
    d_matrix = trans * rot * inv_pivot_trans;

    d_matrixValid = true;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::syncHardwareBuffer() const
{
    // Reallocate h/w buffer as requied
    size_t size = d_hwBuffer->getNumVertices();
    const size_t required_size = d_vertices.size();
    if(size < required_size)
    {
        // calculate new size to use
        while(size < required_size)
            size *= 2;

        // Reallocate the buffer
        cleanupRenderOp(d_renderOp, d_hwBuffer);
        initialiseRenderOp(d_renderOp, d_hwBuffer, size);
    }

    // copy vertex data into hw buffer
    if (required_size > 0)
    {
        std::memcpy(d_hwBuffer->lock(Ogre::HardwareVertexBuffer::HBL_DISCARD),
                    &d_vertices[0], sizeof(OgreVertex) * d_vertices.size());

        d_hwBuffer->unlock();
    }

    d_sync = true;
}

//----------------------------------------------------------------------------//
const Ogre::Matrix4& OgreGeometryBuffer::getMatrix() const
{
    if (!d_matrixValid)
        updateMatrix();

    return d_matrix;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::initialiseTextureStates() const
{
    using namespace Ogre;
    d_renderSystem._setTextureCoordCalculation(0, TEXCALC_NONE);
    d_renderSystem._setTextureCoordSet(0, 0);
    d_renderSystem._setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_POINT);
    d_renderSystem._setTextureAddressingMode(0, S_textureAddressMode);
    d_renderSystem._setTextureMatrix(0, Matrix4::IDENTITY);
    d_renderSystem._setAlphaRejectSettings(CMPF_ALWAYS_PASS, 0, false);
    d_renderSystem._setTextureBlendMode(0, S_colourBlendMode);
    d_renderSystem._setTextureBlendMode(0, S_alphaBlendMode);
    d_renderSystem._disableTextureUnitsFrom(1);
}

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

} // End of  CEGUI namespace section
<commit_msg>Resolve remaining clipping issue with CEGUIOgreRenderer when using Ogre's D3D render system.<commit_after>/***********************************************************************
    filename:   CEGUIOgreGeometryBuffer.cpp
    created:    Tue Feb 17 2009
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2010 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUIOgreGeometryBuffer.h"
#include "CEGUIOgreTexture.h"
#include "CEGUIVertex.h"
#include "CEGUIRenderEffect.h"

#include <OgreRenderSystem.h>
#include <OgreQuaternion.h>
#include <OgreHardwareBufferManager.h>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_colourBlendMode =
{
    Ogre::LBT_COLOUR,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE
};

//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_alphaBlendMode =
{
    Ogre::LBT_ALPHA,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE
};

//----------------------------------------------------------------------------//
static const Ogre::TextureUnitState::UVWAddressingMode S_textureAddressMode =
{
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP
};

//----------------------------------------------------------------------------//
// Helper to allocate a vertex buffer and initialse a Ogre::RenderOperation
static void initialiseRenderOp(Ogre::RenderOperation& rop,
                               Ogre::HardwareVertexBufferSharedPtr& vb,
                               size_t count)
{
    using namespace Ogre;

    // basic initialisation of render op
    rop.vertexData = new VertexData;
    rop.operationType = RenderOperation::OT_TRIANGLE_LIST;
    rop.useIndexes = false;

    // setup vertex declaration for format we will use
    VertexDeclaration* vd = rop.vertexData->vertexDeclaration;
    size_t vd_offset = 0;
    vd->addElement(0, vd_offset, VET_FLOAT3, VES_POSITION);
    vd_offset += VertexElement::getTypeSize(VET_FLOAT3);
    vd->addElement(0, vd_offset, VET_COLOUR, VES_DIFFUSE);
    vd_offset += VertexElement::getTypeSize(VET_COLOUR);
    vd->addElement(0, vd_offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);

    // create hardware vertex buffer
    vb = HardwareBufferManager::getSingleton().createVertexBuffer(
            vd->getVertexSize(0), count,
            HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
            false);

    // bind vertex buffer
    rop.vertexData->vertexBufferBinding->setBinding(0, vb);
}

//----------------------------------------------------------------------------//
// Helper to cleanup what initialiseRenderOp did.
static void cleanupRenderOp(Ogre::RenderOperation& rop,
                            Ogre::HardwareVertexBufferSharedPtr& vb)
{
    delete rop.vertexData;
    rop.vertexData = 0;
    vb.setNull();
}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::OgreGeometryBuffer(OgreRenderer& owner,
                                       Ogre::RenderSystem& rs) :
    d_owner(owner),
    d_renderSystem(rs),
    d_activeTexture(0),
    d_translation(0, 0, 0),
    d_rotation(0, 0, 0),
    d_pivot(0, 0, 0),
    d_effect(0),
    d_texelOffset(rs.getHorizontalTexelOffset(), rs.getVerticalTexelOffset()),
    d_matrixValid(false),
    d_sync(false)
{
    initialiseRenderOp(d_renderOp, d_hwBuffer, 64);
}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::~OgreGeometryBuffer()
{
    cleanupRenderOp(d_renderOp, d_hwBuffer);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::draw() const
{
    // Set up clipping for this buffer
    d_renderSystem.setScissorTest(true, d_clipRect.d_left, d_clipRect.d_top,
                                  d_clipRect.d_right, d_clipRect.d_bottom);

    if (!d_sync)
        syncHardwareBuffer();

    if (!d_matrixValid)
        updateMatrix();

    d_renderSystem._setWorldMatrix(d_matrix);

    d_owner.setupRenderingBlendMode(d_blendMode);

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

        // draw the batches
        size_t pos = 0;
        BatchList::const_iterator i = d_batches.begin();
        for ( ; i != d_batches.end(); ++i)
        {
            d_renderOp.vertexData->vertexStart = pos;
            d_renderOp.vertexData->vertexCount = (*i).second;
            d_renderSystem._setTexture(0, true, (*i).first);
            initialiseTextureStates();
            d_renderSystem._render(d_renderOp);
            pos += (*i).second;
        }
    }

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

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setTranslation(const Vector3& v)
{
    d_translation = v;
    d_matrixValid = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setRotation(const Vector3& r)
{
    d_rotation = r;
    d_matrixValid = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setPivot(const Vector3& p)
{
    d_pivot = p;
    d_matrixValid = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setClippingRegion(const Rect& region)
{
    d_clipRect.d_top    = PixelAligned(region.d_top);
    d_clipRect.d_bottom = PixelAligned(region.d_bottom);
    d_clipRect.d_left   = PixelAligned(region.d_left);
    d_clipRect.d_right  = PixelAligned(region.d_right);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendVertex(const Vertex& vertex)
{
    appendGeometry(&vertex, 1);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendGeometry(const Vertex* const vbuff,
                                        uint vertex_count)
{
    // see if we should start a new batch
    Ogre::TexturePtr t;
    if (d_activeTexture)
        t = d_activeTexture->getOgreTexture();

    if (d_batches.empty() || d_batches.back().first != t)
        d_batches.push_back(BatchInfo(t, 0));

    // update size of current batch
    d_batches.back().second += vertex_count;

    // buffer these vertices
    OgreVertex v;
    for (uint i = 0; i < vertex_count; ++i)
    {
        const Vertex& vs = vbuff[i];
        // convert from CEGUI::Vertex to something directly usable by Ogre.
        v.x       = vs.position.d_x + d_texelOffset.d_x;
        v.y       = vs.position.d_y + d_texelOffset.d_y;
        v.z       = vs.position.d_z;
        v.diffuse = colourToOgre(vs.colour_val);
        v.u       = vs.tex_coords.d_x;
        v.v       = vs.tex_coords.d_y;

        d_vertices.push_back(v);
    }

    d_sync = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setActiveTexture(Texture* texture)
{
    d_activeTexture = static_cast<OgreTexture*>(texture);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::reset()
{
    d_vertices.clear();
    d_batches.clear();
    d_activeTexture = 0;
    d_sync = false;
}

//----------------------------------------------------------------------------//
Texture* OgreGeometryBuffer::getActiveTexture() const
{
    return d_activeTexture;
}

//----------------------------------------------------------------------------//
uint OgreGeometryBuffer::getVertexCount() const
{
    return d_vertices.size();
}

//----------------------------------------------------------------------------//
uint OgreGeometryBuffer::getBatchCount() const
{
    return d_batches.size();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setRenderEffect(RenderEffect* effect)
{
    d_effect = effect;
}

//----------------------------------------------------------------------------//
RenderEffect* OgreGeometryBuffer::getRenderEffect()
{
    return d_effect;
}

//----------------------------------------------------------------------------//
Ogre::RGBA OgreGeometryBuffer::colourToOgre(const colour& col) const
{
    Ogre::ColourValue ocv(col.getRed(),
                          col.getGreen(),
                          col.getBlue(),
                          col.getAlpha());

    uint32 final;
    d_renderSystem.convertColourValue(ocv, &final);

    return final;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::updateMatrix() const
{
    // translation to position geometry and offset to pivot point
    Ogre::Matrix4 trans;
    trans.makeTrans(d_translation.d_x + d_pivot.d_x,
                    d_translation.d_y + d_pivot.d_y,
                    d_translation.d_z + d_pivot.d_z);

    // rotation
    Ogre::Quaternion qz(Ogre::Degree(d_rotation.d_z),
                        Ogre::Vector3::UNIT_Z);
    Ogre::Quaternion qy(Ogre::Degree(d_rotation.d_y),
                        Ogre::Vector3::UNIT_Y);
    Ogre::Quaternion qx(Ogre::Degree(d_rotation.d_x),
                        Ogre::Vector3::UNIT_X);
    Ogre::Matrix4 rot(qz * qy * qx);

    // translation to remove rotation pivot offset
    Ogre::Matrix4 inv_pivot_trans;
    inv_pivot_trans.makeTrans(-d_pivot.d_x, -d_pivot.d_y, -d_pivot.d_z);

    // calculate final matrix
    d_matrix = trans * rot * inv_pivot_trans;

    d_matrixValid = true;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::syncHardwareBuffer() const
{
    // Reallocate h/w buffer as requied
    size_t size = d_hwBuffer->getNumVertices();
    const size_t required_size = d_vertices.size();
    if(size < required_size)
    {
        // calculate new size to use
        while(size < required_size)
            size *= 2;

        // Reallocate the buffer
        cleanupRenderOp(d_renderOp, d_hwBuffer);
        initialiseRenderOp(d_renderOp, d_hwBuffer, size);
    }

    // copy vertex data into hw buffer
    if (required_size > 0)
    {
        std::memcpy(d_hwBuffer->lock(Ogre::HardwareVertexBuffer::HBL_DISCARD),
                    &d_vertices[0], sizeof(OgreVertex) * d_vertices.size());

        d_hwBuffer->unlock();
    }

    d_sync = true;
}

//----------------------------------------------------------------------------//
const Ogre::Matrix4& OgreGeometryBuffer::getMatrix() const
{
    if (!d_matrixValid)
        updateMatrix();

    return d_matrix;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::initialiseTextureStates() const
{
    using namespace Ogre;
    d_renderSystem._setTextureCoordCalculation(0, TEXCALC_NONE);
    d_renderSystem._setTextureCoordSet(0, 0);
    d_renderSystem._setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_POINT);
    d_renderSystem._setTextureAddressingMode(0, S_textureAddressMode);
    d_renderSystem._setTextureMatrix(0, Matrix4::IDENTITY);
    d_renderSystem._setAlphaRejectSettings(CMPF_ALWAYS_PASS, 0, false);
    d_renderSystem._setTextureBlendMode(0, S_colourBlendMode);
    d_renderSystem._setTextureBlendMode(0, S_alphaBlendMode);
    d_renderSystem._disableTextureUnitsFrom(1);
}

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

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before><commit_msg>p11002 - Towards Zero: time tweak<commit_after><|endoftext|>