<commit_before>#include <tut/tut.hpp>
#include <tut/tut_macros.hpp>
#include <string>
#include <sstream>
#include <stdexcept>

using std::string;
using std::ostringstream;
using std::runtime_error;

namespace {
enum test_ids {
    test_id_eq = 1
    , test_id_ne
    , test_id_ge
    , test_id_le
    , test_id_lt
    , test_id_gt
};
}

namespace tut
{
  /**
   * Testing ensure_op() method.
   */
  struct ensure_op_test
  {
      virtual ~ensure_op_test()
      {
      }
  };

  typedef test_group<ensure_op_test> tf;
  typedef tf::object object;
  tf ensure_op_test("ensure_op");

  template<>
  template<>
  void object::test<test_id_eq>()
  {
      ensure_eq("Eq int", 1, 1);
      ensure_eq("Eq str", "a", "a");
      ensure_throws<failure>
        ("ensure_eq should fail here", []() {
          ensure_eq("Eq int", 1, 2);
        });
  }

  template<>
  template<>
  void object::test<test_id_ne>()
  {
      ensure_ne("Eq int", 1, 3);
      ensure_ne("Eq str", "a", "b");
      ensure_throws<failure>
        ("ensure_ne should fail here", []() {
          ensure_ne("ne int", 1, 1);
        });
  }

  template<>
  template<>
  void object::test<test_id_ge>()
  {
      ensure_ge("ge int", 1, 1);
      ensure_ge("ge int", 2, 1);
      ensure_ge("ge str", "a", "a");
      ensure_ge("ge str", "b", "a");
      ensure_throws<failure>
        ("ensure_ge should fail here", []() {
          ensure_ge("ge int", 1, 2);
        });
  }

  template<>
  template<>
  void object::test<test_id_le>()
  {
      ensure_le("le int", 1, 1);
      ensure_le("le int", 1, 2);
      ensure_le("le str", "a", "a");
      ensure_le("le str", "a", "b");
      ensure_throws<failure>
        ("ensure_le should fail here", []() {
          ensure_le("le int", 2, 1);
        });
  }

  template<>
  template<>
  void object::test<test_id_lt>()
  {
      ensure_lt("lt int", 0, 1);
      ensure_lt("lt int", -1, 1);
      ensure_lt("lt str", "a", "b");
      ensure_throws<failure>
        ("ensure_lt should fail here", []() {
          ensure_lt("lt int", 2, 1);
        });
  }

  template<>
  template<>
  void object::test<test_id_gt>()
  {
      ensure_gt("gt int", 1, 0);
      ensure_gt("gt int", 1, -1);
      ensure_gt("gt str", "b", "a");
      ensure_throws<failure>
        ("ensure_gt should fail here", []() {
          ensure_gt("gt int", 1, 2);
        });
  }

}
<commit_msg>[selftest] fixing op tests<commit_after>#include <tut/tut.hpp>
#include <tut/tut_macros.hpp>
#include <string>
#include <sstream>
#include <stdexcept>

using std::string;
using std::ostringstream;
using std::runtime_error;

namespace {

inline std::string str(char const *s) { return std::string(s); }

enum test_ids {
    test_id_eq = 1
    , test_id_ne
    , test_id_ge
    , test_id_le
    , test_id_lt
    , test_id_gt
};
}

namespace tut
{
  /**
   * Testing ensure_op() method.
   */
  struct ensure_op_test
  {
      virtual ~ensure_op_test()
      {
      }
  };

  typedef test_group<ensure_op_test> tf;
  typedef tf::object object;
  tf ensure_op_test("ensure_op");

  template<>
  template<>
  void object::test<test_id_eq>()
  {
      ensure_eq("Eq int", 1, 1);
      ensure_eq("Eq str", str("a"), "a");
      ensure_throws<failure>
        ("ensure_eq should fail here", []() {
          ensure_eq("Eq int", 1, 2);
        });
  }

  template<>
  template<>
  void object::test<test_id_ne>()
  {
      ensure_ne("Eq int", 1, 3);
      ensure_ne("Eq str", str("a"), "b");
      ensure_throws<failure>
        ("ensure_ne should fail here", []() {
          ensure_ne("ne int", 1, 1);
        });
  }

  template<>
  template<>
  void object::test<test_id_ge>()
  {
      ensure_ge("ge int", 1, 1);
      ensure_ge("ge int", 2, 1);
      ensure_ge("ge str", str("a"), "a");
      ensure_ge("ge str", str("b"), "a");
      ensure_throws<failure>
        ("ensure_ge should fail here", []() {
          ensure_ge("ge int", 1, 2);
        });
  }

  template<>
  template<>
  void object::test<test_id_le>()
  {
      ensure_le("le int", 1, 1);
      ensure_le("le int", 1, 2);
      ensure_le("le str", str("a"), "a");
      ensure_le("le str", str("a"), "b");
      ensure_throws<failure>
        ("ensure_le should fail here", []() {
          ensure_le("le int", 2, 1);
        });
  }

  template<>
  template<>
  void object::test<test_id_lt>()
  {
      ensure_lt("lt int", 0, 1);
      ensure_lt("lt int", -1, 1);
      ensure_lt("lt str", str("a"), "b");
      ensure_throws<failure>
        ("ensure_lt should fail here", []() {
          ensure_lt("lt int", 2, 1);
        });
  }

  template<>
  template<>
  void object::test<test_id_gt>()
  {
      ensure_gt("gt int", 1, 0);
      ensure_gt("gt int", 1, -1);
      ensure_gt("gt str", str("b"), "a");
      ensure_throws<failure>
        ("ensure_gt should fail here", []() {
          ensure_gt("gt int", 1, 2);
        });
  }

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <deque>
#include <va/va.h>
#include "common/log.h"
#include "common/lock.h"
#include "vppinputoutput.h"
#include "vppoutputencode.h"
#include "vppinputdecode.h"
#ifdef __ENABLE_CAPI__
#include "vppinputdecodecapi.h"
#endif
using namespace YamiMediaCodec;

#ifndef ANDROID
SharedPtr<VADisplay> createVADisplay()
{
    SharedPtr<VADisplay> display;
    int fd = open("/dev/dri/renderD128", O_RDWR);
    if (fd < 0) {
        ERROR("can't open /dev/dri/renderD128, try to /dev/dri/card0");
        fd = open("/dev/dri/card0", O_RDWR);
    }
    if (fd < 0) {
        ERROR("can't open drm device");
        return display;
    }
    VADisplay vadisplay = vaGetDisplayDRM(fd);
    int majorVersion, minorVersion;
    VAStatus vaStatus = vaInitialize(vadisplay, &majorVersion, &minorVersion);
    if (vaStatus != VA_STATUS_SUCCESS) {
        ERROR("va init failed, status =  %d", vaStatus);
        close(fd);
        return display;
    }
    display.reset(new VADisplay(vadisplay), VADisplayDeleter(fd));
    return display;
}
#endif

SharedPtr<VppInput> VppInput::create(const char* inputFileName, uint32_t fourcc, int width, int height)
{
    SharedPtr<VppInput> input;
    if (!inputFileName)
        return input;

#ifdef __ENABLE_CAPI__
    input.reset(new VppInputDecodeCapi);
    if (input->init(inputFileName, fourcc, width, height))
        return input;
#else
    input.reset(new VppInputDecode);
    if(input->init(inputFileName, fourcc, width, height))
        return input;
#endif
    input.reset(new VppInputFile);
    if (input->init(inputFileName, fourcc, width, height))
        return input;

    ERROR("Wrong input file format %s?", inputFileName);
    input.reset();
    return input;
}

VppInputFile::VppInputFile()
    : m_fp(NULL)
    , m_readToEOS(false)
{
}

bool VppInputFile::config(const SharedPtr<FrameAllocator>& allocator, const SharedPtr<FrameReader>& reader)
{
    if (!allocator->setFormat(m_fourcc, m_width, m_height)) {
        ERROR("set format to %x, %dx%d failed", m_fourcc, m_width, m_height);
        return false;
    }
    m_reader = reader;
    m_allocator = allocator;
    return true;
}

static bool guessFormat(const char* filename, uint32_t& fourcc, int& width, int& height)
{
    if (!width || !height) {
        if (!guessResolution(filename, width, height)) {
            ERROR("failed to guess input width and height\n");
            return false;
        }
    }
    if (!fourcc)
        fourcc = guessFourcc(filename);

    if (!fourcc)
        fourcc = VA_FOURCC('I', '4', '2', '0');
    return true;
}

bool VppInputFile::init(const char* inputFileName, uint32_t fourcc, int width, int height)
{
    if(!fourcc || !width || !height)
        if (!guessFormat(inputFileName, fourcc, width, height))
            return false;

    m_width = width;
    m_height = height;
    m_fourcc = fourcc;

    m_fp = fopen(inputFileName, "r");
    if (!m_fp) {
        fprintf(stderr, "fail to open input file: %s", inputFileName);
        return false;
    }
    return true;
}

bool VppInputFile::read(SharedPtr<VideoFrame>& frame)
{
    if (!m_allocator || !m_reader) {
        ERROR("config VppInputFile with allocator and reader, please!");
        return false;
    }
    if (m_readToEOS)
        return false;

    frame = m_allocator->alloc();
    if (!frame) {
        ERROR("allocate frame failed");
        return false;
    }

    if (!m_reader->read(m_fp, frame))
        m_readToEOS = true;
    return !m_readToEOS;
}

VppInputFile::~VppInputFile()
{
    if(m_fp)
        fclose(m_fp);
}

VppOutput::VppOutput()
    :m_fourcc(0), m_width(0), m_height(0)
{
}

SharedPtr<VppOutput> VppOutput::create(const char* outputFileName, uint32_t fourcc, int width, int height)
{
    SharedPtr<VppOutput> output;
    if (!outputFileName) {
        ERROR("invalid output file name");
        return output;
    }
    output.reset(new VppOutputEncode);
    if (output->init(outputFileName, fourcc, width, height))
        return output;
    output.reset(new VppOutputFile);
    if (output->init(outputFileName, fourcc, width, height))
        return output;
    ERROR("can't open %s, wroing extension?",outputFileName);
    output.reset();
    return output;
}

bool VppOutput::getFormat(uint32_t& fourcc, int& width, int& height)
{
    fourcc = m_fourcc;
    width = m_width;
    height = m_height;
    return true;
}

bool VppOutputFile::init(const char* outputFileName, uint32_t fourcc, int width, int height)
{
    if (!outputFileName) {
        ERROR("output file name is null");
        return false;
    }
    m_fourcc = fourcc;
    m_width = width;
    m_height = height;
    m_fp = fopen(outputFileName, "wb");
    if (!m_fp) {
        ERROR("fail to open input file: %s", outputFileName);
        return false;
    }
    return true;
}

bool VppOutputFile::config(const SharedPtr<FrameWriter>& writer)
{
    m_writer = writer;
    return true;
}

VppOutputFile::~VppOutputFile()
{
    if (m_fp)
        fclose(m_fp);
}

bool VppOutputFile::output(const SharedPtr<VideoFrame>& frame)
{
    return write(frame);
}

bool VppOutputFile::write(const SharedPtr<VideoFrame>& frame)
{
    if (!m_writer) {
        ERROR("config with writer please!");
        return false;
    }
    if (!frame)
        return true;
    return m_writer->write(m_fp, frame);
}

VppOutputFile::VppOutputFile()
    :m_fp(NULL)
{
}
<commit_msg>vppoutput: guess format from file if not provide<commit_after>/*
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <deque>
#include <va/va.h>
#include "common/log.h"
#include "common/lock.h"
#include "vppinputoutput.h"
#include "vppoutputencode.h"
#include "vppinputdecode.h"
#ifdef __ENABLE_CAPI__
#include "vppinputdecodecapi.h"
#endif
using namespace YamiMediaCodec;

#ifndef ANDROID
SharedPtr<VADisplay> createVADisplay()
{
    SharedPtr<VADisplay> display;
    int fd = open("/dev/dri/renderD128", O_RDWR);
    if (fd < 0) {
        ERROR("can't open /dev/dri/renderD128, try to /dev/dri/card0");
        fd = open("/dev/dri/card0", O_RDWR);
    }
    if (fd < 0) {
        ERROR("can't open drm device");
        return display;
    }
    VADisplay vadisplay = vaGetDisplayDRM(fd);
    int majorVersion, minorVersion;
    VAStatus vaStatus = vaInitialize(vadisplay, &majorVersion, &minorVersion);
    if (vaStatus != VA_STATUS_SUCCESS) {
        ERROR("va init failed, status =  %d", vaStatus);
        close(fd);
        return display;
    }
    display.reset(new VADisplay(vadisplay), VADisplayDeleter(fd));
    return display;
}
#endif

SharedPtr<VppInput> VppInput::create(const char* inputFileName, uint32_t fourcc, int width, int height)
{
    SharedPtr<VppInput> input;
    if (!inputFileName)
        return input;

#ifdef __ENABLE_CAPI__
    input.reset(new VppInputDecodeCapi);
    if (input->init(inputFileName, fourcc, width, height))
        return input;
#else
    input.reset(new VppInputDecode);
    if(input->init(inputFileName, fourcc, width, height))
        return input;
#endif
    input.reset(new VppInputFile);
    if (input->init(inputFileName, fourcc, width, height))
        return input;

    ERROR("Wrong input file format %s?", inputFileName);
    input.reset();
    return input;
}

VppInputFile::VppInputFile()
    : m_fp(NULL)
    , m_readToEOS(false)
{
}

bool VppInputFile::config(const SharedPtr<FrameAllocator>& allocator, const SharedPtr<FrameReader>& reader)
{
    if (!allocator->setFormat(m_fourcc, m_width, m_height)) {
        ERROR("set format to %x, %dx%d failed", m_fourcc, m_width, m_height);
        return false;
    }
    m_reader = reader;
    m_allocator = allocator;
    return true;
}

static bool guessFormat(const char* filename, uint32_t& fourcc, int& width, int& height)
{
    if (!width || !height) {
        if (!guessResolution(filename, width, height)) {
            ERROR("failed to guess input width and height\n");
            return false;
        }
    }
    if (!fourcc)
        fourcc = guessFourcc(filename);

    if (!fourcc)
        fourcc = VA_FOURCC('I', '4', '2', '0');
    return true;
}

bool VppInputFile::init(const char* inputFileName, uint32_t fourcc, int width, int height)
{
    if(!fourcc || !width || !height)
        if (!guessFormat(inputFileName, fourcc, width, height))
            return false;

    m_width = width;
    m_height = height;
    m_fourcc = fourcc;

    m_fp = fopen(inputFileName, "r");
    if (!m_fp) {
        fprintf(stderr, "fail to open input file: %s", inputFileName);
        return false;
    }
    return true;
}

bool VppInputFile::read(SharedPtr<VideoFrame>& frame)
{
    if (!m_allocator || !m_reader) {
        ERROR("config VppInputFile with allocator and reader, please!");
        return false;
    }
    if (m_readToEOS)
        return false;

    frame = m_allocator->alloc();
    if (!frame) {
        ERROR("allocate frame failed");
        return false;
    }

    if (!m_reader->read(m_fp, frame))
        m_readToEOS = true;
    return !m_readToEOS;
}

VppInputFile::~VppInputFile()
{
    if(m_fp)
        fclose(m_fp);
}

VppOutput::VppOutput()
    :m_fourcc(0), m_width(0), m_height(0)
{
}

SharedPtr<VppOutput> VppOutput::create(const char* outputFileName, uint32_t fourcc, int width, int height)
{
    SharedPtr<VppOutput> output;
    if (!outputFileName) {
        ERROR("invalid output file name");
        return output;
    }
    output.reset(new VppOutputEncode);
    if (output->init(outputFileName, fourcc, width, height))
        return output;
    output.reset(new VppOutputFile);
    if (output->init(outputFileName, fourcc, width, height))
        return output;
    ERROR("can't open %s, wroing extension?",outputFileName);
    output.reset();
    return output;
}

bool VppOutput::getFormat(uint32_t& fourcc, int& width, int& height)
{
    fourcc = m_fourcc;
    width = m_width;
    height = m_height;
    return true;
}

bool VppOutputFile::init(const char* outputFileName, uint32_t fourcc, int width, int height)
{
    if (!outputFileName) {
        ERROR("output file name is null");
        return false;
    }
    if (!fourcc || !width || !height) {
        if (!guessFormat(outputFileName, fourcc, width, height)) {
            ERROR("can't guess format from %s", outputFileName);
            return false;
        }
    }
    m_fourcc = fourcc;
    m_width = width;
    m_height = height;
    m_fp = fopen(outputFileName, "wb");
    if (!m_fp) {
        ERROR("fail to open input file: %s", outputFileName);
        return false;
    }
    return true;
}

bool VppOutputFile::config(const SharedPtr<FrameWriter>& writer)
{
    m_writer = writer;
    return true;
}

VppOutputFile::~VppOutputFile()
{
    if (m_fp)
        fclose(m_fp);
}

bool VppOutputFile::output(const SharedPtr<VideoFrame>& frame)
{
    return write(frame);
}

bool VppOutputFile::write(const SharedPtr<VideoFrame>& frame)
{
    if (!m_writer) {
        ERROR("config with writer please!");
        return false;
    }
    if (!frame)
        return true;
    return m_writer->write(m_fp, frame);
}

VppOutputFile::VppOutputFile()
    :m_fp(NULL)
{
}
<|endoftext|>


<commit_before>/*
 * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include "test.h"
#include <bx/string.h>
#include <inttypes.h>
#include <float.h>

#ifndef NAN
#	define NAN (0.0/0.0)
#endif // NAN

TEST_CASE("vsnprintf NULL buffer", "No output buffer provided.")
{
	REQUIRE(4 == bx::snprintf(NULL, 0, "test") );

	REQUIRE(1 == bx::snprintf(NULL, 0, "%d", 1) );
}

TEST_CASE("vsnprintf truncated", "Truncated output buffer.")
{
	char buffer[7];

	REQUIRE(10 == bx::snprintf(buffer, BX_COUNTOF(buffer), "Ten chars!") );
	REQUIRE(0  == bx::strncmp(buffer, "Ten ch") );
}

static bool test(const char* _expected, const char* _format, ...)
{
	int32_t max = (int32_t)bx::strnlen(_expected) + 1;
	char* temp = (char*)alloca(max);

	va_list argList;
	va_start(argList, _format);
	int32_t len = bx::vsnprintf(temp, max, _format, argList);
	va_end(argList);

	bool result = true
		&& len == max-1
		&& 0   == bx::strncmp(_expected, temp)
		;

	if (!result)
	{
		printf("result (%d) '%s', expected (%d) '%s'\n", len, temp, max-1, _expected);
	}

	return result;
}

TEST_CASE("vsnprintf f", "")
{
	REQUIRE(test("1.337",    "%0.3f", 1.337) );
	REQUIRE(test("  13.370", "%8.3f", 13.37) );
	REQUIRE(test("  13.370", "%*.*f", 8, 3, 13.37) );
	REQUIRE(test("13.370  ", "%-8.3f", 13.37) );
	REQUIRE(test("13.370  ", "%*.*f", -8, 3, 13.37) );

	REQUIRE(test("nan     ", "%-8f",  NAN) );
	REQUIRE(test("     nan", "%8f",   NAN) );
	REQUIRE(test("-NAN    ", "%-8F", -NAN) );
	REQUIRE(test("     inf", "%8f",   INFINITY) );
	REQUIRE(test("inf     ", "%-8f",  INFINITY) );
	REQUIRE(test("    -INF", "%8F",  -INFINITY) );
}

TEST_CASE("vsnprintf d/i/o/u/x", "")
{
	REQUIRE(test("1337", "%d", 1337) );
	REQUIRE(test("1337                ", "%-20d",  1337) );
	REQUIRE(test("-1337               ", "%-20d", -1337) );

	REQUIRE(test("1337", "%i", 1337) );
	REQUIRE(test("1337                ", "%-20i",  1337) );
	REQUIRE(test("-1337               ", "%-20i", -1337) );

	REQUIRE(test("1337", "%o", 01337) );
	REQUIRE(test("2471", "%o", 1337) );
	REQUIRE(test("1337                ", "%-20o",  01337) );
	REQUIRE(test("37777776441         ", "%-20o", -01337) );

	REQUIRE(test("1337", "%u", 1337) );
	REQUIRE(test("1337                ", "%-20u",  1337) );
	REQUIRE(test("4294965959          ", "%-20u", -1337) );

	REQUIRE(test("1337", "%x", 0x1337) );
	REQUIRE(test("1234abcd            ", "%-20x",  0x1234abcd) );
	REQUIRE(test("1234ABCD            ", "%-20X",  0x1234abcd) );
	REQUIRE(test("edcb5433            ", "%-20x", -0x1234abcd) );
	REQUIRE(test("EDCB5433            ", "%-20X", -0x1234abcd) );
	REQUIRE(test("0000000000001234abcd", "%020x",  0x1234abcd) );
	REQUIRE(test("0000000000001234ABCD", "%020X",  0x1234abcd) );
	REQUIRE(test("000000000000edcb5433", "%020x", -0x1234abcd) );
	REQUIRE(test("000000000000EDCB5433", "%020X", -0x1234abcd) );

	if (BX_ENABLED(BX_ARCH_32BIT) )
	{
		REQUIRE(test("2147483647", "%jd", INTMAX_MAX) );
	}
	else
	{
		REQUIRE(test("9223372036854775807", "%jd", INTMAX_MAX) );
	}

	REQUIRE(test("18446744073709551615", "%" PRIu64, UINT64_MAX) );
	REQUIRE(test("ffffffffffffffff", "%016" PRIx64, UINT64_MAX) );
}

TEST_CASE("vsnprintf modifiers", "")
{
	REQUIRE(test("|  1.000000|", "|%10f|",      1.0f) );
	REQUIRE(test("|1.000000  |", "|%-10f|",     1.0f) );
	REQUIRE(test("|001.000000|", "|%010f|",     1.0f) );
	REQUIRE(test("|0000000001|", "|%010.0f|",   1.0f) );
	REQUIRE(test("|000000001.|", "|%#010.0f|",  1.0f) );
	REQUIRE(test("|         1|", "|%10.0f|",    1.0f) );
	REQUIRE(test("|        1.|", "|%#10.0f|",   1.0f) );
	REQUIRE(test("|       +1.|", "|%#+10.0f|",  1.0f) );
	REQUIRE(test("|1         |", "|%-10.0f|",   1.0f) );
	REQUIRE(test("|1.        |", "|%#-10.0f|",  1.0f) );
	REQUIRE(test("|+1.       |", "|%+#-10.0f|", 1.0f) );
}

TEST_CASE("vsnprintf p", "")
{
	REQUIRE(test("0xbadc0de", "%p", (void*)0xbadc0de) );
	REQUIRE(test("0xbadc0de           ", "%-20p", (void*)0xbadc0de) );
}

TEST_CASE("vsnprintf s", "")
{
	REQUIRE(test("(null)", "%s", NULL) );
}

TEST_CASE("vsnprintf", "")
{
	REQUIRE(test("x", "%c", 'x') );
	REQUIRE(test("x                   ", "%-20c", 'x') );

	REQUIRE(test("hello               ", "%-20s", "hello") );
	REQUIRE(test("hello, world!", "%s, %s!", "hello", "world") );
}
<commit_msg>Fixed VS build.<commit_after>/*
 * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include "test.h"
#include <bx/string.h>
#include <limits>
#include <inttypes.h>

TEST_CASE("vsnprintf NULL buffer", "No output buffer provided.")
{
	REQUIRE(4 == bx::snprintf(NULL, 0, "test") );

	REQUIRE(1 == bx::snprintf(NULL, 0, "%d", 1) );
}

TEST_CASE("vsnprintf truncated", "Truncated output buffer.")
{
	char buffer[7];

	REQUIRE(10 == bx::snprintf(buffer, BX_COUNTOF(buffer), "Ten chars!") );
	REQUIRE(0  == bx::strncmp(buffer, "Ten ch") );
}

static bool test(const char* _expected, const char* _format, ...)
{
	int32_t max = (int32_t)bx::strnlen(_expected) + 1;
	char* temp = (char*)alloca(max);

	va_list argList;
	va_start(argList, _format);
	int32_t len = bx::vsnprintf(temp, max, _format, argList);
	va_end(argList);

	bool result = true
		&& len == max-1
		&& 0   == bx::strncmp(_expected, temp)
		;

	if (!result)
	{
		printf("result (%d) '%s', expected (%d) '%s'\n", len, temp, max-1, _expected);
	}

	return result;
}

TEST_CASE("vsnprintf f", "")
{
	REQUIRE(test("1.337",    "%0.3f", 1.337) );
	REQUIRE(test("  13.370", "%8.3f", 13.37) );
	REQUIRE(test("  13.370", "%*.*f", 8, 3, 13.37) );
	REQUIRE(test("13.370  ", "%-8.3f", 13.37) );
	REQUIRE(test("13.370  ", "%*.*f", -8, 3, 13.37) );

	REQUIRE(test("nan     ", "%-8f",  std::numeric_limits<double>::quiet_NaN() ) );
	REQUIRE(test("     nan", "%8f",   std::numeric_limits<double>::quiet_NaN() ) );
	REQUIRE(test("-NAN    ", "%-8F", -std::numeric_limits<double>::quiet_NaN() ) );
	REQUIRE(test("     inf", "%8f",   std::numeric_limits<double>::infinity() ) );
	REQUIRE(test("inf     ", "%-8f",  std::numeric_limits<double>::infinity() ) );
	REQUIRE(test("    -INF", "%8F",  -std::numeric_limits<double>::infinity() ) );
}

TEST_CASE("vsnprintf d/i/o/u/x", "")
{
	REQUIRE(test("1337", "%d", 1337) );
	REQUIRE(test("1337                ", "%-20d",  1337) );
	REQUIRE(test("-1337               ", "%-20d", -1337) );

	REQUIRE(test("1337", "%i", 1337) );
	REQUIRE(test("1337                ", "%-20i",  1337) );
	REQUIRE(test("-1337               ", "%-20i", -1337) );

	REQUIRE(test("1337", "%o", 01337) );
	REQUIRE(test("2471", "%o", 1337) );
	REQUIRE(test("1337                ", "%-20o",  01337) );
	REQUIRE(test("37777776441         ", "%-20o", -01337) );

	REQUIRE(test("1337", "%u", 1337) );
	REQUIRE(test("1337                ", "%-20u",  1337) );
	REQUIRE(test("4294965959          ", "%-20u", -1337) );

	REQUIRE(test("1337", "%x", 0x1337) );
	REQUIRE(test("1234abcd            ", "%-20x",  0x1234abcd) );
	REQUIRE(test("1234ABCD            ", "%-20X",  0x1234abcd) );
	REQUIRE(test("edcb5433            ", "%-20x", -0x1234abcd) );
	REQUIRE(test("EDCB5433            ", "%-20X", -0x1234abcd) );
	REQUIRE(test("0000000000001234abcd", "%020x",  0x1234abcd) );
	REQUIRE(test("0000000000001234ABCD", "%020X",  0x1234abcd) );
	REQUIRE(test("000000000000edcb5433", "%020x", -0x1234abcd) );
	REQUIRE(test("000000000000EDCB5433", "%020X", -0x1234abcd) );

	if (BX_ENABLED(BX_ARCH_32BIT) )
	{
		REQUIRE(test("2147483647", "%jd", INTMAX_MAX) );
	}
	else
	{
		REQUIRE(test("9223372036854775807", "%jd", INTMAX_MAX) );
	}

	REQUIRE(test("18446744073709551615", "%" PRIu64, UINT64_MAX) );
	REQUIRE(test("ffffffffffffffff", "%016" PRIx64, UINT64_MAX) );
}

TEST_CASE("vsnprintf modifiers", "")
{
	REQUIRE(test("|  1.000000|", "|%10f|",      1.0f) );
	REQUIRE(test("|1.000000  |", "|%-10f|",     1.0f) );
	REQUIRE(test("|001.000000|", "|%010f|",     1.0f) );
	REQUIRE(test("|0000000001|", "|%010.0f|",   1.0f) );
	REQUIRE(test("|000000001.|", "|%#010.0f|",  1.0f) );
	REQUIRE(test("|         1|", "|%10.0f|",    1.0f) );
	REQUIRE(test("|        1.|", "|%#10.0f|",   1.0f) );
	REQUIRE(test("|       +1.|", "|%#+10.0f|",  1.0f) );
	REQUIRE(test("|1         |", "|%-10.0f|",   1.0f) );
	REQUIRE(test("|1.        |", "|%#-10.0f|",  1.0f) );
	REQUIRE(test("|+1.       |", "|%+#-10.0f|", 1.0f) );
}

TEST_CASE("vsnprintf p", "")
{
	REQUIRE(test("0xbadc0de", "%p", (void*)0xbadc0de) );
	REQUIRE(test("0xbadc0de           ", "%-20p", (void*)0xbadc0de) );
}

TEST_CASE("vsnprintf s", "")
{
	REQUIRE(test("(null)", "%s", NULL) );
}

TEST_CASE("vsnprintf", "")
{
	REQUIRE(test("x", "%c", 'x') );
	REQUIRE(test("x                   ", "%-20c", 'x') );

	REQUIRE(test("hello               ", "%-20s", "hello") );
	REQUIRE(test("hello, world!", "%s, %s!", "hello", "world") );
}
<|endoftext|>


<commit_before>#include <iostream>
#include "db_access.h"

static void prompt_pass(string& str);

db_access::db_access(const char* filename)
  : m_config(filename)
{
    string database;
    string host;
    string user;
    string pass_type;
    string pass;
    int num_taps = 16; /* TODO: Possibly make this config-settable */

    bool success = true;

    if(!m_config.getString(database, "database")) {
        printf("db_access::db_access: Error: No key \"database\" Found!\n");
        success = false;
    }
    printf("In db constructor\n");

    if(!m_config.getString(host, "host")) {
        printf("db_access::db_access: Error: No key \"host\" Found!\n");
        success = false;
    }

    if(!m_config.getString(user, "user")) {
        printf("db_access::db_access: Error: No key \"user\" Found!\n");
        success = false;
    }

    if(!m_config.getString(pass_type, "pass_type")) {
        printf("db_access::db_access: Error: No key \"pass_type\" Found!\n");
        success = false;
    }

    if(success){
        if(pass_type == "plaintext" || pass_type == "base64") {
            if(!m_config.getString(pass, "pass")) {
                printf("db_access::db_access: Error: No key \"pass\" yet pass_type is %s!\n",
                    pass_type.c_str());
                success = false;
            }
        }
    }

    if(success && pass_type == "base64") {
        pass = base64_decode(pass);

        /* Some base64 implementations append a newline,
         * this will get rid of it if it does*/
        if (pass.back() == '\n')
          pass.erase(pass.size()-1);
    }

    else if(success && pass_type == "prompt")
        prompt_pass(pass);

    if (success) {
        init_mysql(host.c_str(), database.c_str(),
                   user.c_str(), pass.c_str());

        /* Initialize internal counter for flow taps */
        m_num_taps = num_taps;
        m_flow_meters = new flow_meter[num_taps];

        /* Grab update_oz to determine ticks necessary to push an update
         * If we don't find one, use default of 1.0.
         * TODO: Make this set as a static const in the class for pretty */
        double update_oz;
        if(!m_config.getDouble(update_oz, "update_oz"))
        {
            printf("Note: update_oz unset, using default 1.0\n");
            update_oz = 1.0;
        }

        /* Iterate through the config file (1-indexed)
         * If the flow meter doesn't have a config option in the file
         * use the default provided
         */
        for(int i = 1; i <= num_taps; i++) {
          double tpg;
          if(!m_config.getDouble(tpg, "flow" +
                                      std::to_string(i) +
                                      "_tpg")){
            printf("Note: flow%d_tpg unset, using default %.2f\n", i, DEFAULT_FLOW_TPG);
            tpg = DEFAULT_FLOW_TPG;
          }

          m_flow_meters[i-1].tpg = tpg;
          /* TODO: Make sure this is being honored correctly */
          m_flow_meters[i-1].update_ticks = tpg * update_oz / 128.0;
        }
    }
}

bool db_access::init_mysql(const char* host, const char* database,
                           const char* user, const char* pass )
{
    m_driver = get_driver_instance();
    m_conn = m_driver->connect(host, user, pass);
    m_conn->setSchema(database);

    m_pushactive = m_conn->prepareStatement("UPDATE active SET ticks=ticks+?,"
                                       " dirty=1 WHERE ontap = ?");

    m_pusharchive = m_conn->prepareStatement("INSERT INTO archive"
                                       " (name, ontap, size, volremaining) VALUES"
                                       " (?, ?, ?, ?)");

    m_getname = m_conn->prepareStatement("SELECT name FROM stock WHERE ontap=?");

    m_stmt = m_conn->createStatement();
}
db_access::~db_access()
{
    delete(m_conn);
    delete(m_pushactive);
    delete(m_pusharchive);
    delete(m_getname);
    delete(m_stmt);
    delete(m_res);
    delete(m_flow_meters);
}
bool db_access::add(unsigned int tap, int value)
{
    /* Check bounds first */
    /* Note: Using Unsigned, so only one case; no negatives */
    if(tap > m_num_taps)
        return false;

    m_flow_meters[tap].ticks += value;
    return true;
}
bool db_access::update()
{
    for(unsigned int i = 0; i < m_num_taps; i++)
    {
        /* Update flow meters if they've accrued enough ticks */
        if(m_flow_meters[i].ticks > m_flow_meters[i].update_ticks)
        {
            printf("Flow meter %d at ticks %d \n", i, m_flow_meters[i].ticks);
            /* SET ticks = ticks + m_flow_ticks[i] */
            m_pushactive->setInt(1, m_flow_meters[i].ticks);

            /* WHERE tap = i+1 */
            m_pushactive->setInt(2, i+1);

            /* Sets dirty bit on any values updated */
            m_pushactive->execute();

            /* Clear our accumulator */
            m_flow_meters[i].ticks = 0;
        }
    }
    return true;
}

bool db_access::clear(unsigned int tap)
{
    /* Check bounds first */
    /* Note: Using Unsigned, so only one case; no negatives */
    if(tap > m_num_taps)
        return false;

    m_flow_meters[tap-1].ticks = 0;
    return true;
}

int db_access::access(unsigned int tap)
{
    /* Check bounds first */
    /* Note: Using Unsigned, so only one case; no negatives */
    if(tap > m_num_taps)
        return 0;

    return m_flow_meters[tap-1].ticks;
}

void db_access::print()
{
    m_res = m_stmt->executeQuery("SELECT * FROM active");
    while(m_res->next())
    {
        std::cout << "sensor: " << m_res->getString("sensor");
        std::cout << " ontap: " << m_res->getString("ontap");
        std::cout << " ticks: " << m_res->getString("ticks");
        std::cout << " size: " << m_res->getString("size");
        std::cout << "\n";
    }
}

bool db_access::clear_db()
{
    m_res = m_stmt->executeQuery("UPDATE active SET ticks = 0");
    return true;
}

bool db_access::archive()
{
    /* Push to archive those that have been marked as dirty */
    m_res = m_stmt->executeQuery("SELECT ontap,ticks,size FROM active WHERE dirty=1");
    int size;
    int ticks;
    int ontap;
    std::string name;
    sql::ResultSet* temp=NULL;
    double volremaining;
    double volgone;
    double totalvol;
    while(m_res->next())
    {
        size = m_res->getInt("size");
        ticks = m_res->getInt("ticks");
        ontap = m_res->getInt("ontap");

        /* If there have been no ticks, do not report it */
        /* Sixtel */
        if(size == 0)
            totalvol = 41; /* In pints */
        /* Half barrel */
        else
            totalvol = 124; /* In pints */

        /* TODO: CHECK THIS MATH */
        volgone = (ticks * 8.0) / m_flow_meters[ontap-1].tpg; /* In pints */
        volremaining = totalvol - volgone;             /* In pints */

        /* Set archive beer's name using ontap as a reference */
        m_getname->setInt(1, ontap);
        temp = m_getname->executeQuery();

        /* Get name if there's a valid ontap */
        if(temp->next())
            name = temp->getString("name");
        /* Not a valid name set up for this beer! */
        else
            name = "NO NAME NO TAP";

        m_pusharchive->setString(1, name);
        m_pusharchive->setInt(2, ontap);
        m_pusharchive->setInt(3, size);
        m_pusharchive->setDouble(4, volremaining);

        m_pusharchive->execute();

        if(temp != NULL)
            delete temp;
    }

    return true;
}

static void prompt_pass(string& str) {
    char* pass = getpass("Enter Password: ");
    str = pass;
}

<commit_msg>Fixed memleaks<commit_after>#include <iostream>
#include "db_access.h"

static void prompt_pass(string& str);

db_access::db_access(const char* filename)
  : m_config(filename)
{
    string database;
    string host;
    string user;
    string pass_type;
    string pass;
    int num_taps = 16; /* TODO: Possibly make this config-settable */

    bool success = true;

    if(!m_config.getString(database, "database")) {
        printf("db_access::db_access: Error: No key \"database\" Found!\n");
        success = false;
    }
    printf("In db constructor\n");

    if(!m_config.getString(host, "host")) {
        printf("db_access::db_access: Error: No key \"host\" Found!\n");
        success = false;
    }

    if(!m_config.getString(user, "user")) {
        printf("db_access::db_access: Error: No key \"user\" Found!\n");
        success = false;
    }

    if(!m_config.getString(pass_type, "pass_type")) {
        printf("db_access::db_access: Error: No key \"pass_type\" Found!\n");
        success = false;
    }

    if(success){
        if(pass_type == "plaintext" || pass_type == "base64") {
            if(!m_config.getString(pass, "pass")) {
                printf("db_access::db_access: Error: No key \"pass\" yet pass_type is %s!\n",
                    pass_type.c_str());
                success = false;
            }
        }
    }

    if(success && pass_type == "base64") {
        pass = base64_decode(pass);

        /* Some base64 implementations append a newline,
         * this will get rid of it if it does*/
        if (pass.back() == '\n')
          pass.erase(pass.size()-1);
    }

    else if(success && pass_type == "prompt")
        prompt_pass(pass);

    if (success) {
        init_mysql(host.c_str(), database.c_str(),
                   user.c_str(), pass.c_str());

        /* Initialize internal counter for flow taps */
        m_num_taps = num_taps;
        m_flow_meters = new flow_meter[num_taps];

        /* Grab update_oz to determine ticks necessary to push an update
         * If we don't find one, use default of 1.0.
         * TODO: Make this set as a static const in the class for pretty */
        double update_oz;
        if(!m_config.getDouble(update_oz, "update_oz"))
        {
            printf("Note: update_oz unset, using default 1.0\n");
            update_oz = 1.0;
        }

        /* Iterate through the config file (1-indexed)
         * If the flow meter doesn't have a config option in the file
         * use the default provided
         */
        for(int i = 1; i <= num_taps; i++) {
          double tpg;
          if(!m_config.getDouble(tpg, "flow" +
                                      std::to_string(i) +
                                      "_tpg")){
            printf("Note: flow%d_tpg unset, using default %.2f\n", i, DEFAULT_FLOW_TPG);
            tpg = DEFAULT_FLOW_TPG;
          }

          m_flow_meters[i-1].tpg = tpg;
          /* TODO: Make sure this is being honored correctly */
          m_flow_meters[i-1].update_ticks = tpg * update_oz / 128.0;
        }
    }
}

bool db_access::init_mysql(const char* host, const char* database,
                           const char* user, const char* pass )
{
    m_driver = get_driver_instance();
    m_conn = m_driver->connect(host, user, pass);
    m_conn->setSchema(database);

    m_pushactive = m_conn->prepareStatement("UPDATE active SET ticks=ticks+?,"
                                       " dirty=1 WHERE ontap = ?");

    m_pusharchive = m_conn->prepareStatement("INSERT INTO archive"
                                       " (name, ontap, size, volremaining) VALUES"
                                       " (?, ?, ?, ?)");

    m_getname = m_conn->prepareStatement("SELECT name FROM stock WHERE ontap=?");

    m_stmt = m_conn->createStatement();
}
db_access::~db_access()
{
    delete(m_conn);
    delete(m_pushactive);
    delete(m_pusharchive);
    delete(m_getname);
    delete(m_stmt);
    delete(m_res);
    delete(m_flow_meters);
}
bool db_access::add(unsigned int tap, int value)
{
    /* Check bounds first */
    /* Note: Using Unsigned, so only one case; no negatives */
    if(tap > m_num_taps)
        return false;

    m_flow_meters[tap].ticks += value;
    return true;
}
bool db_access::update()
{
    for(unsigned int i = 0; i < m_num_taps; i++)
    {
        /* Update flow meters if they've accrued enough ticks */
        if(m_flow_meters[i].ticks > m_flow_meters[i].update_ticks)
        {
            printf("Flow meter %d at ticks %d \n", i, m_flow_meters[i].ticks);
            /* SET ticks = ticks + m_flow_ticks[i] */
            m_pushactive->setInt(1, m_flow_meters[i].ticks);

            /* WHERE tap = i+1 */
            m_pushactive->setInt(2, i+1);

            /* Sets dirty bit on any values updated */
            m_pushactive->execute();

            /* Clear our accumulator */
            m_flow_meters[i].ticks = 0;
        }
    }
    return true;
}

bool db_access::clear(unsigned int tap)
{
    /* Check bounds first */
    /* Note: Using Unsigned, so only one case; no negatives */
    if(tap > m_num_taps)
        return false;

    m_flow_meters[tap-1].ticks = 0;
    return true;
}

int db_access::access(unsigned int tap)
{
    /* Check bounds first */
    /* Note: Using Unsigned, so only one case; no negatives */
    if(tap > m_num_taps)
        return 0;

    return m_flow_meters[tap-1].ticks;
}

void db_access::print()
{
    m_res = m_stmt->executeQuery("SELECT * FROM active");
    while(m_res->next())
    {
        std::cout << "sensor: " << m_res->getString("sensor");
        std::cout << " ontap: " << m_res->getString("ontap");
        std::cout << " ticks: " << m_res->getString("ticks");
        std::cout << " size: " << m_res->getString("size");
        std::cout << "\n";
    }
    if (m_res != NULL)
        delete m_res;
}

bool db_access::clear_db()
{
    m_res = m_stmt->executeQuery("UPDATE active SET ticks = 0");
    if (m_res != NULL)
        delete m_res;
    return true;
}

bool db_access::archive()
{
    /* Push to archive those that have been marked as dirty */
    m_res = m_stmt->executeQuery("SELECT ontap,ticks,size FROM active WHERE dirty=1");
    int size;
    int ticks;
    int ontap;
    std::string name;
    sql::ResultSet* temp=NULL;
    double volremaining;
    double volgone;
    double totalvol;
    while(m_res->next())
    {
        size = m_res->getInt("size");
        ticks = m_res->getInt("ticks");
        ontap = m_res->getInt("ontap");

        /* If there have been no ticks, do not report it */
        /* Sixtel */
        if(size == 0)
            totalvol = 41; /* In pints */
        /* Half barrel */
        else
            totalvol = 124; /* In pints */

        /* TODO: CHECK THIS MATH */
        volgone = (ticks * 8.0) / m_flow_meters[ontap-1].tpg; /* In pints */
        volremaining = totalvol - volgone;             /* In pints */

        /* Set archive beer's name using ontap as a reference */
        m_getname->setInt(1, ontap);
        temp = m_getname->executeQuery();

        /* Get name if there's a valid ontap */
        if(temp->next())
            name = temp->getString("name");
        /* Not a valid name set up for this beer! */
        else
            name = "NO NAME NO TAP";

        m_pusharchive->setString(1, name);
        m_pusharchive->setInt(2, ontap);
        m_pusharchive->setInt(3, size);
        m_pusharchive->setDouble(4, volremaining);

        m_pusharchive->execute();

        if(temp != NULL)
            delete temp;
    }
    if (m_res != NULL)
        delete m_res;

    return true;
}

static void prompt_pass(string& str) {
    char* pass = getpass("Enter Password: ");
    str = pass;
}

<|endoftext|>


<commit_before>#include "../src/meshoptimizer.hpp"

#include <algorithm>
#include <cstdio>
#include <ctime>

#include "objparser.hpp"

using namespace meshopt;

const size_t kCacheSize = 24;

struct Vertex
{
	float px, py, pz;
	float nx, ny, nz;
	float tx, ty;
};

struct Mesh
{
	std::vector<Vertex> vertices;
	std::vector<unsigned int> indices;
};

Mesh generatePlane(unsigned int N)
{
	Mesh result;

	result.vertices.reserve((N + 1) * (N + 1));
	result.indices.reserve(N * N * 6);

	for (unsigned int y = 0; y <= N; ++y)
		for (unsigned int x = 0; x <= N; ++x)
		{
			Vertex v = {float(x), float(y), 0, 0, 0, 1, float(x) / float(N), float(y) / float(N)};

			result.vertices.push_back(v);
		}

	for (unsigned int y = 0; y < N; ++y)
		for (unsigned int x = 0; x < N; ++x)
		{
			result.indices.push_back((y + 0) * N + (x + 0));
			result.indices.push_back((y + 0) * N + (x + 1));
			result.indices.push_back((y + 1) * N + (x + 0));

			result.indices.push_back((y + 1) * N + (x + 0));
			result.indices.push_back((y + 0) * N + (x + 1));
			result.indices.push_back((y + 1) * N + (x + 1));
		}

	return result;
}

Mesh parseObj(const char* path, clock_t& reindex)
{
	ObjFile file;

	if (!objParseFile(file, path))
	{
		printf("Error loading %s: file not found\n", path);
		return Mesh();
	}

	if (!objValidate(file))
	{
		printf("Error loading %s: invalid file data\n", path);
		return Mesh();
	}

	objTriangulate(file);

	size_t total_indices = file.f.size() / 3;

	std::vector<Vertex> vertices;
	vertices.reserve(total_indices);

	for (size_t i = 0; i < file.f.size(); i += 3)
	{
		int vi = file.f[i + 0];
		int vti = file.f[i + 1];
		int vni = file.f[i + 2];

		Vertex v =
		    {
		        file.v[vi * 3 + 0],
		        file.v[vi * 3 + 1],
		        file.v[vi * 3 + 2],

		        vni >= 0 ? file.vn[vni * 3 + 0] : 0,
		        vni >= 0 ? file.vn[vni * 3 + 1] : 0,
		        vni >= 0 ? file.vn[vni * 3 + 2] : 0,

		        vti >= 0 ? file.vt[vti * 3 + 0] : 0,
		        vti >= 0 ? file.vt[vti * 3 + 1] : 0,
		    };

		vertices.push_back(v);
	}

	reindex = clock();

	Mesh result;

	std::vector<unsigned int> remap(total_indices);

	size_t total_vertices = generateVertexRemap(&remap[0], NULL, total_indices, &vertices[0], total_indices, sizeof(Vertex));

	result.indices.resize(total_indices);
	remapIndexBuffer(&result.indices[0], NULL, total_indices, &remap[0]);

	result.vertices.resize(total_vertices);
	remapVertexBuffer(&result.vertices[0], &vertices[0], total_indices, sizeof(Vertex), &remap[0]);

	return result;
}

void optNone(Mesh& mesh)
{
	(void)mesh;
}

void optRandomShuffle(Mesh& mesh)
{
	std::vector<unsigned int> faces(mesh.indices.size() / 3);

	for (size_t i = 0; i < faces.size(); ++i)
		faces[i] = static_cast<unsigned int>(i);

	std::random_shuffle(faces.begin(), faces.end());

	std::vector<unsigned int> result(mesh.indices.size());

	for (size_t i = 0; i < faces.size(); ++i)
	{
		result[i * 3 + 0] = mesh.indices[faces[i] * 3 + 0];
		result[i * 3 + 1] = mesh.indices[faces[i] * 3 + 1];
		result[i * 3 + 2] = mesh.indices[faces[i] * 3 + 2];
	}

	mesh.indices.swap(result);
}

void optCache(Mesh& mesh)
{
	optimizeVertexCache(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), kCacheSize);
}

void optCache0(Mesh& mesh)
{
	optimizeVertexCache(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), 0);
}

void optOverdraw(Mesh& mesh)
{
	// use worst-case ACMR threshold so that overdraw optimizer can sort *all* triangles
	// warning: this significantly deteriorates the vertex cache efficiency so it is not advised; look at optComplete for the recommended method
	const float kThreshold = 3.f;
	optimizeOverdraw(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), &mesh.vertices[0].px, sizeof(Vertex), mesh.vertices.size(), kCacheSize, kThreshold);
}

void optFetch(Mesh& mesh)
{
	optimizeVertexFetch(&mesh.vertices[0], &mesh.vertices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), sizeof(Vertex));
}

void optComplete(Mesh& mesh)
{
	// vertex cache optimization should go first as it provides data for overdraw
	optimizeVertexCache(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), kCacheSize);

	// reorder indices for overdraw, balancing overdraw and vertex cache efficiency
	const float kThreshold = 1.05f; // allow up to 5% worse ACMR to get more reordering opportunities for overdraw
	optimizeOverdraw(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), &mesh.vertices[0].px, sizeof(Vertex), mesh.vertices.size(), kCacheSize, kThreshold);

	// vertex fetch optimization should go last as it depends on the final index order
	optimizeVertexFetch(&mesh.vertices[0], &mesh.vertices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), sizeof(Vertex));
}

void optCompleteSimplify(Mesh& mesh)
{
	// generate 4 LOD levels (1-4), with each subsequent LOD using 70% triangles
	// note that each LOD uses the same (shared) vertex buffer
	// vertex cache optimization should go first as it provides data for overdraw
	std::vector<unsigned int> lods[5];

	lods[0] = mesh.indices;

	for (size_t i = 1; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		std::vector<unsigned int>& lod = lods[i];

		size_t target_count = size_t(double(mesh.indices.size()) * pow(0.7, double(i)));

		// we can simplify all the way from base level or from the last result
		// simplifying from the base level sometimes produces better results, but simplifying from last level is faster
		const std::vector<unsigned int>& source = lods[i - 1];

		lod.resize(source.size());
		lod.resize(simplify(&lod[0], &source[0], source.size(), &mesh.vertices[0], mesh.vertices.size(), sizeof(Vertex), target_count));
	}

	// optimize each individual LOD for vertex cache & overdraw
	for (size_t i = 0; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		std::vector<unsigned int>& lod = lods[i];

		optimizeVertexCache(&lod[0], &lod[0], lod.size(), mesh.vertices.size(), kCacheSize);
		optimizeOverdraw(&lod[0], &lod[0], lod.size(), &mesh.vertices[0].px, sizeof(Vertex), mesh.vertices.size(), kCacheSize, 1.0f);
	}

	// concatenate all LODs into one IB
	mesh.indices.clear();

	for (size_t i = 0; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		mesh.indices.insert(mesh.indices.end(), lods[i].begin(), lods[i].end());
	}

	// vertex fetch optimization should go last as it depends on the final index order
	// note that the order of LODs above affects vertex fetch results; here we optimize for LOD0 fetch as a primary goal
	optimizeVertexFetch(&mesh.vertices[0], &mesh.vertices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), sizeof(Vertex));

	printf("%-9s:", "Simplify");

	for (size_t i = 0; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		printf(" LOD%d %d", int(i), int(lods[i].size()) / 3);
	}

	printf("\n");
}

void optimize(const Mesh& mesh, const char* name, void (*optf)(Mesh& mesh))
{
	Mesh copy = mesh;

	clock_t start = clock();
	optf(copy);
	clock_t end = clock();

	VertexCacheStatistics vcs = analyzeVertexCache(&copy.indices[0], copy.indices.size(), copy.vertices.size(), kCacheSize);
	VertexCacheStatistics vc0s = analyzeVertexCache(&copy.indices[0], copy.indices.size(), copy.vertices.size(), 0);
	VertexFetchStatistics vfs = analyzeVertexFetch(&copy.indices[0], copy.indices.size(), copy.vertices.size(), sizeof(Vertex));
	OverdrawStatistics os = analyzeOverdraw(&copy.indices[0], copy.indices.size(), &copy.vertices[0].px, sizeof(Vertex), copy.vertices.size());

	printf("%-9s: ACMR %f ATVR %f (LRU %f) Overfetch %f Overdraw %f in %.2f msec\n", name, vcs.acmr, vcs.atvr, vc0s.atvr, vfs.overfetch, os.overdraw, double(end - start) / CLOCKS_PER_SEC * 1000);
}

void process(const char* path)
{
	Mesh mesh;

	if (path)
	{
		clock_t start = clock();
		clock_t middle;
		mesh = parseObj(path, middle);
		clock_t end = clock();

		if (mesh.vertices.empty())
		{
			printf("Mesh %s is empty, skipping\n", path);
			return;
		}

		printf("# %s: %d vertices, %d triangles; read in %.2f msec; indexed in %.2f msec\n", path, int(mesh.vertices.size()), int(mesh.indices.size() / 3), double(middle - start) / CLOCKS_PER_SEC * 1000, double(end - middle) / CLOCKS_PER_SEC * 1000);
	}
	else
	{
		mesh = generatePlane(1000);

		printf("# tessellated plane: %d vertices, %d triangles\n", int(mesh.vertices.size()), int(mesh.indices.size() / 3));
	}

	optimize(mesh, "Original", optNone);
	optimize(mesh, "Random", optRandomShuffle);
	optimize(mesh, "Cache", optCache);
	optimize(mesh, "Cache0", optCache0);
	optimize(mesh, "Overdraw", optOverdraw);
	optimize(mesh, "Fetch", optFetch);
	optimize(mesh, "Complete", optComplete);

	// note: the ATVR/overdraw output from this pass is not necessarily correct since we analyze all LODs at once
	optimize(mesh, "Simplify", optCompleteSimplify);
}

int main(int argc, char** argv)
{
	if (argc == 1)
	{
		printf("Usage: %s [.obj file]\n", argv[0]);
		process(0);
	}
	else
	{
		for (int i = 1; i < argc; ++i)
		{
			process(argv[i]);
		}
	}
}
<commit_msg>demo: Fix OSX build<commit_after>#include "../src/meshoptimizer.hpp"

#include <algorithm>
#include <cstdio>
#include <ctime>
#include <cmath>

#include "objparser.hpp"

using namespace meshopt;

const size_t kCacheSize = 24;

struct Vertex
{
	float px, py, pz;
	float nx, ny, nz;
	float tx, ty;
};

struct Mesh
{
	std::vector<Vertex> vertices;
	std::vector<unsigned int> indices;
};

Mesh generatePlane(unsigned int N)
{
	Mesh result;

	result.vertices.reserve((N + 1) * (N + 1));
	result.indices.reserve(N * N * 6);

	for (unsigned int y = 0; y <= N; ++y)
		for (unsigned int x = 0; x <= N; ++x)
		{
			Vertex v = {float(x), float(y), 0, 0, 0, 1, float(x) / float(N), float(y) / float(N)};

			result.vertices.push_back(v);
		}

	for (unsigned int y = 0; y < N; ++y)
		for (unsigned int x = 0; x < N; ++x)
		{
			result.indices.push_back((y + 0) * N + (x + 0));
			result.indices.push_back((y + 0) * N + (x + 1));
			result.indices.push_back((y + 1) * N + (x + 0));

			result.indices.push_back((y + 1) * N + (x + 0));
			result.indices.push_back((y + 0) * N + (x + 1));
			result.indices.push_back((y + 1) * N + (x + 1));
		}

	return result;
}

Mesh parseObj(const char* path, clock_t& reindex)
{
	ObjFile file;

	if (!objParseFile(file, path))
	{
		printf("Error loading %s: file not found\n", path);
		return Mesh();
	}

	if (!objValidate(file))
	{
		printf("Error loading %s: invalid file data\n", path);
		return Mesh();
	}

	objTriangulate(file);

	size_t total_indices = file.f.size() / 3;

	std::vector<Vertex> vertices;
	vertices.reserve(total_indices);

	for (size_t i = 0; i < file.f.size(); i += 3)
	{
		int vi = file.f[i + 0];
		int vti = file.f[i + 1];
		int vni = file.f[i + 2];

		Vertex v =
		    {
		        file.v[vi * 3 + 0],
		        file.v[vi * 3 + 1],
		        file.v[vi * 3 + 2],

		        vni >= 0 ? file.vn[vni * 3 + 0] : 0,
		        vni >= 0 ? file.vn[vni * 3 + 1] : 0,
		        vni >= 0 ? file.vn[vni * 3 + 2] : 0,

		        vti >= 0 ? file.vt[vti * 3 + 0] : 0,
		        vti >= 0 ? file.vt[vti * 3 + 1] : 0,
		    };

		vertices.push_back(v);
	}

	reindex = clock();

	Mesh result;

	std::vector<unsigned int> remap(total_indices);

	size_t total_vertices = generateVertexRemap(&remap[0], NULL, total_indices, &vertices[0], total_indices, sizeof(Vertex));

	result.indices.resize(total_indices);
	remapIndexBuffer(&result.indices[0], NULL, total_indices, &remap[0]);

	result.vertices.resize(total_vertices);
	remapVertexBuffer(&result.vertices[0], &vertices[0], total_indices, sizeof(Vertex), &remap[0]);

	return result;
}

void optNone(Mesh& mesh)
{
	(void)mesh;
}

void optRandomShuffle(Mesh& mesh)
{
	std::vector<unsigned int> faces(mesh.indices.size() / 3);

	for (size_t i = 0; i < faces.size(); ++i)
		faces[i] = static_cast<unsigned int>(i);

	std::random_shuffle(faces.begin(), faces.end());

	std::vector<unsigned int> result(mesh.indices.size());

	for (size_t i = 0; i < faces.size(); ++i)
	{
		result[i * 3 + 0] = mesh.indices[faces[i] * 3 + 0];
		result[i * 3 + 1] = mesh.indices[faces[i] * 3 + 1];
		result[i * 3 + 2] = mesh.indices[faces[i] * 3 + 2];
	}

	mesh.indices.swap(result);
}

void optCache(Mesh& mesh)
{
	optimizeVertexCache(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), kCacheSize);
}

void optCache0(Mesh& mesh)
{
	optimizeVertexCache(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), 0);
}

void optOverdraw(Mesh& mesh)
{
	// use worst-case ACMR threshold so that overdraw optimizer can sort *all* triangles
	// warning: this significantly deteriorates the vertex cache efficiency so it is not advised; look at optComplete for the recommended method
	const float kThreshold = 3.f;
	optimizeOverdraw(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), &mesh.vertices[0].px, sizeof(Vertex), mesh.vertices.size(), kCacheSize, kThreshold);
}

void optFetch(Mesh& mesh)
{
	optimizeVertexFetch(&mesh.vertices[0], &mesh.vertices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), sizeof(Vertex));
}

void optComplete(Mesh& mesh)
{
	// vertex cache optimization should go first as it provides data for overdraw
	optimizeVertexCache(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), kCacheSize);

	// reorder indices for overdraw, balancing overdraw and vertex cache efficiency
	const float kThreshold = 1.05f; // allow up to 5% worse ACMR to get more reordering opportunities for overdraw
	optimizeOverdraw(&mesh.indices[0], &mesh.indices[0], mesh.indices.size(), &mesh.vertices[0].px, sizeof(Vertex), mesh.vertices.size(), kCacheSize, kThreshold);

	// vertex fetch optimization should go last as it depends on the final index order
	optimizeVertexFetch(&mesh.vertices[0], &mesh.vertices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), sizeof(Vertex));
}

void optCompleteSimplify(Mesh& mesh)
{
	// generate 4 LOD levels (1-4), with each subsequent LOD using 70% triangles
	// note that each LOD uses the same (shared) vertex buffer
	// vertex cache optimization should go first as it provides data for overdraw
	std::vector<unsigned int> lods[5];

	lods[0] = mesh.indices;

	for (size_t i = 1; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		std::vector<unsigned int>& lod = lods[i];

		size_t target_count = size_t(double(mesh.indices.size()) * pow(0.7, double(i)));

		// we can simplify all the way from base level or from the last result
		// simplifying from the base level sometimes produces better results, but simplifying from last level is faster
		const std::vector<unsigned int>& source = lods[i - 1];

		lod.resize(source.size());
		lod.resize(simplify(&lod[0], &source[0], source.size(), &mesh.vertices[0], mesh.vertices.size(), sizeof(Vertex), target_count));
	}

	// optimize each individual LOD for vertex cache & overdraw
	for (size_t i = 0; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		std::vector<unsigned int>& lod = lods[i];

		optimizeVertexCache(&lod[0], &lod[0], lod.size(), mesh.vertices.size(), kCacheSize);
		optimizeOverdraw(&lod[0], &lod[0], lod.size(), &mesh.vertices[0].px, sizeof(Vertex), mesh.vertices.size(), kCacheSize, 1.0f);
	}

	// concatenate all LODs into one IB
	mesh.indices.clear();

	for (size_t i = 0; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		mesh.indices.insert(mesh.indices.end(), lods[i].begin(), lods[i].end());
	}

	// vertex fetch optimization should go last as it depends on the final index order
	// note that the order of LODs above affects vertex fetch results; here we optimize for LOD0 fetch as a primary goal
	optimizeVertexFetch(&mesh.vertices[0], &mesh.vertices[0], &mesh.indices[0], mesh.indices.size(), mesh.vertices.size(), sizeof(Vertex));

	printf("%-9s:", "Simplify");

	for (size_t i = 0; i < sizeof(lods) / sizeof(lods[0]); ++i)
	{
		printf(" LOD%d %d", int(i), int(lods[i].size()) / 3);
	}

	printf("\n");
}

void optimize(const Mesh& mesh, const char* name, void (*optf)(Mesh& mesh))
{
	Mesh copy = mesh;

	clock_t start = clock();
	optf(copy);
	clock_t end = clock();

	VertexCacheStatistics vcs = analyzeVertexCache(&copy.indices[0], copy.indices.size(), copy.vertices.size(), kCacheSize);
	VertexCacheStatistics vc0s = analyzeVertexCache(&copy.indices[0], copy.indices.size(), copy.vertices.size(), 0);
	VertexFetchStatistics vfs = analyzeVertexFetch(&copy.indices[0], copy.indices.size(), copy.vertices.size(), sizeof(Vertex));
	OverdrawStatistics os = analyzeOverdraw(&copy.indices[0], copy.indices.size(), &copy.vertices[0].px, sizeof(Vertex), copy.vertices.size());

	printf("%-9s: ACMR %f ATVR %f (LRU %f) Overfetch %f Overdraw %f in %.2f msec\n", name, vcs.acmr, vcs.atvr, vc0s.atvr, vfs.overfetch, os.overdraw, double(end - start) / CLOCKS_PER_SEC * 1000);
}

void process(const char* path)
{
	Mesh mesh;

	if (path)
	{
		clock_t start = clock();
		clock_t middle;
		mesh = parseObj(path, middle);
		clock_t end = clock();

		if (mesh.vertices.empty())
		{
			printf("Mesh %s is empty, skipping\n", path);
			return;
		}

		printf("# %s: %d vertices, %d triangles; read in %.2f msec; indexed in %.2f msec\n", path, int(mesh.vertices.size()), int(mesh.indices.size() / 3), double(middle - start) / CLOCKS_PER_SEC * 1000, double(end - middle) / CLOCKS_PER_SEC * 1000);
	}
	else
	{
		mesh = generatePlane(1000);

		printf("# tessellated plane: %d vertices, %d triangles\n", int(mesh.vertices.size()), int(mesh.indices.size() / 3));
	}

	optimize(mesh, "Original", optNone);
	optimize(mesh, "Random", optRandomShuffle);
	optimize(mesh, "Cache", optCache);
	optimize(mesh, "Cache0", optCache0);
	optimize(mesh, "Overdraw", optOverdraw);
	optimize(mesh, "Fetch", optFetch);
	optimize(mesh, "Complete", optComplete);

	// note: the ATVR/overdraw output from this pass is not necessarily correct since we analyze all LODs at once
	optimize(mesh, "Simplify", optCompleteSimplify);
}

int main(int argc, char** argv)
{
	if (argc == 1)
	{
		printf("Usage: %s [.obj file]\n", argv[0]);
		process(0);
	}
	else
	{
		for (int i = 1; i < argc; ++i)
		{
			process(argv[i]);
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Update q_window_trim.cpp<commit_after><|endoftext|>


<commit_before><commit_msg>Update python_object.cpp<commit_after><|endoftext|>


<commit_before><commit_msg>begin_dialog will now properly end combat (immediately, rather than 1ms later)<commit_after><|endoftext|>


<commit_before>#include "dynet/init.h"
#include "dynet/aligned-mem-pool.h"
#include "dynet/dynet.h"
#include "dynet/weight-decay.h"
#include "dynet/globals.h"

#include <iostream>
#include <random>
#include <cmath>

#if HAVE_CUDA
#include "dynet/cuda.h"
#include <device_launch_parameters.h>
#endif

using namespace std;

namespace dynet {

DynetParams::DynetParams() : random_seed(0), mem_descriptor("512"), weight_decay(0), autobatch(1),
  shared_parameters(false)
#if HAVE_CUDA
  , ngpus_requested(false), ids_requested(false), requested_gpus(-1)
#endif
{
#if HAVE_CUDA
  gpu_mask = std::vector<int>(MAX_GPUS, 0);
#endif
}

DynetParams::~DynetParams()
{
}

static void remove_args(int& argc, char**& argv, int& argi, int n) {
  for (int i = argi + n; i < argc; ++i)
    argv[i - n] = argv[i];
  argc -= n;
  DYNET_ASSERT(argc >= 0, "remove_args less than 0");
}

DynetParams extract_dynet_params(int& argc, char**& argv, bool shared_parameters) {
  DynetParams params;
  params.shared_parameters = shared_parameters;

  int argi = 1;

#if HAVE_CUDA
  params.gpu_mask = std::vector<int>(MAX_GPUS, 0);
#endif

  while (argi < argc) {
    string arg = argv[argi];

    // Memory
    if (arg == "--dynet-mem" || arg == "--dynet_mem") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-mem expects an argument (the memory, in megabytes, to reserve)");
      } else {
        params.mem_descriptor = argv[argi + 1];
        remove_args(argc, argv, argi, 2);
      }
    }

    // Weight decay
    else if (arg == "--dynet-weight-decay" || arg == "--dynet_weight_decay") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-weight-decay requires an argument (the weight decay per update)");
      } else {
        string a2 = argv[argi + 1];
        istringstream d(a2); d >> params.weight_decay;
        remove_args(argc, argv, argi, 2);
      }
    }

    // Random seed
    else if (arg == "--dynet-seed" || arg == "--dynet_seed") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-seed expects an argument (the random number seed)");
      } else {
        string a2 = argv[argi + 1];
        istringstream c(a2); c >> params.random_seed;
        remove_args(argc, argv, argi, 2);
      }
    }

    // Memory
    else if (arg == "--dynet-autobatch" || arg == "--dynet_autobatch") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-autobatch expects an argument (0 for none 1 for on)");
      } else {
        string a2 = argv[argi + 1];
        istringstream c(a2); c >> params.autobatch;
        remove_args(argc, argv, argi, 2);
      }
    }

#if HAVE_CUDA
    // Number of GPUs
    else if (arg == "--dynet_gpus" || arg == "--dynet-gpus") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-gpus expects an argument (number of GPUs to use)");
      } else {
        if (params.ngpus_requested)
          throw std::invalid_argument("Multiple instances of --dynet-gpus");
        params.ngpus_requested = true;
        string a2 = argv[argi + 1];
        istringstream c(a2); c >> params.requested_gpus;
        remove_args(argc, argv, argi, 2);
      }
    }

    // GPU ids
    else if (arg == "--dynet_gpu_ids" || arg == "--dynet-gpu-ids") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-gpu-ids expects an argument (comma separated list of physical GPU ids to use)");
      } else {
        string a2 = argv[argi + 1];
        if (params.ids_requested)
          throw std::invalid_argument("Multiple instances of --dynet-gpu-ids");
        params.ids_requested = true;
        if (a2.size() % 2 != 1) {
          ostringstream oss; oss << "Bad argument to --dynet-gpu-ids: " << a2; throw std::invalid_argument(oss.str());
        }
        for (unsigned i = 0; i < a2.size(); ++i) {
          if ((i % 2 == 0 && (a2[i] < '0' || a2[i] > '9')) ||
              (i % 2 == 1 && a2[i] != ',')) {
            ostringstream oss; oss << "Bad argument to --dynet-gpu-ids: " << a2;
            throw std::invalid_argument(oss.str());
          }
          if (i % 2 == 0) {
            int gpu_id = a2[i] - '0';
            if (gpu_id >= MAX_GPUS) { throw std::runtime_error("DyNet hard limit on maximum number of GPUs (MAX_GPUS) exceeded. If you need more, modify the code to raise this hard limit."); }
            params.gpu_mask[gpu_id]++;
            params.requested_gpus++;
            if (params.gpu_mask[gpu_id] != 1) {
              ostringstream oss; oss << "Bad argument to --dynet-gpu-ids: " << a2;
              throw std::invalid_argument(oss.str());
            }
          }
        }
        remove_args(argc, argv, argi, 2);
      }
    }
#endif

    // Go to next argument
    else {
      argi++;
    }

  }

#if HAVE_CUDA
  // Check for conflict between the two ways of requesting GPUs
  if (params.ids_requested && params.ngpus_requested)
    throw std::invalid_argument("Use only --dynet_gpus or --dynet_gpu_ids, not both\n");
#endif

  return params;
}

void initialize(DynetParams& params) {
  if (default_device != nullptr) {
    cerr << "WARNING: Attempting to initialize dynet twice. Ignoring duplicate initialization." << endl;
    return;
  }

  // initialize CUDA
  vector<Device*> gpudevices;
#if HAVE_CUDA
  cerr << "[dynet] initializing CUDA\n";
  gpudevices = initialize_gpu(params);
#endif

  // Set random seed
  if (params.random_seed == 0) {
    random_device rd;
    params.random_seed = rd();
  }
  cerr << "[dynet] random seed: " << params.random_seed << endl;
  rndeng = new mt19937(params.random_seed);

  // Set weight decay rate
  if (params.weight_decay < 0 || params.weight_decay >= 1)
    throw std::invalid_argument("[dynet] weight decay parameter must be between 0 and 1 (probably very small like 1e-6)\n");
  weight_decay_lambda = params.weight_decay;

  // Set autobatch
  autobatch_flag = params.autobatch;

  // Allocate memory
  cerr << "[dynet] allocating memory: " << params.mem_descriptor << "MB\n";
  // TODO: Once multi-device support is added, we will potentially allocate both CPU
  //       and GPU, not either-or
  int default_index = 0;
  if (gpudevices.size() > 0) {
    for (auto gpu : gpudevices)
      devices.push_back(gpu);
  } else {
    devices.push_back(new Device_CPU(devices.size(), params.mem_descriptor, params.shared_parameters));
  }
  default_device = devices[default_index];

  // TODO these should be accessed through the relevant device and removed here
  kSCALAR_MINUSONE = default_device->kSCALAR_MINUSONE;
  kSCALAR_ONE = default_device->kSCALAR_ONE;
  kSCALAR_ZERO = default_device->kSCALAR_ZERO;
  cerr << "[dynet] memory allocation done.\n";

}

void initialize(int& argc, char**& argv, bool shared_parameters) {
  DynetParams params = extract_dynet_params(argc, argv, shared_parameters);
  initialize(params);
}

void cleanup() {
  delete rndeng;
  // TODO: Devices cannot be deleted at the moment
  // for(Device* device : devices) delete device;
  devices.clear();
  default_device = nullptr;
}

} // namespace dynet

<commit_msg>Turned autobatching off by default for now<commit_after>#include "dynet/init.h"
#include "dynet/aligned-mem-pool.h"
#include "dynet/dynet.h"
#include "dynet/weight-decay.h"
#include "dynet/globals.h"

#include <iostream>
#include <random>
#include <cmath>

#if HAVE_CUDA
#include "dynet/cuda.h"
#include <device_launch_parameters.h>
#endif

using namespace std;

namespace dynet {

DynetParams::DynetParams() : random_seed(0), mem_descriptor("512"), weight_decay(0), autobatch(0),
  shared_parameters(false)
#if HAVE_CUDA
  , ngpus_requested(false), ids_requested(false), requested_gpus(-1)
#endif
{
#if HAVE_CUDA
  gpu_mask = std::vector<int>(MAX_GPUS, 0);
#endif
}

DynetParams::~DynetParams()
{
}

static void remove_args(int& argc, char**& argv, int& argi, int n) {
  for (int i = argi + n; i < argc; ++i)
    argv[i - n] = argv[i];
  argc -= n;
  DYNET_ASSERT(argc >= 0, "remove_args less than 0");
}

DynetParams extract_dynet_params(int& argc, char**& argv, bool shared_parameters) {
  DynetParams params;
  params.shared_parameters = shared_parameters;

  int argi = 1;

#if HAVE_CUDA
  params.gpu_mask = std::vector<int>(MAX_GPUS, 0);
#endif

  while (argi < argc) {
    string arg = argv[argi];

    // Memory
    if (arg == "--dynet-mem" || arg == "--dynet_mem") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-mem expects an argument (the memory, in megabytes, to reserve)");
      } else {
        params.mem_descriptor = argv[argi + 1];
        remove_args(argc, argv, argi, 2);
      }
    }

    // Weight decay
    else if (arg == "--dynet-weight-decay" || arg == "--dynet_weight_decay") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-weight-decay requires an argument (the weight decay per update)");
      } else {
        string a2 = argv[argi + 1];
        istringstream d(a2); d >> params.weight_decay;
        remove_args(argc, argv, argi, 2);
      }
    }

    // Random seed
    else if (arg == "--dynet-seed" || arg == "--dynet_seed") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-seed expects an argument (the random number seed)");
      } else {
        string a2 = argv[argi + 1];
        istringstream c(a2); c >> params.random_seed;
        remove_args(argc, argv, argi, 2);
      }
    }

    // Memory
    else if (arg == "--dynet-autobatch" || arg == "--dynet_autobatch") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-autobatch expects an argument (0 for none 1 for on)");
      } else {
        string a2 = argv[argi + 1];
        istringstream c(a2); c >> params.autobatch;
        remove_args(argc, argv, argi, 2);
      }
    }

#if HAVE_CUDA
    // Number of GPUs
    else if (arg == "--dynet_gpus" || arg == "--dynet-gpus") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-gpus expects an argument (number of GPUs to use)");
      } else {
        if (params.ngpus_requested)
          throw std::invalid_argument("Multiple instances of --dynet-gpus");
        params.ngpus_requested = true;
        string a2 = argv[argi + 1];
        istringstream c(a2); c >> params.requested_gpus;
        remove_args(argc, argv, argi, 2);
      }
    }

    // GPU ids
    else if (arg == "--dynet_gpu_ids" || arg == "--dynet-gpu-ids") {
      if ((argi + 1) > argc) {
        throw std::invalid_argument("[dynet] --dynet-gpu-ids expects an argument (comma separated list of physical GPU ids to use)");
      } else {
        string a2 = argv[argi + 1];
        if (params.ids_requested)
          throw std::invalid_argument("Multiple instances of --dynet-gpu-ids");
        params.ids_requested = true;
        if (a2.size() % 2 != 1) {
          ostringstream oss; oss << "Bad argument to --dynet-gpu-ids: " << a2; throw std::invalid_argument(oss.str());
        }
        for (unsigned i = 0; i < a2.size(); ++i) {
          if ((i % 2 == 0 && (a2[i] < '0' || a2[i] > '9')) ||
              (i % 2 == 1 && a2[i] != ',')) {
            ostringstream oss; oss << "Bad argument to --dynet-gpu-ids: " << a2;
            throw std::invalid_argument(oss.str());
          }
          if (i % 2 == 0) {
            int gpu_id = a2[i] - '0';
            if (gpu_id >= MAX_GPUS) { throw std::runtime_error("DyNet hard limit on maximum number of GPUs (MAX_GPUS) exceeded. If you need more, modify the code to raise this hard limit."); }
            params.gpu_mask[gpu_id]++;
            params.requested_gpus++;
            if (params.gpu_mask[gpu_id] != 1) {
              ostringstream oss; oss << "Bad argument to --dynet-gpu-ids: " << a2;
              throw std::invalid_argument(oss.str());
            }
          }
        }
        remove_args(argc, argv, argi, 2);
      }
    }
#endif

    // Go to next argument
    else {
      argi++;
    }

  }

#if HAVE_CUDA
  // Check for conflict between the two ways of requesting GPUs
  if (params.ids_requested && params.ngpus_requested)
    throw std::invalid_argument("Use only --dynet_gpus or --dynet_gpu_ids, not both\n");
#endif

  return params;
}

void initialize(DynetParams& params) {
  if (default_device != nullptr) {
    cerr << "WARNING: Attempting to initialize dynet twice. Ignoring duplicate initialization." << endl;
    return;
  }

  // initialize CUDA
  vector<Device*> gpudevices;
#if HAVE_CUDA
  cerr << "[dynet] initializing CUDA\n";
  gpudevices = initialize_gpu(params);
#endif

  // Set random seed
  if (params.random_seed == 0) {
    random_device rd;
    params.random_seed = rd();
  }
  cerr << "[dynet] random seed: " << params.random_seed << endl;
  rndeng = new mt19937(params.random_seed);

  // Set weight decay rate
  if (params.weight_decay < 0 || params.weight_decay >= 1)
    throw std::invalid_argument("[dynet] weight decay parameter must be between 0 and 1 (probably very small like 1e-6)\n");
  weight_decay_lambda = params.weight_decay;

  // Set autobatch
  autobatch_flag = params.autobatch;

  // Allocate memory
  cerr << "[dynet] allocating memory: " << params.mem_descriptor << "MB\n";
  // TODO: Once multi-device support is added, we will potentially allocate both CPU
  //       and GPU, not either-or
  int default_index = 0;
  if (gpudevices.size() > 0) {
    for (auto gpu : gpudevices)
      devices.push_back(gpu);
  } else {
    devices.push_back(new Device_CPU(devices.size(), params.mem_descriptor, params.shared_parameters));
  }
  default_device = devices[default_index];

  // TODO these should be accessed through the relevant device and removed here
  kSCALAR_MINUSONE = default_device->kSCALAR_MINUSONE;
  kSCALAR_ONE = default_device->kSCALAR_ONE;
  kSCALAR_ZERO = default_device->kSCALAR_ZERO;
  cerr << "[dynet] memory allocation done.\n";

}

void initialize(int& argc, char**& argv, bool shared_parameters) {
  DynetParams params = extract_dynet_params(argc, argv, shared_parameters);
  initialize(params);
}

void cleanup() {
  delete rndeng;
  // TODO: Devices cannot be deleted at the moment
  // for(Device* device : devices) delete device;
  devices.clear();
  default_device = nullptr;
}

} // namespace dynet

<|endoftext|>


<commit_before>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2010 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh is free software: you can redistribute it and/or modify         *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh is distributed in the hope that it will be useful,              *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  CLASS PolyMeshT - IMPLEMENTATION
//
//=============================================================================

#define OPENMESH_POLYMESH_C

//== INCLUDES =================================================================

#include <OpenMesh/Core/Mesh/PolyMeshT.hh>
#include <OpenMesh/Core/Geometry/LoopSchemeMaskT.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/System/omstream.hh>
#include <vector>

//== NAMESPACES ===============================================================

namespace OpenMesh {

//== IMPLEMENTATION ==========================================================

template <class Kernel>
uint PolyMeshT<Kernel>::find_feature_edges(Scalar _angle_tresh)
{
  assert(Kernel::has_edge_status());//this function needs edge status property
  uint n_feature_edges = 0;
  for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it)
  {
    if (fabs(calc_dihedral_angle(e_it)) > _angle_tresh)
    {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh)
      status(e_it).set_feature(true);
      n_feature_edges++;
    }
    else
    {
      status(e_it).set_feature(false);
    }
  }
  return n_feature_edges;
}

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

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(FaceHandle _fh) const
{
  assert(halfedge_handle(_fh).is_valid());
  ConstFaceVertexIter fv_it(cfv_iter(_fh));

  Point p0 = point(fv_it);
  Point p0i = p0; //save point of vertex 0
  ++fv_it;
  Point p1 = point(fv_it);
  Point p1i = p1; //save point of vertex 1
  ++fv_it;
  Point p2;

  //calculate area-weighted average normal of polygon's ears
  Normal n(0,0,0);
  for(; fv_it; ++fv_it)
  {
    p2 = point(fv_it);
    n += vector_cast<Normal>((p2-p1)%(p0-p1));
    p0 = p1;
    p1 = p2;
  }

  //two additional steps since we started at vertex 2, not 0
  n += vector_cast<Normal>((p0i-p1)%(p0-p1));
  n += vector_cast<Normal>((p1i-p0i)%(p1-p0i));

  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
}

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

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(const Point& _p0,
     const Point& _p1,
     const Point& _p2) const
{
#if 1
  // The OpenSG <Vector>::operator -= () does not support the type Point
  // as rhs. Therefore use vector_cast at this point!!!
  // Note! OpenSG distinguishes between Normal and Point!!!
  Normal p1p0(vector_cast<Normal>(_p0));  p1p0 -= vector_cast<Normal>(_p1);
  Normal p1p2(vector_cast<Normal>(_p2));  p1p2 -= vector_cast<Normal>(_p1);

  Normal n    = cross(p1p2, p1p0);
  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
#else
  Point p1p0 = _p0;  p1p0 -= _p1;
  Point p1p2 = _p2;  p1p2 -= _p1;

  Normal n = vector_cast<Normal>(cross(p1p2, p1p0));
  typename Normal::value_type norm = n.length();

  return (norm != 0.0) ? n *= (1.0/norm) : Normal(0,0,0);
#endif
}

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

template <class Kernel>
void
PolyMeshT<Kernel>::
calc_face_centroid(FaceHandle _fh, Point& _pt) const
{
  _pt.vectorize(0);
  uint valence = 0;
  for (ConstFaceVertexIter cfv_it = cfv_iter(_fh); cfv_it; ++cfv_it, ++valence)
  {
    _pt += point(cfv_it);
  }
  _pt /= valence;
}
//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_normals()
{
  if (Kernel::has_face_normals())    update_face_normals();
  if (Kernel::has_vertex_normals())  update_vertex_normals();
}

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

template <class Kernel>
void
PolyMeshT<Kernel>::
update_face_normals()
{
  FaceIter f_it(Kernel::faces_begin()), f_end(Kernel::faces_end());

  for (; f_it != f_end; ++f_it)
    set_normal(f_it.handle(), calc_face_normal(f_it.handle()));
}

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

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_vertex_normal(VertexHandle _vh) const
{
  Normal n;
  calc_vertex_normal_fast(_vh,n);

  Scalar norm = n.length();
  if (norm != 0.0) n *= (1.0/norm);

  return n;
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  for (ConstVertexFaceIter vf_it=cvf_iter(_vh); vf_it; ++vf_it)
    _n += normal(vf_it.handle());
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  ConstVertexIHalfedgeIter cvih_it = cvih_iter(_vh);
  if (!cvih_it)
  {//don't crash on isolated vertices
    return;
  }
  Normal in_he_vec;
  calc_edge_vector(cvih_it, in_he_vec);
  for ( ; cvih_it; ++cvih_it)
  {//calculates the sector normal defined by cvih_it and adds it to _n
    if (is_boundary(cvih_it))
    {
      continue;
    }
    HalfedgeHandle out_heh(next_halfedge_handle(cvih_it));
    Normal out_he_vec;
    calc_edge_vector(out_heh, out_he_vec);
    _n += cross(in_he_vec, out_he_vec);//sector area is taken into account
    in_he_vec = out_he_vec;
    in_he_vec *= -1;//change the orientation
  }
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const
{
  static const LoopSchemeMaskDouble& loop_scheme_mask__ =
                  LoopSchemeMaskDoubleSingleton::Instance();

  Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0);
  unsigned int vh_val = valence(_vh);
  unsigned int i = 0;
  for (ConstVertexOHalfedgeIter cvoh_it = cvoh_iter(_vh); cvoh_it; ++cvoh_it, ++i)
  {
    VertexHandle r1_v(to_vertex_handle(cvoh_it));
    t_v += (typename Point::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*point(r1_v);
    t_w += (typename Point::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*point(r1_v);
  }
  _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed?
}

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

template <class Kernel>
void
PolyMeshT<Kernel>::
update_vertex_normals()
{
  VertexIter  v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end());

  for (; v_it!=v_end; ++v_it)
    set_normal(v_it.handle(), calc_vertex_normal(v_it.handle()));
}

//=============================================================================
} // namespace OpenMesh
//=============================================================================
<commit_msg>Avoid %-operator in normal calculation such that gcc does not throw a compiler error when using vector types of dimension other than three.<commit_after>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2010 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh is free software: you can redistribute it and/or modify         *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh is distributed in the hope that it will be useful,              *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  CLASS PolyMeshT - IMPLEMENTATION
//
//=============================================================================

#define OPENMESH_POLYMESH_C

//== INCLUDES =================================================================

#include <OpenMesh/Core/Mesh/PolyMeshT.hh>
#include <OpenMesh/Core/Geometry/LoopSchemeMaskT.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/System/omstream.hh>
#include <vector>

//== NAMESPACES ===============================================================

namespace OpenMesh {

//== IMPLEMENTATION ==========================================================

template <class Kernel>
uint PolyMeshT<Kernel>::find_feature_edges(Scalar _angle_tresh)
{
  assert(Kernel::has_edge_status());//this function needs edge status property
  uint n_feature_edges = 0;
  for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it)
  {
    if (fabs(calc_dihedral_angle(e_it)) > _angle_tresh)
    {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh)
      status(e_it).set_feature(true);
      n_feature_edges++;
    }
    else
    {
      status(e_it).set_feature(false);
    }
  }
  return n_feature_edges;
}

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

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(FaceHandle _fh) const
{
  assert(halfedge_handle(_fh).is_valid());
  ConstFaceVertexIter fv_it(cfv_iter(_fh));

  Point p0 = point(fv_it);
  Point p0i = p0; //save point of vertex 0
  ++fv_it;
  Point p1 = point(fv_it);
  Point p1i = p1; //save point of vertex 1
  ++fv_it;
  Point p2;

  //calculate area-weighted average normal of polygon's ears
  Normal n(0,0,0);
  for(; fv_it; ++fv_it)
  {
    p2 = point(fv_it);
    n += vector_cast<Normal>(calc_face_normal(p0, p1, p2));
    p0 = p1;
    p1 = p2;
  }

  //two additional steps since we started at vertex 2, not 0
  n += vector_cast<Normal>(calc_face_normal(p0i, p0, p1));
  n += vector_cast<Normal>(calc_face_normal(p1i, p0i, p1));

  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
}

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

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(const Point& _p0,
     const Point& _p1,
     const Point& _p2) const
{
#if 1
  // The OpenSG <Vector>::operator -= () does not support the type Point
  // as rhs. Therefore use vector_cast at this point!!!
  // Note! OpenSG distinguishes between Normal and Point!!!
  Normal p1p0(vector_cast<Normal>(_p0));  p1p0 -= vector_cast<Normal>(_p1);
  Normal p1p2(vector_cast<Normal>(_p2));  p1p2 -= vector_cast<Normal>(_p1);

  Normal n    = cross(p1p2, p1p0);
  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
#else
  Point p1p0 = _p0;  p1p0 -= _p1;
  Point p1p2 = _p2;  p1p2 -= _p1;

  Normal n = vector_cast<Normal>(cross(p1p2, p1p0));
  typename Normal::value_type norm = n.length();

  return (norm != 0.0) ? n *= (1.0/norm) : Normal(0,0,0);
#endif
}

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

template <class Kernel>
void
PolyMeshT<Kernel>::
calc_face_centroid(FaceHandle _fh, Point& _pt) const
{
  _pt.vectorize(0);
  uint valence = 0;
  for (ConstFaceVertexIter cfv_it = cfv_iter(_fh); cfv_it; ++cfv_it, ++valence)
  {
    _pt += point(cfv_it);
  }
  _pt /= valence;
}
//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_normals()
{
  if (Kernel::has_face_normals())    update_face_normals();
  if (Kernel::has_vertex_normals())  update_vertex_normals();
}

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

template <class Kernel>
void
PolyMeshT<Kernel>::
update_face_normals()
{
  FaceIter f_it(Kernel::faces_begin()), f_end(Kernel::faces_end());

  for (; f_it != f_end; ++f_it)
    set_normal(f_it.handle(), calc_face_normal(f_it.handle()));
}

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

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_vertex_normal(VertexHandle _vh) const
{
  Normal n;
  calc_vertex_normal_fast(_vh,n);

  Scalar norm = n.length();
  if (norm != 0.0) n *= (1.0/norm);

  return n;
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  for (ConstVertexFaceIter vf_it=cvf_iter(_vh); vf_it; ++vf_it)
    _n += normal(vf_it.handle());
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  ConstVertexIHalfedgeIter cvih_it = cvih_iter(_vh);
  if (!cvih_it)
  {//don't crash on isolated vertices
    return;
  }
  Normal in_he_vec;
  calc_edge_vector(cvih_it, in_he_vec);
  for ( ; cvih_it; ++cvih_it)
  {//calculates the sector normal defined by cvih_it and adds it to _n
    if (is_boundary(cvih_it))
    {
      continue;
    }
    HalfedgeHandle out_heh(next_halfedge_handle(cvih_it));
    Normal out_he_vec;
    calc_edge_vector(out_heh, out_he_vec);
    _n += cross(in_he_vec, out_he_vec);//sector area is taken into account
    in_he_vec = out_he_vec;
    in_he_vec *= -1;//change the orientation
  }
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const
{
  static const LoopSchemeMaskDouble& loop_scheme_mask__ =
                  LoopSchemeMaskDoubleSingleton::Instance();

  Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0);
  unsigned int vh_val = valence(_vh);
  unsigned int i = 0;
  for (ConstVertexOHalfedgeIter cvoh_it = cvoh_iter(_vh); cvoh_it; ++cvoh_it, ++i)
  {
    VertexHandle r1_v(to_vertex_handle(cvoh_it));
    t_v += (typename Point::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*point(r1_v);
    t_w += (typename Point::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*point(r1_v);
  }
  _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed?
}

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

template <class Kernel>
void
PolyMeshT<Kernel>::
update_vertex_normals()
{
  VertexIter  v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end());

  for (; v_it!=v_end; ++v_it)
    set_normal(v_it.handle(), calc_vertex_normal(v_it.handle()));
}

//=============================================================================
} // namespace OpenMesh
//=============================================================================
<|endoftext|>


<commit_before>#include <algorithm>

#include "pixelboost/animation/timeline/timeline.h"
#include "pixelboost/debug/log.h"

using namespace pb;

Timeline::Timeline()
{
    _LengthDirty = true;
}

Timeline::~Timeline()
{
    for (const auto& element : _Elements)
    {
        delete element;
    }
}

float Timeline::GetLength()
{
    if (_LengthDirty)
    {
        _Length = 0.f;

        if (_Elements.size())
        {
            for (auto element : _Elements)
            {
                _Length = glm::max(_Length, element->GetEndTime());
            }
        }
    }

    return _Length;
}

void Timeline::Insert(TimelineElement* element, float time)
{
    auto bound = std::lower_bound(_Elements.begin(), _Elements.end(), time, [](const TimelineElement* element, float time) {return element->GetStartTime() < time;} );
    auto item = _Elements.insert(bound, element);
    (*item)->_StartTime = time;
}

void Timeline::Append(TimelineElement* element)
{
    Insert(element, GetLength());
}

void Timeline::AddLabel(const std::string& name, float time)
{
    _Labels[name] = time;
}

void Timeline::OnUpdate(float time, float delta)
{
    auto start = std::lower_bound(_Elements.begin(), _Elements.end(), time - delta, [](const TimelineElement* element, float time) {return element->GetStartTime() < time;} );
    auto end = std::upper_bound(_Elements.begin(), _Elements.end(), time, [](float time, const TimelineElement* element) {return time <= element->GetStartTime();} );

    auto it = start;

    while (it != end)
    {
        (*it)->Reset();
        (*it)->Play();
        it++;
    }

    for (auto element : _Elements)
    {
        element->Update(delta);
    }
}
<commit_msg>Hack to make sure the last element in a timeline is executed<commit_after>#include <algorithm>

#include "pixelboost/animation/timeline/timeline.h"
#include "pixelboost/debug/log.h"

using namespace pb;

Timeline::Timeline()
{
    _LengthDirty = true;
}

Timeline::~Timeline()
{
    for (const auto& element : _Elements)
    {
        delete element;
    }
}

float Timeline::GetLength()
{
    if (_LengthDirty)
    {
        _Length = 0.f;

        if (_Elements.size())
        {
            for (auto element : _Elements)
            {
                _Length = glm::max(_Length, element->GetEndTime());
            }
        }
    }

    return _Length + 1.f; // Hack. Make sure the last element is executed
}

void Timeline::Insert(TimelineElement* element, float time)
{
    auto bound = std::lower_bound(_Elements.begin(), _Elements.end(), time, [](const TimelineElement* element, float time) {return element->GetStartTime() < time;} );
    auto item = _Elements.insert(bound, element);
    (*item)->_StartTime = time;
}

void Timeline::Append(TimelineElement* element)
{
    Insert(element, GetLength());
}

void Timeline::AddLabel(const std::string& name, float time)
{
    _Labels[name] = time;
}

void Timeline::OnUpdate(float time, float delta)
{
    auto start = std::lower_bound(_Elements.begin(), _Elements.end(), time - delta, [](const TimelineElement* element, float time) {return element->GetStartTime() < time;} );
    auto end = std::upper_bound(_Elements.begin(), _Elements.end(), time, [](float time, const TimelineElement* element) {return time <= element->GetStartTime();} );

    auto it = start;

    while (it != end)
    {
        (*it)->Reset();
        (*it)->Play();
        it++;
    }

    for (auto element : _Elements)
    {
        element->Update(delta);
    }
}
<|endoftext|>