<commit_before>//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "../Precompiled.h"

#include "../Core/ProcessUtils.h"

#include <cstdio>
#include <fcntl.h>

#ifdef __APPLE__
#include "TargetConditionals.h"
#endif

#if defined(IOS)
#include "../Math/MathDefs.h"
#include <mach/mach_host.h>
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)
#include <LibCpuId/src/libcpuid.h>
#endif

#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#endif

#if defined(_MSC_VER)
#include <float.h>
#elif !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(EMSCRIPTEN)
// From http://stereopsis.com/FPU.html

#define FPU_CW_PREC_MASK        0x0300
#define FPU_CW_PREC_SINGLE      0x0000
#define FPU_CW_PREC_DOUBLE      0x0200
#define FPU_CW_PREC_EXTENDED    0x0300
#define FPU_CW_ROUND_MASK       0x0c00
#define FPU_CW_ROUND_NEAR       0x0000
#define FPU_CW_ROUND_DOWN       0x0400
#define FPU_CW_ROUND_UP         0x0800
#define FPU_CW_ROUND_CHOP       0x0c00

inline unsigned GetFPUState()
{
    unsigned control = 0;
    __asm__ __volatile__ ("fnstcw %0" : "=m" (control));
    return control;
}

inline void SetFPUState(unsigned control)
{
    __asm__ __volatile__ ("fldcw %0" : : "m" (control));
}

#endif

#include "../DebugNew.h"

namespace Atomic
{

#ifdef WIN32
static bool consoleOpened = false;
#endif
static String currentLine;
static Vector<String> arguments;

#if defined(IOS)
static void GetCPUData(host_basic_info_data_t* data)
{
    mach_msg_type_number_t infoCount;
    infoCount = HOST_BASIC_INFO_COUNT;
    host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)data, &infoCount);
}
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)

static void GetCPUData(struct cpu_id_t* data)
{
    if (cpu_identify(0, data) < 0)
    {
        data->num_logical_cpus = 1;
        data->num_cores = 1;
    }
}

#endif

void InitFPU()
{
#if !defined(ATOMIC_LUAJIT) && !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(__x86_64__) && !defined(_M_AMD64) && !defined(EMSCRIPTEN)
    // Make sure FPU is in round-to-nearest, single precision mode
    // This ensures Direct3D and OpenGL behave similarly, and all threads behave similarly
#ifdef _MSC_VER
    _controlfp(_RC_NEAR | _PC_24, _MCW_RC | _MCW_PC);
#else
    unsigned control = GetFPUState();
    control &= ~(FPU_CW_PREC_MASK | FPU_CW_ROUND_MASK);
    control |= (FPU_CW_PREC_SINGLE | FPU_CW_ROUND_NEAR);
    SetFPUState(control);
#endif
#endif
}

void ErrorDialog(const String& title, const String& message)
{
#ifdef WIN32
    MessageBoxW(0, WString(message).CString(), WString(title).CString(), 0);
#else
    PrintLine(message, true);
#endif
}

void ErrorExit(const String& message, int exitCode)
{
    if (!message.Empty())
        PrintLine(message, true);

    exit(exitCode);
}

void OpenConsoleWindow()
{
#ifdef WIN32
    if (consoleOpened)
        return;

    AllocConsole();

    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    int hCrt = _open_osfhandle((size_t)hOut, _O_TEXT);
    FILE* outFile = _fdopen(hCrt, "w");
    setvbuf(outFile, NULL, _IONBF, 1);
    *stdout = *outFile;

    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    hCrt = _open_osfhandle((size_t)hIn, _O_TEXT);
    FILE* inFile = _fdopen(hCrt, "r");
    setvbuf(inFile, NULL, _IONBF, 128);
    *stdin = *inFile;

    consoleOpened = true;
#endif
}

void PrintUnicode(const String& str, bool error)
{
#if !defined(ANDROID) && !defined(IOS)
#ifdef WIN32
    // If the output stream has been redirected, use fprintf instead of WriteConsoleW,
    // though it means that proper Unicode output will not work
    FILE* out = error ? stderr : stdout;
    if (!_isatty(_fileno(out)))
        fprintf(out, "%s", str.CString());
    else
    {
        HANDLE stream = GetStdHandle(error ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
        if (stream == INVALID_HANDLE_VALUE)
            return;
        WString strW(str);
        DWORD charsWritten;
        WriteConsoleW(stream, strW.CString(), strW.Length(), &charsWritten, 0);
    }
#else
    fprintf(error ? stderr : stdout, "%s", str.CString());
#endif
#endif
}

void PrintUnicodeLine(const String& str, bool error)
{
    PrintUnicode(str + '\n', error);
}

void PrintLine(const String& str, bool error)
{
#if !defined(ANDROID) && !defined(IOS)
    fprintf(error ? stderr : stdout, "%s\n", str.CString());
#endif
}

const Vector<String>& ParseArguments(const String& cmdLine, bool skipFirstArgument)
{
    arguments.Clear();

    unsigned cmdStart = 0, cmdEnd = 0;
    bool inCmd = false;
    bool inQuote = false;

    for (unsigned i = 0; i < cmdLine.Length(); ++i)
    {
        if (cmdLine[i] == '\"')
            inQuote = !inQuote;
        if (cmdLine[i] == ' ' && !inQuote)
        {
            if (inCmd)
            {
                inCmd = false;
                cmdEnd = i;
                // Do not store the first argument (executable name)
                if (!skipFirstArgument)
                    arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
                skipFirstArgument = false;
            }
        }
        else
        {
            if (!inCmd)
            {
                inCmd = true;
                cmdStart = i;
            }
        }
    }
    if (inCmd)
    {
        cmdEnd = cmdLine.Length();
        if (!skipFirstArgument)
            arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
    }

    // Strip double quotes from the arguments
    for (unsigned i = 0; i < arguments.Size(); ++i)
        arguments[i].Replace("\"", "");

    return arguments;
}

const Vector<String>& ParseArguments(const char* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const WString& cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const wchar_t* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(int argc, char** argv)
{
    String cmdLine;

    for (int i = 0; i < argc; ++i)
        cmdLine.AppendWithFormat("\"%s\" ", (const char*)argv[i]);

    return ParseArguments(cmdLine);
}

const Vector<String>& GetArguments()
{
    return arguments;
}

String GetConsoleInput()
{
    String ret;
#ifdef ATOMIC_TESTING
    // When we are running automated tests, reading the console may block. Just return empty in that case
    return ret;
#endif

#ifdef WIN32
    HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
    if (input == INVALID_HANDLE_VALUE || output == INVALID_HANDLE_VALUE)
        return ret;

    // Use char-based input
    SetConsoleMode(input, ENABLE_PROCESSED_INPUT);

    INPUT_RECORD record;
    DWORD events = 0;
    DWORD readEvents = 0;

    if (!GetNumberOfConsoleInputEvents(input, &events))
        return ret;

    while (events--)
    {
        ReadConsoleInputW(input, &record, 1, &readEvents);
        if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
        {
            unsigned c = record.Event.KeyEvent.uChar.UnicodeChar;
            if (c)
            {
                if (c == '\b')
                {
                    PrintUnicode("\b \b");
                    int length = currentLine.LengthUTF8();
                    if (length)
                        currentLine = currentLine.SubstringUTF8(0, length - 1);
                }
                else if (c == '\r')
                {
                    PrintUnicode("\n");
                    ret = currentLine;
                    currentLine.Clear();
                    return ret;
                }
                else
                {
                    // We have disabled echo, so echo manually
                    wchar_t out = c;
                    DWORD charsWritten;
                    WriteConsoleW(output, &out, 1, &charsWritten, 0);
                    currentLine.AppendUTF8(c);
                }
            }
        }
    }
#elif !defined(ANDROID) && !defined(IOS)
    int flags = fcntl(STDIN_FILENO, F_GETFL);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
    for (;;)
    {
        int ch = fgetc(stdin);
        if (ch >= 0 && ch != '\n')
            ret += (char)ch;
        else
            break;
    }
#endif

    return ret;
}

String GetPlatform()
{
#if defined(ANDROID)
    return "Android";
#elif defined(IOS)
    return "iOS";
#elif defined(WIN32)
    return "Windows";
#elif defined(__APPLE__)
    return "Mac OS X";
#elif defined(RPI)
    return "Raspberry Pi";
#elif defined(EMSCRIPTEN)
    return "HTML5";
#elif defined(__linux__)
    return "Linux";
#else
    return String::EMPTY;
#endif
}

#if defined(ANDROID) || defined(RPI)
static unsigned GetArmCPUCount()
{
    FILE* fp;
    int res, i = -1, j = -1;

    fp = fopen("/sys/devices/system/cpu/present", "r");
    // If failed, return at least 1
    if (fp == 0)
        return 1;

    res = fscanf(fp, "%d-%d", &i, &j);
    fclose(fp);

    if (res == 1 && i == 0)
        return 1;
    else if (res == 2 && i == 0)
        return j + 1;

    // If failed, return at least 1
    return 1;
}
#endif

unsigned GetNumPhysicalCPUs()
{
#if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
#if defined(TARGET_IPHONE_SIMULATOR)
    // Hardcoded to dual-core on simulator mode even if the host has more
    return Min(2, data.physical_cpu);
#else
    return data.physical_cpu;
#endif
#elif defined(ANDROID) || defined(RPI)
    return GetArmCPUCount();
#elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return (unsigned)data.num_cores;
#else
    /// \todo Implement properly
    return 1;
#endif
}

unsigned GetNumLogicalCPUs()
{
#if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
#if defined(TARGET_IPHONE_SIMULATOR)
    return Min(2, data.logical_cpu);
#else
    return data.logical_cpu;
#endif
#elif defined(ANDROID) || defined (RPI)
    return GetArmCPUCount();
#elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return (unsigned)data.num_logical_cpus;
#else
    /// \todo Implement properly
    return 1;
#endif
}

}
<commit_msg>--log-std now logs to debugging Visual Studio's output pane while editor is running<commit_after>//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "../Precompiled.h"

#include "../Core/ProcessUtils.h"

#include <cstdio>
#include <fcntl.h>

#ifdef __APPLE__
#include "TargetConditionals.h"
#endif

#if defined(IOS)
#include "../Math/MathDefs.h"
#include <mach/mach_host.h>
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)
#include <LibCpuId/src/libcpuid.h>
#endif

#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#endif

#if defined(_MSC_VER)
#include <float.h>
#elif !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(EMSCRIPTEN)
// From http://stereopsis.com/FPU.html

#define FPU_CW_PREC_MASK        0x0300
#define FPU_CW_PREC_SINGLE      0x0000
#define FPU_CW_PREC_DOUBLE      0x0200
#define FPU_CW_PREC_EXTENDED    0x0300
#define FPU_CW_ROUND_MASK       0x0c00
#define FPU_CW_ROUND_NEAR       0x0000
#define FPU_CW_ROUND_DOWN       0x0400
#define FPU_CW_ROUND_UP         0x0800
#define FPU_CW_ROUND_CHOP       0x0c00

inline unsigned GetFPUState()
{
    unsigned control = 0;
    __asm__ __volatile__ ("fnstcw %0" : "=m" (control));
    return control;
}

inline void SetFPUState(unsigned control)
{
    __asm__ __volatile__ ("fldcw %0" : : "m" (control));
}

#endif

#include "../DebugNew.h"

namespace Atomic
{

#ifdef WIN32
static bool consoleOpened = false;
#endif
static String currentLine;
static Vector<String> arguments;

#if defined(IOS)
static void GetCPUData(host_basic_info_data_t* data)
{
    mach_msg_type_number_t infoCount;
    infoCount = HOST_BASIC_INFO_COUNT;
    host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)data, &infoCount);
}
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)

static void GetCPUData(struct cpu_id_t* data)
{
    if (cpu_identify(0, data) < 0)
    {
        data->num_logical_cpus = 1;
        data->num_cores = 1;
    }
}

#endif

void InitFPU()
{
#if !defined(ATOMIC_LUAJIT) && !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(__x86_64__) && !defined(_M_AMD64) && !defined(EMSCRIPTEN)
    // Make sure FPU is in round-to-nearest, single precision mode
    // This ensures Direct3D and OpenGL behave similarly, and all threads behave similarly
#ifdef _MSC_VER
    _controlfp(_RC_NEAR | _PC_24, _MCW_RC | _MCW_PC);
#else
    unsigned control = GetFPUState();
    control &= ~(FPU_CW_PREC_MASK | FPU_CW_ROUND_MASK);
    control |= (FPU_CW_PREC_SINGLE | FPU_CW_ROUND_NEAR);
    SetFPUState(control);
#endif
#endif
}

void ErrorDialog(const String& title, const String& message)
{
#ifdef WIN32
    MessageBoxW(0, WString(message).CString(), WString(title).CString(), 0);
#else
    PrintLine(message, true);
#endif
}

void ErrorExit(const String& message, int exitCode)
{
    if (!message.Empty())
        PrintLine(message, true);

    exit(exitCode);
}

void OpenConsoleWindow()
{
#ifdef WIN32
    if (consoleOpened)
        return;

    AllocConsole();

    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    int hCrt = _open_osfhandle((size_t)hOut, _O_TEXT);
    FILE* outFile = _fdopen(hCrt, "w");
    setvbuf(outFile, NULL, _IONBF, 1);
    *stdout = *outFile;

    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    hCrt = _open_osfhandle((size_t)hIn, _O_TEXT);
    FILE* inFile = _fdopen(hCrt, "r");
    setvbuf(inFile, NULL, _IONBF, 128);
    *stdin = *inFile;

    consoleOpened = true;
#endif
}

void PrintUnicode(const String& str, bool error)
{
#if !defined(ANDROID) && !defined(IOS)
#ifdef WIN32
    // If the output stream has been redirected, use fprintf instead of WriteConsoleW,
    // though it means that proper Unicode output will not work
    FILE* out = error ? stderr : stdout;
    if (!_isatty(_fileno(out)))
        fprintf(out, "%s", str.CString());
    else
    {
        HANDLE stream = GetStdHandle(error ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
        if (stream == INVALID_HANDLE_VALUE)
            return;
        WString strW(str);
        DWORD charsWritten;
        WriteConsoleW(stream, strW.CString(), strW.Length(), &charsWritten, 0);
        if (IsDebuggerPresent())
        {
            OutputDebugString(str.CString());
        }
    }
#else
    fprintf(error ? stderr : stdout, "%s", str.CString());
#endif
#endif
}

void PrintUnicodeLine(const String& str, bool error)
{
    PrintUnicode(str + '\n', error);
}

void PrintLine(const String& str, bool error)
{
#if !defined(ANDROID) && !defined(IOS)
    fprintf(error ? stderr : stdout, "%s\n", str.CString());
#endif
}

const Vector<String>& ParseArguments(const String& cmdLine, bool skipFirstArgument)
{
    arguments.Clear();

    unsigned cmdStart = 0, cmdEnd = 0;
    bool inCmd = false;
    bool inQuote = false;

    for (unsigned i = 0; i < cmdLine.Length(); ++i)
    {
        if (cmdLine[i] == '\"')
            inQuote = !inQuote;
        if (cmdLine[i] == ' ' && !inQuote)
        {
            if (inCmd)
            {
                inCmd = false;
                cmdEnd = i;
                // Do not store the first argument (executable name)
                if (!skipFirstArgument)
                    arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
                skipFirstArgument = false;
            }
        }
        else
        {
            if (!inCmd)
            {
                inCmd = true;
                cmdStart = i;
            }
        }
    }
    if (inCmd)
    {
        cmdEnd = cmdLine.Length();
        if (!skipFirstArgument)
            arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
    }

    // Strip double quotes from the arguments
    for (unsigned i = 0; i < arguments.Size(); ++i)
        arguments[i].Replace("\"", "");

    return arguments;
}

const Vector<String>& ParseArguments(const char* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const WString& cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const wchar_t* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(int argc, char** argv)
{
    String cmdLine;

    for (int i = 0; i < argc; ++i)
        cmdLine.AppendWithFormat("\"%s\" ", (const char*)argv[i]);

    return ParseArguments(cmdLine);
}

const Vector<String>& GetArguments()
{
    return arguments;
}

String GetConsoleInput()
{
    String ret;
#ifdef ATOMIC_TESTING
    // When we are running automated tests, reading the console may block. Just return empty in that case
    return ret;
#endif

#ifdef WIN32
    HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
    if (input == INVALID_HANDLE_VALUE || output == INVALID_HANDLE_VALUE)
        return ret;

    // Use char-based input
    SetConsoleMode(input, ENABLE_PROCESSED_INPUT);

    INPUT_RECORD record;
    DWORD events = 0;
    DWORD readEvents = 0;

    if (!GetNumberOfConsoleInputEvents(input, &events))
        return ret;

    while (events--)
    {
        ReadConsoleInputW(input, &record, 1, &readEvents);
        if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
        {
            unsigned c = record.Event.KeyEvent.uChar.UnicodeChar;
            if (c)
            {
                if (c == '\b')
                {
                    PrintUnicode("\b \b");
                    int length = currentLine.LengthUTF8();
                    if (length)
                        currentLine = currentLine.SubstringUTF8(0, length - 1);
                }
                else if (c == '\r')
                {
                    PrintUnicode("\n");
                    ret = currentLine;
                    currentLine.Clear();
                    return ret;
                }
                else
                {
                    // We have disabled echo, so echo manually
                    wchar_t out = c;
                    DWORD charsWritten;
                    WriteConsoleW(output, &out, 1, &charsWritten, 0);
                    currentLine.AppendUTF8(c);
                }
            }
        }
    }
#elif !defined(ANDROID) && !defined(IOS)
    int flags = fcntl(STDIN_FILENO, F_GETFL);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
    for (;;)
    {
        int ch = fgetc(stdin);
        if (ch >= 0 && ch != '\n')
            ret += (char)ch;
        else
            break;
    }
#endif

    return ret;
}

String GetPlatform()
{
#if defined(ANDROID)
    return "Android";
#elif defined(IOS)
    return "iOS";
#elif defined(WIN32)
    return "Windows";
#elif defined(__APPLE__)
    return "Mac OS X";
#elif defined(RPI)
    return "Raspberry Pi";
#elif defined(EMSCRIPTEN)
    return "HTML5";
#elif defined(__linux__)
    return "Linux";
#else
    return String::EMPTY;
#endif
}

#if defined(ANDROID) || defined(RPI)
static unsigned GetArmCPUCount()
{
    FILE* fp;
    int res, i = -1, j = -1;

    fp = fopen("/sys/devices/system/cpu/present", "r");
    // If failed, return at least 1
    if (fp == 0)
        return 1;

    res = fscanf(fp, "%d-%d", &i, &j);
    fclose(fp);

    if (res == 1 && i == 0)
        return 1;
    else if (res == 2 && i == 0)
        return j + 1;

    // If failed, return at least 1
    return 1;
}
#endif

unsigned GetNumPhysicalCPUs()
{
#if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
#if defined(TARGET_IPHONE_SIMULATOR)
    // Hardcoded to dual-core on simulator mode even if the host has more
    return Min(2, data.physical_cpu);
#else
    return data.physical_cpu;
#endif
#elif defined(ANDROID) || defined(RPI)
    return GetArmCPUCount();
#elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return (unsigned)data.num_cores;
#else
    /// \todo Implement properly
    return 1;
#endif
}

unsigned GetNumLogicalCPUs()
{
#if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
#if defined(TARGET_IPHONE_SIMULATOR)
    return Min(2, data.logical_cpu);
#else
    return data.logical_cpu;
#endif
#elif defined(ANDROID) || defined (RPI)
    return GetArmCPUCount();
#elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return (unsigned)data.num_logical_cpus;
#else
    /// \todo Implement properly
    return 1;
#endif
}

}
<|endoftext|>


<commit_before>#include "QMLPlugin.hpp"

#include <cutehmi/gui/CuteApplication.hpp>
#include <cutehmi/gui/ColorSet.hpp>
#include <cutehmi/gui/Palette.hpp>
#include <cutehmi/gui/Fonts.hpp>
#include <cutehmi/gui/Units.hpp>
#include <cutehmi/gui/Theme.hpp>

#include <QtQml>

//<Doxygen-3.workaround target="Doxygen" cause="missing">
#ifdef DOXYGEN_WORKAROUND

namespace CuteHMI {
namespace GUI {

/**
 * Exposes cutehmi::gui::CuteApplication to QML.
 */
class CuteApplication: public cutehmi::gui::CuteApplication {};

/**
 * Exposes cutehmi::gui::ColorSet to QML.
 */
class ColorSet: public cutehmi::gui::ColorSet {};

/**
 * Exposes cutehmi::gui::Palette to QML.
 */
class Palette: public cutehmi::gui::Palette  {};

/**
 * Exposes cutehmi::gui::Fonts to QML.
 */
class Fonts: public cutehmi::gui::Fonts {};

/**
 * Exposes cutehmi::gui::Units to QML.
 */
class Units: public cutehmi::gui::Units {};

/**
 * Exposes cutehmi::gui::Theme to QML.
 */
class Theme: public cutehmi::gui::Theme {};

}
}

#endif
//</Doxygen-3.workaround>

namespace cutehmi {
namespace gui {
namespace internal {

/**
 * Register QML types.
 * @param uri URI.
 */
void QMLPlugin::registerTypes(const char * uri)
{
	Q_ASSERT(uri == QLatin1String("CuteHMI.GUI"));

	// @uri CuteHMI.GUI
	qmlRegisterType<cutehmi::gui::ColorSet>(uri, CUTEHMI_GUI_MAJOR, 0, "ColorSet");
	qmlRegisterType<cutehmi::gui::Palette>(uri, CUTEHMI_GUI_MAJOR, 0, "Palette");
	qmlRegisterType<cutehmi::gui::Fonts>(uri, CUTEHMI_GUI_MAJOR, 0, "Fonts");
	qmlRegisterType<cutehmi::gui::Units>(uri, CUTEHMI_GUI_MAJOR, 0, "Units");

	qmlRegisterSingletonType<cutehmi::gui::Theme>(uri, CUTEHMI_GUI_MAJOR, 0, "Theme", ThemeProvider);

	if (qEnvironmentVariableIsSet("QML_PUPPET_MODE")) {
		//<CuteHMI.LockScreen-1.workaround target="Qt" cause="design">
		// @uri CuteHMI.GUI
		qmlRegisterSingletonType<cutehmi::gui::CuteApplication>(uri, CUTEHMI_GUI_MAJOR, 0, "CuteApplication", CuteApplicationProvider);
		//</CuteHMI.LockScreen-1.workaround>
	}
}

QObject * QMLPlugin::CuteApplicationProvider(QQmlEngine * engine, QJSEngine * scriptEngine)
{
	Q_UNUSED(scriptEngine)

	QObject * app = cutehmi::gui::CuteApplication::instance();
	engine->setObjectOwnership(app, QQmlEngine::CppOwnership);
	return app;
}

QObject * QMLPlugin::ThemeProvider(QQmlEngine * engine, QJSEngine * scriptEngine)
{
	Q_UNUSED(scriptEngine)

	QObject * theme = & cutehmi::gui::Theme::Instance();
	engine->setObjectOwnership(theme, QQmlEngine::CppOwnership);
	return theme;
}

}
}
}

//(c)C: Copyright © 2020, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: SPDX-License-Identifier: LGPL-3.0-or-later OR MIT
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI 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.
//(c)C: CuteHMI 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.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
//(c)C: Additionally, this file is licensed under terms of MIT license as expressed below.
//(c)C: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//(c)C: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//(c)C: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<commit_msg>Fix condition<commit_after>#include "QMLPlugin.hpp"

#include <cutehmi/gui/CuteApplication.hpp>
#include <cutehmi/gui/ColorSet.hpp>
#include <cutehmi/gui/Palette.hpp>
#include <cutehmi/gui/Fonts.hpp>
#include <cutehmi/gui/Units.hpp>
#include <cutehmi/gui/Theme.hpp>

#include <QtQml>

//<Doxygen-3.workaround target="Doxygen" cause="missing">
#ifdef DOXYGEN_WORKAROUND

namespace CuteHMI {
namespace GUI {

/**
 * Exposes cutehmi::gui::CuteApplication to QML.
 */
class CuteApplication: public cutehmi::gui::CuteApplication {};

/**
 * Exposes cutehmi::gui::ColorSet to QML.
 */
class ColorSet: public cutehmi::gui::ColorSet {};

/**
 * Exposes cutehmi::gui::Palette to QML.
 */
class Palette: public cutehmi::gui::Palette  {};

/**
 * Exposes cutehmi::gui::Fonts to QML.
 */
class Fonts: public cutehmi::gui::Fonts {};

/**
 * Exposes cutehmi::gui::Units to QML.
 */
class Units: public cutehmi::gui::Units {};

/**
 * Exposes cutehmi::gui::Theme to QML.
 */
class Theme: public cutehmi::gui::Theme {};

}
}

#endif
//</Doxygen-3.workaround>

namespace cutehmi {
namespace gui {
namespace internal {

/**
 * Register QML types.
 * @param uri URI.
 */
void QMLPlugin::registerTypes(const char * uri)
{
	Q_ASSERT(uri == QLatin1String("CuteHMI.GUI"));

	// @uri CuteHMI.GUI
	qmlRegisterType<cutehmi::gui::ColorSet>(uri, CUTEHMI_GUI_MAJOR, 0, "ColorSet");
	qmlRegisterType<cutehmi::gui::Palette>(uri, CUTEHMI_GUI_MAJOR, 0, "Palette");
	qmlRegisterType<cutehmi::gui::Fonts>(uri, CUTEHMI_GUI_MAJOR, 0, "Fonts");
	qmlRegisterType<cutehmi::gui::Units>(uri, CUTEHMI_GUI_MAJOR, 0, "Units");

	qmlRegisterSingletonType<cutehmi::gui::Theme>(uri, CUTEHMI_GUI_MAJOR, 0, "Theme", ThemeProvider);

	if (!qEnvironmentVariableIsSet("QML_PUPPET_MODE")) {
		//<CuteHMI.LockScreen-1.workaround target="Qt" cause="design">
		// @uri CuteHMI.GUI
		qmlRegisterSingletonType<cutehmi::gui::CuteApplication>(uri, CUTEHMI_GUI_MAJOR, 0, "CuteApplication", CuteApplicationProvider);
		//</CuteHMI.LockScreen-1.workaround>
	}
}

QObject * QMLPlugin::CuteApplicationProvider(QQmlEngine * engine, QJSEngine * scriptEngine)
{
	Q_UNUSED(scriptEngine)

	QObject * app = cutehmi::gui::CuteApplication::instance();
	engine->setObjectOwnership(app, QQmlEngine::CppOwnership);
	return app;
}

QObject * QMLPlugin::ThemeProvider(QQmlEngine * engine, QJSEngine * scriptEngine)
{
	Q_UNUSED(scriptEngine)

	QObject * theme = & cutehmi::gui::Theme::Instance();
	engine->setObjectOwnership(theme, QQmlEngine::CppOwnership);
	return theme;
}

}
}
}

//(c)C: Copyright © 2020, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: SPDX-License-Identifier: LGPL-3.0-or-later OR MIT
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI 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.
//(c)C: CuteHMI 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.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
//(c)C: Additionally, this file is licensed under terms of MIT license as expressed below.
//(c)C: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//(c)C: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//(c)C: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<|endoftext|>


<commit_before>#include "CellFeature.h"

#include "GameEntity.h"
#include "GamePlayer.h"
#include "GameType.h"
#include "RtsGame.h"
#include "MetaData.h"
#include <cmath>

using namespace IStrategizer;

CellFeature::CellFeature(const PlanStepParameters& p_parameters)
{
	m_alliedBuildingDescription.m_numberOfBuildings = p_parameters.at(PARAM_AlliedBuildingsCount);
	m_alliedBuildingDescription.m_numberOfCriticalBuildings = p_parameters.at(PARAM_AlliedCriticalBuildingsCount);
	m_alliedForceDescription.m_numberOfUnits = p_parameters.at(PARAM_AlliedUnitsCount);
	m_alliedForceDescription.m_totalDamage = p_parameters.at(PARAM_AlliedUnitsTotalDamage);
	m_alliedForceDescription.m_totalHP = p_parameters.at(PARAM_AlliedUnitsTotalHP);
	m_enemyBuildingDescription.m_numberOfBuildings = p_parameters.at(PARAM_EnemyBuildingsCount);
	m_enemyBuildingDescription.m_numberOfCriticalBuildings = p_parameters.at(PARAM_EnemyCriticalBuildingsCount);
	m_enemyForceDescription.m_numberOfUnits = p_parameters.at(PARAM_EnemyUnitsCount);
	m_enemyForceDescription.m_totalDamage = p_parameters.at(PARAM_EnemyUnitsTotalDamage);
	m_enemyForceDescription.m_totalHP = p_parameters.at(PARAM_EnemyUnitsTotalHP);
	m_resourceDescription.m_numberOfPrimary = p_parameters.at(PARAM_NumberOfPrimaryResources);
	m_resourceDescription.m_numberOfSecondary = p_parameters.at(PARAM_NumberOfSecondaryResources);
	m_resourceDescription.m_numberOfSupply = p_parameters.at(PARAM_NumberOfSupplyResources);
	m_distanceFromBase = p_parameters.at(PARAM_DistanceToBase);
	m_distanceFromEnemyBase = p_parameters.at(PARAM_DistanceToEnemyBase);
}
//----------------------------------------------------------------------------------------------
void CellFeature::To(PlanStepParameters& p_parameters) const
{
	p_parameters[PARAM_AlliedBuildingsCount] = m_alliedBuildingDescription.m_numberOfBuildings;
	p_parameters[PARAM_AlliedCriticalBuildingsCount] = m_alliedBuildingDescription.m_numberOfCriticalBuildings;
	p_parameters[PARAM_AlliedUnitsCount] = m_alliedForceDescription.m_numberOfUnits;
	p_parameters[PARAM_AlliedUnitsTotalDamage] = m_alliedForceDescription.m_totalDamage;
	p_parameters[PARAM_AlliedUnitsTotalHP] = m_alliedForceDescription.m_totalHP;
	p_parameters[PARAM_EnemyBuildingsCount] = m_enemyBuildingDescription.m_numberOfBuildings;
	p_parameters[PARAM_EnemyCriticalBuildingsCount] = m_enemyBuildingDescription.m_numberOfCriticalBuildings;
	p_parameters[PARAM_EnemyUnitsCount] = m_enemyForceDescription.m_numberOfUnits;
	p_parameters[PARAM_EnemyUnitsTotalDamage] = m_enemyForceDescription.m_totalDamage;
	p_parameters[PARAM_EnemyUnitsTotalHP] = m_enemyForceDescription.m_totalHP;
	p_parameters[PARAM_NumberOfPrimaryResources] = m_resourceDescription.m_numberOfPrimary;
	p_parameters[PARAM_NumberOfSecondaryResources] = m_resourceDescription.m_numberOfSecondary;
	p_parameters[PARAM_NumberOfSupplyResources] = m_resourceDescription.m_numberOfSupply;
	p_parameters[PARAM_DistanceToBase] = m_distanceFromBase;
	p_parameters[PARAM_DistanceToEnemyBase] = m_distanceFromEnemyBase;
}
//----------------------------------------------------------------------------------------------
void CellFeature::AddEntity(GameEntity *p_entity, bool p_isAllied)
{
	if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_IsBuilding))
	{
		if(p_isAllied)
			m_alliedBuildingDescription.AddEntity(p_entity);
		else
			m_enemyBuildingDescription.AddEntity(p_entity);

	}
	else if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_CanAttack))
	{
		if(p_isAllied)
			m_alliedForceDescription.AddEntity(p_entity);
		else
			m_enemyForceDescription.AddEntity(p_entity);
	}
	else
	{
		m_resourceDescription.AddEntity(p_entity);
	}
}
//----------------------------------------------------------------------------------------------
void CellFeature::RemoveEntity(GameEntity *p_entity, bool p_isAllied)
{
	if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_IsBuilding))
	{
		if(p_isAllied)
			m_alliedBuildingDescription.RemoveEntity(p_entity);
		else
			m_enemyBuildingDescription.RemoveEntity(p_entity);

	}
	else if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_CanAttack))
	{
		if(p_isAllied)
			m_alliedForceDescription.RemoveEntity(p_entity);
		else
			m_enemyForceDescription.RemoveEntity(p_entity);
	}
	else
	{
		m_resourceDescription.RemoveEntity(p_entity);
	}
}
//----------------------------------------------------------------------------------------------
void CellFeature::Clear()
{
	m_alliedBuildingDescription.Clear();
	m_enemyBuildingDescription.Clear();
	m_alliedForceDescription.Clear();
	m_enemyForceDescription.Clear();
	m_resourceDescription.Clear();
	m_distanceFromBase = 0;
	m_distanceFromEnemyBase = 0;
}
//----------------------------------------------------------------------------------------------
float CellFeature::GetDistance(CellFeature *p_other)
{
	float res = 0.0;
	float alliedBuildingDistance = m_alliedBuildingDescription.GetDistance(&(p_other->m_alliedBuildingDescription));
	float enemyBuildingDistance = m_enemyBuildingDescription.GetDistance(&(p_other->m_enemyBuildingDescription));
	float alliedForceDistance = m_alliedForceDescription.GetDistance(&(p_other->m_alliedForceDescription));
	float enemyForceDistance = m_enemyForceDescription.GetDistance(&(p_other->m_enemyForceDescription));
	float resourceDistance = m_resourceDescription.GetDistance(&(p_other->m_resourceDescription));
	float distanceFromBase = GetBaseDistance(this->m_distanceFromBase, p_other->m_distanceFromBase);
	float distanceFromEnemyBase = GetBaseDistance(this->m_distanceFromEnemyBase, p_other->m_distanceFromEnemyBase);

	res += alliedBuildingDistance;
	res += enemyBuildingDistance;
	res += alliedForceDistance;
	res += enemyForceDistance;
	res += resourceDistance;
	res += distanceFromBase;
	res += distanceFromEnemyBase;

	return sqrt(res);
}
//----------------------------------------------------------------------------------------------
void CellFeature::CalculateDistanceToBases(Vector2 cellWorldPosition)
{
	vector<TID> bases;

	g_Game->Enemy()->GetBases(bases);
	CalculateDistanceToBasesAux(cellWorldPosition, bases, m_distanceFromEnemyBase);
	g_Game->Self()->GetBases(bases);
	CalculateDistanceToBasesAux(cellWorldPosition, bases, m_distanceFromBase);
}
void CellFeature::CalculateDistanceToBasesAux(Vector2 cellWorldPosition, vector<TID> bases, double& distance)
{
	assert(bases.size() > 0);
	TID baseId = bases[0];
	GameEntity* pBase = g_Game->Self()->GetEntity(baseId);

	if (pBase == nullptr)
		pBase = g_Game->Enemy()->GetEntity(baseId);

	assert(pBase);

	distance = cellWorldPosition.Distance(pBase->GetPosition());
}
//----------------------------------------------------------------------------------------------
float CellFeature::GetBaseDistance(double firstBase, double secondBase) const
{
	return pow((float)(firstBase - secondBase), 2);
}<commit_msg>Add line separator<commit_after>#include "CellFeature.h"

#include "GameEntity.h"
#include "GamePlayer.h"
#include "GameType.h"
#include "RtsGame.h"
#include "MetaData.h"
#include <cmath>

using namespace IStrategizer;

CellFeature::CellFeature(const PlanStepParameters& p_parameters)
{
	m_alliedBuildingDescription.m_numberOfBuildings = p_parameters.at(PARAM_AlliedBuildingsCount);
	m_alliedBuildingDescription.m_numberOfCriticalBuildings = p_parameters.at(PARAM_AlliedCriticalBuildingsCount);
	m_alliedForceDescription.m_numberOfUnits = p_parameters.at(PARAM_AlliedUnitsCount);
	m_alliedForceDescription.m_totalDamage = p_parameters.at(PARAM_AlliedUnitsTotalDamage);
	m_alliedForceDescription.m_totalHP = p_parameters.at(PARAM_AlliedUnitsTotalHP);
	m_enemyBuildingDescription.m_numberOfBuildings = p_parameters.at(PARAM_EnemyBuildingsCount);
	m_enemyBuildingDescription.m_numberOfCriticalBuildings = p_parameters.at(PARAM_EnemyCriticalBuildingsCount);
	m_enemyForceDescription.m_numberOfUnits = p_parameters.at(PARAM_EnemyUnitsCount);
	m_enemyForceDescription.m_totalDamage = p_parameters.at(PARAM_EnemyUnitsTotalDamage);
	m_enemyForceDescription.m_totalHP = p_parameters.at(PARAM_EnemyUnitsTotalHP);
	m_resourceDescription.m_numberOfPrimary = p_parameters.at(PARAM_NumberOfPrimaryResources);
	m_resourceDescription.m_numberOfSecondary = p_parameters.at(PARAM_NumberOfSecondaryResources);
	m_resourceDescription.m_numberOfSupply = p_parameters.at(PARAM_NumberOfSupplyResources);
	m_distanceFromBase = p_parameters.at(PARAM_DistanceToBase);
	m_distanceFromEnemyBase = p_parameters.at(PARAM_DistanceToEnemyBase);
}
//----------------------------------------------------------------------------------------------
void CellFeature::To(PlanStepParameters& p_parameters) const
{
	p_parameters[PARAM_AlliedBuildingsCount] = m_alliedBuildingDescription.m_numberOfBuildings;
	p_parameters[PARAM_AlliedCriticalBuildingsCount] = m_alliedBuildingDescription.m_numberOfCriticalBuildings;
	p_parameters[PARAM_AlliedUnitsCount] = m_alliedForceDescription.m_numberOfUnits;
	p_parameters[PARAM_AlliedUnitsTotalDamage] = m_alliedForceDescription.m_totalDamage;
	p_parameters[PARAM_AlliedUnitsTotalHP] = m_alliedForceDescription.m_totalHP;
	p_parameters[PARAM_EnemyBuildingsCount] = m_enemyBuildingDescription.m_numberOfBuildings;
	p_parameters[PARAM_EnemyCriticalBuildingsCount] = m_enemyBuildingDescription.m_numberOfCriticalBuildings;
	p_parameters[PARAM_EnemyUnitsCount] = m_enemyForceDescription.m_numberOfUnits;
	p_parameters[PARAM_EnemyUnitsTotalDamage] = m_enemyForceDescription.m_totalDamage;
	p_parameters[PARAM_EnemyUnitsTotalHP] = m_enemyForceDescription.m_totalHP;
	p_parameters[PARAM_NumberOfPrimaryResources] = m_resourceDescription.m_numberOfPrimary;
	p_parameters[PARAM_NumberOfSecondaryResources] = m_resourceDescription.m_numberOfSecondary;
	p_parameters[PARAM_NumberOfSupplyResources] = m_resourceDescription.m_numberOfSupply;
	p_parameters[PARAM_DistanceToBase] = m_distanceFromBase;
	p_parameters[PARAM_DistanceToEnemyBase] = m_distanceFromEnemyBase;
}
//----------------------------------------------------------------------------------------------
void CellFeature::AddEntity(GameEntity *p_entity, bool p_isAllied)
{
	if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_IsBuilding))
	{
		if(p_isAllied)
			m_alliedBuildingDescription.AddEntity(p_entity);
		else
			m_enemyBuildingDescription.AddEntity(p_entity);

	}
	else if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_CanAttack))
	{
		if(p_isAllied)
			m_alliedForceDescription.AddEntity(p_entity);
		else
			m_enemyForceDescription.AddEntity(p_entity);
	}
	else
	{
		m_resourceDescription.AddEntity(p_entity);
	}
}
//----------------------------------------------------------------------------------------------
void CellFeature::RemoveEntity(GameEntity *p_entity, bool p_isAllied)
{
	if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_IsBuilding))
	{
		if(p_isAllied)
			m_alliedBuildingDescription.RemoveEntity(p_entity);
		else
			m_enemyBuildingDescription.RemoveEntity(p_entity);

	}
	else if(g_Game->GetEntityType(p_entity->Type())->Attr(ECATTR_CanAttack))
	{
		if(p_isAllied)
			m_alliedForceDescription.RemoveEntity(p_entity);
		else
			m_enemyForceDescription.RemoveEntity(p_entity);
	}
	else
	{
		m_resourceDescription.RemoveEntity(p_entity);
	}
}
//----------------------------------------------------------------------------------------------
void CellFeature::Clear()
{
	m_alliedBuildingDescription.Clear();
	m_enemyBuildingDescription.Clear();
	m_alliedForceDescription.Clear();
	m_enemyForceDescription.Clear();
	m_resourceDescription.Clear();
	m_distanceFromBase = 0;
	m_distanceFromEnemyBase = 0;
}
//----------------------------------------------------------------------------------------------
float CellFeature::GetDistance(CellFeature *p_other)
{
	float res = 0.0;
	float alliedBuildingDistance = m_alliedBuildingDescription.GetDistance(&(p_other->m_alliedBuildingDescription));
	float enemyBuildingDistance = m_enemyBuildingDescription.GetDistance(&(p_other->m_enemyBuildingDescription));
	float alliedForceDistance = m_alliedForceDescription.GetDistance(&(p_other->m_alliedForceDescription));
	float enemyForceDistance = m_enemyForceDescription.GetDistance(&(p_other->m_enemyForceDescription));
	float resourceDistance = m_resourceDescription.GetDistance(&(p_other->m_resourceDescription));
	float distanceFromBase = GetBaseDistance(this->m_distanceFromBase, p_other->m_distanceFromBase);
	float distanceFromEnemyBase = GetBaseDistance(this->m_distanceFromEnemyBase, p_other->m_distanceFromEnemyBase);

	res += alliedBuildingDistance;
	res += enemyBuildingDistance;
	res += alliedForceDistance;
	res += enemyForceDistance;
	res += resourceDistance;
	res += distanceFromBase;
	res += distanceFromEnemyBase;

	return sqrt(res);
}
//----------------------------------------------------------------------------------------------
void CellFeature::CalculateDistanceToBases(Vector2 cellWorldPosition)
{
	vector<TID> bases;

	g_Game->Enemy()->GetBases(bases);
	CalculateDistanceToBasesAux(cellWorldPosition, bases, m_distanceFromEnemyBase);
	g_Game->Self()->GetBases(bases);
	CalculateDistanceToBasesAux(cellWorldPosition, bases, m_distanceFromBase);
}
//----------------------------------------------------------------------------------------------
void CellFeature::CalculateDistanceToBasesAux(Vector2 cellWorldPosition, vector<TID> bases, double& distance)
{
	assert(bases.size() > 0);
	TID baseId = bases[0];
	GameEntity* pBase = g_Game->Self()->GetEntity(baseId);

	if (pBase == nullptr)
		pBase = g_Game->Enemy()->GetEntity(baseId);

	assert(pBase);

	distance = cellWorldPosition.Distance(pBase->GetPosition());
}
//----------------------------------------------------------------------------------------------
float CellFeature::GetBaseDistance(double firstBase, double secondBase) const
{
	return pow((float)(firstBase - secondBase), 2);
}<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CppUnitTest.h"
#include "..\ProjectEuler\Problem1.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace ProjectEulerTests
{
	TEST_CLASS(Problem1Tests)
	{
	public:

		TEST_METHOD(SumMultiplesOf3And5Below_Input0_Returns0)
		{
            auto result = Problem1::SumMultiplesOf3And5Below(0);
            Assert::AreEqual(0, result);
		}

        TEST_METHOD(SumMultiplesOf3And5Below_Input1_Returns0)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(1);
            Assert::AreEqual(0, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input2_Returns0)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(2);
            Assert::AreEqual(0, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input3_Returns0)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(3);
            Assert::AreEqual(0, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input4_Returns3)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(4);
            Assert::AreEqual(3, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input5_Returns3)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(5);
            Assert::AreEqual(3, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input6_Returns8)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(6);
            Assert::AreEqual(8, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input7_Returns14)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(7);
            Assert::AreEqual(14, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input8_Returns14)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(8);
            Assert::AreEqual(14, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input9_Returns14)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(9);
            Assert::AreEqual(14, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input10_Returns23)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(10);
            Assert::AreEqual(23, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input100_Returns2318)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(100);
            Assert::AreEqual(2318, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input1000_Returns233168)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(1000);
            Assert::AreEqual(233168, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input10000_Returns23331668)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(10000);
            Assert::AreEqual(23331668, result);
        }

        TEST_METHOD(SumBelow_Input0_Returns0)
        {
            auto result = Problem1::SumBelow(0);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumBelow_Input1_Returns0)
        {
            auto result = Problem1::SumBelow(1);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumBelow_Input2_Returns1)
        {
            auto result = Problem1::SumBelow(2);
            Assert::AreEqual(1L, result);
        }

        TEST_METHOD(SumBelow_Input3_Returns3)
        {
            auto result = Problem1::SumBelow(3);
            Assert::AreEqual(3L, result);
        }

        TEST_METHOD(SumBelow_Input4_Returns6)
        {
            auto result = Problem1::SumBelow(4);
            Assert::AreEqual(6L, result);
        }

        TEST_METHOD(SumBelow_Input5_Returns10)
        {
            auto result = Problem1::SumBelow(5);
            Assert::AreEqual(10L, result);
        }

        TEST_METHOD(SumBelow_Input6_Returns15)
        {
            auto result = Problem1::SumBelow(6);
            Assert::AreEqual(15L, result);
        }

        TEST_METHOD(SumBelow_Input7_Returns21)
        {
            auto result = Problem1::SumBelow(7);
            Assert::AreEqual(21L, result);
        }

        TEST_METHOD(SumBelow_Input8_Returns28)
        {
            auto result = Problem1::SumBelow(8);
            Assert::AreEqual(28L, result);
        }

        TEST_METHOD(SumBelow_Input9_Returns36)
        {
            auto result = Problem1::SumBelow(9);
            Assert::AreEqual(36L, result);
        }

        TEST_METHOD(SumBelow_Input10_Returns45)
        {
            auto result = Problem1::SumBelow(10);
            Assert::AreEqual(45L, result);
        }

        TEST_METHOD(SumBelow_Input100_Returns4950)
        {
            auto result = Problem1::SumBelow(100);
            Assert::AreEqual(4950L, result);
        }

        TEST_METHOD(SumBelow_Input100000_Returns704982704)
        {
            auto result = Problem1::SumBelow(100000);
            Assert::AreEqual(704982704L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and0_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 0L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and1_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 1L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and2_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 2L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and3_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 3L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and4_Returns3)
        {
            auto result = Problem1::SumDivisibleBy(3, 4L);
            Assert::AreEqual(3L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and0_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 0L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and1_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 1L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and2_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 2L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and3_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 3L);
            Assert::AreEqual(0L, result);
        }
	};
}<commit_msg>red-commit - SumDivisibleBy_Input5and4_Returns0<commit_after>#include "stdafx.h"
#include "CppUnitTest.h"
#include "..\ProjectEuler\Problem1.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace ProjectEulerTests
{
	TEST_CLASS(Problem1Tests)
	{
	public:

		TEST_METHOD(SumMultiplesOf3And5Below_Input0_Returns0)
		{
            auto result = Problem1::SumMultiplesOf3And5Below(0);
            Assert::AreEqual(0, result);
		}

        TEST_METHOD(SumMultiplesOf3And5Below_Input1_Returns0)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(1);
            Assert::AreEqual(0, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input2_Returns0)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(2);
            Assert::AreEqual(0, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input3_Returns0)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(3);
            Assert::AreEqual(0, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input4_Returns3)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(4);
            Assert::AreEqual(3, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input5_Returns3)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(5);
            Assert::AreEqual(3, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input6_Returns8)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(6);
            Assert::AreEqual(8, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input7_Returns14)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(7);
            Assert::AreEqual(14, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input8_Returns14)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(8);
            Assert::AreEqual(14, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input9_Returns14)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(9);
            Assert::AreEqual(14, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input10_Returns23)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(10);
            Assert::AreEqual(23, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input100_Returns2318)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(100);
            Assert::AreEqual(2318, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input1000_Returns233168)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(1000);
            Assert::AreEqual(233168, result);
        }

        TEST_METHOD(SumMultiplesOf3And5Below_Input10000_Returns23331668)
        {
            auto result = Problem1::SumMultiplesOf3And5Below(10000);
            Assert::AreEqual(23331668, result);
        }

        TEST_METHOD(SumBelow_Input0_Returns0)
        {
            auto result = Problem1::SumBelow(0);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumBelow_Input1_Returns0)
        {
            auto result = Problem1::SumBelow(1);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumBelow_Input2_Returns1)
        {
            auto result = Problem1::SumBelow(2);
            Assert::AreEqual(1L, result);
        }

        TEST_METHOD(SumBelow_Input3_Returns3)
        {
            auto result = Problem1::SumBelow(3);
            Assert::AreEqual(3L, result);
        }

        TEST_METHOD(SumBelow_Input4_Returns6)
        {
            auto result = Problem1::SumBelow(4);
            Assert::AreEqual(6L, result);
        }

        TEST_METHOD(SumBelow_Input5_Returns10)
        {
            auto result = Problem1::SumBelow(5);
            Assert::AreEqual(10L, result);
        }

        TEST_METHOD(SumBelow_Input6_Returns15)
        {
            auto result = Problem1::SumBelow(6);
            Assert::AreEqual(15L, result);
        }

        TEST_METHOD(SumBelow_Input7_Returns21)
        {
            auto result = Problem1::SumBelow(7);
            Assert::AreEqual(21L, result);
        }

        TEST_METHOD(SumBelow_Input8_Returns28)
        {
            auto result = Problem1::SumBelow(8);
            Assert::AreEqual(28L, result);
        }

        TEST_METHOD(SumBelow_Input9_Returns36)
        {
            auto result = Problem1::SumBelow(9);
            Assert::AreEqual(36L, result);
        }

        TEST_METHOD(SumBelow_Input10_Returns45)
        {
            auto result = Problem1::SumBelow(10);
            Assert::AreEqual(45L, result);
        }

        TEST_METHOD(SumBelow_Input100_Returns4950)
        {
            auto result = Problem1::SumBelow(100);
            Assert::AreEqual(4950L, result);
        }

        TEST_METHOD(SumBelow_Input100000_Returns704982704)
        {
            auto result = Problem1::SumBelow(100000);
            Assert::AreEqual(704982704L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and0_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 0L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and1_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 1L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and2_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 2L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and3_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(3, 3L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input3and4_Returns3)
        {
            auto result = Problem1::SumDivisibleBy(3, 4L);
            Assert::AreEqual(3L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and0_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 0L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and1_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 1L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and2_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 2L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and3_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 3L);
            Assert::AreEqual(0L, result);
        }

        TEST_METHOD(SumDivisibleBy_Input5and4_Returns0)
        {
            auto result = Problem1::SumDivisibleBy(5, 4L);
            Assert::AreEqual(0L, result);
        }
	};
}<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/DBusProxyFactory>
#include "TelepathyQt4/dbus-proxy-factory-internal.h"

#include "TelepathyQt4/_gen/dbus-proxy-factory-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/DBusProxy>
#include <TelepathyQt4/ReadyObject>
#include <TelepathyQt4/PendingReady>

#include <QDBusConnection>

namespace Tp
{

struct DBusProxyFactory::Private
{
    Private(const QDBusConnection &bus)
        : bus(bus), cache(new Cache) {}

    ~Private()
    {
        delete cache;
    }

    QDBusConnection bus;
    Cache *cache;
};

/**
 * \class DBusProxyFactory
 * \ingroup clientreadiness
 * \headerfile TelepathyQt4/dbus-proxy-factory.h <TelepathyQt4/DBusProxyFactory>
 *
 * Base class for all D-Bus proxy factory classes. Handles proxy caching and making them ready as
 * appropriate.
 */

/**
 * Class constructor.
 *
 * The intention for storing the bus here is that it generally doesn't make sense to construct
 * proxies for multiple buses in the same context. Allowing that would lead to more complex keying
 * needs in the cache, as well.
 *
 * \param bus The D-Bus bus connection for the objects constructed using this factory.
 */
DBusProxyFactory::DBusProxyFactory(const QDBusConnection &bus)
    : mPriv(new Private(bus))
{
}

/**
 * Class destructor.
 */
DBusProxyFactory::~DBusProxyFactory()
{
    delete mPriv;
}

/**
 * Returns the D-Bus connection all of the proxies from this factory communicate with.
 *
 * \return The connection.
 */
const QDBusConnection &DBusProxyFactory::dbusConnection() const
{
    return mPriv->bus;
}

/**
 * Returns a cached proxy with the given \a busName and \a objectPath.
 *
 * If a proxy has not been previously put into the cache by nowHaveProxy for those identifying
 * attributes, or a previously cached proxy has since been invalidated and/or destroyed, a \c Null
 * shared pointer is returned instead.
 *
 * \param busName Bus name of the proxy to return.
 * \param objectPath Object path of the proxy to return.
 * \return The proxy, if any.
 */
SharedPtr<RefCounted> DBusProxyFactory::cachedProxy(const QString &busName,
        const QString &objectPath) const
{
    QString finalName = finalBusNameFrom(busName);
    return mPriv->cache->get(Cache::Key(finalName, objectPath));
}

/**
 * Should be called by subclasses when they have a proxy, be it a newly-constructed one or one from
 * the cache.
 *
 * This function will then do the rest of the factory work, including caching the proxy if it's not
 * cached already, doing any prepare() work if appropriate, and making the features from
 * featuresFor() ready if they aren't already.
 *
 * The returned PendingReady only finishes when the prepare() operation for the proxy has completed,
 * and the requested features have all been made ready (or found unable to be made ready). Note that
 * this might have happened already before calling this function, if the proxy was not a newly
 * created one, but was looked up from the cache. DBusProxyFactory handles the necessary subleties
 * for this to work.
 *
 * Access to the proxy instance is allowed as soon as this method returns through
 * PendingReady::proxy(), if the proxy is needed in a context where it's not required to be ready.
 *
 * \param proxy The proxy which the factory should now make sure is prepared and made ready.
 * \return Readifying operation, which finishes when the proxy is usable.
 */
PendingReady *DBusProxyFactory::nowHaveProxy(const SharedPtr<RefCounted> &proxy) const
{
    Q_ASSERT(!proxy.isNull());

    // I really hate the casts needed in this function - we must really do something about the
    // DBusProxy class hierarchy so that every DBusProxy(Something) is always a ReadyObject and a
    // RefCounted, in the API/ABI break - then most of these proxyMisc-> things become just proxy->

    ReadyObject *proxyReady = dynamic_cast<ReadyObject *>(proxy.data());
    Q_ASSERT(proxyReady != NULL);

    Features specificFeatures = featuresFor(proxy);

    // FIXME: prepare currently doesn't work
    PendingOperation *prepareOp = NULL;

    mPriv->cache->put(proxy);

    if (prepareOp || (!specificFeatures.isEmpty() && !proxyReady->isReady(specificFeatures))) {
        return new PendingReady(prepareOp, specificFeatures, proxy, 0);
    }

    // No features requested or they are all ready - optimize a bit by not calling ReadinessHelper
    PendingReady *readyOp = new PendingReady(0, specificFeatures, proxy, 0);
    readyOp->setFinished();
    return readyOp;
}

/**
 * Allows subclasses to do arbitrary manipulation on the object before it is attempted to be made
 * ready.
 *
 * If a non-\c NULL operation is returned, the completion of that operation is waited for before
 * starting to make the object ready whenever nowHaveProxy() is called the first time around for a
 * given proxy.
 *
 * \return \c NULL ie. nothing to do.
 */
PendingOperation *DBusProxyFactory::prepare(const SharedPtr<RefCounted> &object) const
{
    // Nothing we could think about needs doing
    return NULL;
}

DBusProxyFactory::Cache::Cache()
{
}

DBusProxyFactory::Cache::~Cache()
{
}

SharedPtr<RefCounted> DBusProxyFactory::Cache::get(const Key &key) const
{
    SharedPtr<RefCounted> counted(proxies.value(key));

    // We already assert for it being a DBusProxy in put()
    if (!counted || !dynamic_cast<DBusProxy *>(counted.data())->isValid()) {
        // Weak pointer invalidated or proxy invalidated during this mainloop iteration and we still
        // haven't got the invalidated() signal for it
        return SharedPtr<RefCounted>();
    }

    return counted;
}

void DBusProxyFactory::Cache::put(const SharedPtr<RefCounted> &obj)
{
    DBusProxy *proxyProxy = dynamic_cast<DBusProxy *>(obj.data());
    Q_ASSERT(proxyProxy != NULL);

    Key key(proxyProxy->busName(), proxyProxy->objectPath());

    SharedPtr<RefCounted> existingProxy = SharedPtr<RefCounted>(proxies.value(key));
    if (!existingProxy || existingProxy != obj) {
        connect(proxyProxy,
                SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
                SLOT(onProxyInvalidated(Tp::DBusProxy*)));

        debug() << "Inserting to factory cache proxy for" << key;
        proxies.insert(key, obj);
    }
}

void DBusProxyFactory::Cache::onProxyInvalidated(Tp::DBusProxy *proxy)
{
    Key key(proxy->busName(), proxy->objectPath());

    // Not having it would indicate invalidated() signaled twice for the same proxy, or us having
    // connected to two proxies with the same key, neither of which should happen
    Q_ASSERT(proxies.contains(key));

    debug() << "Removing from factory cache invalidated proxy for" << key;

    proxies.remove(key);
}

}
<commit_msg>Warn in DBusProxyFactory docs that prepare() is not currently really used<commit_after>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/DBusProxyFactory>
#include "TelepathyQt4/dbus-proxy-factory-internal.h"

#include "TelepathyQt4/_gen/dbus-proxy-factory-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/DBusProxy>
#include <TelepathyQt4/ReadyObject>
#include <TelepathyQt4/PendingReady>

#include <QDBusConnection>

namespace Tp
{

struct DBusProxyFactory::Private
{
    Private(const QDBusConnection &bus)
        : bus(bus), cache(new Cache) {}

    ~Private()
    {
        delete cache;
    }

    QDBusConnection bus;
    Cache *cache;
};

/**
 * \class DBusProxyFactory
 * \ingroup clientreadiness
 * \headerfile TelepathyQt4/dbus-proxy-factory.h <TelepathyQt4/DBusProxyFactory>
 *
 * Base class for all D-Bus proxy factory classes. Handles proxy caching and making them ready as
 * appropriate.
 */

/**
 * Class constructor.
 *
 * The intention for storing the bus here is that it generally doesn't make sense to construct
 * proxies for multiple buses in the same context. Allowing that would lead to more complex keying
 * needs in the cache, as well.
 *
 * \param bus The D-Bus bus connection for the objects constructed using this factory.
 */
DBusProxyFactory::DBusProxyFactory(const QDBusConnection &bus)
    : mPriv(new Private(bus))
{
}

/**
 * Class destructor.
 */
DBusProxyFactory::~DBusProxyFactory()
{
    delete mPriv;
}

/**
 * Returns the D-Bus connection all of the proxies from this factory communicate with.
 *
 * \return The connection.
 */
const QDBusConnection &DBusProxyFactory::dbusConnection() const
{
    return mPriv->bus;
}

/**
 * Returns a cached proxy with the given \a busName and \a objectPath.
 *
 * If a proxy has not been previously put into the cache by nowHaveProxy for those identifying
 * attributes, or a previously cached proxy has since been invalidated and/or destroyed, a \c Null
 * shared pointer is returned instead.
 *
 * \param busName Bus name of the proxy to return.
 * \param objectPath Object path of the proxy to return.
 * \return The proxy, if any.
 */
SharedPtr<RefCounted> DBusProxyFactory::cachedProxy(const QString &busName,
        const QString &objectPath) const
{
    QString finalName = finalBusNameFrom(busName);
    return mPriv->cache->get(Cache::Key(finalName, objectPath));
}

/**
 * Should be called by subclasses when they have a proxy, be it a newly-constructed one or one from
 * the cache.
 *
 * This function will then do the rest of the factory work, including caching the proxy if it's not
 * cached already, doing any prepare() work if appropriate, and making the features from
 * featuresFor() ready if they aren't already.
 *
 * The returned PendingReady only finishes when the prepare() operation for the proxy has completed,
 * and the requested features have all been made ready (or found unable to be made ready). Note that
 * this might have happened already before calling this function, if the proxy was not a newly
 * created one, but was looked up from the cache. DBusProxyFactory handles the necessary subleties
 * for this to work.
 *
 * Access to the proxy instance is allowed as soon as this method returns through
 * PendingReady::proxy(), if the proxy is needed in a context where it's not required to be ready.
 *
 * \param proxy The proxy which the factory should now make sure is prepared and made ready.
 * \return Readifying operation, which finishes when the proxy is usable.
 */
PendingReady *DBusProxyFactory::nowHaveProxy(const SharedPtr<RefCounted> &proxy) const
{
    Q_ASSERT(!proxy.isNull());

    // I really hate the casts needed in this function - we must really do something about the
    // DBusProxy class hierarchy so that every DBusProxy(Something) is always a ReadyObject and a
    // RefCounted, in the API/ABI break - then most of these proxyMisc-> things become just proxy->

    ReadyObject *proxyReady = dynamic_cast<ReadyObject *>(proxy.data());
    Q_ASSERT(proxyReady != NULL);

    Features specificFeatures = featuresFor(proxy);

    // FIXME: prepare currently doesn't work
    PendingOperation *prepareOp = NULL;

    mPriv->cache->put(proxy);

    if (prepareOp || (!specificFeatures.isEmpty() && !proxyReady->isReady(specificFeatures))) {
        return new PendingReady(prepareOp, specificFeatures, proxy, 0);
    }

    // No features requested or they are all ready - optimize a bit by not calling ReadinessHelper
    PendingReady *readyOp = new PendingReady(0, specificFeatures, proxy, 0);
    readyOp->setFinished();
    return readyOp;
}

/**
 * Allows subclasses to do arbitrary manipulation on the object before it is attempted to be made
 * ready.
 *
 * If a non-\c NULL operation is returned, the completion of that operation is waited for before
 * starting to make the object ready whenever nowHaveProxy() is called the first time around for a
 * given proxy.
 *
 * \todo FIXME actually implement this... :)
 * \return \c NULL ie. nothing to do.
 */
PendingOperation *DBusProxyFactory::prepare(const SharedPtr<RefCounted> &object) const
{
    // Nothing we could think about needs doing
    return NULL;
}

DBusProxyFactory::Cache::Cache()
{
}

DBusProxyFactory::Cache::~Cache()
{
}

SharedPtr<RefCounted> DBusProxyFactory::Cache::get(const Key &key) const
{
    SharedPtr<RefCounted> counted(proxies.value(key));

    // We already assert for it being a DBusProxy in put()
    if (!counted || !dynamic_cast<DBusProxy *>(counted.data())->isValid()) {
        // Weak pointer invalidated or proxy invalidated during this mainloop iteration and we still
        // haven't got the invalidated() signal for it
        return SharedPtr<RefCounted>();
    }

    return counted;
}

void DBusProxyFactory::Cache::put(const SharedPtr<RefCounted> &obj)
{
    DBusProxy *proxyProxy = dynamic_cast<DBusProxy *>(obj.data());
    Q_ASSERT(proxyProxy != NULL);

    Key key(proxyProxy->busName(), proxyProxy->objectPath());

    SharedPtr<RefCounted> existingProxy = SharedPtr<RefCounted>(proxies.value(key));
    if (!existingProxy || existingProxy != obj) {
        connect(proxyProxy,
                SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
                SLOT(onProxyInvalidated(Tp::DBusProxy*)));

        debug() << "Inserting to factory cache proxy for" << key;
        proxies.insert(key, obj);
    }
}

void DBusProxyFactory::Cache::onProxyInvalidated(Tp::DBusProxy *proxy)
{
    Key key(proxy->busName(), proxy->objectPath());

    // Not having it would indicate invalidated() signaled twice for the same proxy, or us having
    // connected to two proxies with the same key, neither of which should happen
    Q_ASSERT(proxies.contains(key));

    debug() << "Removing from factory cache invalidated proxy for" << key;

    proxies.remove(key);
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <list>

using namespace std;

char proc_char(char c)
{
    if (c == -127) c = -111;
    else if (c <= -81) c += 32;
    if (c >= -74) c++;
    if (c == -111) c = -74;
    return c;
}

bool cmp(char c1, char c2)
{
    if ((c1 == -48 || c1 == -47) && (c2 == -48 || c2 == -47)) return false;
    return proc_char(c1) < proc_char(c2);
}

int main()
{
    int n;
    string s;
    cin >> n;
    list<string> lst;
    for (int i = 0; i< n; i++)
    {
        cin >> s;
        lst.push_back(s);
    }
    lst.sort();
    lst.reverse();

    cout << "\nSorted + reversed:\n";
    for (auto i = lst.begin(); i != lst.end(); i++)
        cout << *i << endl;

    cout << "\nRemoved strings with digits in first place:\n";

    lst.remove_if([](string& s){return isdigit(s[0]);});

    for (auto i = lst.begin(); i != lst.end(); i++)
        cout << *i << endl;

    cout << "\nRussian strings sorted properly:\n";

    lst.sort([](string& s1, string& s2){return lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), cmp);});

    for (auto i = lst.begin(); i != lst.end(); i++)
        cout << *i << endl;

    return 0;
}
<commit_msg>Added copyright<commit_after>/*
    Copyright (c) 2017 Maxim Teryokhin
    This code is licensed under MIT. See LICENSE file for more details.
*/

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <list>

using namespace std;

char proc_char(char c)
{
    if (c == -127) c = -111;
    else if (c <= -81) c += 32;
    if (c >= -74) c++;
    if (c == -111) c = -74;
    return c;
}

bool cmp(char c1, char c2)
{
    if ((c1 == -48 || c1 == -47) && (c2 == -48 || c2 == -47)) return false;
    return proc_char(c1) < proc_char(c2);
}

int main()
{
    int n;
    string s;
    cin >> n;
    list<string> lst;
    for (int i = 0; i< n; i++)
    {
        cin >> s;
        lst.push_back(s);
    }
    lst.sort();
    lst.reverse();

    cout << "\nSorted + reversed:\n";
    for (auto i = lst.begin(); i != lst.end(); i++)
        cout << *i << endl;

    cout << "\nRemoved strings with digits in first place:\n";

    lst.remove_if([](string& s){return isdigit(s[0]);});

    for (auto i = lst.begin(); i != lst.end(); i++)
        cout << *i << endl;

    cout << "\nRussian strings sorted properly:\n";

    lst.sort([](string& s1, string& s2){return lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), cmp);});

    for (auto i = lst.begin(); i != lst.end(); i++)
        cout << *i << endl;

    return 0;
}
<|endoftext|>


<commit_before>//
// SRTerrain class : a subclass of vtDynTerrainGeom which encapsulates
//  Stefan Roettger's CLOD algorithm.
//
// utilizes: Roettger's MINI library implementation
// http://wwwvis.informatik.uni-stuttgart.de/~roettger
//
// Copyright (c) 2002-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "SRTerrain.h"
#include "vtdata/vtLog.h"

#if VTLIB_NI
// stub
SRTerrain::SRTerrain() {}
SRTerrain::~SRTerrain() {}
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const { return 0; }
void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const {}
void SRTerrain::DoCulling(const vtCamera *pCam) {}
void SRTerrain::DoRender() {}
void SRTerrain::SetVerticalExag(float fExag) {}
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale) { return DTErr_NOMEM; }
#else

#include "mini.h"
#include "ministub.hpp"

using namespace mini;
#ifdef _MSC_VER
#pragma comment( lib, "libMini.lib" )
#endif

/////////////////////////////////////////////////////////////////////////////

//
// Constructor/destructor
//
SRTerrain::SRTerrain() : vtDynTerrainGeom()
{
	m_fResolution	= 10000.0f;
	m_fHResolution	= 20000.0f;
	m_fLResolution	=     0.0f;
	m_pMini = NULL;
}

SRTerrain::~SRTerrain()
{
	if (m_pMini)
	{
		delete m_pMini;
		m_pMini = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////

//
// Unfortunately the following statics are required because libMini only
// supports some functionality by callback, and the callback is only a
// simple C function which has no context to tell us which terrain.
//
static const vtElevationGrid *s_pGrid;
static SRTerrain *s_pSRTerrain;
static int myfancnt, myvtxcnt;

void beginfan_vtp()
{
	if (myfancnt++>0)
		glEnd();
	glBegin(GL_TRIANGLE_FAN);
	myvtxcnt-=2;	// 2 vertices are needed to start each fan
}

void fanvertex_vtp(float x, float y, float z)
{
	glVertex3f(x,y,z);
	myvtxcnt++;
}

void notify_vtp(int i, int j, int size)
{
	// check to see if we need to switch texture
	if (s_pSRTerrain->m_iTPatchDim > 1 && size == s_pSRTerrain->m_iBlockSize)
	{
		int a = i / size;
		int b = j / size;
		s_pSRTerrain->LoadBlockMaterial(a, b);
	}
}

short int getelevation_vtp1(int i, int j, int size)
{
	return s_pGrid->GetValue(i, j);
}

float getelevation_vtp2(int i, int j, int size)
{
	return s_pGrid->GetFValue(i, j);
}

//
// Initialize the terrain data
// fZScale converts from height values (meters) to world coordinates
//
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale)
{
	// Initializes necessary field of the parent class
	DTErr err = BasicInit(pGrid);
	if (err != DTErr_OK)
		return err;

	if (m_iColumns != m_iRows)
		return DTErr_NOTSQUARE;

	// compute n (log2 of grid size)
	// ensure that the grid is size (1 << n) + 1
	int n = vt_log2(m_iColumns - 1);
	int required_size = (1<<n) + 1;
	if (m_iColumns != required_size || m_iRows != required_size)
		return DTErr_NOTPOWER2;

	int size = m_iColumns;
	float dim = m_fXStep;
	float cellaspect = m_fZStep / m_fXStep;

	s_pGrid = pGrid;

#if 0
	// NOTE: the following workaround is no longer needed with libMini 5.02
	//
	// Totally strange but repeatable behavior: runtime exit in Release-mode
	//  libMini with values over a certain level.  Workaround here!
	// Exit happens if (scale * maximum_height / dim > 967)
	//
	// 	scale * maximum_height / dim > 967
	//	scale > dim * 967 / maximum_height
	//
	float fMin, fMax;
	pGrid->GetHeightExtents(fMin, fMax);
	// Avoid trouble with fMax small or zero
	if (fMax < 10) fMax = 10;
	// compute the largest supported value for MaxScale
	float fMaxMax = dim * 960 / fMax;
	// values greater than 10 are unnecessarily large
	if (fMaxMax > 10)
		fMaxMax = 10;
	m_fMaximumScale = fMaxMax;
#else
	// This maxiumum scale is a reasonable tradeoff between the exaggeration
	//  that the user is likely to need, and numerical precision issues.
	m_fMaximumScale = 10;
#endif

	m_fHeightScale = fZScale;
	m_fDrawScale = m_fHeightScale / m_fMaximumScale;

	if (pGrid->IsFloatMode())
	{
		float *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp2);
	}
	else
	{
		short *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp1);
	}

	m_iDrawnTriangles = -1;
	m_iBlockSize = m_iColumns / 4;

	return DTErr_OK;
}

void SRTerrain::SetVerticalExag(float fExag)
{
	m_fHeightScale = fExag;

	// safety check
	if (m_fHeightScale > m_fMaximumScale)
		m_fHeightScale = m_fMaximumScale;

	m_fDrawScale = m_fHeightScale / m_fMaximumScale;
}

//
// This will be called once per frame, during the culling pass.
//
// However, libMini does not allow you to call the culling pass
// independently of the rendering pass, so we cannot do culling here.
// Instead, just store the values for later use.
//
void SRTerrain::DoCulling(const vtCamera *pCam)
{
	// Grab necessary values from the VTP Scene framework, store for later
	m_eyepos_ogl = pCam->GetTrans();
	m_window_size = vtGetScene()->GetWindowSize();
	m_fAspect = (float)m_window_size.x / m_window_size.y;
	m_fNear = pCam->GetHither();
	m_fFar = pCam->GetYon();

	// Get up vector and direction vector from camera matrix
	FMatrix4 mat;
	pCam->GetTransform1(mat);
	FPoint3 up(0.0f, 1.0f, 0.0f);
	mat.TransformVector(up, eye_up);

	FPoint3 forward(0.0f, 0.0f, -1.0f);
	mat.TransformVector(forward, eye_forward);

	if (pCam->IsOrtho())
	{
		// libMini supports orthographic viewing as of libMini 5.0.
		// A negative FOV value indicates to the library that the FOV is
		//  actually the orthographic height of the camera.
		m_fFOVY = pCam->GetWidth() / m_fAspect;
		m_fFOVY = -m_fFOVY;
	}
	else
	{
		float fov = pCam->GetFOV();
		float fov_y2 = atan(tan (fov/2) / m_fAspect);
		m_fFOVY = fov_y2 * 2.0f * 180 / PIf;
	}
}

void SRTerrain::DoRender()
{
	// Prepare the render state for our OpenGL usage
	PreRender();

	// Render the triangles
	RenderSurface();

	// Clean up
	PostRender();
}

void SRTerrain::LoadSingleMaterial()
{
	// single texture for the whole terrain
	vtMaterial *pMat = GetMaterial(0);
	if (pMat)
	{
		pMat->Apply();
		SetupTexGen(1.0f);
	}
}

void SRTerrain::LoadBlockMaterial(int a, int b)
{
	// we can't change the texture between glBegin/glEnd
	if (myfancnt++>0)
		glEnd();

	// each block has it's own texture map
	int matidx = a*m_iTPatchDim + (m_iTPatchDim-1-b);
	vtMaterial *pMat = GetMaterial(matidx);
	if (pMat)
	{
		pMat->Apply();
		SetupBlockTexGen(a, b);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glBegin(GL_TRIANGLE_FAN);
}

void SRTerrain::RenderSurface()
{
	s_pSRTerrain = this;

	if (m_iTPatchDim == 1)
		LoadSingleMaterial();

	RenderPass();

	// how to do a second rendering pass
	if (m_bDetailTexture)
	{
		// once again, with the detail texture material
		m_pDetailMat->Apply();

		// the uv tiling is different (usually highly repetitive)
		SetupTexGen(m_fDetailTiling);

		// draw the second pass
		glPolygonOffset(-1.0f, -1.0f);
		glEnable(GL_POLYGON_OFFSET_FILL);
		RenderPass();
		glDisable(GL_POLYGON_OFFSET_FILL);
	}
	DisableTexGen();
}

void SRTerrain::RenderPass()
{
	float ex = m_eyepos_ogl.x;
	float ey = m_eyepos_ogl.y;
	float ez = m_eyepos_ogl.z;

	float fov = m_fFOVY;

	float ux = eye_up.x;
	float uy = eye_up.y;
	float uz = eye_up.z;

	float dx = eye_forward.x;
	float dy = eye_forward.y;
	float dz = eye_forward.z;

	myfancnt = myvtxcnt = 0;

	// Convert the eye location to the unusual coordinate scheme of libMini.
	ex -= (m_iColumns/2)*m_fXStep;
	ez += (m_iRows/2)*m_fZStep;

	m_pMini->draw(m_fResolution,
				ex, ey, ez,
				dx, dy, dz,
				ux, uy, uz,
				fov, m_fAspect,
				m_fNear, m_fFar,
				m_fDrawScale);

	if (myfancnt>0) glEnd();

	// We are drawing fans, so the number of triangles is roughly equal to
	// number of vertices
	m_iDrawnTriangles = myvtxcnt;

	// adaptively adjust resolution threshold up or down to attain
	// the desired polygon (vertex) count target
	int diff = m_iDrawnTriangles - m_iPolygonTarget;
	int iRange = m_iPolygonTarget / 10;		// ensure within 10%

	// If we aren't within the triangle count range adjust the input resolution
	// like a binary search
	if (diff < -iRange || diff > iRange)
	{
//		VTLOG("diff %d, ", diff);
		if (diff < -iRange)
		{
			m_fLResolution = m_fResolution;

			// if the high end isn't high enough, double it
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("increase HRes, ");
				m_fHResolution *= 10;
			}
		}
		else
		{
			m_fHResolution = m_fResolution;
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("decrease LRes, ");
				m_fLResolution = 0;
			}
		}
		m_fResolution = m_fLResolution + (m_fHResolution - m_fLResolution) / 2;
//		VTLOG("rez: [%.1f, %.1f, %.1f] (%d/%d)\n", m_fLResolution, m_fResolution, m_fHResolution, m_iDrawnTriangles, m_iPolygonTarget);

		// keep the error within reasonable bounds
		if (m_fResolution < 5.0f)
			m_fResolution = 5.0f;
		if (m_fResolution > 4E7)
			m_fResolution = 4E7;
	}
}

//
// These methods are called when the framework needs to know the surface
// position of the terrain at a given grid point.  Supply the height
// value from our own data structures.
//
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const
{
	float height = m_pMini->getheight(iX, iZ);

	if (iX<0 || iX>m_iColumns-1 || iZ<0 || iZ>m_iRows-1)
		return 0.0f;

	if (bTrue)
		// convert stored value to true value
		return height / m_fMaximumScale;
	else
		// convert stored value to drawn value
		return height * m_fDrawScale;
}

void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const
{
	float height = m_pMini->getheight(i, j);

	if (bTrue)
		// convert stored value to true value
		height /= m_fMaximumScale;
	else
		// convert stored value to drawn value
		height *= m_fDrawScale;

	p.Set(m_fXLookup[i],
		  height,
		  m_fZLookup[j]);
}

void SRTerrain::SetPolygonCount(int iPolygonCount)
{
	vtDynTerrainGeom::SetPolygonCount(iPolygonCount);
	m_fResolution = iPolygonCount * 5;
	m_fHResolution = 2 * m_fResolution;
	m_fLResolution = 0;
}

#endif	// VTLIB_NI
<commit_msg>updated for libMini 5.4<commit_after>//
// SRTerrain class : a subclass of vtDynTerrainGeom which encapsulates
//  Stefan Roettger's CLOD algorithm.
//
// utilizes: Roettger's MINI library implementation
// http://wwwvis.informatik.uni-stuttgart.de/~roettger
//
// Copyright (c) 2002-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "SRTerrain.h"
#include "vtdata/vtLog.h"

#if VTLIB_NI
// stub
SRTerrain::SRTerrain() {}
SRTerrain::~SRTerrain() {}
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const { return 0; }
void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const {}
void SRTerrain::DoCulling(const vtCamera *pCam) {}
void SRTerrain::DoRender() {}
void SRTerrain::SetVerticalExag(float fExag) {}
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale) { return DTErr_NOMEM; }
#else

#include "mini.h"
#include "ministub.hpp"

using namespace mini;
#ifdef _MSC_VER
#pragma comment( lib, "libMini.lib" )
#endif

/////////////////////////////////////////////////////////////////////////////

//
// Constructor/destructor
//
SRTerrain::SRTerrain() : vtDynTerrainGeom()
{
	m_fResolution	= 10000.0f;
	m_fHResolution	= 20000.0f;
	m_fLResolution	=     0.0f;
	m_pMini = NULL;
}

SRTerrain::~SRTerrain()
{
	if (m_pMini)
	{
		delete m_pMini;
		m_pMini = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////

//
// Unfortunately the following statics are required because libMini only
// supports some functionality by callback, and the callback is only a
// simple C function which has no context to tell us which terrain.
//
static const vtElevationGrid *s_pGrid;
static SRTerrain *s_pSRTerrain;
static int myfancnt, myvtxcnt;
static int s_iRows;

void beginfan_vtp()
{
	if (myfancnt++>0)
		glEnd();
	glBegin(GL_TRIANGLE_FAN);
	myvtxcnt-=2;	// 2 vertices are needed to start each fan
}

void fanvertex_vtp(float x, float y, float z)
{
	glVertex3f(x,y,z);
	myvtxcnt++;
}

void notify_vtp(int i, int j, int size)
{
	// check to see if we need to switch texture
	if (s_pSRTerrain->m_iTPatchDim > 1 && size == s_pSRTerrain->m_iBlockSize)
	{
		int a = i / size;
		int b = j / size;
		s_pSRTerrain->LoadBlockMaterial(a, b);
	}
}

short int getelevation_vtp1(int i, int j, int size, void *data_unused)
{
	return s_pGrid->GetValue(i, s_iRows-1-j);
}

float getelevation_vtp2(int i, int j, int size, void *data_unused)
{
	return s_pGrid->GetFValue(i, s_iRows-1-j);
}

//
// Initialize the terrain data
// fZScale converts from height values (meters) to world coordinates
//
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale)
{
	// Initializes necessary field of the parent class
	DTErr err = BasicInit(pGrid);
	if (err != DTErr_OK)
		return err;

	if (m_iColumns != m_iRows)
		return DTErr_NOTSQUARE;

	// compute n (log2 of grid size)
	// ensure that the grid is size (1 << n) + 1
	int n = vt_log2(m_iColumns - 1);
	int required_size = (1<<n) + 1;
	if (m_iColumns != required_size || m_iRows != required_size)
		return DTErr_NOTPOWER2;

	int size = m_iColumns;
	float dim = m_fXStep;
	float cellaspect = m_fZStep / m_fXStep;

	s_pGrid = pGrid;
	s_iRows = m_iRows;

#if 0
	// NOTE: the following workaround is no longer needed with libMini 5.02
	//
	// Totally strange but repeatable behavior: runtime exit in Release-mode
	//  libMini with values over a certain level.  Workaround here!
	// Exit happens if (scale * maximum_height / dim > 967)
	//
	// 	scale * maximum_height / dim > 967
	//	scale > dim * 967 / maximum_height
	//
	float fMin, fMax;
	pGrid->GetHeightExtents(fMin, fMax);
	// Avoid trouble with fMax small or zero
	if (fMax < 10) fMax = 10;
	// compute the largest supported value for MaxScale
	float fMaxMax = dim * 960 / fMax;
	// values greater than 10 are unnecessarily large
	if (fMaxMax > 10)
		fMaxMax = 10;
	m_fMaximumScale = fMaxMax;
#else
	// This maxiumum scale is a reasonable tradeoff between the exaggeration
	//  that the user is likely to need, and numerical precision issues.
	m_fMaximumScale = 10;
#endif

	m_fHeightScale = fZScale;
	m_fDrawScale = m_fHeightScale / m_fMaximumScale;

	if (pGrid->IsFloatMode())
	{
		float *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				0.0f, 0.0f, 0.0f,	// grid center
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp2);
	}
	else
	{
		short *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				0.0f, 0.0f, 0.0f,	// grid center
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp1);
	}

	m_iDrawnTriangles = -1;
	m_iBlockSize = m_iColumns / 4;

	return DTErr_OK;
}

void SRTerrain::SetVerticalExag(float fExag)
{
	m_fHeightScale = fExag;

	// safety check
	if (m_fHeightScale > m_fMaximumScale)
		m_fHeightScale = m_fMaximumScale;

	m_fDrawScale = m_fHeightScale / m_fMaximumScale;
}

//
// This will be called once per frame, during the culling pass.
//
// However, libMini does not allow you to call the culling pass
// independently of the rendering pass, so we cannot do culling here.
// Instead, just store the values for later use.
//
void SRTerrain::DoCulling(const vtCamera *pCam)
{
	// Grab necessary values from the VTP Scene framework, store for later
	m_eyepos_ogl = pCam->GetTrans();
	m_window_size = vtGetScene()->GetWindowSize();
	m_fAspect = (float)m_window_size.x / m_window_size.y;
	m_fNear = pCam->GetHither();
	m_fFar = pCam->GetYon();

	// Get up vector and direction vector from camera matrix
	FMatrix4 mat;
	pCam->GetTransform1(mat);
	FPoint3 up(0.0f, 1.0f, 0.0f);
	mat.TransformVector(up, eye_up);

	FPoint3 forward(0.0f, 0.0f, -1.0f);
	mat.TransformVector(forward, eye_forward);

	if (pCam->IsOrtho())
	{
		// libMini supports orthographic viewing as of libMini 5.0.
		// A negative FOV value indicates to the library that the FOV is
		//  actually the orthographic height of the camera.
		m_fFOVY = pCam->GetWidth() / m_fAspect;
		m_fFOVY = -m_fFOVY;
	}
	else
	{
		float fov = pCam->GetFOV();
		float fov_y2 = atan(tan (fov/2) / m_fAspect);
		m_fFOVY = fov_y2 * 2.0f * 180 / PIf;
	}
}

void SRTerrain::DoRender()
{
	// Prepare the render state for our OpenGL usage
	PreRender();

	// Render the triangles
	RenderSurface();

	// Clean up
	PostRender();
}

void SRTerrain::LoadSingleMaterial()
{
	// single texture for the whole terrain
	vtMaterial *pMat = GetMaterial(0);
	if (pMat)
	{
		pMat->Apply();
		SetupTexGen(1.0f);
	}
}

void SRTerrain::LoadBlockMaterial(int a, int b)
{
	// we can't change the texture between glBegin/glEnd
	if (myfancnt++>0)
		glEnd();

	// each block has it's own texture map
	int matidx = a*m_iTPatchDim + (m_iTPatchDim-1-b);
	vtMaterial *pMat = GetMaterial(matidx);
	if (pMat)
	{
		pMat->Apply();
		SetupBlockTexGen(a, b);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glBegin(GL_TRIANGLE_FAN);
}

void SRTerrain::RenderSurface()
{
	s_pSRTerrain = this;

	if (m_iTPatchDim == 1)
		LoadSingleMaterial();

	RenderPass();

	// how to do a second rendering pass
	if (m_bDetailTexture)
	{
		// once again, with the detail texture material
		m_pDetailMat->Apply();

		// the uv tiling is different (usually highly repetitive)
		SetupTexGen(m_fDetailTiling);

		// draw the second pass
		glPolygonOffset(-1.0f, -1.0f);
		glEnable(GL_POLYGON_OFFSET_FILL);
		RenderPass();
		glDisable(GL_POLYGON_OFFSET_FILL);
	}
	DisableTexGen();
}

void SRTerrain::RenderPass()
{
	float ex = m_eyepos_ogl.x;
	float ey = m_eyepos_ogl.y;
	float ez = m_eyepos_ogl.z;

	float fov = m_fFOVY;

	float ux = eye_up.x;
	float uy = eye_up.y;
	float uz = eye_up.z;

	float dx = eye_forward.x;
	float dy = eye_forward.y;
	float dz = eye_forward.z;

	myfancnt = myvtxcnt = 0;

	// Convert the eye location to the unusual coordinate scheme of libMini.
	ex -= (m_iColumns/2)*m_fXStep;
	ez += (m_iRows/2)*m_fZStep;

	m_pMini->draw(m_fResolution,
				ex, ey, ez,
				dx, dy, dz,
				ux, uy, uz,
				fov, m_fAspect,
				m_fNear, m_fFar,
				m_fDrawScale);

	if (myfancnt>0) glEnd();

	// We are drawing fans, so the number of triangles is roughly equal to
	// number of vertices
	m_iDrawnTriangles = myvtxcnt;

	// adaptively adjust resolution threshold up or down to attain
	// the desired polygon (vertex) count target
	int diff = m_iDrawnTriangles - m_iPolygonTarget;
	int iRange = m_iPolygonTarget / 10;		// ensure within 10%

	// If we aren't within the triangle count range adjust the input resolution
	// like a binary search
	if (diff < -iRange || diff > iRange)
	{
//		VTLOG("diff %d, ", diff);
		if (diff < -iRange)
		{
			m_fLResolution = m_fResolution;

			// if the high end isn't high enough, double it
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("increase HRes, ");
				m_fHResolution *= 10;
			}
		}
		else
		{
			m_fHResolution = m_fResolution;
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("decrease LRes, ");
				m_fLResolution = 0;
			}
		}
		m_fResolution = m_fLResolution + (m_fHResolution - m_fLResolution) / 2;
//		VTLOG("rez: [%.1f, %.1f, %.1f] (%d/%d)\n", m_fLResolution, m_fResolution, m_fHResolution, m_iDrawnTriangles, m_iPolygonTarget);

		// keep the error within reasonable bounds
		if (m_fResolution < 5.0f)
			m_fResolution = 5.0f;
		if (m_fResolution > 4E7)
			m_fResolution = 4E7;
	}
}

//
// These methods are called when the framework needs to know the surface
// position of the terrain at a given grid point.  Supply the height
// value from our own data structures.
//
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const
{
	float height = m_pMini->getheight(iX, iZ);

	if (iX<0 || iX>m_iColumns-1 || iZ<0 || iZ>m_iRows-1)
		return 0.0f;

	if (bTrue)
		// convert stored value to true value
		return height / m_fMaximumScale;
	else
		// convert stored value to drawn value
		return height * m_fDrawScale;
}

void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const
{
	float height = m_pMini->getheight(i, j);

	if (bTrue)
		// convert stored value to true value
		height /= m_fMaximumScale;
	else
		// convert stored value to drawn value
		height *= m_fDrawScale;

	p.Set(m_fXLookup[i],
		  height,
		  m_fZLookup[j]);
}

void SRTerrain::SetPolygonCount(int iPolygonCount)
{
	vtDynTerrainGeom::SetPolygonCount(iPolygonCount);
	m_fResolution = iPolygonCount * 5;
	m_fHResolution = 2 * m_fResolution;
	m_fLResolution = 0;
}

#endif	// VTLIB_NI
<|endoftext|>