<commit_before>#include <SPI.h>
#include "RF24.h"
#include <ArduinoHardware.h>

/* Definições */
#define NUMBER_OF_ROBOTS 5

/* Declaração das funções */
void radioSetup();
void enviaMensagem();
void atualizaVelocidades();

/* Pinos para o rádio */
int CE = 3;
int CS = 2;

/* Objeto que gerencia o rádio */
RF24 radio(CE,CS);

/* Endereços */
uint64_t txPipeAddress = 0xABCDABCD71L;
uint64_t rxPipeAddress = 0x744d52687CL;

/* Estrutura para a mensagem a ser transmitida */
struct Velocidade{
  int16_t motorA[5];
  int16_t motorB[5];
};

/* Estrutura para a mensagem a ser recebida do USB */
struct VelocidadeSerial {
  Velocidade data;
  int16_t checksum;
};

/* Mensagem a ser transmitida */
Velocidade velocidades;

/* Contagem de erros de transmissão via USB detectados */
uint32_t erros = 0;
uint32_t lastOK = 0;

/* Loop de setup */
void setup(void) {
  Serial.begin(115200);
  //radioSetup();
  pinMode(LED_BUILTIN, OUTPUT);
}

/* Loop que é executado continuamente */
void loop(){
  atualizaVelocidades();
  //enviaMensagem();
  //recebeDadosDebug();
  //enviaDebugSerial();
  if(millis()-lastOK < 5){
    digitalWrite(LED_BUILTIN, HIGH);
  }
  else{
    digitalWrite(LED_BUILTIN, LOW);
  }
}

/* Envia a mensagem pelo rádio */
void enviaMensagem(){
  // Garante que o rádio não está escutando
  radio.stopListening();

  // Permite chamadas de write sem ACK
  radio.enableDynamicAck();

  // Abre um pipe para escrita
  radio.openWritingPipe(txPipeAddress);

  // Envia a mensagem
  radio.write(&velocidades,sizeof(velocidades), 1);
}

/* Configura o rádio */
void radioSetup(){
  // inicializa radio
  radio.begin();

  // muda para um canal de frequencia diferente de 2.4Ghz
  radio.setChannel(108);

  // usa potencia maxima
  radio.setPALevel(RF24_PA_MAX);

  // usa velocidade maxima
  radio.setDataRate(RF24_2MBPS);

  // escuta pelo pipe1
  radio.openReadingPipe(1,rxPipeAddress);

  // ativa payloads dinamicos(pacote tamamhos diferentes do padrao)
  radio.enableDynamicPayloads();

  // ajusta o tamanho dos pacotes ao tamanho da mensagem
  radio.setPayloadSize(sizeof(velocidades));

  // Start listening
  radio.startListening();
}

/* Lê do serial novas velocidades */
void atualizaVelocidades(){
  int initCounter = 0;
  while(Serial.available()){
    /* Lê um caracter da mensagem */
    char character = Serial.read();

    /* Incrementa o contador se for 'B' */
    if(character == 'B') initCounter++;

    /* Se os três primeiros caracteres são 'B' então de fato é o início da mensagem */
    if(initCounter >= 3){
      VelocidadeSerial receber;

      /* Lê a mensagem até o caracter de terminação e a decodifica */
      Serial.readBytes((char*)(&receber), (size_t)sizeof(VelocidadeSerial));

      /* Faz o checksum */
      int16_t checksum = 0;
      for(int i=0 ; i<5 ; i++){
        checksum += receber.data.motorA[i] + receber.data.motorB[i];
      }

      /* Verifica o checksum */
      if(checksum == receber.checksum){
        /* Copia para o buffer global de velocidades */
        velocidades = receber.data;

        /* Reporta que deu certo */
        Serial.printf("%d\t%d\t%d\n", checksum, velocidades.motorA[0], velocidades.motorB[0]);
        lastOK = millis();
      }
      else {
        /* Devolve o checksum calculado se deu errado */
        Serial.printf("%d\t%d\t%d\n", checksum, velocidades.motorA[0], velocidades.motorB[0]);
      }

      /* Zera o contador */
      initCounter = 0;
    }
  }
}
<commit_msg>Versao testada com o radio no ESP32 e os pinos 12 para CE e 13 para CS alem dos pinos de SCK (18), MOSI (23) e MISO (19)<commit_after>#include <SPI.h>
#include "RF24.h"
#include <ArduinoHardware.h>

/* Definições */
#define NUMBER_OF_ROBOTS 5

/* Declaração das funções */
void radioSetup();
void enviaMensagem();
void atualizaVelocidades();

/* Pinos para o rádio */
int CE = 12;
int CS = 13;

/* Objeto que gerencia o rádio */
RF24 radio(CE,CS);

/* Endereços */
uint64_t txPipeAddress = 0xABCDABCD71L;
uint64_t rxPipeAddress = 0x744d52687CL;

/* Estrutura para a mensagem a ser transmitida */
struct Velocidade{
  int16_t motorA[5];
  int16_t motorB[5];
};

/* Estrutura para a mensagem a ser recebida do USB */
struct VelocidadeSerial {
  Velocidade data;
  int16_t checksum;
};

/* Mensagem a ser transmitida */
Velocidade velocidades;

/* Contagem de erros de transmissão via USB detectados */
uint32_t erros = 0;
uint32_t lastOK = 0;

/* Loop de setup */
void setup(void) {
  Serial.begin(115200);
  while(!Serial);
  radioSetup();
  pinMode(LED_BUILTIN, OUTPUT);
}

/* Loop que é executado continuamente */
void loop(){
  atualizaVelocidades();
  enviaMensagem();
  //recebeDadosDebug();
  //enviaDebugSerial();
  if(millis()-lastOK < 5){
    digitalWrite(LED_BUILTIN, HIGH);
  }
  else{
    digitalWrite(LED_BUILTIN, LOW);
  }
  //delay(5);
  /*digitalWrite(LED_BUILTIN, HIGH);
  sleep(1);
  digitalWrite(LED_BUILTIN, LOW);
  sleep(1);*/
}

/* Envia a mensagem pelo rádio */
void enviaMensagem(){
  // Garante que o rádio não está escutando
  //radio.stopListening();

  // Permite chamadas de write sem ACK
  radio.enableDynamicAck();

  // Abre um pipe para escrita
  radio.openWritingPipe(txPipeAddress);

  // Envia a mensagem
  radio.write(&velocidades,sizeof(velocidades), 1);
}

/* Configura o rádio */
void radioSetup(){
  // inicializa radio
  radio.begin();

  // muda para um canal de frequencia diferente de 2.4Ghz
  radio.setChannel(108);

  // usa potencia maxima
  radio.setPALevel(RF24_PA_MAX);

  // usa velocidade maxima
  radio.setDataRate(RF24_2MBPS);

  // escuta pelo pipe1
  radio.openReadingPipe(1,rxPipeAddress);

  // ativa payloads dinamicos(pacote tamamhos diferentes do padrao)
  radio.enableDynamicPayloads();

  // ajusta o tamanho dos pacotes ao tamanho da mensagem
  radio.setPayloadSize(sizeof(velocidades));

  // Start listening
  radio.startListening();

  radio.stopListening();
}

/* Lê do serial novas velocidades */
void atualizaVelocidades(){
  int initCounter = 0;

  while(Serial.available()){
    /* Lê um caracter da mensagem */
    char character = Serial.read();

    /* Incrementa o contador se for 'B' */
    if(character == 'B') initCounter++;

    /* Se os três primeiros caracteres são 'B' então de fato é o início da mensagem */
    if(initCounter >= 3){
      VelocidadeSerial receber;

      /* Lê a mensagem até o caracter de terminação e a decodifica */
      Serial.readBytes((char*)(&receber), (size_t)sizeof(VelocidadeSerial));

      /* Faz o checksum */
      int16_t checksum = 0;
      for(int i=0 ; i<5 ; i++){
        checksum += receber.data.motorA[i] + receber.data.motorB[i];
      }

      /* Verifica o checksum */
      if(checksum == receber.checksum){
        /* Copia para o buffer global de velocidades */
        velocidades = receber.data;

        /* Reporta que deu certo */
        Serial.printf("%d\t%d\t%d\n", checksum, velocidades.motorA[0], velocidades.motorB[0]);
        lastOK = millis();
      }
      else {
        /* Devolve o checksum calculado se deu errado */
        Serial.printf("%d\t%d\t%d\n", checksum, velocidades.motorA[0], velocidades.motorB[0]);
      }

      /* Zera o contador */
      initCounter = 0;
    }
  }
}
<|endoftext|>


<commit_before>#include <stdexcept>
#include <limits>
#include <algorithm>
#include <array>
#include <memory>
#include <iomanip>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
//#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>

#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
/*
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
*/

#ifndef EFU_CURLEASY_H
#include "curleasy.h"
#endif

#if defined(_WIN32) && !defined(EFU_WINERRORSTRING_H)
#include "win_error_string.hpp"
#endif

const std::string version("0.1.0");
const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");

const std::string file_checksum(const std::string &path);

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

void make_dir(const std::string &path)
{
#ifdef _WIN32
    unsigned file_start = path.find_last_of("/\\");
    if (!CreateDirectory(path.substr(0, file_start).c_str(), nullptr))
    {
        WinErrorString wes;
        if (wes.code() != ERROR_ALREADY_EXISTS)
        {
            throw std::ios_base::failure("sdf" + wes.str());
        }
    }
#else
    auto elems = split(path, '/');
    std::string descend;
    for (size_t i = 0, k = elems.size() - 1; i < k; ++i)
    {
        const std::string &s(elems[i]);
        if (s.size() && s != ".")
        {
            descend.append((i > 0 ? "/" : "") + s);
            auto status = mkdir(descend.c_str(), S_IRWXU);
            if (status == -1)
            {
                std::error_code err(errno, std::generic_category());
                if (err != std::errc::file_exists)
                {
                    std::cout << "error making dir: "
                        << descend << ": "
                        << err.message() << std::endl;
                }
            }
        }
    }
#endif
}

// TODO
#ifdef CPP11_ENUM_CLASS
#define ENUM_CLASS enum class
#else
#define ENUM_CLASS enum
#endif
class Target
{
    public:
        ENUM_CLASS Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ? name :
                    name, name.find_first_of('/') + 1, name.size() - 1),
            m_checksum(checksum)
            {}
        std::string name() const { return m_name; }
        const std::string checksum() const { return m_checksum; }

        void fetch() const
        {
            std::cout << "Statting target " << name() << "...";
            std::fstream fs(name(), std::ios_base::in);
            if (!fs.good())
            {
                fs.close();
                std::cout << " doesn't exist, creating new." << std::endl;
                make_dir(name());
                fs.open(name(), std::ios_base::out);
                if (!fs.good())
                {
                    fs.close();
                    std::cout << "Failed to create file: " << name() << std::endl;
                }
                else
                {
                    fs.close();
                    do_fetch();
                    return;
                }
            }
            if (fs.good())
            {
                fs.close();
                if (status() == Status::Current)
                {
                    std::cout << " already up to date." << std::endl;
                }
                else
                {
                    std::cout << " outdated, downloading new." << std::endl;
                    do_fetch();
                }
            }
        }

        Status status() const
        {
            std::ifstream is(name());
            if (!is.good())
            {
                return Status::Nonexistent;
            }
            is.close();

            auto calcsum(file_checksum(name()));
            if (calcsum == checksum())
            {
                return Status::Current;
            }
            else
            {
                return Status::Outdated;
            }
        }

    private:
        void do_fetch() const
        {
            std::ofstream ofs(name(), std::ios::binary);
            if (ofs.good())
            {
                std::string s;
                std::string url(patch_dir + name());
                CurlEasy curl(url);
                curl.write_to(s);
                curl.progressbar(true);
                curl.perform();

                ofs << s;
                ofs.close();
                std::cout << "Finished downloading " << name() << std::endl;
            }
            else
            {
                std::cout << "Couldn't write to " << name() << std::endl;
            }
        }

        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

const std::string file_checksum(const std::string &path)
{
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ios::binary);
    if (!is.good())
    {
        std::cout << "Couldn't open file " << path
           << " for checksumming." << std::endl;
        return std::string();
    }

    const int length = 8192;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

#ifdef CPP11_FOR_EACH
    for (const unsigned char c : result)
#else
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](const unsigned char c)
#endif
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
#ifndef CPP11_FOR_EACH
    );
#endif

    return calcsum.str();
}

namespace Options
{
    bool version(const std::string &val)
    {
        return val == "version";
    }
    bool update_path(const std::string &val)
    {
        return val == "update path";
    }
};

bool confirm()
{
    char c;
    do
    {
        std::cin >> c;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        c = static_cast<char>(tolower(c));
    } while (c != 'y' && c != 'n');
    return c == 'y';
}

class EfuLauncher
{
    public:
    // TODO: assignment, copy operator
        explicit EfuLauncher(const std::string path,
                const std::string update_check):
            m_path(path),
            m_update_check(update_check),
            m_has_update(false)
    {}

        bool has_update()
        {
            if (m_has_update)
            {
                return m_has_update;
            }

            std::string fetch;
            CurlEasy curl(m_update_check.c_str());
            curl.write_to(fetch);
            //TODO
            try
            {
                curl.perform();
            }
            catch (CurlEasyException &e)
            {
                std::cout << e.what() << std::endl;
            }

            std::vector<std::string> lines(split(fetch, '\n'));
            fetch.clear();
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto keyvals(split(*beg, '='));
                if (keyvals.size() != 2)
                {
                    std::cerr << "Malformed option: " + *beg +
                        ", aborting launcher update check." << std::endl;
                    return m_has_update = false;
                }
                if (Options::version(keyvals[0]))
                {
                    const std::string version_test(keyvals[1]);
                    m_has_update = version_test != version;
                }
                else if (Options::update_path(keyvals[0]))
                {
                    m_update_path = keyvals[1];
                }

            }
            return m_has_update;
        }

        bool get_update()
        {
            if (!m_has_update || m_update_path.empty())
            {
                return m_has_update = false;
            }
            return !(m_has_update = false);
        }

        void stat_targets()
        {
            std::string fetch;
            CurlEasy curl(listing);
            curl.write_to(fetch);
            curl.perform();

            auto lines(split(fetch, '\n'));
            std::vector<Target> new_targets, old_targets;
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto data(split(*beg, '@'));
                Target t(data[0], data[data.size() - 1]);
                auto status = t.status();
// TODO
#ifdef CPP11_ENUM_CLASS
                if (status == Target::Status::Nonexistent)
#else
                if (status == Target::Nonexistent)
#endif
                {
                    new_targets.push_back(std::move(t));
                }
// TODO
#ifdef CPP11_ENUM_CLASS
                else if (status == Target::Status::Outdated)
#else
                else if (status == Target::Outdated)
#endif
                {
                    old_targets.push_back(std::move(t));
                }
            }
            if (new_targets.size())
            {
                std::cout << "New targets: " << new_targets.size() << std::endl;
#ifdef CPP11_FOR_EACH
                for (auto &t : new_targets)
#else
                std::for_each(new_targets.cbegin(), new_targets.cend(),
                    [](const Target &t)
#endif
                {
                    std::cout << "- " << t.name() << std::endl;
                }
#ifndef CPP11_FOR_EACH
                );
#endif
            }
            else
            {
                std::cout << "No new targets." << std::endl;
            }

            if (old_targets.size())
            {
                std::cout << "Outdated targets: " << old_targets.size() << std::endl;
#ifdef CPP11_FOR_EACH
                for (auto &t : old_targets)
#else
                std::for_each(old_targets.cbegin(), old_targets.cend(),
                    [](const Target &t)
#endif
                {
                    std::cout << "- " << t.name() << std::endl;
                }
#ifndef CPP11_FOR_EACH
                );
#endif
            }
            else
            {
                std::cout << "No targets out of date." << std::endl;
            }

#ifndef DEBUG
#ifdef CPP11_FOR_EACH
            for (auto &t : new_targets)
#else
            std::for_each(new_targets.cbegin(), new_targets.cend(),
                [](const Target &t)
#endif
            {
                t.fetch();
            }
#ifndef CPP11_FOR_EACH
            );

            std::for_each(old_targets.cbegin(), old_targets.cend(),
                [](const Target &t)
#else
            for (auto &t : old_targets)
#endif
            {
                t.fetch();
            }
#ifndef CPP11_FOR_EACH
            );
#endif
#endif
        }

    private:
        const std::string path() const { return m_path; }

        const std::string m_path;
        const std::string m_update_check;
        std::string m_update_path;
        bool m_has_update;
};

int main(int argc, char *argv[])
{
    CurlGlobalInit curl_global;

    EfuLauncher l(argv[0],
            "https://raw.github.com/commonquail/efulauncher/"\
            "master/versioncheck");

    if (l.has_update())
    {
        std::cout << "A new version of the launcher is available."\
            " Would you like to download it (y/n)?" << std::endl;
        bool download(confirm());
        if (!download)
        {
            std::cout << "It is strongly recommended to always use"\
                " the latest launcher. Would you like to download it (y/n)?"
                << std::endl;
            download = confirm();
        }
        if (download)
        {
            // Download.
            std::cout << "Downloading new launcher..." << std::endl;
            if (l.get_update())
            {
                std::cout << "Done. Please extract and run the new launcher." << std::endl;
            }
            return 0;
        }
    }

    try
    {
        l.stat_targets();
    }
    catch (std::exception &e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}
<commit_msg>Use more readable numbers and rely on constant folding.<commit_after>#include <stdexcept>
#include <limits>
#include <algorithm>
#include <array>
#include <memory>
#include <iomanip>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
//#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>

#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
/*
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
*/

#ifndef EFU_CURLEASY_H
#include "curleasy.h"
#endif

#if defined(_WIN32) && !defined(EFU_WINERRORSTRING_H)
#include "win_error_string.hpp"
#endif

const std::string version("0.1.0");
const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");

const std::string file_checksum(const std::string &path);

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

void make_dir(const std::string &path)
{
#ifdef _WIN32
    unsigned file_start = path.find_last_of("/\\");
    if (!CreateDirectory(path.substr(0, file_start).c_str(), nullptr))
    {
        WinErrorString wes;
        if (wes.code() != ERROR_ALREADY_EXISTS)
        {
            throw std::ios_base::failure("sdf" + wes.str());
        }
    }
#else
    auto elems = split(path, '/');
    std::string descend;
    for (size_t i = 0, k = elems.size() - 1; i < k; ++i)
    {
        const std::string &s(elems[i]);
        if (s.size() && s != ".")
        {
            descend.append((i > 0 ? "/" : "") + s);
            auto status = mkdir(descend.c_str(), S_IRWXU);
            if (status == -1)
            {
                std::error_code err(errno, std::generic_category());
                if (err != std::errc::file_exists)
                {
                    std::cout << "error making dir: "
                        << descend << ": "
                        << err.message() << std::endl;
                }
            }
        }
    }
#endif
}

// TODO
#ifdef CPP11_ENUM_CLASS
#define ENUM_CLASS enum class
#else
#define ENUM_CLASS enum
#endif
class Target
{
    public:
        ENUM_CLASS Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ? name :
                    name, name.find_first_of('/') + 1, name.size() - 1),
            m_checksum(checksum)
            {}
        std::string name() const { return m_name; }
        const std::string checksum() const { return m_checksum; }

        void fetch() const
        {
            std::cout << "Statting target " << name() << "...";
            std::fstream fs(name(), std::ios_base::in);
            if (!fs.good())
            {
                fs.close();
                std::cout << " doesn't exist, creating new." << std::endl;
                make_dir(name());
                fs.open(name(), std::ios_base::out);
                if (!fs.good())
                {
                    fs.close();
                    std::cout << "Failed to create file: " << name() << std::endl;
                }
                else
                {
                    fs.close();
                    do_fetch();
                    return;
                }
            }
            if (fs.good())
            {
                fs.close();
                if (status() == Status::Current)
                {
                    std::cout << " already up to date." << std::endl;
                }
                else
                {
                    std::cout << " outdated, downloading new." << std::endl;
                    do_fetch();
                }
            }
        }

        Status status() const
        {
            std::ifstream is(name());
            if (!is.good())
            {
                return Status::Nonexistent;
            }
            is.close();

            auto calcsum(file_checksum(name()));
            if (calcsum == checksum())
            {
                return Status::Current;
            }
            else
            {
                return Status::Outdated;
            }
        }

    private:
        void do_fetch() const
        {
            std::ofstream ofs(name(), std::ios::binary);
            if (ofs.good())
            {
                std::string s;
                std::string url(patch_dir + name());
                CurlEasy curl(url);
                curl.write_to(s);
                curl.progressbar(true);
                curl.perform();

                ofs << s;
                ofs.close();
                std::cout << "Finished downloading " << name() << std::endl;
            }
            else
            {
                std::cout << "Couldn't write to " << name() << std::endl;
            }
        }

        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

const std::string file_checksum(const std::string &path)
{
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ios::binary);
    if (!is.good())
    {
        std::cout << "Couldn't open file " << path
           << " for checksumming." << std::endl;
        return std::string();
    }

    const int length = 8 * 1024;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

#ifdef CPP11_FOR_EACH
    for (const unsigned char c : result)
#else
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](const unsigned char c)
#endif
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
#ifndef CPP11_FOR_EACH
    );
#endif

    return calcsum.str();
}

namespace Options
{
    bool version(const std::string &val)
    {
        return val == "version";
    }
    bool update_path(const std::string &val)
    {
        return val == "update path";
    }
};

bool confirm()
{
    char c;
    do
    {
        std::cin >> c;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        c = static_cast<char>(tolower(c));
    } while (c != 'y' && c != 'n');
    return c == 'y';
}

class EfuLauncher
{
    public:
    // TODO: assignment, copy operator
        explicit EfuLauncher(const std::string path,
                const std::string update_check):
            m_path(path),
            m_update_check(update_check),
            m_has_update(false)
    {}

        bool has_update()
        {
            if (m_has_update)
            {
                return m_has_update;
            }

            std::string fetch;
            CurlEasy curl(m_update_check.c_str());
            curl.write_to(fetch);
            //TODO
            try
            {
                curl.perform();
            }
            catch (CurlEasyException &e)
            {
                std::cout << e.what() << std::endl;
            }

            std::vector<std::string> lines(split(fetch, '\n'));
            fetch.clear();
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto keyvals(split(*beg, '='));
                if (keyvals.size() != 2)
                {
                    std::cerr << "Malformed option: " + *beg +
                        ", aborting launcher update check." << std::endl;
                    return m_has_update = false;
                }
                if (Options::version(keyvals[0]))
                {
                    const std::string version_test(keyvals[1]);
                    m_has_update = version_test != version;
                }
                else if (Options::update_path(keyvals[0]))
                {
                    m_update_path = keyvals[1];
                }

            }
            return m_has_update;
        }

        bool get_update()
        {
            if (!m_has_update || m_update_path.empty())
            {
                return m_has_update = false;
            }
            return !(m_has_update = false);
        }

        void stat_targets()
        {
            std::string fetch;
            CurlEasy curl(listing);
            curl.write_to(fetch);
            curl.perform();

            auto lines(split(fetch, '\n'));
            std::vector<Target> new_targets, old_targets;
            for (auto beg = std::begin(lines), end = std::end(lines);
                    beg != end; ++beg)
            {
                auto data(split(*beg, '@'));
                Target t(data[0], data[data.size() - 1]);
                auto status = t.status();
// TODO
#ifdef CPP11_ENUM_CLASS
                if (status == Target::Status::Nonexistent)
#else
                if (status == Target::Nonexistent)
#endif
                {
                    new_targets.push_back(std::move(t));
                }
// TODO
#ifdef CPP11_ENUM_CLASS
                else if (status == Target::Status::Outdated)
#else
                else if (status == Target::Outdated)
#endif
                {
                    old_targets.push_back(std::move(t));
                }
            }
            if (new_targets.size())
            {
                std::cout << "New targets: " << new_targets.size() << std::endl;
#ifdef CPP11_FOR_EACH
                for (auto &t : new_targets)
#else
                std::for_each(new_targets.cbegin(), new_targets.cend(),
                    [](const Target &t)
#endif
                {
                    std::cout << "- " << t.name() << std::endl;
                }
#ifndef CPP11_FOR_EACH
                );
#endif
            }
            else
            {
                std::cout << "No new targets." << std::endl;
            }

            if (old_targets.size())
            {
                std::cout << "Outdated targets: " << old_targets.size() << std::endl;
#ifdef CPP11_FOR_EACH
                for (auto &t : old_targets)
#else
                std::for_each(old_targets.cbegin(), old_targets.cend(),
                    [](const Target &t)
#endif
                {
                    std::cout << "- " << t.name() << std::endl;
                }
#ifndef CPP11_FOR_EACH
                );
#endif
            }
            else
            {
                std::cout << "No targets out of date." << std::endl;
            }

#ifndef DEBUG
#ifdef CPP11_FOR_EACH
            for (auto &t : new_targets)
#else
            std::for_each(new_targets.cbegin(), new_targets.cend(),
                [](const Target &t)
#endif
            {
                t.fetch();
            }
#ifndef CPP11_FOR_EACH
            );

            std::for_each(old_targets.cbegin(), old_targets.cend(),
                [](const Target &t)
#else
            for (auto &t : old_targets)
#endif
            {
                t.fetch();
            }
#ifndef CPP11_FOR_EACH
            );
#endif
#endif
        }

    private:
        const std::string path() const { return m_path; }

        const std::string m_path;
        const std::string m_update_check;
        std::string m_update_path;
        bool m_has_update;
};

int main(int argc, char *argv[])
{
    CurlGlobalInit curl_global;

    EfuLauncher l(argv[0],
            "https://raw.github.com/commonquail/efulauncher/"\
            "master/versioncheck");

    if (l.has_update())
    {
        std::cout << "A new version of the launcher is available."\
            " Would you like to download it (y/n)?" << std::endl;
        bool download(confirm());
        if (!download)
        {
            std::cout << "It is strongly recommended to always use"\
                " the latest launcher. Would you like to download it (y/n)?"
                << std::endl;
            download = confirm();
        }
        if (download)
        {
            // Download.
            std::cout << "Downloading new launcher..." << std::endl;
            if (l.get_update())
            {
                std::cout << "Done. Please extract and run the new launcher." << std::endl;
            }
            return 0;
        }
    }

    try
    {
        l.stat_targets();
    }
    catch (std::exception &e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"

#include "map/map.h"
#include "map/water.h"
#include "map/terrain.h"

#include "stratlib/player_state.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  auto cam_ptr = glfwGetWindowUserPointer(window);
  auto& camera = *((game::gfx::Camera*) cam_ptr);

  camera.fp.pos += -deltay;
}

game::ui::Mouse_State gen_mouse_state(GLFWwindow* w)
{
  game::ui::Mouse_State ret;

  ret.button_down =glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;

  game::Vec<double> pos;
  glfwGetCursorPos(w, &pos.x, &pos.y);
  ret.position = game::vec_cast<int>(pos);

  return ret;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

struct Command_Options
{
};

Command_Options parse_command_line(int argc, char**)
{
  Command_Options opt;
  for(int i = 0; i < argc; ++i)
  {
    //auto option = argv[i];
  }
  return opt;
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Parse command line arguments.
  auto options = parse_command_line(argc - 1, argv+1);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  {
  // Make an OpenGL driver.
  gfx::gl::Driver driver{Vec<int>{1000, 1000}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/v");
  default_shader->load_fragment_part("shader/basic/f");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Make an isometric camera.
  auto cam = gfx::make_isometric_camera();

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();
  Map map({1000, 1000}); // <-- Map size for now
  strat::Player_State player_state{strat::Player_State_Type::Nothing};

  auto structures_future =
    std::async(std::launch::async, load_structures,"structure/structures.json",
               ref_mo(structure_mesh));

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Our quick hack to avoid splitting into multiple functions and dealing
  // either with global variables or like a bound struct or something.
  bool has_clicked_down = false;

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  auto controller = ui::Simple_Controller{};

  auto structures = structures_future.get();

  hud->find_child_r("build_house")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[0];
  });
  hud->find_child_r("build_gvn_build")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[1];
  });

  hud->layout(driver.window_extents());

  controller.add_drag_listener([&](auto const& np, auto const& op)
  {
    // pan
    auto movement = vec_cast<float>(np - op);
    movement /= -75;

    glm::vec4 move_vec(movement.x, 0.0f, movement.y, 0.0f);
    move_vec = glm::inverse(camera_view_matrix(cam)) * move_vec;

    cam.fp.pos.x += move_vec.x;
    cam.fp.pos.z += move_vec.z;
  });

  glfwSetWindowUserPointer(window, &cam);
  glfwSetScrollCallback(window, scroll_callback);

  //water_obj.material->diffuse_color = Color{0xaa, 0xaa, 0xff};

  while(!glfwWindowShouldClose(window))
  {
    ++fps;
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, cam);

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    // Render the terrain before we calculate the depth of the mouse position.
    auto mouse_state = gen_mouse_state(window);
    controller.step(hud, mouse_state);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};
      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();
  }
  }
  glfwTerminate();
  return 0;
}
<commit_msg>We are now using the map mouse-unprojecting function in our main loop.<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"

#include "map/map.h"
#include "map/water.h"
#include "map/terrain.h"

#include "stratlib/player_state.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  auto cam_ptr = glfwGetWindowUserPointer(window);
  auto& camera = *((game::gfx::Camera*) cam_ptr);

  camera.fp.pos += -deltay;
}

game::ui::Mouse_State gen_mouse_state(GLFWwindow* w)
{
  game::ui::Mouse_State ret;

  ret.button_down =glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;

  game::Vec<double> pos;
  glfwGetCursorPos(w, &pos.x, &pos.y);
  ret.position = game::vec_cast<int>(pos);

  return ret;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

struct Command_Options
{
};

Command_Options parse_command_line(int argc, char**)
{
  Command_Options opt;
  for(int i = 0; i < argc; ++i)
  {
    //auto option = argv[i];
  }
  return opt;
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Parse command line arguments.
  auto options = parse_command_line(argc - 1, argv+1);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  {
  // Make an OpenGL driver.
  gfx::gl::Driver driver{Vec<int>{1000, 1000}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/v");
  default_shader->load_fragment_part("shader/basic/f");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Make an isometric camera.
  auto cam = gfx::make_isometric_camera();

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();
  Map map({1000, 1000}); // <-- Map size for now
  strat::Player_State player_state{strat::Player_State_Type::Nothing};

  auto structures_future =
    std::async(std::launch::async, load_structures,"structure/structures.json",
               ref_mo(structure_mesh));

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Our quick hack to avoid splitting into multiple functions and dealing
  // either with global variables or like a bound struct or something.
  bool has_clicked_down = false;

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  auto controller = ui::Simple_Controller{};

  auto structures = structures_future.get();

  hud->find_child_r("build_house")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[0];
  });
  hud->find_child_r("build_gvn_build")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[1];
  });

  hud->layout(driver.window_extents());

  controller.add_drag_listener([&](auto const& np, auto const& op)
  {
    // pan
    auto movement = vec_cast<float>(np - op);
    movement /= -75;

    glm::vec4 move_vec(movement.x, 0.0f, movement.y, 0.0f);
    move_vec = glm::inverse(camera_view_matrix(cam)) * move_vec;

    cam.fp.pos.x += move_vec.x;
    cam.fp.pos.z += move_vec.z;
  });

  glfwSetWindowUserPointer(window, &cam);
  glfwSetScrollCallback(window, scroll_callback);

  //water_obj.material->diffuse_color = Color{0xaa, 0xaa, 0xff};

  while(!glfwWindowShouldClose(window))
  {
    ++fps;
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, cam);

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    // Render the terrain before we calculate the depth of the mouse position.
    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    auto mouse_state = gen_mouse_state(window);

    auto map_coord = unproject_mouse_coordinates(driver, cam, terrain_model,
                                                 mouse_state.position);
    log_i("% %", map_coord.x, map_coord.y);

    controller.step(hud, mouse_state);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};
      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();
  }
  }
  glfwTerminate();
  return 0;
}
<|endoftext|>


<commit_before>// Minimal main example (with truss sdl)

#include "truss.h"
#include "truss_sdl.h"
#include "addons/bgfx_nanovg/nanovg_addon.h"
#include "addons/websocket_client/wsclient_addon.h"
#include <iostream>
#include <sstream>

#if defined(WIN32)
// On Windows, manually construct an RPATH to the `./lib` subdirectory.
#include "windows.h"
void setWindowsRPath() {
	char exe_filepath[MAX_PATH], exe_drive[MAX_PATH], exe_path[MAX_PATH];
	GetModuleFileName(NULL, exe_filepath, MAX_PATH);
	_splitpath_s(exe_filepath, exe_drive, MAX_PATH, exe_path, MAX_PATH, NULL, 0, NULL, 0);
	std::stringstream ss;
	ss << exe_drive << exe_path << "\\lib";
	SetDllDirectory(ss.str().c_str());
}
#endif

void storeArgs(int argc, char** argv) {
	for (int i = 0; i < argc; ++i) {
		std::stringstream ss;
		ss << "arg" << i;
		std::string val(argv[i]);
		trss::core()->setStoreValue(ss.str(), val);
	}
}

int main(int argc, char** argv) {
#	if defined(WIN32)
	setWindowsRPath();
#	endif

	trss_test();
	trss_log(0, "Entered main!");
	storeArgs(argc, argv);

	// set up physFS filesystem
	trss::core()->initFS(argv[0], true); // mount the base directory
	trss::core()->setWriteDir("save");   // write into basedir/save/

	trss::Interpreter* interpreter = trss::core()->spawnInterpreter("interpreter_0");
	interpreter->setDebug(0); // want most verbose debugging output
	// interpreter->attachAddon(new SDLAddon);
	interpreter->attachAddon(new NanoVGAddon);
	interpreter->attachAddon(new WSClientAddon);
	trss_log(0, "Starting interpreter!");
	// startUnthreaded starts the interpreter in the current thread,
	// which means the call will block until the interpreter is stopped
	//interpreter->startUnthreaded("examples/dart_gui_test.t");
	if (argc > 1) {
		interpreter->startUnthreaded(argv[1]);
	}
	else {
		interpreter->startUnthreaded("examples/dart_gui_test.t");
	}
	return 0;
}<commit_msg>Fixed issue with forced loading of windows libraries.<commit_after>// Minimal main example (with truss sdl)

#include "truss.h"
#include "truss_sdl.h"
#include "addons/bgfx_nanovg/nanovg_addon.h"
#include "addons/websocket_client/wsclient_addon.h"
#include <iostream>
#include <sstream>

#if defined(WIN32)
// On Windows, manually construct an RPATH to the `./lib` subdirectory.
// TODO: refactor this into a config.in
#include "windows.h"
void setWindowsRPath() {
	// Get path to current executable.
	char exe_filepath[MAX_PATH], exe_drive[MAX_PATH], exe_path[MAX_PATH];
	GetModuleFileName(NULL, exe_filepath, MAX_PATH);
	_splitpath_s(exe_filepath, exe_drive, MAX_PATH, exe_path, MAX_PATH, NULL, 0, NULL, 0);

	// Add absolute path to "./lib" directory to "RPATH".
	std::stringstream ss;
	ss << exe_drive << exe_path << "\\lib";
	SetDllDirectory(ss.str().c_str());

	// Manually force loading of DELAYLOAD-ed libraries.
	LoadLibrary("bgfx-shared-libRelease.dll");
}
#endif

void storeArgs(int argc, char** argv) {
	for (int i = 0; i < argc; ++i) {
		std::stringstream ss;
		ss << "arg" << i;
		std::string val(argv[i]);
		trss::core()->setStoreValue(ss.str(), val);
	}
}

int main(int argc, char** argv) {
#	if defined(WIN32)
	setWindowsRPath();
#	endif

	trss_test();
	trss_log(0, "Entered main!");
	storeArgs(argc, argv);

	// set up physFS filesystem
	trss::core()->initFS(argv[0], true); // mount the base directory
	trss::core()->setWriteDir("save");   // write into basedir/save/

	trss::Interpreter* interpreter = trss::core()->spawnInterpreter("interpreter_0");
	interpreter->setDebug(0); // want most verbose debugging output
	interpreter->attachAddon(new SDLAddon);
	interpreter->attachAddon(new NanoVGAddon);
	interpreter->attachAddon(new WSClientAddon);
	trss_log(0, "Starting interpreter!");
	// startUnthreaded starts the interpreter in the current thread,
	// which means the call will block until the interpreter is stopped
	//interpreter->startUnthreaded("examples/dart_gui_test.t");
	if (argc > 1) {
		interpreter->startUnthreaded(argv[1]);
	}
	else {
		interpreter->startUnthreaded("examples/dart_gui_test.t");
	}
	return 0;
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"
#include "gfx/support/unproject.h"
#include "gfx/immediate_renderer.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"
#include "ui/pie_menu.h"

#include "map/map.h"
#include "map/water.h"
#include "map/terrain.h"

#include "stratlib/player_state.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

struct Glfw_User_Data
{
  game::gfx::IDriver& driver;
  game::gfx::Camera& cam;
  game::ui::Mouse_State mouse_state;
};

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  auto ptr = glfwGetWindowUserPointer(window);
  auto& data = *((Glfw_User_Data*) ptr);

  namespace gfx = game::gfx;
  gfx::apply_zoom(data.cam, deltay, data.mouse_state.position, data.driver);
}

game::ui::Mouse_State gen_mouse_state(GLFWwindow* w)
{
  game::ui::Mouse_State ret;

  if(glfwGetMouseButton(w,GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
  {
    ret.buttons = game::ui::Mouse_Button_Left;
  }
  else
  {
    ret.buttons = 0x00;
  }

  game::Vec<double> pos;
  glfwGetCursorPos(w, &pos.x, &pos.y);
  ret.position = game::vec_cast<int>(pos);

  return ret;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  {
  // Make an OpenGL driver.
  gfx::gl::Driver driver{Vec<int>{1000, 1000}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/v");
  default_shader->load_fragment_part("shader/basic/f");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Make an isometric camera.
  auto cam = gfx::make_isometric_camera();

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();
  Map map({1000, 1000}); // <-- Map size for now
  strat::Player_State player_state{strat::Player_State_Type::Nothing};

  auto structures = load_structures("structure/structures.json",
                                    ref_mo(structure_mesh),
                                    driver);

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Our quick hack to avoid splitting into multiple functions and dealing
  // either with global variables or like a bound struct or something.
  bool has_clicked_down = false;

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  auto controller = ui::Simple_Controller{};

  hud->find_child_r("build_house")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[0];
  });
  hud->find_child_r("build_gvn_build")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[1];
  });

  hud->layout(driver.window_extents());

  controller.add_drag_listener([&](auto const& np, auto const& op)
  {
    // Only drag if we don't have anything else to do.
    if(player_state.type != strat::Player_State_Type::Nothing) return;

    gfx::apply_pan(cam, np, op, driver);
  });

  Glfw_User_Data data{driver, cam};

  glfwSetWindowUserPointer(window, &data);
  glfwSetScrollCallback(window, scroll_callback);

  //water_obj.material->diffuse_color = Color{0xaa, 0xaa, 0xff};

  ui::Mouse_State old_mouse = gen_mouse_state(window);

  ui::Pie_Menu pie_menu;
  pie_menu.radius(200);
  pie_menu.font_renderer(freetype_font);
  pie_menu.num_buttons(3);
  pie_menu.center_button("Place");
  pie_menu.radial_button(0, "Analyze");
  pie_menu.radial_button(1, "Rotate");
  pie_menu.radial_button(2, "Cancel");

  bool render_pie = false;

  int action_countdown = 0;

  gfx::Immediate_Renderer ir{driver};

  while(!glfwWindowShouldClose(window))
  {
    action_countdown = std::max(action_countdown - 1, 0);

    // TODO: Combine button and mouse state or something, this is terrible.
    auto mouse_state = gen_mouse_state(window);
    data.mouse_state = mouse_state;

    ++fps;
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, cam);

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    // Render the terrain before we calculate the depth of the mouse position.
    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    // Render any structures.
    // Maybe the mouse?

    // We only want to be able to pan the terrain for now. That's why we need
    // to do this before any structure rendering.
    auto mouse_world = gfx::unproject_screen(driver, cam, glm::mat4(1.0f),
                                             mouse_state.position);
    controller.step(hud, mouse_state);

    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS &&
       player_state.type == strat::Player_State_Type::Building &&
       action_countdown == 0)
    {
      player_state.type = strat::Player_State_Type::Nothing;
      action_countdown = 500;
    }
    else if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS &&
            player_state.type == strat::Player_State_Type::Nothing &&
            action_countdown == 0)
    {
      glfwSetWindowShouldClose(window, true);
    }

    if(player_state.type == strat::Player_State_Type::Building)
    {
      auto& st = *player_state.building.to_build;

      // TODO: Put this stuff somewhere to access it a bunch

      auto mouse_map = Vec<float>{mouse_world.x, mouse_world.z};
      //auto new_pos = st.on_snap(mouse_map);
      render_structure(driver, st, mouse_map);
    }

    // Render all the other structures.
    for(auto const& st : map.structures)
    {
      // TODO: Find/store correct y somehow?
      render_structure_instance(driver, st);
    }

    // If we release the mouse find the item of the pie menu the user selected.
    if(ui::is_click(mouse_state, old_mouse, true) &&
       player_state.type == strat::Player_State_Type::Building)
    {
      // Enable viewing of the pie menu
      render_pie = true;

      pie_menu.center(mouse_state.position);

      // Make sure we don't pan or build or whatever
      player_state.type = strat::Player_State_Type::Pie_Menu;

      // But place the object down.
      auto st_pos = Vec<float>{};
      st_pos.x = mouse_world.x;
      st_pos.y = mouse_world.z;

      ir.reset();
      if(!try_structure_place(map, *player_state.building.to_build,st_pos,&ir))
      {
        // Tell the user!
      }
    }
    else if(ui::is_release(mouse_state, old_mouse, true) &&
            player_state.type == strat::Player_State_Type::Pie_Menu)
    {
      // Disable viewing of the pie menu
      render_pie = false;

      // Get current button
      auto cur_radial = pie_menu.current_radial_button();

      // It was either the center button
      if(pie_menu.active_center_button())
      {
        // For now we know the center button places the object. Also, since the
        // map already has it as a structure, we can just let things be.
      }
      // Or a radial button.
      else if(cur_radial)
      {
        // For now brute force it.
        switch(cur_radial.value())
        {
          case 0:
            break;
          case 1:
            break;
          case 2:
            // Cancel
            map.structures.erase(map.structures.end() - 1);
            break;
          default: break;
        }
      }
      else
      {
        // No button, reverse the initial placement.
        map.structures.erase(map.structures.end() - 1);
      }
      player_state.type = strat::Player_State_Type::Building;
    }

    ir.render(cam);

    if(render_pie) pie_menu.handle_event(mouse_state);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};

      if(render_pie) pie_menu.render(ui_adapter);

      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();

    old_mouse = mouse_state;
  }
  }
  glfwTerminate();
  return 0;
}
<commit_msg>Remove some unnecesarily code in the main function<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"
#include "gfx/support/unproject.h"
#include "gfx/immediate_renderer.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"
#include "ui/pie_menu.h"

#include "map/map.h"
#include "map/water.h"
#include "map/terrain.h"

#include "stratlib/player_state.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

struct Glfw_User_Data
{
  game::gfx::IDriver& driver;
  game::gfx::Camera& cam;
  game::ui::Mouse_State mouse_state;
};

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  auto ptr = glfwGetWindowUserPointer(window);
  auto& data = *((Glfw_User_Data*) ptr);

  namespace gfx = game::gfx;
  gfx::apply_zoom(data.cam, deltay, data.mouse_state.position, data.driver);
}

game::ui::Mouse_State gen_mouse_state(GLFWwindow* w)
{
  game::ui::Mouse_State ret;

  if(glfwGetMouseButton(w,GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
  {
    ret.buttons = game::ui::Mouse_Button_Left;
  }
  else
  {
    ret.buttons = 0x00;
  }

  game::Vec<double> pos;
  glfwGetCursorPos(w, &pos.x, &pos.y);
  ret.position = game::vec_cast<int>(pos);

  return ret;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  {
  // Make an OpenGL driver.
  gfx::gl::Driver driver{Vec<int>{1000, 1000}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/v");
  default_shader->load_fragment_part("shader/basic/f");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Make an isometric camera.
  auto cam = gfx::make_isometric_camera();

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();
  Map map({1000, 1000}); // <-- Map size for now
  strat::Player_State player_state{strat::Player_State_Type::Nothing};

  auto structures = load_structures("structure/structures.json",
                                    ref_mo(structure_mesh),
                                    driver);

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  auto controller = ui::Simple_Controller{};

  hud->find_child_r("build_house")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[0];
  });
  hud->find_child_r("build_gvn_build")->add_click_listener([&](auto const& pt)
  {
    player_state.type = strat::Player_State_Type::Building;
    player_state.building.to_build = &structures[1];
  });

  hud->layout(driver.window_extents());

  controller.add_drag_listener([&](auto const& np, auto const& op)
  {
    // Only drag if we don't have anything else to do.
    if(player_state.type != strat::Player_State_Type::Nothing) return;

    gfx::apply_pan(cam, np, op, driver);
  });

  Glfw_User_Data data{driver, cam};

  glfwSetWindowUserPointer(window, &data);
  glfwSetScrollCallback(window, scroll_callback);

  //water_obj.material->diffuse_color = Color{0xaa, 0xaa, 0xff};

  ui::Mouse_State old_mouse = gen_mouse_state(window);

  ui::Pie_Menu pie_menu;
  pie_menu.radius(200);
  pie_menu.font_renderer(freetype_font);
  pie_menu.num_buttons(3);
  pie_menu.center_button("Place");
  pie_menu.radial_button(0, "Analyze");
  pie_menu.radial_button(1, "Rotate");
  pie_menu.radial_button(2, "Cancel");

  bool render_pie = false;

  int action_countdown = 0;

  gfx::Immediate_Renderer ir{driver};

  while(!glfwWindowShouldClose(window))
  {
    action_countdown = std::max(action_countdown - 1, 0);

    // TODO: Combine button and mouse state or something, this is terrible.
    auto mouse_state = gen_mouse_state(window);
    data.mouse_state = mouse_state;

    ++fps;
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, cam);

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    // Render the terrain before we calculate the depth of the mouse position.
    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    // Render any structures.
    // Maybe the mouse?

    // We only want to be able to pan the terrain for now. That's why we need
    // to do this before any structure rendering.
    auto mouse_world = gfx::unproject_screen(driver, cam, glm::mat4(1.0f),
                                             mouse_state.position);
    controller.step(hud, mouse_state);

    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS &&
       player_state.type == strat::Player_State_Type::Building &&
       action_countdown == 0)
    {
      player_state.type = strat::Player_State_Type::Nothing;
      action_countdown = 500;
    }
    else if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS &&
            player_state.type == strat::Player_State_Type::Nothing &&
            action_countdown == 0)
    {
      glfwSetWindowShouldClose(window, true);
    }

    if(player_state.type == strat::Player_State_Type::Building)
    {
      auto& st = *player_state.building.to_build;

      // TODO: Put this stuff somewhere to access it a bunch

      auto mouse_map = Vec<float>{mouse_world.x, mouse_world.z};
      //auto new_pos = st.on_snap(mouse_map);
      render_structure(driver, st, mouse_map);
    }

    // Render all the other structures.
    for(auto const& st : map.structures)
    {
      // TODO: Find/store correct y somehow?
      render_structure_instance(driver, st);
    }

    // If we release the mouse find the item of the pie menu the user selected.
    if(ui::is_click(mouse_state, old_mouse, true) &&
       player_state.type == strat::Player_State_Type::Building)
    {
      // Enable viewing of the pie menu
      render_pie = true;

      pie_menu.center(mouse_state.position);

      // Make sure we don't pan or build or whatever
      player_state.type = strat::Player_State_Type::Pie_Menu;

      // But place the object down.
      auto st_pos = Vec<float>{};
      st_pos.x = mouse_world.x;
      st_pos.y = mouse_world.z;

      ir.reset();
      if(!try_structure_place(map, *player_state.building.to_build,st_pos,&ir))
      {
        // Tell the user!
      }
    }
    else if(ui::is_release(mouse_state, old_mouse, true) &&
            player_state.type == strat::Player_State_Type::Pie_Menu)
    {
      // Disable viewing of the pie menu
      render_pie = false;

      // Get current button
      auto cur_radial = pie_menu.current_radial_button();

      // It was either the center button
      if(pie_menu.active_center_button())
      {
        // For now we know the center button places the object. Also, since the
        // map already has it as a structure, we can just let things be.
      }
      // Or a radial button.
      else if(cur_radial)
      {
        // For now brute force it.
        switch(cur_radial.value())
        {
          case 0:
            break;
          case 1:
            break;
          case 2:
            // Cancel
            map.structures.erase(map.structures.end() - 1);
            break;
          default: break;
        }
      }
      else
      {
        // No button, reverse the initial placement.
        map.structures.erase(map.structures.end() - 1);
      }
      player_state.type = strat::Player_State_Type::Building;
    }

    ir.render(cam);

    if(render_pie) pie_menu.handle_event(mouse_state);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};

      if(render_pie) pie_menu.render(ui_adapter);

      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();

    old_mouse = mouse_state;
  }
  }
  glfwTerminate();
  return 0;
}
<|endoftext|>


<commit_before>#include "compiler.h"
#include "mswin.h"
#include "glinit.h"
#include "model.h"
#include "cmdline.h"
#include <windowsx.h>
// #include "tinyscheme-config.h"
// #include <scheme-private.h>
// #include <scheme.h>
#include <cstdint>

namespace usr {
  // Program name.
  static const TCHAR * const program_name = TEXT ("Polymorph");
  static const TCHAR * const message =
  TEXT ("And the ratios of their numbers, motions, and ")
  TEXT ("other properties, everywhere God, as far as ")
  TEXT ("necessity allowed or gave consent, has exactly ")
  TEXT ("perfected, and harmonised in due proportion.");
  // TEXT ("\n\nThis screensaver includes TinyScheme, developed by Dimitrios ")
  // TEXT ("Souflis and licensed under the Modified BSD License. ")
  // TEXT ("See \"tinyscheme/COPYING.txt\" for details.");
}

inline std::uint64_t qpc ()
{
  LARGE_INTEGER t;
  ::QueryPerformanceCounter (& t);
  return t.QuadPart;
}

struct window_struct_t
{
  model_t model;
  POINT initial_cursor_position;
  run_mode_t mode;
};

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HGLRC setup_opengl_context (HWND hwnd);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
  // Read command line arguments.

  HWND parent = NULL;
  run_mode_t mode = parse_command_line (::GetCommandLine (), & parent);

  if (mode == configure) {
    ::MessageBox (NULL, usr::message, usr::program_name, MB_OK | MB_ICONASTERISK);
    return 0;
  }

  // Placement and window style of the main window.

  RECT rect;
  DWORD style;
  DWORD ex_style  = 0;

  if (mode == embedded) {
    style = WS_CHILD | WS_VISIBLE;
    ::GetClientRect (parent, & rect); // 0, 0, width, height
  }
  else {
    style = WS_POPUP | WS_VISIBLE;
    if (mode == fullscreen) ex_style = WS_EX_TOPMOST;
    rect.left =   ::GetSystemMetrics (SM_XVIRTUALSCREEN);
    rect.top =    ::GetSystemMetrics (SM_YVIRTUALSCREEN);
    rect.right =  ::GetSystemMetrics (SM_CXVIRTUALSCREEN); // actually width, not right
    rect.bottom = ::GetSystemMetrics (SM_CYVIRTUALSCREEN); // actually height, not bottom
  }

  window_struct_t ws ALIGNED16;
  ws.mode = mode;

  // Create a window with an OpenGL rendering context.

  // To obtain a proper OpenGL pixel format, we need to call wglChoosePixelFormatARB, but
  // first we must obtain the address of that function by calling using wglGetProcAddress,
  // which requires that an OpenGL rendering context is current, which requires a device
  // context that supports OpenGL, which requires a window with an OpenGL pixel format.

  // Bootstrap the process with a legacy OpenGL pixel format. According to MSDN,
  // "Once a window's pixel format is set, it cannot be changed", so the window
  // and associated resources are of no further use and are destroyed here.

  // Create the dummy window. See InitWndProc.
  // Note this window does not survive creation.
  WNDCLASS init_wc = { 0, & InitWndProc, 0, 0, hInstance, NULL, NULL, NULL, NULL, TEXT ("GLinit") };
  ATOM init_wc_atom = ::RegisterClass (& init_wc);
  ::CreateWindowEx (0, MAKEINTATOM (init_wc_atom), TEXT (""), 0,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                    NULL, NULL, hInstance, NULL);
  ::UnregisterClass (MAKEINTATOM (init_wc_atom), hInstance);

  // Exit if we failed to get the function pointers.
  if (! wglChoosePixelFormatARB) return -1;

  // Create the main window. See MainWndProc.
  HICON icon = ::LoadIcon (hInstance, MAKEINTRESOURCE (257));
  WNDCLASS main_wc = { 0, & MainWndProc, 0, 0, hInstance, icon, NULL, NULL, NULL, usr::program_name };
  ATOM main_wc_atom = ::RegisterClass (& main_wc);
  HWND hwnd = ::CreateWindowEx (ex_style, MAKEINTATOM (main_wc_atom), usr::program_name, style,
                                rect.left, rect.top, rect.right, rect.bottom,
                                parent, NULL, hInstance, & ws);

  // Exit if we failed to create the window.
  if (! hwnd) return 1;

  // Enter the main loop.
  MSG msg;
  while (::GetMessage (& msg, NULL, 0, 0)) {
    ::TranslateMessage (& msg);
    ::DispatchMessage (& msg);
  }

  ::UnregisterClass (MAKEINTATOM (main_wc_atom), hInstance);
  return msg.wParam;
}

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  if (msg == WM_NCCREATE) {
    // Set up a legacy rendering context to get the OpenGL function pointers.
    PIXELFORMATDESCRIPTOR pfd = { sizeof pfd, 1, PFD_SUPPORT_OPENGL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
    if (HDC hdc = ::GetDC (hwnd)) {
      int pf = ::ChoosePixelFormat (hdc, & pfd);
      ::SetPixelFormat (hdc, pf, & pfd);
      if (HGLRC hglrc = ::wglCreateContext (hdc)) {
        ::wglMakeCurrent (hdc, hglrc);
        // Get the function pointers.
        get_glprocs ();
        ::wglMakeCurrent (NULL, NULL);
        ::wglDeleteContext (hglrc);
      }
      ::ReleaseDC (hwnd, hdc);
    }
    return FALSE; // Abort window creation.
  }
  else {
    return ::DefWindowProc (hwnd, msg, wParam, lParam);
  }
}

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  LRESULT result = 0;
  bool call_def_window_proc = false, close_window = false;

  // Retrieve the window-struct pointer from the window userdata.
  window_struct_t * ws = reinterpret_cast <window_struct_t *> (::GetWindowLongPtr (hwnd, GWLP_USERDATA));

  switch (msg) {
  case WM_CREATE: {
    result = -1; // Abort window creation.

    // Stash the window-struct pointer in the window userdata.
    CREATESTRUCT * cs = reinterpret_cast <CREATESTRUCT *> (lParam);
    ws = reinterpret_cast <window_struct_t *> (cs->lpCreateParams);
    ::SetWindowLongPtr (hwnd, GWLP_USERDATA, reinterpret_cast <LONG_PTR> (ws));

    // Remember initial mouse-pointer position to detect mouse movement.
    ::GetCursorPos (& ws->initial_cursor_position);

    // Set up OpenGL rendering context.
    HGLRC hglrc = setup_opengl_context (hwnd);
    if (hglrc) {
      ws->model.initialize (qpc (), cs->cx, cs->cy);
      ::PostMessage (hwnd, WM_APP, 0, 0);  // Start the simulation.
      result = 0;                          // Allow window creation to continue.
    }
    break;
  }

  case WM_APP: {
    ws->model.draw_next ();
    ::InvalidateRect (hwnd, NULL, FALSE);
    break;
  }

  case WM_PAINT: {
    PAINTSTRUCT ps;
    ::BeginPaint (hwnd, & ps);
    ::SwapBuffers (ps.hdc);
    ::EndPaint (hwnd, & ps);
    ::PostMessage (hwnd, WM_APP, 0, 0);
    break;
  }

  case WM_SETCURSOR:
    ::SetCursor (ws->mode == fullscreen ? NULL : (::LoadCursor (NULL, IDC_ARROW)));
    break;

  case WM_MOUSEMOVE:
    if (ws->mode == fullscreen) {
      // Compare the current mouse position with the one stored in the window struct.
      POINT current = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) };
      ::ClientToScreen (hwnd, & current);
      SHORT dx = current.x - ws->initial_cursor_position.x;
      SHORT dy = current.y - ws->initial_cursor_position.y;
      close_window = dx > 10 || dy > 10 || dx * dx + dy * dy  > 100;
    }
    break;

  case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN:
    close_window = ws->mode == fullscreen || ws->mode == special;
    break;

  case WM_ACTIVATE: case WM_ACTIVATEAPP: case WM_NCACTIVATE:
    close_window = ws->mode == fullscreen && LOWORD (wParam) == WA_INACTIVE;
    call_def_window_proc = true;
    break;

  case WM_SYSCOMMAND:
    call_def_window_proc = ! (ws->mode == fullscreen && wParam == SC_SCREENSAVE);
    break;

  case WM_DESTROY:
    ::wglMakeCurrent (NULL, NULL);
    //::wglDeleteContext (ws->hglrc);
    ::PostQuitMessage (0);
    break;

  default:
    call_def_window_proc = true;
    break;
  }

  if (close_window) {
    ::PostMessage (hwnd, WM_CLOSE, 0, 0);
  }

  if (call_def_window_proc) {
    result = ::DefWindowProc (hwnd, msg, wParam, lParam);
  }

  return result;
}

// Set up a proper pixel format and rendering context for the main window.
HGLRC setup_opengl_context (HWND hwnd)
{
  const int pf_attribs [] = {
    WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
    WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
    WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
    WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
    WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB,
    WGL_COLOR_BITS_ARB, 32,
    WGL_DEPTH_BITS_ARB, 4,
    WGL_SAMPLE_BUFFERS_ARB, GL_FALSE,
    //WGL_SAMPLES_ARB, 5,
    0, 0,
  };

  const int context_attribs [] = {
    WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
    WGL_CONTEXT_MINOR_VERSION_ARB, 2,
    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    0, 0,
  };

  HGLRC hglrc = NULL;
  int pf;
  UINT pfcount;
  if (HDC hdc = ::GetDC (hwnd)) {
    if (wglChoosePixelFormatARB (hdc, pf_attribs, NULL, 1, & pf, & pfcount)) {
      if (::SetPixelFormat (hdc, pf, NULL)) {
        hglrc = wglCreateContextAttribsARB (hdc, NULL, context_attribs);
        if (hglrc) {
          ::wglMakeCurrent (hdc, hglrc);
        }
      }
    }
    ::ReleaseDC (hwnd, hdc);
  }
  return hglrc;
}

#ifdef TINY

// Tiny startup.

// No standard handles, window placement, environment variables,
// command-line transformation, global constructors and destructors,
// atexit functions, stack realignment, thread-local storage,
// runtime relocation fixups, 387 floating-point initialization,
// signal handlers or exceptions.

extern "C"
{
  // This symbol is provided by all recent GCC and MSVC linkers.
  IMAGE_DOS_HEADER __ImageBase;

  // This entry point must be specified in the linker command line.
  void custom_startup ()
  {
    HINSTANCE hInstance = reinterpret_cast <HINSTANCE> (& __ImageBase);
    int status = WinMain (hInstance, NULL, NULL, 0);
    ::ExitProcess (static_cast <UINT> (status));
  }
}

#endif
<commit_msg>main.cpp: fix and simplify mouse position comparison.<commit_after>#include "compiler.h"
#include "mswin.h"
#include "glinit.h"
#include "model.h"
#include "cmdline.h"
#include <windowsx.h>
// #include "tinyscheme-config.h"
// #include <scheme-private.h>
// #include <scheme.h>
#include <cstdint>

namespace usr {
  // Program name.
  static const TCHAR * const program_name = TEXT ("Polymorph");
  static const TCHAR * const message =
  TEXT ("And the ratios of their numbers, motions, and ")
  TEXT ("other properties, everywhere God, as far as ")
  TEXT ("necessity allowed or gave consent, has exactly ")
  TEXT ("perfected, and harmonised in due proportion.");
  // TEXT ("\n\nThis screensaver includes TinyScheme, developed by Dimitrios ")
  // TEXT ("Souflis and licensed under the Modified BSD License. ")
  // TEXT ("See \"tinyscheme/COPYING.txt\" for details.");
}

inline std::uint64_t qpc ()
{
  LARGE_INTEGER t;
  ::QueryPerformanceCounter (& t);
  return t.QuadPart;
}

struct window_struct_t
{
  model_t model;
  POINT initial_cursor_position;
  run_mode_t mode;
};

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HGLRC setup_opengl_context (HWND hwnd);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
  // Read command line arguments.

  HWND parent = NULL;
  run_mode_t mode = parse_command_line (::GetCommandLine (), & parent);

  if (mode == configure) {
    ::MessageBox (NULL, usr::message, usr::program_name, MB_OK | MB_ICONASTERISK);
    return 0;
  }

  // Placement and window style of the main window.

  RECT rect;
  DWORD style;
  DWORD ex_style  = 0;

  if (mode == embedded) {
    style = WS_CHILD | WS_VISIBLE;
    ::GetClientRect (parent, & rect); // 0, 0, width, height
  }
  else {
    style = WS_POPUP | WS_VISIBLE;
    if (mode == fullscreen) ex_style = WS_EX_TOPMOST;
    rect.left =   ::GetSystemMetrics (SM_XVIRTUALSCREEN);
    rect.top =    ::GetSystemMetrics (SM_YVIRTUALSCREEN);
    rect.right =  ::GetSystemMetrics (SM_CXVIRTUALSCREEN); // actually width, not right
    rect.bottom = ::GetSystemMetrics (SM_CYVIRTUALSCREEN); // actually height, not bottom
  }

  window_struct_t ws ALIGNED16;
  ws.mode = mode;

  // Create a window with an OpenGL rendering context.

  // To obtain a proper OpenGL pixel format, we need to call wglChoosePixelFormatARB, but
  // first we must obtain the address of that function by calling using wglGetProcAddress,
  // which requires that an OpenGL rendering context is current, which requires a device
  // context that supports OpenGL, which requires a window with an OpenGL pixel format.

  // Bootstrap the process with a legacy OpenGL pixel format. According to MSDN,
  // "Once a window's pixel format is set, it cannot be changed", so the window
  // and associated resources are of no further use and are destroyed here.

  // Create the dummy window. See InitWndProc.
  // Note this window does not survive creation.
  WNDCLASS init_wc = { 0, & InitWndProc, 0, 0, hInstance, NULL, NULL, NULL, NULL, TEXT ("GLinit") };
  ATOM init_wc_atom = ::RegisterClass (& init_wc);
  ::CreateWindowEx (0, MAKEINTATOM (init_wc_atom), TEXT (""), 0,
                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                    NULL, NULL, hInstance, NULL);
  ::UnregisterClass (MAKEINTATOM (init_wc_atom), hInstance);

  // Exit if we failed to get the function pointers.
  if (! wglChoosePixelFormatARB) return -1;

  // Create the main window. See MainWndProc.
  HICON icon = ::LoadIcon (hInstance, MAKEINTRESOURCE (257));
  WNDCLASS main_wc = { 0, & MainWndProc, 0, 0, hInstance, icon, NULL, NULL, NULL, usr::program_name };
  ATOM main_wc_atom = ::RegisterClass (& main_wc);
  HWND hwnd = ::CreateWindowEx (ex_style, MAKEINTATOM (main_wc_atom), usr::program_name, style,
                                rect.left, rect.top, rect.right, rect.bottom,
                                parent, NULL, hInstance, & ws);

  // Exit if we failed to create the window.
  if (! hwnd) return 1;

  // Enter the main loop.
  MSG msg;
  while (::GetMessage (& msg, NULL, 0, 0)) {
    ::TranslateMessage (& msg);
    ::DispatchMessage (& msg);
  }

  ::UnregisterClass (MAKEINTATOM (main_wc_atom), hInstance);
  return msg.wParam;
}

LRESULT CALLBACK InitWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  if (msg == WM_NCCREATE) {
    // Set up a legacy rendering context to get the OpenGL function pointers.
    PIXELFORMATDESCRIPTOR pfd = { sizeof pfd, 1, PFD_SUPPORT_OPENGL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
    if (HDC hdc = ::GetDC (hwnd)) {
      int pf = ::ChoosePixelFormat (hdc, & pfd);
      ::SetPixelFormat (hdc, pf, & pfd);
      if (HGLRC hglrc = ::wglCreateContext (hdc)) {
        ::wglMakeCurrent (hdc, hglrc);
        // Get the function pointers.
        get_glprocs ();
        ::wglMakeCurrent (NULL, NULL);
        ::wglDeleteContext (hglrc);
      }
      ::ReleaseDC (hwnd, hdc);
    }
    return FALSE; // Abort window creation.
  }
  else {
    return ::DefWindowProc (hwnd, msg, wParam, lParam);
  }
}

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  LRESULT result = 0;
  bool call_def_window_proc = false, close_window = false;

  // Retrieve the window-struct pointer from the window userdata.
  window_struct_t * ws = reinterpret_cast <window_struct_t *> (::GetWindowLongPtr (hwnd, GWLP_USERDATA));

  switch (msg) {
  case WM_CREATE: {
    result = -1; // Abort window creation.

    // Stash the window-struct pointer in the window userdata.
    CREATESTRUCT * cs = reinterpret_cast <CREATESTRUCT *> (lParam);
    ws = reinterpret_cast <window_struct_t *> (cs->lpCreateParams);
    ::SetWindowLongPtr (hwnd, GWLP_USERDATA, reinterpret_cast <LONG_PTR> (ws));

    // Remember initial mouse-pointer position to detect mouse movement.
    POINT cursor;
    ::GetCursorPos (& cursor);
    ::ScreenToClient (hwnd, & cursor);
    ws->initial_cursor_position = cursor;

    // Set up OpenGL rendering context.
    HGLRC hglrc = setup_opengl_context (hwnd);
    if (hglrc) {
      ws->model.initialize (qpc (), cs->cx, cs->cy);
      ::PostMessage (hwnd, WM_APP, 0, 0);  // Start the simulation.
      result = 0;                          // Allow window creation to continue.
    }
    break;
  }

  case WM_APP: {
    ws->model.draw_next ();
    ::InvalidateRect (hwnd, NULL, FALSE);
    break;
  }

  case WM_PAINT: {
    PAINTSTRUCT ps;
    ::BeginPaint (hwnd, & ps);
    ::SwapBuffers (ps.hdc);
    ::EndPaint (hwnd, & ps);
    ::PostMessage (hwnd, WM_APP, 0, 0);
    break;
  }

  case WM_SETCURSOR:
    ::SetCursor (ws->mode == fullscreen ? NULL : (::LoadCursor (NULL, IDC_ARROW)));
    break;

  case WM_MOUSEMOVE:
    if (ws->mode == fullscreen) {
      // Compare the current mouse position with the one stored in the window struct.
      DWORD cursor = (DWORD) lParam;
      int dx = GET_X_LPARAM (cursor) - ws->initial_cursor_position.x;
      int dy = GET_Y_LPARAM (cursor) - ws->initial_cursor_position.y;
      close_window = (dx < -10 || dx > 10) || (dy < -10 || dy > 10);
    }
    break;

  case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN:
    close_window = ws->mode == fullscreen || ws->mode == special;
    break;

  case WM_ACTIVATE: case WM_ACTIVATEAPP: case WM_NCACTIVATE:
    close_window = ws->mode == fullscreen && LOWORD (wParam) == WA_INACTIVE;
    call_def_window_proc = true;
    break;

  case WM_SYSCOMMAND:
    call_def_window_proc = ! (ws->mode == fullscreen && wParam == SC_SCREENSAVE);
    break;

  case WM_DESTROY:
    ::wglMakeCurrent (NULL, NULL);
    //::wglDeleteContext (ws->hglrc);
    ::PostQuitMessage (0);
    break;

  default:
    call_def_window_proc = true;
    break;
  }

  if (close_window) {
    ::PostMessage (hwnd, WM_CLOSE, 0, 0);
  }

  if (call_def_window_proc) {
    result = ::DefWindowProc (hwnd, msg, wParam, lParam);
  }

  return result;
}

// Set up a proper pixel format and rendering context for the main window.
HGLRC setup_opengl_context (HWND hwnd)
{
  const int pf_attribs [] = {
    WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
    WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
    WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
    WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
    WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB,
    WGL_COLOR_BITS_ARB, 32,
    WGL_DEPTH_BITS_ARB, 4,
    WGL_SAMPLE_BUFFERS_ARB, GL_FALSE,
    //WGL_SAMPLES_ARB, 5,
    0, 0,
  };

  const int context_attribs [] = {
    WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
    WGL_CONTEXT_MINOR_VERSION_ARB, 2,
    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    0, 0,
  };

  HGLRC hglrc = NULL;
  int pf;
  UINT pfcount;
  if (HDC hdc = ::GetDC (hwnd)) {
    if (wglChoosePixelFormatARB (hdc, pf_attribs, NULL, 1, & pf, & pfcount)) {
      if (::SetPixelFormat (hdc, pf, NULL)) {
        hglrc = wglCreateContextAttribsARB (hdc, NULL, context_attribs);
        if (hglrc) {
          ::wglMakeCurrent (hdc, hglrc);
        }
      }
    }
    ::ReleaseDC (hwnd, hdc);
  }
  return hglrc;
}

#ifdef TINY

// Tiny startup.

// No standard handles, window placement, environment variables,
// command-line transformation, global constructors and destructors,
// atexit functions, stack realignment, thread-local storage,
// runtime relocation fixups, 387 floating-point initialization,
// signal handlers or exceptions.

extern "C"
{
  // This symbol is provided by all recent GCC and MSVC linkers.
  IMAGE_DOS_HEADER __ImageBase;

  // This entry point must be specified in the linker command line.
  void custom_startup ()
  {
    HINSTANCE hInstance = reinterpret_cast <HINSTANCE> (& __ImageBase);
    int status = WinMain (hInstance, NULL, NULL, 0);
    ::ExitProcess (static_cast <UINT> (status));
  }
}

#endif
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>

/// The main function

int main () {
	std::cout << "Hello !" << std::endl;
	return 0;
}<commit_msg>Include headers for GLEW and glfw3<commit_after>#include <GL/glew.h> // to load OpenGL extensions at runtime
#include <GLFW/glfw3.h> // to set up the OpenGL context and manage window lifecycle and inputs

#include <stdio.h>
#include <iostream>

/// The main function

int main () {
	std::cout << "Hello !" << std::endl;
	return 0;
}<|endoftext|>