<commit_before>/*
 *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS. All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "libyuv/cpu_id.h"

#if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h>  // For __cpuidex()
#endif
#if !defined(__pnacl__) && !defined(__CLR_VER) && \
    !defined(__native_client__)  && \
    defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219) && \
    (defined(_M_IX86) || defined(_M_X64))
#include <immintrin.h>  // For _xgetbv()
#endif

#if !defined(__native_client__)
#include <stdlib.h>  // For getenv()
#endif

// For ArmCpuCaps() but unittested on all platforms
#include <stdio.h>
#include <string.h>

#include "libyuv/basic_types.h"  // For CPU_X86

#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif

// For functions that use the stack and have runtime checks for overflow,
// use SAFEBUFFERS to avoid additional check.
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
#define SAFEBUFFERS __declspec(safebuffers)
#else
#define SAFEBUFFERS
#endif

// Low level cpuid for X86. Returns zeros on other CPUs.
#if !defined(__pnacl__) && !defined(__CLR_VER) && \
    (defined(_M_IX86) || defined(_M_X64) || \
    defined(__i386__) || defined(__x86_64__))
LIBYUV_API
void CpuId(uint32 info_eax, uint32 info_ecx, uint32* cpu_info) {
#if defined(_MSC_VER) && !defined(__clang__)
#if (_MSC_FULL_VER >= 160040219)
  __cpuidex((int*)(cpu_info), info_eax, info_ecx);
#endif
#if defined(_M_IX86)
  __asm {
    mov        eax, info_eax
    mov        ecx, info_ecx
    mov        edi, cpu_info
    cpuid
    mov        [edi], eax
    mov        [edi + 4], ebx
    mov        [edi + 8], ecx
    mov        [edi + 12], edx
  }
#else
  if (info_ecx == 0) {
    __cpuid((int*)(cpu_info), info_eax);
  } else {
    cpu_info[3] = cpu_info[2] = cpu_info[1] = cpu_info[0] = 0;
  }
#endif
#else  // defined(_MSC_VER)
  uint32 info_ebx, info_edx;
  asm volatile (  // NOLINT
#if defined( __i386__) && defined(__PIC__)
    // Preserve ebx for fpic 32 bit.
    "mov %%ebx, %%edi                          \n"
    "cpuid                                     \n"
    "xchg %%edi, %%ebx                         \n"
    : "=D" (info_ebx),
#else
    "cpuid                                     \n"
    : "=b" (info_ebx),
#endif  //  defined( __i386__) && defined(__PIC__)
      "+a" (info_eax), "+c" (info_ecx), "=d" (info_edx));
  cpu_info[0] = info_eax;
  cpu_info[1] = info_ebx;
  cpu_info[2] = info_ecx;
  cpu_info[3] = info_edx;
#endif  // defined(_MSC_VER)
}

#if !defined(__native_client__)
#define HAS_XGETBV
// X86 CPUs have xgetbv to detect OS saves high parts of ymm registers.
int TestOsSaveYmm() {
  uint32 xcr0 = 0u;
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
  xcr0 = (uint32)(_xgetbv(0));  // VS2010 SP1 required.
#endif
#if defined(_M_IX86) && defined(_MSC_VER)
  __asm {
    xor        ecx, ecx    // xcr 0
    _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0  // For VS2010 and earlier.
    mov        xcr0, eax
  }
#endif
#if defined(__i386__) || defined(__x86_64__)
  asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcr0) : "c" (0) : "%edx");
#endif  // defined(_MSC_VER)
  return((xcr0 & 6) == 6);  // Is ymm saved?
}
#endif  // !defined(__native_client__)
#else
LIBYUV_API
void CpuId(uint32 eax, uint32 ecx, uint32* cpu_info) {
  cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
}
#endif

// based on libvpx arm_cpudetect.c
// For Arm, but public to allow testing on any CPU
LIBYUV_API SAFEBUFFERS
int ArmCpuCaps(const char* cpuinfo_name) {
  char cpuinfo_line[512];
  FILE* f = fopen(cpuinfo_name, "r");
  if (!f) {
    // Assume Neon if /proc/cpuinfo is unavailable.
    // This will occur for Chrome sandbox for Pepper or Render process.
    return kCpuHasNEON;
  }
  while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f)) {
    if (memcmp(cpuinfo_line, "Features", 8) == 0) {
      char* p = strstr(cpuinfo_line, " neon");
      if (p && (p[5] == ' ' || p[5] == '\n')) {
        fclose(f);
        return kCpuHasNEON;
      }
      // aarch64 uses asimd for Neon.
      p = strstr(cpuinfo_line, " asimd");
      if (p && (p[6] == ' ' || p[6] == '\n')) {
        fclose(f);
        return kCpuHasNEON;
      }
    }
  }
  fclose(f);
  return 0;
}

#if defined(__mips__) && defined(__linux__)
static int MipsCpuCaps(const char* search_string) {
  char cpuinfo_line[512];
  const char* file_name = "/proc/cpuinfo";
  FILE* f = fopen(file_name, "r");
  if (!f) {
    // Assume DSP if /proc/cpuinfo is unavailable.
    // This will occur for Chrome sandbox for Pepper or Render process.
    return kCpuHasMIPS_DSP;
  }
  while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f) != NULL) {
    if (strstr(cpuinfo_line, search_string) != NULL) {
      fclose(f);
      return kCpuHasMIPS_DSP;
    }
  }
  fclose(f);
  return 0;
}
#endif

// CPU detect function for SIMD instruction sets.
LIBYUV_API
int cpu_info_ = kCpuInit;  // cpu_info is not initialized yet.

// Test environment variable for disabling CPU features. Any non-zero value
// to disable. Zero ignored to make it easy to set the variable on/off.
#if !defined(__native_client__) && !defined(_M_ARM)

static LIBYUV_BOOL TestEnv(const char* name) {
  const char* var = getenv(name);
  if (var) {
    if (var[0] != '0') {
      return LIBYUV_TRUE;
    }
  }
  return LIBYUV_FALSE;
}
#else  // nacl does not support getenv().
static LIBYUV_BOOL TestEnv(const char*) {
  return LIBYUV_FALSE;
}
#endif

LIBYUV_API SAFEBUFFERS
int InitCpuFlags(void) {
#if !defined(__pnacl__) && !defined(__CLR_VER) && defined(CPU_X86)

  uint32 cpu_info0[4] = { 0, 0, 0, 0 };
  uint32 cpu_info1[4] = { 0, 0, 0, 0 };
  uint32 cpu_info7[4] = { 0, 0, 0, 0 };
  CpuId(0, 0, cpu_info0);
  CpuId(1, 0, cpu_info1);
  if (cpu_info0[0] >= 7) {
    CpuId(7, 0, cpu_info7);
  }
  cpu_info_ = ((cpu_info1[3] & 0x04000000) ? kCpuHasSSE2 : 0) |
              ((cpu_info1[2] & 0x00000200) ? kCpuHasSSSE3 : 0) |
              ((cpu_info1[2] & 0x00080000) ? kCpuHasSSE41 : 0) |
              ((cpu_info1[2] & 0x00100000) ? kCpuHasSSE42 : 0) |
              ((cpu_info7[1] & 0x00000200) ? kCpuHasERMS : 0) |
              ((cpu_info1[2] & 0x00001000) ? kCpuHasFMA3 : 0) |
              kCpuHasX86;

#ifdef HAS_XGETBV
  if ((cpu_info1[2] & 0x18000000) == 0x18000000 &&  // AVX and OSSave
      TestOsSaveYmm()) {  // Saves YMM.
    cpu_info_ |= ((cpu_info7[1] & 0x00000020) ? kCpuHasAVX2 : 0) |
                 kCpuHasAVX;
  }
#endif
  // Environment variable overrides for testing.
  if (TestEnv("LIBYUV_DISABLE_X86")) {
    cpu_info_ &= ~kCpuHasX86;
  }
  if (TestEnv("LIBYUV_DISABLE_SSE2")) {
    cpu_info_ &= ~kCpuHasSSE2;
  }
  if (TestEnv("LIBYUV_DISABLE_SSSE3")) {
    cpu_info_ &= ~kCpuHasSSSE3;
  }
  if (TestEnv("LIBYUV_DISABLE_SSE41")) {
    cpu_info_ &= ~kCpuHasSSE41;
  }
  if (TestEnv("LIBYUV_DISABLE_SSE42")) {
    cpu_info_ &= ~kCpuHasSSE42;
  }
  if (TestEnv("LIBYUV_DISABLE_AVX")) {
    cpu_info_ &= ~kCpuHasAVX;
  }
  if (TestEnv("LIBYUV_DISABLE_AVX2")) {
    cpu_info_ &= ~kCpuHasAVX2;
  }
  if (TestEnv("LIBYUV_DISABLE_ERMS")) {
    cpu_info_ &= ~kCpuHasERMS;
  }
  if (TestEnv("LIBYUV_DISABLE_FMA3")) {
    cpu_info_ &= ~kCpuHasFMA3;
  }
#endif
#if defined(__mips__) && defined(__linux__)
  // Linux mips parse text file for dsp detect.
  cpu_info_ = MipsCpuCaps("dsp");  // set kCpuHasMIPS_DSP.
#if defined(__mips_dspr2)
  cpu_info_ |= kCpuHasMIPS_DSPR2;
#endif
  cpu_info_ |= kCpuHasMIPS;

  if (getenv("LIBYUV_DISABLE_MIPS")) {
    cpu_info_ &= ~kCpuHasMIPS;
  }
  if (getenv("LIBYUV_DISABLE_MIPS_DSP")) {
    cpu_info_ &= ~kCpuHasMIPS_DSP;
  }
  if (getenv("LIBYUV_DISABLE_MIPS_DSPR2")) {
    cpu_info_ &= ~kCpuHasMIPS_DSPR2;
  }
#endif
#if defined(__arm__) || defined(__aarch64__)
// gcc -mfpu=neon defines __ARM_NEON__
// __ARM_NEON__ generates code that requires Neon.  NaCL also requires Neon.
// For Linux, /proc/cpuinfo can be tested but without that assume Neon.
#if defined(__ARM_NEON__) || defined(__native_client__) || !defined(__linux__)
  cpu_info_ = kCpuHasNEON;
// For aarch64(arm64), /proc/cpuinfo's feature is not complete, e.g. no neon
// flag in it.
// So for aarch64, neon enabling is hard coded here.
#endif
#if defined(__aarch64__)
  cpu_info_ = kCpuHasNEON;
#else
  // Linux arm parse text file for neon detect.
  cpu_info_ = ArmCpuCaps("/proc/cpuinfo");
#endif
  cpu_info_ |= kCpuHasARM;
  if (TestEnv("LIBYUV_DISABLE_NEON")) {
    cpu_info_ &= ~kCpuHasNEON;
  }
#endif  // __arm__
  if (TestEnv("LIBYUV_DISABLE_ASM")) {
    cpu_info_ = 0;
  }
  return cpu_info_;
}

LIBYUV_API
void MaskCpuFlags(int enable_flags) {
  cpu_info_ = InitCpuFlags() & enable_flags;
}

#ifdef __cplusplus
}  // extern "C"
}  // namespace libyuv
#endif
<commit_msg>cpuid ifdefs fixed to remove some duplicate code cases. BUG=none TESTED=local windows build R=tpsiaki@google.com<commit_after>/*
 *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS. All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "libyuv/cpu_id.h"

#if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h>  // For __cpuidex()
#endif
#if !defined(__pnacl__) && !defined(__CLR_VER) && \
    !defined(__native_client__)  && \
    defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219) && \
    (defined(_M_IX86) || defined(_M_X64))
#include <immintrin.h>  // For _xgetbv()
#endif

#if !defined(__native_client__)
#include <stdlib.h>  // For getenv()
#endif

// For ArmCpuCaps() but unittested on all platforms
#include <stdio.h>
#include <string.h>

#include "libyuv/basic_types.h"  // For CPU_X86

#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif

// For functions that use the stack and have runtime checks for overflow,
// use SAFEBUFFERS to avoid additional check.
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
#define SAFEBUFFERS __declspec(safebuffers)
#else
#define SAFEBUFFERS
#endif

// Low level cpuid for X86.
#if (defined(_M_IX86) || defined(_M_X64) || \
    defined(__i386__) || defined(__x86_64__)) && \
    !defined(__pnacl__) && !defined(__CLR_VER)
LIBYUV_API
void CpuId(uint32 info_eax, uint32 info_ecx, uint32* cpu_info) {
#if defined(_MSC_VER) && !defined(__clang__)
// Visual C version uses intrinsic or inline x86 assembly.
#if (_MSC_FULL_VER >= 160040219)
  __cpuidex((int*)(cpu_info), info_eax, info_ecx);
#elif defined(_M_IX86)
  __asm {
    mov        eax, info_eax
    mov        ecx, info_ecx
    mov        edi, cpu_info
    cpuid
    mov        [edi], eax
    mov        [edi + 4], ebx
    mov        [edi + 8], ecx
    mov        [edi + 12], edx
  }
#else
  if (info_ecx == 0) {
    __cpuid((int*)(cpu_info), info_eax);
  } else {
    cpu_info[3] = cpu_info[2] = cpu_info[1] = cpu_info[0] = 0;
  }
#endif
// GCC version uses inline x86 assembly.
#else  // defined(_MSC_VER) && !defined(__clang__)
  uint32 info_ebx, info_edx;
  asm volatile (  // NOLINT
#if defined( __i386__) && defined(__PIC__)
    // Preserve ebx for fpic 32 bit.
    "mov %%ebx, %%edi                          \n"
    "cpuid                                     \n"
    "xchg %%edi, %%ebx                         \n"
    : "=D" (info_ebx),
#else
    "cpuid                                     \n"
    : "=b" (info_ebx),
#endif  //  defined( __i386__) && defined(__PIC__)
      "+a" (info_eax), "+c" (info_ecx), "=d" (info_edx));
  cpu_info[0] = info_eax;
  cpu_info[1] = info_ebx;
  cpu_info[2] = info_ecx;
  cpu_info[3] = info_edx;
#endif  // defined(_MSC_VER) && !defined(__clang__)
}
#else  // (defined(_M_IX86) || defined(_M_X64) ...
LIBYUV_API
void CpuId(uint32 eax, uint32 ecx, uint32* cpu_info) {
  cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
}
#endif

// TODO(fbarchard): Enable xgetbv when validator supports it.
#if (defined(_M_IX86) || defined(_M_X64) || \
    defined(__i386__) || defined(__x86_64__)) && \
    !defined(__pnacl__) && !defined(__CLR_VER) && !defined(__native_client__)
#define HAS_XGETBV
// X86 CPUs have xgetbv to detect OS saves high parts of ymm registers.
int TestOsSaveYmm() {
  uint32 xcr0 = 0u;
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
  xcr0 = (uint32)(_xgetbv(0));  // VS2010 SP1 required.
#elif defined(_M_IX86) && defined(_MSC_VER) && !defined(__clang__)
  __asm {
    xor        ecx, ecx    // xcr 0
    _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0  // For VS2010 and earlier.
    mov        xcr0, eax
  }
#elif defined(__i386__) || defined(__x86_64__)
  asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcr0) : "c" (0) : "%edx");
#endif  // defined(__i386__) || defined(__x86_64__)
  return((xcr0 & 6) == 6);  // Is ymm saved?
}
#endif  // defined(_M_IX86) || defined(_M_X64) ..

// based on libvpx arm_cpudetect.c
// For Arm, but public to allow testing on any CPU
LIBYUV_API SAFEBUFFERS
int ArmCpuCaps(const char* cpuinfo_name) {
  char cpuinfo_line[512];
  FILE* f = fopen(cpuinfo_name, "r");
  if (!f) {
    // Assume Neon if /proc/cpuinfo is unavailable.
    // This will occur for Chrome sandbox for Pepper or Render process.
    return kCpuHasNEON;
  }
  while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f)) {
    if (memcmp(cpuinfo_line, "Features", 8) == 0) {
      char* p = strstr(cpuinfo_line, " neon");
      if (p && (p[5] == ' ' || p[5] == '\n')) {
        fclose(f);
        return kCpuHasNEON;
      }
      // aarch64 uses asimd for Neon.
      p = strstr(cpuinfo_line, " asimd");
      if (p && (p[6] == ' ' || p[6] == '\n')) {
        fclose(f);
        return kCpuHasNEON;
      }
    }
  }
  fclose(f);
  return 0;
}

#if defined(__mips__) && defined(__linux__)
static int MipsCpuCaps(const char* search_string) {
  char cpuinfo_line[512];
  const char* file_name = "/proc/cpuinfo";
  FILE* f = fopen(file_name, "r");
  if (!f) {
    // Assume DSP if /proc/cpuinfo is unavailable.
    // This will occur for Chrome sandbox for Pepper or Render process.
    return kCpuHasMIPS_DSP;
  }
  while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f) != NULL) {
    if (strstr(cpuinfo_line, search_string) != NULL) {
      fclose(f);
      return kCpuHasMIPS_DSP;
    }
  }
  fclose(f);
  return 0;
}
#endif

// CPU detect function for SIMD instruction sets.
LIBYUV_API
int cpu_info_ = kCpuInit;  // cpu_info is not initialized yet.

// Test environment variable for disabling CPU features. Any non-zero value
// to disable. Zero ignored to make it easy to set the variable on/off.
#if !defined(__native_client__) && !defined(_M_ARM)

static LIBYUV_BOOL TestEnv(const char* name) {
  const char* var = getenv(name);
  if (var) {
    if (var[0] != '0') {
      return LIBYUV_TRUE;
    }
  }
  return LIBYUV_FALSE;
}
#else  // nacl does not support getenv().
static LIBYUV_BOOL TestEnv(const char*) {
  return LIBYUV_FALSE;
}
#endif

LIBYUV_API SAFEBUFFERS
int InitCpuFlags(void) {
#if !defined(__pnacl__) && !defined(__CLR_VER) && defined(CPU_X86)

  uint32 cpu_info0[4] = { 0, 0, 0, 0 };
  uint32 cpu_info1[4] = { 0, 0, 0, 0 };
  uint32 cpu_info7[4] = { 0, 0, 0, 0 };
  CpuId(0, 0, cpu_info0);
  CpuId(1, 0, cpu_info1);
  if (cpu_info0[0] >= 7) {
    CpuId(7, 0, cpu_info7);
  }
  cpu_info_ = ((cpu_info1[3] & 0x04000000) ? kCpuHasSSE2 : 0) |
              ((cpu_info1[2] & 0x00000200) ? kCpuHasSSSE3 : 0) |
              ((cpu_info1[2] & 0x00080000) ? kCpuHasSSE41 : 0) |
              ((cpu_info1[2] & 0x00100000) ? kCpuHasSSE42 : 0) |
              ((cpu_info7[1] & 0x00000200) ? kCpuHasERMS : 0) |
              ((cpu_info1[2] & 0x00001000) ? kCpuHasFMA3 : 0) |
              kCpuHasX86;

#ifdef HAS_XGETBV
  if ((cpu_info1[2] & 0x18000000) == 0x18000000 &&  // AVX and OSSave
      TestOsSaveYmm()) {  // Saves YMM.
    cpu_info_ |= ((cpu_info7[1] & 0x00000020) ? kCpuHasAVX2 : 0) |
                 kCpuHasAVX;
  }
#endif
  // Environment variable overrides for testing.
  if (TestEnv("LIBYUV_DISABLE_X86")) {
    cpu_info_ &= ~kCpuHasX86;
  }
  if (TestEnv("LIBYUV_DISABLE_SSE2")) {
    cpu_info_ &= ~kCpuHasSSE2;
  }
  if (TestEnv("LIBYUV_DISABLE_SSSE3")) {
    cpu_info_ &= ~kCpuHasSSSE3;
  }
  if (TestEnv("LIBYUV_DISABLE_SSE41")) {
    cpu_info_ &= ~kCpuHasSSE41;
  }
  if (TestEnv("LIBYUV_DISABLE_SSE42")) {
    cpu_info_ &= ~kCpuHasSSE42;
  }
  if (TestEnv("LIBYUV_DISABLE_AVX")) {
    cpu_info_ &= ~kCpuHasAVX;
  }
  if (TestEnv("LIBYUV_DISABLE_AVX2")) {
    cpu_info_ &= ~kCpuHasAVX2;
  }
  if (TestEnv("LIBYUV_DISABLE_ERMS")) {
    cpu_info_ &= ~kCpuHasERMS;
  }
  if (TestEnv("LIBYUV_DISABLE_FMA3")) {
    cpu_info_ &= ~kCpuHasFMA3;
  }
#endif
#if defined(__mips__) && defined(__linux__)
  // Linux mips parse text file for dsp detect.
  cpu_info_ = MipsCpuCaps("dsp");  // set kCpuHasMIPS_DSP.
#if defined(__mips_dspr2)
  cpu_info_ |= kCpuHasMIPS_DSPR2;
#endif
  cpu_info_ |= kCpuHasMIPS;

  if (getenv("LIBYUV_DISABLE_MIPS")) {
    cpu_info_ &= ~kCpuHasMIPS;
  }
  if (getenv("LIBYUV_DISABLE_MIPS_DSP")) {
    cpu_info_ &= ~kCpuHasMIPS_DSP;
  }
  if (getenv("LIBYUV_DISABLE_MIPS_DSPR2")) {
    cpu_info_ &= ~kCpuHasMIPS_DSPR2;
  }
#endif
#if defined(__arm__) || defined(__aarch64__)
// gcc -mfpu=neon defines __ARM_NEON__
// __ARM_NEON__ generates code that requires Neon.  NaCL also requires Neon.
// For Linux, /proc/cpuinfo can be tested but without that assume Neon.
#if defined(__ARM_NEON__) || defined(__native_client__) || !defined(__linux__)
  cpu_info_ = kCpuHasNEON;
// For aarch64(arm64), /proc/cpuinfo's feature is not complete, e.g. no neon
// flag in it.
// So for aarch64, neon enabling is hard coded here.
#endif
#if defined(__aarch64__)
  cpu_info_ = kCpuHasNEON;
#else
  // Linux arm parse text file for neon detect.
  cpu_info_ = ArmCpuCaps("/proc/cpuinfo");
#endif
  cpu_info_ |= kCpuHasARM;
  if (TestEnv("LIBYUV_DISABLE_NEON")) {
    cpu_info_ &= ~kCpuHasNEON;
  }
#endif  // __arm__
  if (TestEnv("LIBYUV_DISABLE_ASM")) {
    cpu_info_ = 0;
  }
  return cpu_info_;
}

LIBYUV_API
void MaskCpuFlags(int enable_flags) {
  cpu_info_ = InitCpuFlags() & enable_flags;
}

#ifdef __cplusplus
}  // extern "C"
}  // namespace libyuv
#endif
<|endoftext|>


<commit_before>//needed for testing
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>

//other stuff needed
#include <glm/vec3.hpp>
#include <cmath>
#include <iostream>

//include classes for testing
#include "shape.hpp"
#include "sphere.hpp"
#include "box.hpp"
#include "material.hpp"
#include "color.hpp"
#include "sdfloader.hpp"

// ----------------------------------
// SHAPE TESTS
// ----------------------------------

//karos änderung

TEST_CASE("getter shape","[shape]")
{
	Sphere s {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f},1.0f};
	REQUIRE(s.get_name() == "name");

	Material c{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f};
	REQUIRE(s.get_material() == c); //added operator == in color.hpp
}

TEST_CASE("operator<< and print shape","[shape]")
{
	Sphere es {"empty_sphere"};
	std::cout << es;

	Sphere s {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f},1.0f};
	std::cout << s;
//trolololo
}

// ----------------------------------
// SPHERE TESTS
// ----------------------------------

TEST_CASE("constructors of sphere","[sphere]")
{
	Sphere s1 {"name"};
	Sphere s2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};

	REQUIRE(s1.get_center() == s2.get_center());
	REQUIRE(s1.get_radius() == s2.get_radius());
}

TEST_CASE("get_center and get_radius","[sphere]")
{
	Sphere s {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};

	REQUIRE(s.get_radius() == 1.0f);
	REQUIRE(s.get_center() == glm::vec3{0.0f});
}

TEST_CASE("area","[sphere]")
{
	Sphere s {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};
	REQUIRE(12.566f == Approx(s.area()).epsilon(0.001));
}

TEST_CASE("volume","[sphere]")
{
	Sphere s {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};
	REQUIRE(4.189 == Approx(s.volume()).epsilon(0.001));
}

TEST_CASE("print sphere","[sphere]")
{
	Sphere es {"empty_sphere"};
	std::cout << es;

	Sphere s {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f},1.0f};
	std::cout << s;
}

// ----------------------------------
// BOX TESTS
// ----------------------------------

TEST_CASE("constructors of box","[box]")
{
	Box b1 {"name"};
	Box b2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, glm::vec3{1.0f}};

	REQUIRE(b1.get_min() == b2.get_min());
	REQUIRE(b1.get_max() == b2.get_max());
}

TEST_CASE("get_min and get_max","[box]")
{
	Box b2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, glm::vec3{1.0f}};

	REQUIRE(b2.get_min() == glm::vec3{0.0f});
	REQUIRE(b2.get_max() == glm::vec3{1.0f});
}

TEST_CASE("area of box","[box]")
{
	Box b2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, glm::vec3{1.0f}};
	REQUIRE(6.0f == Approx(b2.area()).epsilon(0.001));
}

TEST_CASE("volume of box","[box]")
{
	Box b2 {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f}, glm::vec3{0.0f}, glm::vec3{1.0f}};

	REQUIRE(1.0f == Approx(b2.volume()).epsilon(0.001));
}

TEST_CASE("print box","[box]")
{
	Box eb {"empty_box"};
	std::cout << eb;

	Box b {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f}, glm::vec3{0.0f}, glm::vec3{1.0f}};
	std::cout << b;
}

// ----------------------------------
// AUFGABE 5.6 TEST
// ----------------------------------

TEST_CASE("intersectRaySphere", "[intersect]")
{
	//Ray
	glm::vec3 ray_origin{0.0f, 0.0f, 0.0f};
	//ray direction has to be normalized !
	//you can use:
		//v = glm::normalize(some_vector);
	glm::vec3 ray_direction{0.0f, 0.0f, 1.0f};

	//Sphere
	glm::vec3 sphere_center{0.0f, 0.0f, 5.0f};
	float sphere_radius{1.0f};

	float distance{0.0f};
	auto result = glm::intersectRaySphere(
		ray_origin, ray_direction,
		sphere_center,
		sphere_radius * sphere_radius,
		distance);

	REQUIRE(distance == Approx(4.0f));

	Sphere s {"some_sphere", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},
		sphere_center, sphere_radius};

	Ray r {ray_origin,ray_direction};

	s.intersect(r,distance);

	REQUIRE(distance == Approx(4.0f));
}

// ----------------------------------
// AUFGABE 5.8 TEST
// ----------------------------------

TEST_CASE("virtual", "[Destructors]")
{

	std::cout << "\ntesting virtual and non-virtual construction and destruction\n";

	Color c_red {255.0f, 0.0f, 0.0f};
	Material red {"", c_red, c_red, c_red, 0.0f};

	glm::vec3 position {0.0f,0.0f,0.0f};

	std::cout << "Create s1\n";
	Sphere* s1 = new Sphere("sphere0",red,position,1.2f);
	std::cout << "Create s2\n";
	Shape* s2 = new Sphere("sphere1",red,position,1.2f);

	std::cout << "Printing objects: \n";
	std::cout << *s1;
	std::cout << *s2 << "\n";

	std::cout << "Delete s1\n";
	delete s1;
	std::cout << "Delete s2\n";
	delete s2;
}

// ----------------------------------
// MATERIAL Tests
// ----------------------------------

TEST_CASE("material in place of color struct", "Material")
{
	Color c{0.0f,0.0f,0.0f};
	Material mate1 {};
	std::cout << mate1;

	Material mate2 {"some material",c,c,c,0.0f};
	std::cout << mate2;
}

int main(int argc, char *argv[])
{
  return Catch::Session().run(argc, argv);
}

TEST_CASE("SDFloader test", "[SDFloader]")
{
	SDFloader load();
	load.sdfLoad("/Users/lissyscholz/Documents/programmiersprachen/raytracer/programmiersprachen-raytracer/source/material_input.txt");
}

// ----------------------------------
// INTERSECTION Tests
// ----------------------------------

TEST_CASE("intersection tests","Box")
{
	Color c {0.0f,0.0f,0.0f};
	Ray ray1 {glm::vec3{0.0f}, //from koordinatenursprung
			glm::vec3{1.0f,1.0f,-1.0f}}; //richung

	Ray ray2 {glm::vec3{0.0f}, //from koordinatenursprung
			glm::vec3{1.0f,1.0f,-2.0f}}; //richtung

	Ray ray3 {glm::vec3{1.0f,1.0f,-2.0f}, //von innerhalb der Box aus
			glm::vec3{0.0f,0.0f,-1.0f}};

	Box box {"test_box",
		Material{"",c,c,c, 0.0f},
		glm::vec3{0.0f,0.0f,-1.0f},	//min
		glm::vec3{2.0f,2.0f,-3.0f}	//max
	};

	std::cout << box;

	float distance = 0.0f;
	std::cout << "\n\nray 1: \n";
	bool hit = box.intersect(ray1,distance);
	std::cout << "\nHit? " << hit << " Distance: " << distance;

	distance = 0.0f;
	std::cout << "\n\nray 2: \n";
	hit = box.intersect(ray2,distance);
	std::cout << "\n\nHit? " << hit << " Distance: " << distance;

	distance = 0.0f;
	std::cout << "\n\nray 3: \n";
	hit = box.intersect(ray3,distance);
	std::cout << "\n\nHit? " << hit << " Distance: " << distance;
}

‚‚
//lissylissylissy <33333
<commit_msg>dont wanna ruin your test<commit_after>//needed for testing
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>

//other stuff needed
#include <glm/vec3.hpp>
#include <cmath>
#include <iostream>

//include classes for testing
#include "shape.hpp"
#include "sphere.hpp"
#include "box.hpp"
#include "material.hpp"
#include "color.hpp"
#include "sdfloader.hpp"

// ----------------------------------
// SHAPE TESTS
// ----------------------------------

//karos änderung

TEST_CASE("getter shape","[shape]")
{
	Sphere s {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f},1.0f};
	REQUIRE(s.get_name() == "name");

	Material c{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f};
	REQUIRE(s.get_material() == c); //added operator == in color.hpp
}

TEST_CASE("operator<< and print shape","[shape]")
{
	Sphere es {"empty_sphere"};
	std::cout << es;

	Sphere s {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f},1.0f};
	std::cout << s;
//trolololo
}

// ----------------------------------
// SPHERE TESTS
// ----------------------------------

TEST_CASE("constructors of sphere","[sphere]")
{
	Sphere s1 {"name"};
	Sphere s2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};

	REQUIRE(s1.get_center() == s2.get_center());
	REQUIRE(s1.get_radius() == s2.get_radius());
}

TEST_CASE("get_center and get_radius","[sphere]")
{
	Sphere s {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};

	REQUIRE(s.get_radius() == 1.0f);
	REQUIRE(s.get_center() == glm::vec3{0.0f});
}

TEST_CASE("area","[sphere]")
{
	Sphere s {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};
	REQUIRE(12.566f == Approx(s.area()).epsilon(0.001));
}

TEST_CASE("volume","[sphere]")
{
	Sphere s {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, 1.0f};
	REQUIRE(4.189 == Approx(s.volume()).epsilon(0.001));
}

TEST_CASE("print sphere","[sphere]")
{
	Sphere es {"empty_sphere"};
	std::cout << es;

	Sphere s {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f},1.0f};
	std::cout << s;
}

// ----------------------------------
// BOX TESTS
// ----------------------------------

TEST_CASE("constructors of box","[box]")
{
	Box b1 {"name"};
	Box b2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, glm::vec3{1.0f}};

	REQUIRE(b1.get_min() == b2.get_min());
	REQUIRE(b1.get_max() == b2.get_max());
}

TEST_CASE("get_min and get_max","[box]")
{
	Box b2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, glm::vec3{1.0f}};

	REQUIRE(b2.get_min() == glm::vec3{0.0f});
	REQUIRE(b2.get_max() == glm::vec3{1.0f});
}

TEST_CASE("area of box","[box]")
{
	Box b2 {"name",Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},glm::vec3{0.0f}, glm::vec3{1.0f}};
	REQUIRE(6.0f == Approx(b2.area()).epsilon(0.001));
}

TEST_CASE("volume of box","[box]")
{
	Box b2 {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f}, glm::vec3{0.0f}, glm::vec3{1.0f}};

	REQUIRE(1.0f == Approx(b2.volume()).epsilon(0.001));
}

TEST_CASE("print box","[box]")
{
	Box eb {"empty_box"};
	std::cout << eb;

	Box b {"name", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f}, glm::vec3{0.0f}, glm::vec3{1.0f}};
	std::cout << b;
}

// ----------------------------------
// AUFGABE 5.6 TEST
// ----------------------------------

TEST_CASE("intersectRaySphere", "[intersect]")
{
	//Ray
	glm::vec3 ray_origin{0.0f, 0.0f, 0.0f};
	//ray direction has to be normalized !
	//you can use:
		//v = glm::normalize(some_vector);
	glm::vec3 ray_direction{0.0f, 0.0f, 1.0f};

	//Sphere
	glm::vec3 sphere_center{0.0f, 0.0f, 5.0f};
	float sphere_radius{1.0f};

	float distance{0.0f};
	auto result = glm::intersectRaySphere(
		ray_origin, ray_direction,
		sphere_center,
		sphere_radius * sphere_radius,
		distance);

	REQUIRE(distance == Approx(4.0f));

	Sphere s {"some_sphere", Material{"",Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},Color{0.0f,0.0f,0.0f},0.0f},
		sphere_center, sphere_radius};

	Ray r {ray_origin,ray_direction};

	s.intersect(r,distance);

	REQUIRE(distance == Approx(4.0f));
}

// ----------------------------------
// AUFGABE 5.8 TEST
// ----------------------------------

TEST_CASE("virtual", "[Destructors]")
{

	std::cout << "\ntesting virtual and non-virtual construction and destruction\n";

	Color c_red {255.0f, 0.0f, 0.0f};
	Material red {"", c_red, c_red, c_red, 0.0f};

	glm::vec3 position {0.0f,0.0f,0.0f};

	std::cout << "Create s1\n";
	Sphere* s1 = new Sphere("sphere0",red,position,1.2f);
	std::cout << "Create s2\n";
	Shape* s2 = new Sphere("sphere1",red,position,1.2f);

	std::cout << "Printing objects: \n";
	std::cout << *s1;
	std::cout << *s2 << "\n";

	std::cout << "Delete s1\n";
	delete s1;
	std::cout << "Delete s2\n";
	delete s2;
}

// ----------------------------------
// MATERIAL Tests
// ----------------------------------

TEST_CASE("material in place of color struct", "Material")
{
	Color c{0.0f,0.0f,0.0f};
	Material mate1 {};
	std::cout << mate1;

	Material mate2 {"some material",c,c,c,0.0f};
	std::cout << mate2;
}

int main(int argc, char *argv[])
{
  return Catch::Session().run(argc, argv);
}

/*TEST_CASE("SDFloader test", "[SDFloader]")
{
	SDFloader load();
	load.sdfLoad("/Users/lissyscholz/Documents/programmiersprachen/raytracer/programmiersprachen-raytracer/source/material_input.txt");
}*/

// ----------------------------------
// INTERSECTION Tests
// ----------------------------------

TEST_CASE("intersection tests","Box")
{
	Color c {0.0f,0.0f,0.0f};
	Ray ray1 {glm::vec3{0.0f}, //from koordinatenursprung
			glm::vec3{1.0f,1.0f,-1.0f}}; //richung

	Ray ray2 {glm::vec3{0.0f}, //from koordinatenursprung
			glm::vec3{1.0f,1.0f,-2.0f}}; //richtung

	Ray ray3 {glm::vec3{1.0f,1.0f,-2.0f}, //von innerhalb der Box aus
			glm::vec3{0.0f,0.0f,-1.0f}};

	Box box {"test_box",
		Material{"",c,c,c, 0.0f},
		glm::vec3{0.0f,0.0f,-1.0f},	//min
		glm::vec3{2.0f,2.0f,-3.0f}	//max
	};

	std::cout << box;

	float distance = 0.0f;
	std::cout << "\n\nray 1: \n";
	bool hit = box.intersect(ray1,distance);
	std::cout << "\nHit? " << hit << " Distance: " << distance;

	distance = 0.0f;
	std::cout << "\n\nray 2: \n";
	hit = box.intersect(ray2,distance);
	std::cout << "\n\nHit? " << hit << " Distance: " << distance;

	distance = 0.0f;
	std::cout << "\n\nray 3: \n";
	hit = box.intersect(ray3,distance);
	std::cout << "\n\nHit? " << hit << " Distance: " << distance;
}

‚‚
//lissylissylissy <33333
<|endoftext|>


<commit_before>// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "allocation-tracker.h"

#include "heap-snapshot-generator.h"
#include "frames-inl.h"

namespace v8 {
namespace internal {

AllocationTraceNode::AllocationTraceNode(
    AllocationTraceTree* tree, SnapshotObjectId shared_function_info_id)
    : tree_(tree),
      function_id_(shared_function_info_id),
      total_size_(0),
      allocation_count_(0),
      id_(tree->next_node_id()) {
}

AllocationTraceNode::~AllocationTraceNode() {
  for (int i = 0; i < children_.length(); i++) delete children_[i];
}

AllocationTraceNode* AllocationTraceNode::FindChild(SnapshotObjectId id) {
  for (int i = 0; i < children_.length(); i++) {
    AllocationTraceNode* node = children_[i];
    if (node->function_id() == id) return node;
  }
  return NULL;
}

AllocationTraceNode* AllocationTraceNode::FindOrAddChild(SnapshotObjectId id) {
  AllocationTraceNode* child = FindChild(id);
  if (child == NULL) {
    child = new AllocationTraceNode(tree_, id);
    children_.Add(child);
  }
  return child;
}

void AllocationTraceNode::AddAllocation(unsigned size) {
  total_size_ += size;
  ++allocation_count_;
}

void AllocationTraceNode::Print(int indent, AllocationTracker* tracker) {
  OS::Print("%10u %10u %*c", total_size_, allocation_count_, indent, ' ');
  if (tracker != NULL) {
    const char* name = "<unknown function>";
    if (function_id_ != 0) {
      AllocationTracker::FunctionInfo* info =
          tracker->GetFunctionInfo(function_id_);
      if (info != NULL) {
        name = info->name;
      }
    }
    OS::Print("%s #%u", name, id_);
  } else {
    OS::Print("%u #%u", function_id_, id_);
  }
  OS::Print("\n");
  indent += 2;
  for (int i = 0; i < children_.length(); i++) {
    children_[i]->Print(indent, tracker);
  }
}

AllocationTraceTree::AllocationTraceTree()
    : next_node_id_(1),
      root_(this, 0) {
}

AllocationTraceTree::~AllocationTraceTree() {
}

AllocationTraceNode* AllocationTraceTree::AddPathFromEnd(
    const Vector<SnapshotObjectId>& path) {
  AllocationTraceNode* node = root();
  for (SnapshotObjectId* entry = path.start() + path.length() - 1;
       entry != path.start() - 1;
       --entry) {
    node = node->FindOrAddChild(*entry);
  }
  return node;
}

void AllocationTraceTree::Print(AllocationTracker* tracker) {
  OS::Print("[AllocationTraceTree:]\n");
  OS::Print("Total size | Allocation count | Function id | id\n");
  root()->Print(0, tracker);
}

void AllocationTracker::DeleteUnresolvedLocation(
    UnresolvedLocation** location) {
  delete *location;
}

AllocationTracker::FunctionInfo::FunctionInfo()
    : name(""),
      script_name(""),
      script_id(0),
      line(-1),
      column(-1) {
}

static bool AddressesMatch(void* key1, void* key2) {
  return key1 == key2;
}

AllocationTracker::AllocationTracker(
    HeapObjectsMap* ids, StringsStorage* names)
    : ids_(ids),
      names_(names),
      id_to_function_info_(AddressesMatch) {
}

AllocationTracker::~AllocationTracker() {
  unresolved_locations_.Iterate(DeleteUnresolvedLocation);
  for (HashMap::Entry* p = id_to_function_info_.Start();
       p != NULL;
       p = id_to_function_info_.Next(p)) {
    delete reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value);
  }
}

void AllocationTracker::PrepareForSerialization() {
  List<UnresolvedLocation*> copy(unresolved_locations_.length());
  copy.AddAll(unresolved_locations_);
  unresolved_locations_.Clear();
  for (int i = 0; i < copy.length(); i++) {
    copy[i]->Resolve();
    delete copy[i];
  }
}

void AllocationTracker::AllocationEvent(Address addr, int size) {
  DisallowHeapAllocation no_allocation;
  Heap* heap = ids_->heap();

  // Mark the new block as FreeSpace to make sure the heap is iterable
  // while we are capturing stack trace.
  FreeListNode::FromAddress(addr)->set_size(heap, size);
  ASSERT_EQ(HeapObject::FromAddress(addr)->Size(), size);
  ASSERT(FreeListNode::IsFreeListNode(HeapObject::FromAddress(addr)));

  Isolate* isolate = heap->isolate();
  int length = 0;
  StackTraceFrameIterator it(isolate);
  while (!it.done() && length < kMaxAllocationTraceLength) {
    JavaScriptFrame* frame = it.frame();
    SharedFunctionInfo* shared = frame->function()->shared();
    SnapshotObjectId id = ids_->FindOrAddEntry(
        shared->address(), shared->Size(), false);
    allocation_trace_buffer_[length++] = id;
    AddFunctionInfo(shared, id);
    it.Advance();
  }
  AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
      Vector<SnapshotObjectId>(allocation_trace_buffer_, length));
  top_node->AddAllocation(size);
}

static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) {
  return ComputeIntegerHash(static_cast<uint32_t>(id),
                            v8::internal::kZeroHashSeed);
}

AllocationTracker::FunctionInfo* AllocationTracker::GetFunctionInfo(
    SnapshotObjectId id) {
  HashMap::Entry* entry = id_to_function_info_.Lookup(
      reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), false);
  if (entry == NULL) {
    return NULL;
  }
  return reinterpret_cast<FunctionInfo*>(entry->value);
}

void AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared,
                                        SnapshotObjectId id) {
  HashMap::Entry* entry = id_to_function_info_.Lookup(
      reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), true);
  if (entry->value == NULL) {
    FunctionInfo* info = new FunctionInfo();
    info->name = names_->GetFunctionName(shared->DebugName());
    if (shared->script()->IsScript()) {
      Script* script = Script::cast(shared->script());
      if (script->name()->IsName()) {
        Name* name = Name::cast(script->name());
        info->script_name = names_->GetName(name);
      }
      info->script_id = script->id()->value();
      // Converting start offset into line and column may cause heap
      // allocations so we postpone them until snapshot serialization.
      unresolved_locations_.Add(new UnresolvedLocation(
          script,
          shared->start_position(),
          info));
    }
    entry->value = info;
  }
}

AllocationTracker::UnresolvedLocation::UnresolvedLocation(
    Script* script, int start, FunctionInfo* info)
    : start_position_(start),
      info_(info) {
  script_ = Handle<Script>::cast(
      script->GetIsolate()->global_handles()->Create(script));
  GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
                          this,
                          &HandleWeakScript);
}

AllocationTracker::UnresolvedLocation::~UnresolvedLocation() {
  if (!script_.is_null()) {
    GlobalHandles::Destroy(reinterpret_cast<Object**>(script_.location()));
  }
}

void AllocationTracker::UnresolvedLocation::Resolve() {
  if (script_.is_null()) return;
  info_->line = GetScriptLineNumber(script_, start_position_);
  info_->column = GetScriptColumnNumber(script_, start_position_);
}

void AllocationTracker::UnresolvedLocation::HandleWeakScript(
    const v8::WeakCallbackData<v8::Value, void>& data) {
  UnresolvedLocation* loc =
      reinterpret_cast<UnresolvedLocation*>(data.GetParameter());
  GlobalHandles::Destroy(reinterpret_cast<Object**>(loc->script_.location()));
  loc->script_ = Handle<Script>::null();
}

} }  // namespace v8::internal
<commit_msg>Create HandleScope before calling GetScriptLineNumber<commit_after>// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "allocation-tracker.h"

#include "heap-snapshot-generator.h"
#include "frames-inl.h"

namespace v8 {
namespace internal {

AllocationTraceNode::AllocationTraceNode(
    AllocationTraceTree* tree, SnapshotObjectId shared_function_info_id)
    : tree_(tree),
      function_id_(shared_function_info_id),
      total_size_(0),
      allocation_count_(0),
      id_(tree->next_node_id()) {
}

AllocationTraceNode::~AllocationTraceNode() {
  for (int i = 0; i < children_.length(); i++) delete children_[i];
}

AllocationTraceNode* AllocationTraceNode::FindChild(SnapshotObjectId id) {
  for (int i = 0; i < children_.length(); i++) {
    AllocationTraceNode* node = children_[i];
    if (node->function_id() == id) return node;
  }
  return NULL;
}

AllocationTraceNode* AllocationTraceNode::FindOrAddChild(SnapshotObjectId id) {
  AllocationTraceNode* child = FindChild(id);
  if (child == NULL) {
    child = new AllocationTraceNode(tree_, id);
    children_.Add(child);
  }
  return child;
}

void AllocationTraceNode::AddAllocation(unsigned size) {
  total_size_ += size;
  ++allocation_count_;
}

void AllocationTraceNode::Print(int indent, AllocationTracker* tracker) {
  OS::Print("%10u %10u %*c", total_size_, allocation_count_, indent, ' ');
  if (tracker != NULL) {
    const char* name = "<unknown function>";
    if (function_id_ != 0) {
      AllocationTracker::FunctionInfo* info =
          tracker->GetFunctionInfo(function_id_);
      if (info != NULL) {
        name = info->name;
      }
    }
    OS::Print("%s #%u", name, id_);
  } else {
    OS::Print("%u #%u", function_id_, id_);
  }
  OS::Print("\n");
  indent += 2;
  for (int i = 0; i < children_.length(); i++) {
    children_[i]->Print(indent, tracker);
  }
}

AllocationTraceTree::AllocationTraceTree()
    : next_node_id_(1),
      root_(this, 0) {
}

AllocationTraceTree::~AllocationTraceTree() {
}

AllocationTraceNode* AllocationTraceTree::AddPathFromEnd(
    const Vector<SnapshotObjectId>& path) {
  AllocationTraceNode* node = root();
  for (SnapshotObjectId* entry = path.start() + path.length() - 1;
       entry != path.start() - 1;
       --entry) {
    node = node->FindOrAddChild(*entry);
  }
  return node;
}

void AllocationTraceTree::Print(AllocationTracker* tracker) {
  OS::Print("[AllocationTraceTree:]\n");
  OS::Print("Total size | Allocation count | Function id | id\n");
  root()->Print(0, tracker);
}

void AllocationTracker::DeleteUnresolvedLocation(
    UnresolvedLocation** location) {
  delete *location;
}

AllocationTracker::FunctionInfo::FunctionInfo()
    : name(""),
      script_name(""),
      script_id(0),
      line(-1),
      column(-1) {
}

static bool AddressesMatch(void* key1, void* key2) {
  return key1 == key2;
}

AllocationTracker::AllocationTracker(
    HeapObjectsMap* ids, StringsStorage* names)
    : ids_(ids),
      names_(names),
      id_to_function_info_(AddressesMatch) {
}

AllocationTracker::~AllocationTracker() {
  unresolved_locations_.Iterate(DeleteUnresolvedLocation);
  for (HashMap::Entry* p = id_to_function_info_.Start();
       p != NULL;
       p = id_to_function_info_.Next(p)) {
    delete reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value);
  }
}

void AllocationTracker::PrepareForSerialization() {
  List<UnresolvedLocation*> copy(unresolved_locations_.length());
  copy.AddAll(unresolved_locations_);
  unresolved_locations_.Clear();
  for (int i = 0; i < copy.length(); i++) {
    copy[i]->Resolve();
    delete copy[i];
  }
}

void AllocationTracker::AllocationEvent(Address addr, int size) {
  DisallowHeapAllocation no_allocation;
  Heap* heap = ids_->heap();

  // Mark the new block as FreeSpace to make sure the heap is iterable
  // while we are capturing stack trace.
  FreeListNode::FromAddress(addr)->set_size(heap, size);
  ASSERT_EQ(HeapObject::FromAddress(addr)->Size(), size);
  ASSERT(FreeListNode::IsFreeListNode(HeapObject::FromAddress(addr)));

  Isolate* isolate = heap->isolate();
  int length = 0;
  StackTraceFrameIterator it(isolate);
  while (!it.done() && length < kMaxAllocationTraceLength) {
    JavaScriptFrame* frame = it.frame();
    SharedFunctionInfo* shared = frame->function()->shared();
    SnapshotObjectId id = ids_->FindOrAddEntry(
        shared->address(), shared->Size(), false);
    allocation_trace_buffer_[length++] = id;
    AddFunctionInfo(shared, id);
    it.Advance();
  }
  AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
      Vector<SnapshotObjectId>(allocation_trace_buffer_, length));
  top_node->AddAllocation(size);
}

static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) {
  return ComputeIntegerHash(static_cast<uint32_t>(id),
                            v8::internal::kZeroHashSeed);
}

AllocationTracker::FunctionInfo* AllocationTracker::GetFunctionInfo(
    SnapshotObjectId id) {
  HashMap::Entry* entry = id_to_function_info_.Lookup(
      reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), false);
  if (entry == NULL) {
    return NULL;
  }
  return reinterpret_cast<FunctionInfo*>(entry->value);
}

void AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared,
                                        SnapshotObjectId id) {
  HashMap::Entry* entry = id_to_function_info_.Lookup(
      reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), true);
  if (entry->value == NULL) {
    FunctionInfo* info = new FunctionInfo();
    info->name = names_->GetFunctionName(shared->DebugName());
    if (shared->script()->IsScript()) {
      Script* script = Script::cast(shared->script());
      if (script->name()->IsName()) {
        Name* name = Name::cast(script->name());
        info->script_name = names_->GetName(name);
      }
      info->script_id = script->id()->value();
      // Converting start offset into line and column may cause heap
      // allocations so we postpone them until snapshot serialization.
      unresolved_locations_.Add(new UnresolvedLocation(
          script,
          shared->start_position(),
          info));
    }
    entry->value = info;
  }
}

AllocationTracker::UnresolvedLocation::UnresolvedLocation(
    Script* script, int start, FunctionInfo* info)
    : start_position_(start),
      info_(info) {
  script_ = Handle<Script>::cast(
      script->GetIsolate()->global_handles()->Create(script));
  GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
                          this,
                          &HandleWeakScript);
}

AllocationTracker::UnresolvedLocation::~UnresolvedLocation() {
  if (!script_.is_null()) {
    GlobalHandles::Destroy(reinterpret_cast<Object**>(script_.location()));
  }
}

void AllocationTracker::UnresolvedLocation::Resolve() {
  if (script_.is_null()) return;
  HandleScope scope(script_->GetIsolate());
  info_->line = GetScriptLineNumber(script_, start_position_);
  info_->column = GetScriptColumnNumber(script_, start_position_);
}

void AllocationTracker::UnresolvedLocation::HandleWeakScript(
    const v8::WeakCallbackData<v8::Value, void>& data) {
  UnresolvedLocation* loc =
      reinterpret_cast<UnresolvedLocation*>(data.GetParameter());
  GlobalHandles::Destroy(reinterpret_cast<Object**>(loc->script_.location()));
  loc->script_ = Handle<Script>::null();
}

} }  // namespace v8::internal
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstring>
#include <iostream>

#include <improbable/standard_library.h>
#include <improbable/worker.h>
#include <shoveler.h>

extern "C" {
#include <shoveler/spatialos/log.h>
#include <shoveler/spatialos/worker/view/base/view.h>
#include <shoveler/spatialos/worker/view/base/position.h>
}

using shoveler::Bootstrap;
using CreateClientEntity = shoveler::Bootstrap::Commands::CreateClientEntity;
using shoveler::Client;
using shoveler::Color;
using shoveler::CreateClientEntityRequest;
using shoveler::CreateClientEntityResponse;
using shoveler::Drawable;
using shoveler::DrawableType;
using shoveler::Light;
using shoveler::LightType;
using shoveler::Material;
using shoveler::MaterialType;
using shoveler::Model;
using shoveler::PolygonMode;
using improbable::EntityAcl;
using improbable::EntityAclData;
using improbable::Metadata;
using improbable::Persistence;
using improbable::Position;
using improbable::WorkerAttributeSet;
using improbable::WorkerRequirementSet;

int main(int argc, char **argv) {
	if (argc != 5) {
		return 1;
	}

	worker::ConnectionParameters parameters;
	parameters.WorkerType = "ShovelerServer";
	parameters.Network.ConnectionType = worker::NetworkConnectionType::kTcp;
	parameters.Network.UseExternalIp = false;

	const std::string workerId = argv[1];
	const std::string hostname = argv[2];
	const std::uint16_t port = static_cast<std::uint16_t>(std::stoi(argv[3]));
	const std::string logFileLocation = argv[4];

	FILE *logFile = fopen(logFileLocation.c_str(), "r+");
	if(logFile == NULL) {
		std::cerr << "Failed to open output log file at " << logFileLocation << ": " << strerror(errno) << std::endl;
		return 1;
	}

	shovelerSpatialosLogInit(SHOVELER_SPATIALOS_LOG_LEVEL_ALL, logFile);
	shovelerSpatialosLogInfo("Connecting as worker %s to %s:%d.", workerId.c_str(), hostname.c_str(), port);

	const worker::ComponentRegistry& components = worker::Components<
		shoveler::Bootstrap,
		shoveler::Client,
		shoveler::Light,
		shoveler::Model,
		improbable::EntityAcl,
		improbable::Metadata,
		improbable::Persistence,
		improbable::Position>{};

	worker::Connection connection = worker::Connection::ConnectAsync(components, hostname, port, workerId, parameters).Get();
	bool disconnected = false;
	worker::Dispatcher dispatcher{components};

	dispatcher.OnDisconnect([&](const worker::DisconnectOp& op) {
		shovelerSpatialosLogError("Disconnected from SpatialOS: %s", op.Reason.c_str());
		disconnected = true;
	});

	dispatcher.OnMetrics([&](const worker::MetricsOp& op) {
		auto metrics = op.Metrics;
		connection.SendMetrics(metrics);
	});

	dispatcher.OnLogMessage([&](const worker::LogMessageOp& op) {
		switch(op.Level) {
			case worker::LogLevel::kDebug:
				shovelerSpatialosLogTrace(op.Message.c_str());
				break;
			case worker::LogLevel::kInfo:
				shovelerSpatialosLogInfo(op.Message.c_str());
				break;
			case worker::LogLevel::kWarn:
				shovelerSpatialosLogWarning(op.Message.c_str());
				break;
			case worker::LogLevel::kError:
				shovelerSpatialosLogError(op.Message.c_str());
				break;
			case worker::LogLevel::kFatal:
				shovelerSpatialosLogError(op.Message.c_str());
				std::terminate();
			default:
				break;
		}
	});

	dispatcher.OnAddEntity([&](const worker::AddEntityOp& op) {
		shovelerSpatialosLogInfo("Adding entity %lld.", op.EntityId);
	});

	dispatcher.OnRemoveEntity([&](const worker::RemoveEntityOp& op) {
		shovelerSpatialosLogInfo("Removing entity %lld.", op.EntityId);
	});

	dispatcher.OnAddComponent<Bootstrap>([&](const worker::AddComponentOp<Bootstrap>& op) {
		shovelerSpatialosLogInfo("Adding bootstrap to entity %lld.", op.EntityId);
	});

	dispatcher.OnComponentUpdate<Bootstrap>([&](const worker::ComponentUpdateOp<Bootstrap>& op) {
		shovelerSpatialosLogInfo("Updating bootstrap for entity %lld.", op.EntityId);
	});

	dispatcher.OnRemoveComponent<Bootstrap>([&](const worker::RemoveComponentOp& op) {
		shovelerSpatialosLogInfo("Removing bootstrap from entity %lld.", op.EntityId);
	});

	dispatcher.OnAuthorityChange<Bootstrap>([&](const worker::AuthorityChangeOp& op) {
		shovelerSpatialosLogInfo("Authority change to %d for entity %lld.", op.Authority, op.EntityId);
	});

	dispatcher.OnCommandRequest<CreateClientEntity>([&](const worker::CommandRequestOp<CreateClientEntity>& op) {
		shovelerSpatialosLogInfo("Received create client entity request from: %s", op.CallerWorkerId.c_str());

		Color whiteColor{1.0f, 1.0f, 1.0f};

		Drawable pointDrawable{DrawableType::POINT};
		Material whiteParticleMaterial{MaterialType::PARTICLE, whiteColor, {}};

		worker::Entity clientEntity;
		clientEntity.Add<Metadata>({"client"});
		clientEntity.Add<Client>({});
		clientEntity.Add<Persistence>({});
		clientEntity.Add<Position>({{0, 0, 0}});
		clientEntity.Add<Model>({pointDrawable, whiteParticleMaterial, {0.0f, 0.0f, 0.0f}, {0.1f, 0.1f, 0.0f}, true, true, false, false, PolygonMode::FILL});
		clientEntity.Add<Light>({LightType::POINT, 1024, 1024, 1, 0.01f, 80.0f, {0.1f, 0.1f, 0.1f}, {}});

		WorkerAttributeSet clientAttributeSet({"client"});
		WorkerAttributeSet serverAttributeSet({"server"});
		WorkerRequirementSet specificClientRequirementSet({op.CallerAttributeSet});
		WorkerRequirementSet clientAndServerRequirementSet({clientAttributeSet, serverAttributeSet});
		worker::Map<std::uint32_t, WorkerRequirementSet> clientEntityComponentAclMap;
		clientEntityComponentAclMap.insert({{Client::ComponentId, specificClientRequirementSet}});
		clientEntityComponentAclMap.insert({{Position::ComponentId, specificClientRequirementSet}});
		EntityAclData clientEntityAclData(clientAndServerRequirementSet, clientEntityComponentAclMap);
		clientEntity.Add<EntityAcl>(clientEntityAclData);
		connection.SendCreateEntityRequest(clientEntity, {}, {});
		connection.SendCommandResponse<CreateClientEntity>(op.RequestId, {});
	});

	while(!disconnected) {
		dispatcher.Process(connection.GetOpList(1000));
	}
}
<commit_msg>added client ping command handler to server<commit_after>#include <cstdio>
#include <cstring>
#include <iostream>

#include <improbable/standard_library.h>
#include <improbable/view.h>
#include <improbable/worker.h>
#include <shoveler.h>

extern "C" {
#include <glib.h>

#include <shoveler/spatialos/log.h>
#include <shoveler/spatialos/worker/view/base/view.h>
#include <shoveler/spatialos/worker/view/base/position.h>
}

using shoveler::Bootstrap;
using shoveler::Client;
using shoveler::ClientHeartbeat;
using shoveler::Color;
using shoveler::CreateClientEntityRequest;
using shoveler::CreateClientEntityResponse;
using shoveler::Drawable;
using shoveler::DrawableType;
using shoveler::Light;
using shoveler::LightType;
using shoveler::Material;
using shoveler::MaterialType;
using shoveler::Model;
using shoveler::PolygonMode;
using improbable::EntityAcl;
using improbable::EntityAclData;
using improbable::Metadata;
using improbable::Persistence;
using improbable::Position;
using improbable::WorkerAttributeSet;
using improbable::WorkerRequirementSet;

using CreateClientEntity = shoveler::Bootstrap::Commands::CreateClientEntity;
using ClientPing = shoveler::Bootstrap::Commands::ClientPing;

int main(int argc, char **argv) {
	if (argc != 5) {
		return 1;
	}

	worker::ConnectionParameters parameters;
	parameters.WorkerType = "ShovelerServer";
	parameters.Network.ConnectionType = worker::NetworkConnectionType::kTcp;
	parameters.Network.UseExternalIp = false;

	const std::string workerId = argv[1];
	const std::string hostname = argv[2];
	const std::uint16_t port = static_cast<std::uint16_t>(std::stoi(argv[3]));
	const std::string logFileLocation = argv[4];

	FILE *logFile = fopen(logFileLocation.c_str(), "r+");
	if(logFile == NULL) {
		std::cerr << "Failed to open output log file at " << logFileLocation << ": " << strerror(errno) << std::endl;
		return 1;
	}

	shovelerSpatialosLogInit(SHOVELER_SPATIALOS_LOG_LEVEL_ALL, logFile);
	shovelerSpatialosLogInfo("Connecting as worker %s to %s:%d.", workerId.c_str(), hostname.c_str(), port);

	auto components = worker::Components<
		shoveler::Bootstrap,
		shoveler::Client,
		shoveler::ClientHeartbeat,
		shoveler::Light,
		shoveler::Model,
		improbable::EntityAcl,
		improbable::Metadata,
		improbable::Persistence,
		improbable::Position>{};

	worker::Connection connection = worker::Connection::ConnectAsync(components, hostname, port, workerId, parameters).Get();
	bool disconnected = false;
	worker::View view{components};
	worker::Dispatcher& dispatcher = view;

	dispatcher.OnDisconnect([&](const worker::DisconnectOp& op) {
		shovelerSpatialosLogError("Disconnected from SpatialOS: %s", op.Reason.c_str());
		disconnected = true;
	});

	dispatcher.OnMetrics([&](const worker::MetricsOp& op) {
		auto metrics = op.Metrics;
		connection.SendMetrics(metrics);
	});

	dispatcher.OnLogMessage([&](const worker::LogMessageOp& op) {
		switch(op.Level) {
			case worker::LogLevel::kDebug:
				shovelerSpatialosLogTrace(op.Message.c_str());
				break;
			case worker::LogLevel::kInfo:
				shovelerSpatialosLogInfo(op.Message.c_str());
				break;
			case worker::LogLevel::kWarn:
				shovelerSpatialosLogWarning(op.Message.c_str());
				break;
			case worker::LogLevel::kError:
				shovelerSpatialosLogError(op.Message.c_str());
				break;
			case worker::LogLevel::kFatal:
				shovelerSpatialosLogError(op.Message.c_str());
				std::terminate();
			default:
				break;
		}
	});

	dispatcher.OnAddEntity([&](const worker::AddEntityOp& op) {
		shovelerSpatialosLogInfo("Adding entity %lld.", op.EntityId);
	});

	dispatcher.OnRemoveEntity([&](const worker::RemoveEntityOp& op) {
		shovelerSpatialosLogInfo("Removing entity %lld.", op.EntityId);
	});

	dispatcher.OnAddComponent<Bootstrap>([&](const worker::AddComponentOp<Bootstrap>& op) {
		shovelerSpatialosLogInfo("Adding bootstrap to entity %lld.", op.EntityId);
	});

	dispatcher.OnComponentUpdate<Bootstrap>([&](const worker::ComponentUpdateOp<Bootstrap>& op) {
		shovelerSpatialosLogInfo("Updating bootstrap for entity %lld.", op.EntityId);
	});

	dispatcher.OnRemoveComponent<Bootstrap>([&](const worker::RemoveComponentOp& op) {
		shovelerSpatialosLogInfo("Removing bootstrap from entity %lld.", op.EntityId);
	});

	dispatcher.OnAuthorityChange<Bootstrap>([&](const worker::AuthorityChangeOp& op) {
		shovelerSpatialosLogInfo("Authority change to %d for entity %lld.", op.Authority, op.EntityId);
	});

	dispatcher.OnCommandRequest<CreateClientEntity>([&](const worker::CommandRequestOp<CreateClientEntity>& op) {
		shovelerSpatialosLogInfo("Received create client entity request from: %s", op.CallerWorkerId.c_str());

		Color whiteColor{1.0f, 1.0f, 1.0f};

		Drawable pointDrawable{DrawableType::POINT};
		Material whiteParticleMaterial{MaterialType::PARTICLE, whiteColor, {}};

		GDateTime *now = g_date_time_new_now_utc();
		int64_t timestamp = g_date_time_to_unix(now);
		g_date_time_unref(now);

		worker::Entity clientEntity;
		clientEntity.Add<Metadata>({"client"});
		clientEntity.Add<Client>({});
		clientEntity.Add<ClientHeartbeat>({timestamp});
		clientEntity.Add<Persistence>({});
		clientEntity.Add<Position>({{0, 0, 0}});
		clientEntity.Add<Model>({pointDrawable, whiteParticleMaterial, {0.0f, 0.0f, 0.0f}, {0.1f, 0.1f, 0.0f}, true, true, false, false, PolygonMode::FILL});
		clientEntity.Add<Light>({LightType::POINT, 1024, 1024, 1, 0.01f, 80.0f, {0.1f, 0.1f, 0.1f}, {}});

		WorkerAttributeSet clientAttributeSet({"client"});
		WorkerAttributeSet serverAttributeSet({"server"});
		WorkerRequirementSet specificClientRequirementSet({op.CallerAttributeSet});
		WorkerRequirementSet serverRequirementSet({serverAttributeSet});
		WorkerRequirementSet clientAndServerRequirementSet({clientAttributeSet, serverAttributeSet});
		worker::Map<std::uint32_t, WorkerRequirementSet> clientEntityComponentAclMap;
		clientEntityComponentAclMap.insert({{Client::ComponentId, specificClientRequirementSet}});
		clientEntityComponentAclMap.insert({{ClientHeartbeat::ComponentId, serverRequirementSet}});
		clientEntityComponentAclMap.insert({{Position::ComponentId, specificClientRequirementSet}});
		EntityAclData clientEntityAclData(clientAndServerRequirementSet, clientEntityComponentAclMap);
		clientEntity.Add<EntityAcl>(clientEntityAclData);
		connection.SendCreateEntityRequest(clientEntity, {}, {});
		connection.SendCommandResponse<CreateClientEntity>(op.RequestId, {});
	});

	dispatcher.OnCommandRequest<ClientPing>([&](const worker::CommandRequestOp<ClientPing>& op) {
		worker::EntityId clientEntityId = op.Request.client_entity_id();
		worker::Map<worker::EntityId, worker::Map<worker::ComponentId, worker::Authority>>::const_iterator entityAuthorityQuery = view.ComponentAuthority.find(clientEntityId);
		if(entityAuthorityQuery == view.ComponentAuthority.end()) {
			shovelerSpatialosLogWarning("Received client ping from %s for unknown client entity %lld, ignoring.", op.CallerWorkerId.c_str(), clientEntityId);
			return;
		}
		const worker::Map<worker::ComponentId, worker::Authority>& componentAuthorityMap = entityAuthorityQuery->second;

		worker::Map<worker::ComponentId, worker::Authority>::const_iterator componentAuthorityQuery = componentAuthorityMap.find(ClientHeartbeat::ComponentId);
		if(componentAuthorityQuery == componentAuthorityMap.end()) {
			shovelerSpatialosLogWarning("Received client ping from %s for client entity %lld without client heartbeat component, ignoring.", op.CallerWorkerId.c_str(), clientEntityId);
			return;
		}
		const worker::Authority& clientHeartbeatAuthority = componentAuthorityQuery->second;

		if(clientHeartbeatAuthority != worker::Authority::kAuthoritative) {
			shovelerSpatialosLogWarning("Received client ping from %s for client entity %lld without authoritative client heartbeat component, ignoring.", op.CallerWorkerId.c_str(), clientEntityId);
			return;
		}

		ClientHeartbeat::Update clientHeartbeatUpdate;
		clientHeartbeatUpdate.set_last_heartbeat(op.Request.heartbeat());
		connection.SendComponentUpdate<ClientHeartbeat>(clientEntityId, clientHeartbeatUpdate);

		shovelerSpatialosLogWarning("Received client ping from %s for client entity %lld: %lld.", op.CallerWorkerId.c_str(), clientEntityId, op.Request.heartbeat());
	});

	while(!disconnected) {
		dispatcher.Process(connection.GetOpList(1000));
	}
}
<|endoftext|>


<commit_before>// $Id$
// Copyright (c) 2008 Oliver Lau <oliver@ersatzworld.net>
// Alle Rechte vorbehalten.

#include <iostream>
#include <cstdlib>

#include <getopt.h>

#include "gpslib/WPL1000File.h"
#include "gpslib/GPXFile.h"

// gettext-Dummy
#define _(s) s

using namespace std;
using namespace GPS;

#ifdef WIN32
const char PathDelimiter = '\\';
#else
const char PathDelimiter = '/';
#endif

enum _long_options {
    SELECT_HELP,
    SELECT_DEBUG,
    SELECT_QUIET,
    SELECT_VERBOSE,
    SELECT_MULTI,
    SELECT_VERSION,
    SELECT_SIMULATE
};

static struct option long_options[] = {
    { "help",      no_argument,       0, SELECT_HELP },
    { "quiet",     no_argument,       0, SELECT_QUIET },
    { "verbose",   no_argument,       0, SELECT_VERBOSE },
    { "version",   no_argument,       0, SELECT_VERSION },
    { "simulate",  no_argument,       0, SELECT_SIMULATE },
    { "multi",     no_argument,       0, SELECT_MULTI },
    { 0,           0,                 0, 0 }
};

const string VERSION = "0.9.5";
bool quiet = false;
bool multi = false;
bool simulate = false;
int verbose = 0;

void disclaimer(void)
{
    if (!quiet)
    {
        cout << _("wpl1000reader - Tracks aus einem GPS-Logger vom Typ 'Wintec WPL-1000\n"
            << "                (Easy Showily)' oder 'Navilock NL-456DL Easy Logger'\n"
            << "                auslesen und als GPX-Datei speichern.\n")
            << _("Copyright (c) 2008 Oliver Lau <oliver@ersatzworld.net>") << endl
            << _("Alle Rechte vorbehalten.") << endl
            << endl;
    }
}

void usage(void)
{
    cout << _("Aufruf: wpl1000reader [Optionen] <nvpipe.dat> <ausgabedatei.gpx>") << endl
        << endl
        << _("Optionen:\n"
        << "  -v            Mehr Information ber Verarbeitungsschritte ausgeben\n"
        << "  -m  --multi   Jeden Track in eine separate Datei schreiben\n"
        << "  -q            Smtliche Ausgaben unterdrcken\n"
        << "  --simulate    Nichts schreiben, sondern nur so tun als ob\n"
        << "                (funktioniert nur zusammen mit --multi)\n"
        << "  --version     Versionsinformationen ausgeben")
        << endl << endl;
}

int main(int argc, char* argv[])
{
    for (;;) {
        int option_index = 0;
        int c = getopt_long(argc, argv, "h?vqm", long_options, &option_index);
        if (c == -1)
            break;
        switch (c)
        {
        case 'h':
            /* fall-through */
        case '?':
            /* fall-through */
        case SELECT_HELP:
            usage();
            return 0;
            break;
        case SELECT_VERBOSE:
            /* fall-through */
        case 'v':
            ++verbose;
            break;
        case SELECT_QUIET:
            /* fall-through */
        case 'q':
            quiet = true;
            break;
        case SELECT_MULTI:
            /* fall-through */
        case 'm':
            multi = true;
            break;
        case SELECT_SIMULATE:
            simulate = true;
            break;
        case SELECT_VERSION:
            disclaimer();
            cout << "Version: " << VERSION;
            exit(EXIT_SUCCESS);
            break;
        default:
            usage();
            exit(EXIT_FAILURE);
            break;
        }
    }

    disclaimer();

    if ((argc - optind) < 2) {
        usage();
        return EXIT_FAILURE;
    }

    string wpl1000Filename = argv[optind++];
    string gpxFilename = argv[optind++];

    if (!quiet)
        cout << _("Laden von ") << wpl1000Filename << " .." << endl;
    WPL1000File wpl1000File;
    errno_t rc = wpl1000File.load(wpl1000Filename);
    if (rc != 0) {
        cout << _("FEHLER: Laden von ") << wpl1000Filename << _(" fehlgeschlagen.") << endl;
        return rc;
    }
    if (wpl1000File.tracks().size() > 0)
    {
        if (multi)
        {
            for (TrackList::const_iterator i = wpl1000File.tracks().begin(); i != wpl1000File.tracks().end(); ++i)
            {
                GPXFile trkFile;
                trkFile.addTrack(*i);
                int spos = gpxFilename.find_last_of(PathDelimiter);
                string trkFilename = gpxFilename;
                trkFilename.insert(spos+1, (*i)->startTimestamp().toString("%Y%m%d-%H%M") + "-");
                if (!quiet)
                    cout << _("Speichern von ") << trkFilename << " .." << endl;
                if (!simulate)
                {
                    rc = trkFile.write(trkFilename);
                    if (rc != 0) {
                        cout << _("FEHLER: Speichern von ") << gpxFilename << _(" fehlgeschlagen.") << endl;
                        return rc;
                    }
                }
            }
            if (!simulate)
            {
                GPXFile wptFile;
                wptFile.setWaypoints(wpl1000File.waypoints());
                string wptFilename = gpxFilename;
                int ppos = gpxFilename.find_last_of('.');
                wptFilename.insert(ppos, "-waypoints");
                wptFile.write(wptFilename);
            }
        }
        else // !multi
        {
            GPXFile gpxFile;
            gpxFile.setTracks(wpl1000File.tracks());
            gpxFile.setWaypoints(wpl1000File.waypoints());
            if (!quiet && verbose > 0) {
                cout << "Track(s) @ ";
                for (TrackList::const_iterator i = gpxFile.tracks().begin(); i != gpxFile.tracks().end(); ++i)
                    cout << (*i)->name() << " ";
            }
            if (!quiet)
                cout << _("Speichern unter ") << gpxFilename << " .." << endl;
            rc = gpxFile.write(gpxFilename);
            if (rc != 0) {
                cout << _("FEHLER: Speichern von ") << gpxFilename << _(" fehlgeschlagen.") << endl;
                return rc;
            }
        }
    }
    else
    {
        cout << _("Die Datei enthlt keine Tracks!") << endl;
        return EXIT_FAILURE;
    }
    if (!quiet)
        cout << endl << endl;
    return EXIT_SUCCESS;
}
<commit_msg>wpl1000reader: Code weiter aufgeraeumt.<commit_after>// $Id$
// Copyright (c) 2008 Oliver Lau <oliver@ersatzworld.net>
// Alle Rechte vorbehalten.

#include <iostream>
#include <cstdlib>

#include <getopt.h>

#include "gpslib/WPL1000File.h"
#include "gpslib/GPXFile.h"

// gettext-Dummy
#define _(s) s

using namespace std;
using namespace GPS;

#ifdef WIN32
const char PathDelimiter = '\\';
#else
const char PathDelimiter = '/';
#endif

enum _long_options {
    SELECT_HELP,
    SELECT_DEBUG,
    SELECT_QUIET,
    SELECT_VERBOSE,
    SELECT_MULTI,
    SELECT_VERSION,
    SELECT_SIMULATE
};

static struct option long_options[] = {
    { "help",      no_argument,       0, SELECT_HELP },
    { "quiet",     no_argument,       0, SELECT_QUIET },
    { "verbose",   no_argument,       0, SELECT_VERBOSE },
    { "version",   no_argument,       0, SELECT_VERSION },
    { "simulate",  no_argument,       0, SELECT_SIMULATE },
    { "multi",     no_argument,       0, SELECT_MULTI },
    { 0,           0,                 0, 0 }
};

const string VERSION = "0.9.5";
bool quiet = false;
bool multi = false;
bool simulate = false;
int verbose = 0;

void disclaimer(void)
{
    if (!quiet)
    {
        cout << _("wpl1000reader - Tracks aus einem GPS-Logger vom Typ 'Wintec WPL-1000\n"
            << "                (Easy Showily)' oder 'Navilock NL-456DL Easy Logger'\n"
            << "                auslesen und als GPX-Datei speichern.\n")
            << _("Copyright (c) 2008 Oliver Lau <oliver@ersatzworld.net>") << endl
            << _("Alle Rechte vorbehalten.") << endl
            << endl;
    }
}

void usage(void)
{
    cout << _("Aufruf: wpl1000reader [Optionen] <nvpipe.dat> <ausgabedatei.gpx>") << endl
        << endl
        << _("Optionen:\n"
        << "  -v            Mehr Information ber Verarbeitungsschritte ausgeben\n"
        << "  -m  --multi   Jeden Track in eine separate Datei schreiben\n"
        << "  -q            Smtliche Ausgaben unterdrcken\n"
        << "  --simulate    Nichts schreiben, sondern nur so tun als ob\n"
        << "                (funktioniert nur zusammen mit --multi)\n"
        << "  --version     Versionsinformationen ausgeben")
        << endl << endl;
}

int main(int argc, char* argv[])
{
    for (;;) {
        int option_index = 0;
        int c = getopt_long(argc, argv, "h?vqm", long_options, &option_index);
        if (c == -1)
            break;
        switch (c)
        {
        case 'h':
            /* fall-through */
        case '?':
            /* fall-through */
        case SELECT_HELP:
            usage();
            return 0;
            break;
        case SELECT_VERBOSE:
            /* fall-through */
        case 'v':
            ++verbose;
            break;
        case SELECT_QUIET:
            /* fall-through */
        case 'q':
            quiet = true;
            break;
        case SELECT_MULTI:
            /* fall-through */
        case 'm':
            multi = true;
            break;
        case SELECT_SIMULATE:
            simulate = true;
            break;
        case SELECT_VERSION:
            disclaimer();
            cout << "Version: " << VERSION;
            exit(EXIT_SUCCESS);
            break;
        default:
            usage();
            exit(EXIT_FAILURE);
            break;
        }
    }

    disclaimer();

    if ((argc - optind) < 2) {
        usage();
        return EXIT_FAILURE;
    }

    string wpl1000Filename = argv[optind];
    string gpxFilename = argv[++optind];

    if (!quiet)
        cout << _("Laden von ") << wpl1000Filename << " .." << endl;
    WPL1000File wpl1000File;
    errno_t rc = wpl1000File.load(wpl1000Filename);
    if (rc != 0) {
        cout << _("FEHLER: Laden von ") << wpl1000Filename << _(" fehlgeschlagen.") << endl;
        return rc;
    }
    if (wpl1000File.tracks().size() > 0)
    {
        if (multi)
        {
            for (TrackList::const_iterator i = wpl1000File.tracks().begin(); i != wpl1000File.tracks().end(); ++i)
            {
                GPXFile trkFile;
                trkFile.addTrack(*i);
                int spos = gpxFilename.find_last_of(PathDelimiter);
                string trkFilename = gpxFilename;
                trkFilename.insert(spos+1, (*i)->startTimestamp().toString("%Y%m%d-%H%M") + "-");
                if (!quiet)
                    cout << _("Speichern von ") << trkFilename << " .." << endl;
                if (!simulate)
                {
                    rc = trkFile.write(trkFilename);
                    if (rc != 0) {
                        cout << _("FEHLER: Speichern von ") << gpxFilename << _(" fehlgeschlagen.") << endl;
                        return rc;
                    }
                }
            }
            if (!simulate)
            {
                GPXFile wptFile;
                wptFile.setWaypoints(wpl1000File.waypoints());
                string wptFilename = gpxFilename;
                int ppos = gpxFilename.find_last_of('.');
                wptFilename.insert(ppos, "-waypoints");
                wptFile.write(wptFilename);
            }
        }
        else // !multi
        {
            GPXFile gpxFile;
            gpxFile.setTracks(wpl1000File.tracks());
            gpxFile.setWaypoints(wpl1000File.waypoints());
            if (!quiet && verbose > 0) {
                cout << "Track(s) @ ";
                for (TrackList::const_iterator i = gpxFile.tracks().begin(); i != gpxFile.tracks().end(); ++i)
                    cout << (*i)->name() << " ";
            }
            if (!quiet)
                cout << _("Speichern unter ") << gpxFilename << " .." << endl;
            rc = gpxFile.write(gpxFilename);
            if (rc != 0) {
                cout << _("FEHLER: Speichern von ") << gpxFilename << _(" fehlgeschlagen.") << endl;
                return rc;
            }
        }
    }
    else
    {
        cout << _("Die Datei enthlt keine Tracks!") << endl;
        return EXIT_FAILURE;
    }
    if (!quiet)
        cout << endl << endl;
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. 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.
 *****************************************************************************/

#include "modules/prediction/common/validation_checker.h"

#include <algorithm>
#include <cmath>

#include "modules/common/math/math_utils.h"
#include "modules/prediction/common/prediction_gflags.h"

namespace apollo {
namespace prediction {

using apollo::common::PathPoint;
using apollo::common::TrajectoryPoint;

double ValidationChecker::ProbabilityByCentripetalAcceleration(
    const LaneSequence& lane_sequence, const double speed) {
  double centripetal_acc_cost_sum = 0.0;
  double centripetal_acc_cost_sqr_sum = 0.0;
  for (int i = 0; i < lane_sequence.path_point_size(); ++i) {
    const PathPoint& path_point = lane_sequence.path_point(i);
    double centripetal_acc = speed * speed * path_point.kappa();
    double centripetal_acc_cost =
        centripetal_acc / FLAGS_centripedal_acc_threshold;
    centripetal_acc_cost_sum += centripetal_acc_cost;
    centripetal_acc_cost_sqr_sum += centripetal_acc_cost * centripetal_acc_cost;
  }
  double mean_cost = centripetal_acc_cost_sqr_sum /
                     (centripetal_acc_cost_sum + FLAGS_double_precision);
  return std::exp(-FLAGS_centripetal_acc_coeff * mean_cost);
}

bool ValidationChecker::ValidCentripetalAcceleration(
    const std::vector<TrajectoryPoint>& trajectory_points) {
  std::size_t num_point = trajectory_points.size();
  if (num_point < 2) {
    return true;
  }
  double max_centripedal_acc = 0.0;
  for (std::size_t i = 0; i + 1 < num_point; ++i) {
    const auto& first_point = trajectory_points[i];
    const auto& second_point = trajectory_points[i + 1];
    double theta_diff = std::abs(common::math::NormalizeAngle(
        second_point.path_point().theta() -
        first_point.path_point().theta()));
    double time_diff =
        std::abs(second_point.relative_time() - first_point.relative_time());
    if (time_diff < FLAGS_double_precision) {
      continue;
    }
    double v = (first_point.v() + second_point.v()) / 2.0;
    double centripedal_acc = v * theta_diff / time_diff;
    max_centripedal_acc = std::max(max_centripedal_acc, centripedal_acc);
  }
  return max_centripedal_acc < FLAGS_centripedal_acc_threshold;
}

bool ValidationChecker::ValidTrajectoryPoint(
    const TrajectoryPoint& trajectory_point) {
  return trajectory_point.has_path_point() &&
         (!std::isnan(trajectory_point.path_point().x())) &&
         (!std::isnan(trajectory_point.path_point().y())) &&
         (!std::isnan(trajectory_point.path_point().theta())) &&
         (!std::isnan(trajectory_point.v())) &&
         (!std::isnan(trajectory_point.a())) &&
         (!std::isnan(trajectory_point.relative_time()));
}

}  // namespace prediction
}  // namespace apollo
<commit_msg>prediction: bug fix in ValidationChecker; minor code refactor<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. 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.
 *****************************************************************************/

#include "modules/prediction/common/validation_checker.h"

#include <algorithm>
#include <cmath>

#include "modules/common/math/math_utils.h"
#include "modules/prediction/common/prediction_gflags.h"

namespace apollo {
namespace prediction {

using apollo::common::PathPoint;
using apollo::common::TrajectoryPoint;

double ValidationChecker::ProbabilityByCentripetalAcceleration(
    const LaneSequence& lane_sequence, const double speed) {
  double centripetal_acc_cost_sum = 0.0;
  double centripetal_acc_cost_sqr_sum = 0.0;
  for (int i = 0; i < lane_sequence.path_point_size(); ++i) {
    const auto& path_point = lane_sequence.path_point(i);
    double centripetal_acc = speed * speed * std::fabs(path_point.kappa());
    double centripetal_acc_cost =
        centripetal_acc / FLAGS_centripedal_acc_threshold;
    centripetal_acc_cost_sum += centripetal_acc_cost;
    centripetal_acc_cost_sqr_sum += centripetal_acc_cost * centripetal_acc_cost;
  }
  double mean_cost = centripetal_acc_cost_sqr_sum /
                     (centripetal_acc_cost_sum + FLAGS_double_precision);
  return std::exp(-FLAGS_centripetal_acc_coeff * mean_cost);
}

bool ValidationChecker::ValidCentripetalAcceleration(
    const std::vector<TrajectoryPoint>& trajectory_points) {
  double max_centripetal_acc = 0.0;
  for (auto i = 0; i + 1 < trajectory_points.size(); ++i) {
    const auto& first_point = trajectory_points[i];
    const auto& second_point = trajectory_points[i + 1];
    double theta_diff = std::abs(common::math::NormalizeAngle(
        second_point.path_point().theta() -
        first_point.path_point().theta()));
    double time_diff =
        std::abs(second_point.relative_time() - first_point.relative_time());
    if (time_diff < FLAGS_double_precision) {
      continue;
    }
    double v = (first_point.v() + second_point.v()) * 0.5;
    double centripedal_acc = v * theta_diff / time_diff;
    max_centripetal_acc = std::max(max_centripetal_acc, centripedal_acc);
  }
  return max_centripetal_acc < FLAGS_centripedal_acc_threshold;
}

bool ValidationChecker::ValidTrajectoryPoint(
    const TrajectoryPoint& trajectory_point) {
  return trajectory_point.has_path_point() &&
         (!std::isnan(trajectory_point.path_point().x())) &&
         (!std::isnan(trajectory_point.path_point().y())) &&
         (!std::isnan(trajectory_point.path_point().theta())) &&
         (!std::isnan(trajectory_point.v())) &&
         (!std::isnan(trajectory_point.a())) &&
         (!std::isnan(trajectory_point.relative_time()));
}

}  // namespace prediction
}  // namespace apollo
<|endoftext|>


<commit_before>#include "Base.h"
#include "ImageControl.h"

namespace gameplay
{

ImageControl::ImageControl() :
    _srcRegion(Rectangle::empty()), _dstRegion(Rectangle::empty()), _batch(NULL),
    _tw(0.0f), _th(0.0f), _uvs(Theme::UVs::full())
{
}

ImageControl::~ImageControl()
{
    SAFE_DELETE(_batch);
}

ImageControl* ImageControl::create(const char* id, Theme::Style* style)
{
    GP_ASSERT(style);

    ImageControl* imageControl = new ImageControl();
    if (id)
        imageControl->_id = id;
    imageControl->setStyle(style);

    imageControl->_consumeInputEvents = false;
    imageControl->_focusIndex = -2;

    return imageControl;
}

ImageControl* ImageControl::create(Theme::Style* style, Properties* properties)
{
    ImageControl* imageControl = new ImageControl();
    imageControl->initialize(style, properties);

    imageControl->_consumeInputEvents = false;
    imageControl->_focusIndex = -2;

    return imageControl;
}

void ImageControl::initialize(Theme::Style* style, Properties* properties)
{
    GP_ASSERT(properties);

    Control::initialize(style, properties);

    const char* path = properties->getString("path");
    if (path)
    {
        setImage(path);
    }

    if (properties->exists("srcRegion"))
    {
        Vector4 region;
        properties->getVector4("srcRegion", &region);
        setRegionSrc(region.x, region.y, region.z, region.w);
    }

    if (properties->exists("dstRegion"))
    {
        Vector4 region;
        properties->getVector4("dstRegion", &region);
        setRegionDst(region.x, region.y, region.z, region.w);
    }
}

void ImageControl::setImage(const char* path)
{
    SAFE_DELETE(_batch);
    Texture* texture = Texture::create(path);
    _batch = SpriteBatch::create(texture);
    _tw = 1.0f / texture->getWidth();
    _th = 1.0f / texture->getHeight();
    texture->release();
}

void ImageControl::setRegionSrc(float x, float y, float width, float height)
{
    _srcRegion.set(x, y, width, height);

    _uvs.u1 = x * _tw;
    _uvs.u2 = (x + width) * _tw;
    _uvs.v1 = 1.0f - (y * _th);
    _uvs.v2 = 1.0f - ((y + height) * _tw);
}

void ImageControl::setRegionSrc(const Rectangle& region)
{
    setRegionSrc(region.x, region.y, region.width, region.height);
}

const Rectangle& ImageControl::getRegionSrc() const
{
    return _srcRegion;
}

void ImageControl::setRegionDst(float x, float y, float width, float height)
{
    _dstRegion.set(x, y, width, height);
}

void ImageControl::setRegionDst(const Rectangle& region)
{
    setRegionDst(region.x, region.y, region.width, region.height);
}

const Rectangle& ImageControl::getRegionDst() const
{
    return _dstRegion;
}

void ImageControl::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
{
    spriteBatch->finish();

    // An ImageControl is not part of the texture atlas but should use the same projection matrix.
    _batch->setProjectionMatrix(spriteBatch->getProjectionMatrix());

    _batch->start();
    if (_dstRegion.isEmpty())
    {
        _batch->draw(_viewportBounds.x, _viewportBounds.y, _viewportBounds.width, _viewportBounds.height,
            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, Vector4::one(), _viewportClipBounds);
    }
    else
    {
        _batch->draw(_viewportBounds.x + _dstRegion.x, _viewportBounds.y + _dstRegion.y,
            _dstRegion.width, _dstRegion.height,
            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, Vector4::one(), _viewportClipBounds);
    }
    _batch->finish();

    spriteBatch->start();
}

}<commit_msg>Fixes a typo in ImageControl's UV calculations. Allows opacity to affect ImageControls.<commit_after>#include "Base.h"
#include "ImageControl.h"

namespace gameplay
{

ImageControl::ImageControl() :
    _srcRegion(Rectangle::empty()), _dstRegion(Rectangle::empty()), _batch(NULL),
    _tw(0.0f), _th(0.0f), _uvs(Theme::UVs::full())
{
}

ImageControl::~ImageControl()
{
    SAFE_DELETE(_batch);
}

ImageControl* ImageControl::create(const char* id, Theme::Style* style)
{
    GP_ASSERT(style);

    ImageControl* imageControl = new ImageControl();
    if (id)
        imageControl->_id = id;
    imageControl->setStyle(style);

    imageControl->_consumeInputEvents = false;
    imageControl->_focusIndex = -2;

    return imageControl;
}

ImageControl* ImageControl::create(Theme::Style* style, Properties* properties)
{
    ImageControl* imageControl = new ImageControl();
    imageControl->initialize(style, properties);

    imageControl->_consumeInputEvents = false;
    imageControl->_focusIndex = -2;

    return imageControl;
}

void ImageControl::initialize(Theme::Style* style, Properties* properties)
{
    GP_ASSERT(properties);

    Control::initialize(style, properties);

    const char* path = properties->getString("path");
    if (path)
    {
        setImage(path);
    }

    if (properties->exists("srcRegion"))
    {
        Vector4 region;
        properties->getVector4("srcRegion", &region);
        setRegionSrc(region.x, region.y, region.z, region.w);
    }

    if (properties->exists("dstRegion"))
    {
        Vector4 region;
        properties->getVector4("dstRegion", &region);
        setRegionDst(region.x, region.y, region.z, region.w);
    }
}

void ImageControl::setImage(const char* path)
{
    SAFE_DELETE(_batch);
    Texture* texture = Texture::create(path);
    _batch = SpriteBatch::create(texture);
    _tw = 1.0f / texture->getWidth();
    _th = 1.0f / texture->getHeight();
    texture->release();
}

void ImageControl::setRegionSrc(float x, float y, float width, float height)
{
    _srcRegion.set(x, y, width, height);

    _uvs.u1 = x * _tw;
    _uvs.u2 = (x + width) * _tw;
    _uvs.v1 = 1.0f - (y * _th);
    _uvs.v2 = 1.0f - ((y + height) * _th);
}

void ImageControl::setRegionSrc(const Rectangle& region)
{
    setRegionSrc(region.x, region.y, region.width, region.height);
}

const Rectangle& ImageControl::getRegionSrc() const
{
    return _srcRegion;
}

void ImageControl::setRegionDst(float x, float y, float width, float height)
{
    _dstRegion.set(x, y, width, height);
}

void ImageControl::setRegionDst(const Rectangle& region)
{
    setRegionDst(region.x, region.y, region.width, region.height);
}

const Rectangle& ImageControl::getRegionDst() const
{
    return _dstRegion;
}

void ImageControl::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
{
    spriteBatch->finish();

    // An ImageControl is not part of the texture atlas but should use the same projection matrix.
    _batch->setProjectionMatrix(spriteBatch->getProjectionMatrix());

    Vector4 color = Vector4::one();
    color.w *= _opacity;

    _batch->start();
    if (_dstRegion.isEmpty())
    {
        _batch->draw(_viewportBounds.x, _viewportBounds.y, _viewportBounds.width, _viewportBounds.height,
            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, color, _viewportClipBounds);
    }
    else
    {
        _batch->draw(_viewportBounds.x + _dstRegion.x, _viewportBounds.y + _dstRegion.y,
            _dstRegion.width, _dstRegion.height,
            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, color, _viewportClipBounds);
    }
    _batch->finish();

    spriteBatch->start();
}

}<|endoftext|>