<commit_before>//===- ProfileInfoLoad.cpp - Load profile information from disk -----------===//
//
//                      The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The ProfileInfoLoader class is used to load and represent profiling
// information read in from the dump file.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/ProfileInfoLoader.h"
#include "llvm/Analysis/ProfileInfoTypes.h"
#include "llvm/Module.h"
#include "llvm/InstrTypes.h"
#include <cstdio>
#include <map>
using namespace llvm;

// ByteSwap - Byteswap 'Var' if 'Really' is true.
//
static inline unsigned ByteSwap(unsigned Var, bool Really) {
  if (!Really) return Var;
  return ((Var & (255<< 0)) << 24) |
         ((Var & (255<< 8)) <<  8) |
         ((Var & (255<<16)) >>  8) |
         ((Var & (255<<24)) >> 24);
}

static void ReadProfilingBlock(const char *ToolName, FILE *F,
                               bool ShouldByteSwap,
                               std::vector<unsigned> &Data) {
  // Read the number of entries...
  unsigned NumEntries;
  if (fread(&NumEntries, sizeof(unsigned), 1, F) != 1) {
    std::cerr << ToolName << ": data packet truncated!\n";
    perror(0);
    exit(1);
  }
  NumEntries = ByteSwap(NumEntries, ShouldByteSwap);

  // Read the counts...
  std::vector<unsigned> TempSpace(NumEntries);

  // Read in the block of data...
  if (fread(&TempSpace[0], sizeof(unsigned)*NumEntries, 1, F) != 1) {
    std::cerr << ToolName << ": data packet truncated!\n";
    perror(0);
    exit(1);
  }

  // Make sure we have enough space...
  if (Data.size() < NumEntries)
    Data.resize(NumEntries);

  // Accumulate the data we just read into the data.
  if (!ShouldByteSwap) {
    for (unsigned i = 0; i != NumEntries; ++i)
      Data[i] += TempSpace[i];
  } else {
    for (unsigned i = 0; i != NumEntries; ++i)
      Data[i] += ByteSwap(TempSpace[i], true);
  }
}

// ProfileInfoLoader ctor - Read the specified profiling data file, exiting the
// program if the file is invalid or broken.
//
ProfileInfoLoader::ProfileInfoLoader(const char *ToolName,
                                     const std::string &Filename,
                                     Module &TheModule) : M(TheModule) {
  FILE *F = fopen(Filename.c_str(), "r");
  if (F == 0) {
    std::cerr << ToolName << ": Error opening '" << Filename << "': ";
    perror(0);
    exit(1);
  }

  // Keep reading packets until we run out of them.
  unsigned PacketType;
  while (fread(&PacketType, sizeof(unsigned), 1, F) == 1) {
    // If the low eight bits of the packet are zero, we must be dealing with an
    // endianness mismatch.  Byteswap all words read from the profiling
    // information.
    bool ShouldByteSwap = (char)PacketType == 0;
    PacketType = ByteSwap(PacketType, ShouldByteSwap);

    switch (PacketType) {
    case ArgumentInfo: {
      unsigned ArgLength;
      if (fread(&ArgLength, sizeof(unsigned), 1, F) != 1) {
        std::cerr << ToolName << ": arguments packet truncated!\n";
        perror(0);
        exit(1);
      }
      ArgLength = ByteSwap(ArgLength, ShouldByteSwap);

      // Read in the arguments...
      std::vector<char> Chars(ArgLength+4);

      if (ArgLength)
        if (fread(&Chars[0], (ArgLength+3) & ~3, 1, F) != 1) {
          std::cerr << ToolName << ": arguments packet truncated!\n";
          perror(0);
          exit(1);
        }
      CommandLines.push_back(std::string(&Chars[0], &Chars[ArgLength]));
      break;
    }

    case FunctionInfo:
      ReadProfilingBlock(ToolName, F, ShouldByteSwap, FunctionCounts);
      break;

    case BlockInfo:
      ReadProfilingBlock(ToolName, F, ShouldByteSwap, BlockCounts);
      break;

    case EdgeInfo:
      ReadProfilingBlock(ToolName, F, ShouldByteSwap, EdgeCounts);
      break;

    default:
      std::cerr << ToolName << ": Unknown packet type #" << PacketType << "!\n";
      exit(1);
    }
  }

  fclose(F);
}

// getFunctionCounts - This method is used by consumers of function counting
// information.  If we do not directly have function count information, we
// compute it from other, more refined, types of profile information.
//
void ProfileInfoLoader::getFunctionCounts(std::vector<std::pair<Function*,
                                                      unsigned> > &Counts) {
  if (FunctionCounts.empty()) {
    if (hasAccurateBlockCounts()) {
      // Synthesize function frequency information from the number of times
      // their entry blocks were executed.
      std::vector<std::pair<BasicBlock*, unsigned> > BlockCounts;
      getBlockCounts(BlockCounts);

      for (unsigned i = 0, e = BlockCounts.size(); i != e; ++i)
        if (&BlockCounts[i].first->getParent()->front() == BlockCounts[i].first)
          Counts.push_back(std::make_pair(BlockCounts[i].first->getParent(),
                                          BlockCounts[i].second));
    } else {
      std::cerr << "Function counts are not available!\n";
    }
    return;
  }

  unsigned Counter = 0;
  for (Module::iterator I = M.begin(), E = M.end();
       I != E && Counter != FunctionCounts.size(); ++I)
    if (!I->isExternal())
      Counts.push_back(std::make_pair(I, FunctionCounts[Counter++]));
}

// getBlockCounts - This method is used by consumers of block counting
// information.  If we do not directly have block count information, we
// compute it from other, more refined, types of profile information.
//
void ProfileInfoLoader::getBlockCounts(std::vector<std::pair<BasicBlock*,
                                                         unsigned> > &Counts) {
  if (BlockCounts.empty()) {
    if (hasAccurateEdgeCounts()) {
      // Synthesize block count information from edge frequency information.
      // The block execution frequency is equal to the sum of the execution
      // frequency of all outgoing edges from a block.
      //
      // If a block has no successors, this will not be correct, so we have to
      // special case it. :(
      std::vector<std::pair<Edge, unsigned> > EdgeCounts;
      getEdgeCounts(EdgeCounts);

      std::map<BasicBlock*, unsigned> InEdgeFreqs;

      BasicBlock *LastBlock = 0;
      TerminatorInst *TI = 0;
      for (unsigned i = 0, e = EdgeCounts.size(); i != e; ++i) {
        if (EdgeCounts[i].first.first != LastBlock) {
          LastBlock = EdgeCounts[i].first.first;
          TI = LastBlock->getTerminator();
          Counts.push_back(std::make_pair(LastBlock, 0));
        }
        Counts.back().second += EdgeCounts[i].second;
        unsigned SuccNum = EdgeCounts[i].first.second;
        if (SuccNum >= TI->getNumSuccessors()) {
          static bool Warned = false;
          if (!Warned) {
            std::cerr << "WARNING: profile info doesn't seem to match"
                      << " the program!\n";
            Warned = true;
          }
        } else {
          // If this successor has no successors of its own, we will never
          // compute an execution count for that block.  Remember the incoming
          // edge frequencies to add later.
          BasicBlock *Succ = TI->getSuccessor(SuccNum);
          if (Succ->getTerminator()->getNumSuccessors() == 0)
            InEdgeFreqs[Succ] += EdgeCounts[i].second;
        }
      }

      // Now we have to accumulate information for those blocks without
      // successors into our table.
      for (std::map<BasicBlock*, unsigned>::iterator I = InEdgeFreqs.begin(),
             E = InEdgeFreqs.end(); I != E; ++I) {
        unsigned i = 0;
        for (; i != Counts.size() && Counts[i].first != I->first; ++i)
          /*empty*/;
        if (i == Counts.size()) Counts.push_back(std::make_pair(I->first, 0));
        Counts[i].second += I->second;
      }

    } else {
      std::cerr << "Block counts are not available!\n";
    }
    return;
  }

  unsigned Counter = 0;
  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F)
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
      Counts.push_back(std::make_pair(BB, BlockCounts[Counter++]));
      if (Counter == BlockCounts.size())
        return;
    }
}

// getEdgeCounts - This method is used by consumers of edge counting
// information.  If we do not directly have edge count information, we compute
// it from other, more refined, types of profile information.
//
void ProfileInfoLoader::getEdgeCounts(std::vector<std::pair<Edge,
                                                  unsigned> > &Counts) {
  if (EdgeCounts.empty()) {
    std::cerr << "Edge counts not available, and no synthesis "
              << "is implemented yet!\n";
    return;
  }

  unsigned Counter = 0;
  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F)
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
      for (unsigned i = 0, e = BB->getTerminator()->getNumSuccessors();
           i != e; ++i) {
        Counts.push_back(std::make_pair(Edge(BB, i), EdgeCounts[Counter++]));
        if (Counter == EdgeCounts.size())
          return;
      }
}
<commit_msg>Add stub support for reading BBTraces.<commit_after>//===- ProfileInfoLoad.cpp - Load profile information from disk -----------===//
//
//                      The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The ProfileInfoLoader class is used to load and represent profiling
// information read in from the dump file.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/ProfileInfoLoader.h"
#include "llvm/Analysis/ProfileInfoTypes.h"
#include "llvm/Module.h"
#include "llvm/InstrTypes.h"
#include <cstdio>
#include <map>
using namespace llvm;

// ByteSwap - Byteswap 'Var' if 'Really' is true.
//
static inline unsigned ByteSwap(unsigned Var, bool Really) {
  if (!Really) return Var;
  return ((Var & (255<< 0)) << 24) |
         ((Var & (255<< 8)) <<  8) |
         ((Var & (255<<16)) >>  8) |
         ((Var & (255<<24)) >> 24);
}

static void ReadProfilingBlock(const char *ToolName, FILE *F,
                               bool ShouldByteSwap,
                               std::vector<unsigned> &Data) {
  // Read the number of entries...
  unsigned NumEntries;
  if (fread(&NumEntries, sizeof(unsigned), 1, F) != 1) {
    std::cerr << ToolName << ": data packet truncated!\n";
    perror(0);
    exit(1);
  }
  NumEntries = ByteSwap(NumEntries, ShouldByteSwap);

  // Read the counts...
  std::vector<unsigned> TempSpace(NumEntries);

  // Read in the block of data...
  if (fread(&TempSpace[0], sizeof(unsigned)*NumEntries, 1, F) != 1) {
    std::cerr << ToolName << ": data packet truncated!\n";
    perror(0);
    exit(1);
  }

  // Make sure we have enough space...
  if (Data.size() < NumEntries)
    Data.resize(NumEntries);

  // Accumulate the data we just read into the data.
  if (!ShouldByteSwap) {
    for (unsigned i = 0; i != NumEntries; ++i)
      Data[i] += TempSpace[i];
  } else {
    for (unsigned i = 0; i != NumEntries; ++i)
      Data[i] += ByteSwap(TempSpace[i], true);
  }
}

// ProfileInfoLoader ctor - Read the specified profiling data file, exiting the
// program if the file is invalid or broken.
//
ProfileInfoLoader::ProfileInfoLoader(const char *ToolName,
                                     const std::string &Filename,
                                     Module &TheModule) : M(TheModule) {
  FILE *F = fopen(Filename.c_str(), "r");
  if (F == 0) {
    std::cerr << ToolName << ": Error opening '" << Filename << "': ";
    perror(0);
    exit(1);
  }

  // Keep reading packets until we run out of them.
  unsigned PacketType;
  while (fread(&PacketType, sizeof(unsigned), 1, F) == 1) {
    // If the low eight bits of the packet are zero, we must be dealing with an
    // endianness mismatch.  Byteswap all words read from the profiling
    // information.
    bool ShouldByteSwap = (char)PacketType == 0;
    PacketType = ByteSwap(PacketType, ShouldByteSwap);

    switch (PacketType) {
    case ArgumentInfo: {
      unsigned ArgLength;
      if (fread(&ArgLength, sizeof(unsigned), 1, F) != 1) {
        std::cerr << ToolName << ": arguments packet truncated!\n";
        perror(0);
        exit(1);
      }
      ArgLength = ByteSwap(ArgLength, ShouldByteSwap);

      // Read in the arguments...
      std::vector<char> Chars(ArgLength+4);

      if (ArgLength)
        if (fread(&Chars[0], (ArgLength+3) & ~3, 1, F) != 1) {
          std::cerr << ToolName << ": arguments packet truncated!\n";
          perror(0);
          exit(1);
        }
      CommandLines.push_back(std::string(&Chars[0], &Chars[ArgLength]));
      break;
    }

    case FunctionInfo:
      ReadProfilingBlock(ToolName, F, ShouldByteSwap, FunctionCounts);
      break;

    case BlockInfo:
      ReadProfilingBlock(ToolName, F, ShouldByteSwap, BlockCounts);
      break;

    case EdgeInfo:
      ReadProfilingBlock(ToolName, F, ShouldByteSwap, EdgeCounts);
      break;

    case BBTraceInfo:
      ReadProfilingBlock(ToolName, F, ShouldByteSwap, BBTrace);
      break;

    default:
      std::cerr << ToolName << ": Unknown packet type #" << PacketType << "!\n";
      exit(1);
    }
  }

  fclose(F);
}

// getFunctionCounts - This method is used by consumers of function counting
// information.  If we do not directly have function count information, we
// compute it from other, more refined, types of profile information.
//
void ProfileInfoLoader::getFunctionCounts(std::vector<std::pair<Function*,
                                                      unsigned> > &Counts) {
  if (FunctionCounts.empty()) {
    if (hasAccurateBlockCounts()) {
      // Synthesize function frequency information from the number of times
      // their entry blocks were executed.
      std::vector<std::pair<BasicBlock*, unsigned> > BlockCounts;
      getBlockCounts(BlockCounts);

      for (unsigned i = 0, e = BlockCounts.size(); i != e; ++i)
        if (&BlockCounts[i].first->getParent()->front() == BlockCounts[i].first)
          Counts.push_back(std::make_pair(BlockCounts[i].first->getParent(),
                                          BlockCounts[i].second));
    } else {
      std::cerr << "Function counts are not available!\n";
    }
    return;
  }

  unsigned Counter = 0;
  for (Module::iterator I = M.begin(), E = M.end();
       I != E && Counter != FunctionCounts.size(); ++I)
    if (!I->isExternal())
      Counts.push_back(std::make_pair(I, FunctionCounts[Counter++]));
}

// getBlockCounts - This method is used by consumers of block counting
// information.  If we do not directly have block count information, we
// compute it from other, more refined, types of profile information.
//
void ProfileInfoLoader::getBlockCounts(std::vector<std::pair<BasicBlock*,
                                                         unsigned> > &Counts) {
  if (BlockCounts.empty()) {
    if (hasAccurateEdgeCounts()) {
      // Synthesize block count information from edge frequency information.
      // The block execution frequency is equal to the sum of the execution
      // frequency of all outgoing edges from a block.
      //
      // If a block has no successors, this will not be correct, so we have to
      // special case it. :(
      std::vector<std::pair<Edge, unsigned> > EdgeCounts;
      getEdgeCounts(EdgeCounts);

      std::map<BasicBlock*, unsigned> InEdgeFreqs;

      BasicBlock *LastBlock = 0;
      TerminatorInst *TI = 0;
      for (unsigned i = 0, e = EdgeCounts.size(); i != e; ++i) {
        if (EdgeCounts[i].first.first != LastBlock) {
          LastBlock = EdgeCounts[i].first.first;
          TI = LastBlock->getTerminator();
          Counts.push_back(std::make_pair(LastBlock, 0));
        }
        Counts.back().second += EdgeCounts[i].second;
        unsigned SuccNum = EdgeCounts[i].first.second;
        if (SuccNum >= TI->getNumSuccessors()) {
          static bool Warned = false;
          if (!Warned) {
            std::cerr << "WARNING: profile info doesn't seem to match"
                      << " the program!\n";
            Warned = true;
          }
        } else {
          // If this successor has no successors of its own, we will never
          // compute an execution count for that block.  Remember the incoming
          // edge frequencies to add later.
          BasicBlock *Succ = TI->getSuccessor(SuccNum);
          if (Succ->getTerminator()->getNumSuccessors() == 0)
            InEdgeFreqs[Succ] += EdgeCounts[i].second;
        }
      }

      // Now we have to accumulate information for those blocks without
      // successors into our table.
      for (std::map<BasicBlock*, unsigned>::iterator I = InEdgeFreqs.begin(),
             E = InEdgeFreqs.end(); I != E; ++I) {
        unsigned i = 0;
        for (; i != Counts.size() && Counts[i].first != I->first; ++i)
          /*empty*/;
        if (i == Counts.size()) Counts.push_back(std::make_pair(I->first, 0));
        Counts[i].second += I->second;
      }

    } else {
      std::cerr << "Block counts are not available!\n";
    }
    return;
  }

  unsigned Counter = 0;
  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F)
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
      Counts.push_back(std::make_pair(BB, BlockCounts[Counter++]));
      if (Counter == BlockCounts.size())
        return;
    }
}

// getEdgeCounts - This method is used by consumers of edge counting
// information.  If we do not directly have edge count information, we compute
// it from other, more refined, types of profile information.
//
void ProfileInfoLoader::getEdgeCounts(std::vector<std::pair<Edge,
                                                  unsigned> > &Counts) {
  if (EdgeCounts.empty()) {
    std::cerr << "Edge counts not available, and no synthesis "
              << "is implemented yet!\n";
    return;
  }

  unsigned Counter = 0;
  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F)
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
      for (unsigned i = 0, e = BB->getTerminator()->getNumSuccessors();
           i != e; ++i) {
        Counts.push_back(std::make_pair(Edge(BB, i), EdgeCounts[Counter++]));
        if (Counter == EdgeCounts.size())
          return;
      }
}

// getBBTrace - This method is used by consumers of basic-block trace
// information.
//
void ProfileInfoLoader::getBBTrace(std::vector<BasicBlock *> &Trace) {
  if (BBTrace.empty ()) {
    std::cerr << "Basic block trace is not available!\n";
    return;
  }
  std::cerr << "Basic block trace loading is not implemented yet!\n";
}

<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_kf_test.cpp
 * \date Febuary 2015
 * \author Jan Issac (jan.issac@gmail.com)
 */

#include <gtest/gtest.h>

#include <Eigen/Dense>

#include <cmath>
#include <iostream>

#include <fl/model/process/linear_process_model.hpp>
#include <fl/model/observation/linear_observation_model.hpp>
#include <fl/filter/filter_interface.hpp>
#include <fl/filter/gaussian/gaussian_filter.hpp>
#include <fl/util/math/linear_algebra.hpp>

using namespace fl;

TEST(KalmanFilterTests, init_fixed_size_predict)
{
    typedef double Scalar;
    typedef Eigen::Matrix<Scalar, 10, 1> State;
    typedef Eigen::Matrix<Scalar, 1 , 1> Input;
    typedef Eigen::Matrix<Scalar, 20, 1> Obsrv;

    typedef LinearGaussianProcessModel<State, Input> LinearProcess;
    typedef LinearObservationModel<Obsrv, State> LinearObservation;

    // the KalmanFilter
    typedef GaussianFilter<LinearProcess, LinearObservation> Algo;
    typedef FilterInterface<Algo> Filter;

    LinearProcess::SecondMoment Q = LinearProcess::SecondMoment::Identity();
    Filter&& filter = Algo(LinearProcess(Q), LinearObservation());

    Filter::StateDistribution state_dist;

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(state_dist.covariance().isIdentity());

    filter.predict(1.0, Input(1), state_dist, state_dist);

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(fl::are_similar(state_dist.covariance(), 2. * Q));
}

TEST(KalmanFilterTests, init_dynamic_size_predict)
{
    typedef double Scalar;
    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> State;
    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Input;
    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Obsrv;

    const int dim_state = 10;
    const int dim_obsrv = 20;

    typedef LinearGaussianProcessModel<State, Input> LinearProcess;
    typedef LinearObservationModel<Obsrv, State> LinearObservation;

    // the KalmanFilter
    typedef GaussianFilter<LinearProcess, LinearObservation> Algo;
    typedef FilterInterface<Algo> Filter;

    LinearProcess::SecondMoment Q =
        LinearProcess::SecondMoment::Identity(dim_state, dim_state);

//    Traits<ObservationModel>::SecondMoment R =
//        Traits<ObservationModel>::SecondMoment::Identity(dim_obsrv, dim_obsrv);

    Filter&& filter = Algo(
        LinearProcess(Q, dim_state),
        LinearObservation(dim_obsrv, dim_state));

    auto state_dist  = Filter::StateDistribution(dim_state);

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(state_dist.covariance().isIdentity());

    filter.predict(1.0, Input(1), state_dist, state_dist);

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(fl::are_similar(state_dist.covariance(), 2. * Q));
}

//TEST(KalmanFilterTests, fixed_size_predict_update)
//{
//    typedef double Scalar;
//    typedef Eigen::Matrix<Scalar, 6, 1> State;
//    typedef Eigen::Matrix<Scalar, 6, 1> Input;
//    typedef Eigen::Matrix<Scalar, 6, 1> Obsrv;

//    // the KalmanFilter
//    typedef GaussianFilter<
//                LinearGaussianProcessModel<State, Input>,
//                LinearObservationModel<Obsrv, State>
//            > Algo;

//    typedef FilterInterface<Algo> Filter;

//    typedef typename Traits<Algo>::ProcessModel ProcessModel;
//    typedef typename Traits<Algo>::ObservationModel ObservationModel;

//    Traits<ProcessModel>::SecondMoment Q =
//        Traits<ProcessModel>::SecondMoment::Random() * 1.5;
////    Traits<ObservationModel>::SecondMoment R =
////        Traits<ObservationModel>::SecondMoment::Random();

//    Q *= Q.transpose();
//    R *= R.transpose();

//    Traits<ProcessModel>::DynamicsMatrix A =
//        Traits<ProcessModel>::DynamicsMatrix::Random();

//    Traits<ObservationModel>::SensorMatrix H =
//        Traits<ObservationModel>::SensorMatrix::Random();

//    ProcessModel process_model = ProcessModel(Q);
//    ObservationModel obsrv_model = ObservationModel(R);

//    process_model.A(A);
//    obsrv_model.H(H);

//    Filter&& filter = Algo(process_model, obsrv_model);

//    Filter::StateDistribution state_dist;

//    EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//    for (int i = 0; i < 2000; ++i)
//    {
//        filter.predict(1.0, Input(), state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//        Obsrv y = Obsrv::Random();
//        filter.update(y, state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());
//    }
//}

//TEST(KalmanFilterTests, dynamic_size_predict_update)
//{
//    typedef double Scalar;
//    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> State;
//    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Input;
//    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Obsrv;

//    const int dim_state = 10;
//    const int dim_obsrv = 10;

//    // the KalmanFilter
//    typedef GaussianFilter<
//                LinearGaussianProcessModel<State, Input>,
//                LinearGaussianObservationModel<Obsrv, State>
//            > Algo;

//    typedef FilterInterface<Algo> Filter;

//    typedef typename Traits<Algo>::ProcessModel ProcessModel;
//    typedef typename Traits<Algo>::ObservationModel ObservationModel;

//    Traits<ProcessModel>::SecondMoment Q =
//        Traits<ProcessModel>::SecondMoment::Random(dim_state, dim_state) * 1.5;
//    Q *= Q.transpose();

//    Traits<ProcessModel>::DynamicsMatrix A =
//        Traits<ProcessModel>::DynamicsMatrix::Random(dim_state, dim_state);

//    Traits<ObservationModel>::SecondMoment R =
//        Traits<ObservationModel>::SecondMoment::Random(dim_obsrv, dim_obsrv);
//    R *= R.transpose();

//    Traits<ObservationModel>::SensorMatrix H =
//        Traits<ObservationModel>::SensorMatrix::Random(dim_obsrv, dim_state);

//    ProcessModel process_model =
//        ProcessModel(Q, dim_state);

//    ObservationModel obsrv_model =
//        ObservationModel(R, dim_obsrv, dim_state);

//    process_model.A(A);
//    obsrv_model.H(H);

//    Filter&& filter = Algo(process_model, obsrv_model);

//    Filter::StateDistribution state_dist(dim_state);

//    EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//    for (int i = 0; i < 2000; ++i)
//    {
//        filter.predict(1.0, Input(1), state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//        Obsrv y = Obsrv::Random(dim_obsrv);
//        filter.update(y, state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());
//    }
//}
<commit_msg>updated KF unit tests<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_kf_test.cpp
 * \date Febuary 2015
 * \author Jan Issac (jan.issac@gmail.com)
 */

#include <gtest/gtest.h>

#include <Eigen/Dense>

#include <cmath>
#include <iostream>

#include <fl/model/process/linear_process_model.hpp>
#include <fl/model/observation/linear_observation_model.hpp>
#include <fl/filter/filter_interface.hpp>
#include <fl/filter/gaussian/gaussian_filter.hpp>
#include <fl/util/math/linear_algebra.hpp>

using namespace fl;

TEST(KalmanFilterTests, init_fixed_size_predict)
{
    typedef double Scalar;
    typedef Eigen::Matrix<Scalar, 10, 1> State;
    typedef Eigen::Matrix<Scalar, 1 , 1> Input;
    typedef Eigen::Matrix<Scalar, 20, 1> Obsrv;

    typedef LinearStateTransitionModel<State, Input> LinearProcess;
    typedef LinearObservationModel<Obsrv, State> LinearObservation;

    // the KalmanFilter
    typedef GaussianFilter<LinearProcess, LinearObservation> Filter;
    auto filter = Filter(LinearProcess(), LinearObservation());
    Filter::StateDistribution state_dist;

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(state_dist.covariance().isIdentity());

    filter.predict(1.0, Input(1), state_dist, state_dist);

    auto Q = filter.process_model().noise_matrix_squared();

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(fl::are_similar(state_dist.covariance(), 2. * Q));
}

TEST(KalmanFilterTests, init_dynamic_size_predict)
{
    typedef double Scalar;
    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> State;
    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Input;
    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Obsrv;

    const int dim_state = 10;
    const int dim_obsrv = 20;
    const int dim_input = 1;

    typedef LinearStateTransitionModel<State, Input> LinearProcess;
    typedef LinearObservationModel<Obsrv, State> LinearObservation;

    // the KalmanFilter
    typedef GaussianFilter<LinearProcess, LinearObservation> Filter;

    auto filter = Filter(LinearProcess(dim_state, dim_input),
                         LinearObservation(dim_obsrv, dim_state));

    auto state_dist  = Filter::StateDistribution(dim_state);

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(state_dist.covariance().isIdentity());

    filter.predict(1.0, Input(1), state_dist, state_dist);

    auto Q = filter.process_model().noise_matrix_squared();

    EXPECT_TRUE(state_dist.mean().isZero());
    EXPECT_TRUE(fl::are_similar(state_dist.covariance(), 2. * Q));
}

//TEST(KalmanFilterTests, fixed_size_predict_update)
//{
//    typedef double Scalar;
//    typedef Eigen::Matrix<Scalar, 6, 1> State;
//    typedef Eigen::Matrix<Scalar, 6, 1> Input;
//    typedef Eigen::Matrix<Scalar, 6, 1> Obsrv;

//    // the KalmanFilter
//    typedef GaussianFilter<
//                LinearGaussianProcessModel<State, Input>,
//                LinearObservationModel<Obsrv, State>
//            > Algo;

//    typedef FilterInterface<Algo> Filter;

//    typedef typename Traits<Algo>::ProcessModel ProcessModel;
//    typedef typename Traits<Algo>::ObservationModel ObservationModel;

//    Traits<ProcessModel>::SecondMoment Q =
//        Traits<ProcessModel>::SecondMoment::Random() * 1.5;
////    Traits<ObservationModel>::SecondMoment R =
////        Traits<ObservationModel>::SecondMoment::Random();

//    Q *= Q.transpose();
//    R *= R.transpose();

//    Traits<ProcessModel>::DynamicsMatrix A =
//        Traits<ProcessModel>::DynamicsMatrix::Random();

//    Traits<ObservationModel>::SensorMatrix H =
//        Traits<ObservationModel>::SensorMatrix::Random();

//    ProcessModel process_model = ProcessModel(Q);
//    ObservationModel obsrv_model = ObservationModel(R);

//    process_model.A(A);
//    obsrv_model.H(H);

//    Filter&& filter = Algo(process_model, obsrv_model);

//    Filter::StateDistribution state_dist;

//    EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//    for (int i = 0; i < 2000; ++i)
//    {
//        filter.predict(1.0, Input(), state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//        Obsrv y = Obsrv::Random();
//        filter.update(y, state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());
//    }
//}

//TEST(KalmanFilterTests, dynamic_size_predict_update)
//{
//    typedef double Scalar;
//    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> State;
//    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Input;
//    typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Obsrv;

//    const int dim_state = 10;
//    const int dim_obsrv = 10;

//    // the KalmanFilter
//    typedef GaussianFilter<
//                LinearGaussianProcessModel<State, Input>,
//                LinearGaussianObservationModel<Obsrv, State>
//            > Algo;

//    typedef FilterInterface<Algo> Filter;

//    typedef typename Traits<Algo>::ProcessModel ProcessModel;
//    typedef typename Traits<Algo>::ObservationModel ObservationModel;

//    Traits<ProcessModel>::SecondMoment Q =
//        Traits<ProcessModel>::SecondMoment::Random(dim_state, dim_state) * 1.5;
//    Q *= Q.transpose();

//    Traits<ProcessModel>::DynamicsMatrix A =
//        Traits<ProcessModel>::DynamicsMatrix::Random(dim_state, dim_state);

//    Traits<ObservationModel>::SecondMoment R =
//        Traits<ObservationModel>::SecondMoment::Random(dim_obsrv, dim_obsrv);
//    R *= R.transpose();

//    Traits<ObservationModel>::SensorMatrix H =
//        Traits<ObservationModel>::SensorMatrix::Random(dim_obsrv, dim_state);

//    ProcessModel process_model =
//        ProcessModel(Q, dim_state);

//    ObservationModel obsrv_model =
//        ObservationModel(R, dim_obsrv, dim_state);

//    process_model.A(A);
//    obsrv_model.H(H);

//    Filter&& filter = Algo(process_model, obsrv_model);

//    Filter::StateDistribution state_dist(dim_state);

//    EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//    for (int i = 0; i < 2000; ++i)
//    {
//        filter.predict(1.0, Input(1), state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());

//        Obsrv y = Obsrv::Random(dim_obsrv);
//        filter.update(y, state_dist, state_dist);
//        EXPECT_TRUE(state_dist.covariance().ldlt().isPositive());
//    }
//}
<|endoftext|>


<commit_before>// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr -g %s -O3 -o %t
// RUN: %run %t &> %t.log
// RUN: cat %t.log | not count 0 && FileCheck --input-file %t.log %s || cat %t.log | count 0

// REQUIRES: cxxabi

#include <sys/mman.h>
#include <unistd.h>

class Base {
public:
  int i;
  virtual void print() {}
};

class Derived : public Base {
public:
  void print() {}
};

int main() {
  int page_size = getpagesize();

  void *non_accessible = mmap(nullptr, page_size, PROT_NONE,
                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

  if (non_accessible == MAP_FAILED)
    return 0;

  void *accessible = mmap((char*)non_accessible + page_size, page_size,
                          PROT_READ | PROT_WRITE,
                          MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (accessible == MAP_FAILED)
    return 0;

  char *c = new char[sizeof(Derived)];

  // The goal is to trigger a condition when Vptr points to accessible memory,
  // but VptrPrefix does not. That has been triggering SIGSEGV in UBSan code.
  void **vtable_ptr = reinterpret_cast<void **>(c);
  *vtable_ptr = (void*)accessible;

  Derived *list = (Derived *)c;

// CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base'
// CHECK-NEXT: invalid vptr
  int foo = list->i;
  return 0;
}
<commit_msg>[ubsan] Update a test missed in r309008, NFC<commit_after>// RUN: %clangxx -std=c++11 -frtti -fsanitize=vptr,null -g %s -O3 -o %t
// RUN: %run %t &> %t.log
// RUN: cat %t.log | not count 0 && FileCheck --input-file %t.log %s || cat %t.log | count 0

// REQUIRES: cxxabi

#include <sys/mman.h>
#include <unistd.h>

class Base {
public:
  int i;
  virtual void print() {}
};

class Derived : public Base {
public:
  void print() {}
};

int main() {
  int page_size = getpagesize();

  void *non_accessible = mmap(nullptr, page_size, PROT_NONE,
                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

  if (non_accessible == MAP_FAILED)
    return 0;

  void *accessible = mmap((char*)non_accessible + page_size, page_size,
                          PROT_READ | PROT_WRITE,
                          MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (accessible == MAP_FAILED)
    return 0;

  char *c = new char[sizeof(Derived)];

  // The goal is to trigger a condition when Vptr points to accessible memory,
  // but VptrPrefix does not. That has been triggering SIGSEGV in UBSan code.
  void **vtable_ptr = reinterpret_cast<void **>(c);
  *vtable_ptr = (void*)accessible;

  Derived *list = (Derived *)c;

// CHECK: PR33221.cpp:[[@LINE+2]]:19: runtime error: member access within address {{.*}} which does not point to an object of type 'Base'
// CHECK-NEXT: invalid vptr
  int foo = list->i;
  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <Windows.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <algorithm>
/*
mineBot.cpp
T.Lloyd

An attempt at an openCV minesweeper bot...

*/
using namespace cv;
using namespace std;

#define until for
#define endOfTime (;;)

BOOL captureFrame(Mat &f,HWND mineHandle,int height, int width){
	HDC mineHDC, mineCompat;
	HBITMAP mineBit;
	BITMAP b;
	BITMAPINFOHEADER mineH;
	if (mineHandle == NULL){
		cout << "Game Not Found\n";
		return FALSE;
	}
	mineHDC = GetDC(mineHandle);
	mineCompat = CreateCompatibleDC(mineHDC);
	if (!mineCompat){
		cout << "Error creating compatible DC\n";
		return FALSE;
	}
	//SetStretchBltMode(mineCompat, HALFTONE);
	SetStretchBltMode(mineCompat, HALFTONE);

	mineBit = CreateCompatibleBitmap(mineHDC, width, height);
	if (mineBit == NULL){
		cout << "Bitmap Creation Failed!\n";
		return FALSE;
	}
	mineH.biSize = sizeof(BITMAPINFOHEADER);
	mineH.biPlanes = 1;
	mineH.biWidth = width;
	mineH.biHeight = -height;
	mineH.biBitCount = 32;
	mineH.biCompression = BI_RGB;

	SelectObject(mineCompat, mineBit);
	if (!StretchBlt(mineCompat, 0, 0, width, height, mineHDC, 0, 0, width, height, SRCCOPY)){
		cout << "Error Stretch BLT\n";
		return FALSE;
	}

	//BitBlt(mineCompat, 0, 0, width, height, mineHDC, 0, 0, SRCCOPY);
	//GetObject(mineBit, sizeof(BITMAP), &b);
	//GetDIBits(mineHDC, mineBit, 0, height, frame.data, (BITMAPINFO*)&mineH, DIB_RGB_COLORS);
	GetDIBits(mineCompat, mineBit, 0, height, f.data, (BITMAPINFO*)&mineH, DIB_RGB_COLORS);

	DeleteObject(mineBit);
	DeleteDC(mineCompat);
	ReleaseDC(mineHandle, mineHDC);

	return TRUE;
}

BOOL countSquares(Mat &f,Mat &t, Mat &r,double threshold,vector<Point> &squares,Scalar colour){
	//Frame,Template,Result,Number of squares
	Mat greysrc = f.clone();
	Mat greyTemp = t.clone();
	cvtColor(f, greysrc, COLOR_BGR2GRAY);
	cvtColor(t, greyTemp, COLOR_BGR2GRAY);

	matchTemplate(greysrc, greyTemp, r, TM_CCOEFF_NORMED);
	normalize(r, r, 0, 1, NORM_MINMAX, -1, Mat());

	double minVal;
	double maxVal;
	Point minLoc;
	Point maxLoc;
	Point matchLoc;
	Point prevMatchLoc;
	squares.clear();
	bool edge = FALSE;
	int dup = 0; //count duplicates
	for (int i = 0, j = 0; i < 81; i++){
		//minesweeper has gradient so only detects two of the squares.
		minMaxLoc(r, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
		//if (maxVal > 0.87){
		if ((maxVal > threshold)){
			matchLoc = maxLoc;
			for (int k = 0; k < squares.size(); k++){
				if (((abs(matchLoc.y - squares[k].y) <= 3) && (abs(matchLoc.x - squares[k].x) <= 3))){
					//cout << "!";
					dup++;
				}
			}
			if (matchLoc.x > 30){
				edge = TRUE;
			}
			else{
				edge = FALSE;
			}
				//cout << "Duplicates=" << dup << "\n";
				//dup = 0;
				if ((dup == 0)&&(edge==TRUE)){
					squares.push_back(matchLoc);
					rectangle(r, matchLoc, Point(matchLoc.x + t.cols, matchLoc.y + t.rows), Scalar(0, 0, 0), CV_FILLED, 8, 0);
					rectangle(f, matchLoc, Point(matchLoc.x + t.cols, matchLoc.y + t.rows), colour, 1, 8, 0);
				}
			//}
			//}
		}
	}
	greysrc.release();
	greyTemp.release();
	//cout << "Vector Size=" << squares.size() << "\n";
	return TRUE;
}

void printSquares(vector<Point> &p){
	for (int k = 0; k < p.size(); k++){
		cout << "(" << p[k].x << "," << p[k].y << ")\n";
	}
}

bool sortX(Point p1, Point p2){return (p1.x < p2.x);}
bool sortY(Point p1, Point p2){ return (p1.y < p2.y); }

void sortGrid(vector<Point> &p){
	//9x9 Grid Sorting Algorithm
	std::sort(p.begin(), p.end(), sortX);
	for (int i = 0; i < 9; i++){
		std::sort(p.begin() + (i * 9), p.begin() + ((i + 1) * 9), sortY);
	}
}
void printGrid(char** &g){
	for (int j = 0; j < 9; j++){
		for (int k = 0; k < 9; k++){
			cout << +g[k][j];
		}
		cout << "\n";
	}
}

void updateGrid(char** &g,vector<Point>&s,vector<Point>&masterGrid,char value){
	for (int j = 0; j < s.size(); j++){
		for (int k = 0; k < masterGrid.size(); k++){
			if ((s[j].x > masterGrid[k].x) && (s[j].x <(masterGrid[k].x + 16)) && (s[j].y > masterGrid[k].y) && (s[j].y < (masterGrid[k].y + 16))){
				int xpos = (int)(k / 9);
				int ypos = (int)(k % 9);
				g[xpos][ypos] = value;
			}
		}
	}
}

int main(void){
	std::cout << "mineBot\nT.Lloyd\n";
	Mat frame;
	HWND mineHandle = FindWindow(NULL,L"Minesweeper");
	if (mineHandle == NULL){
		cout << "Game Not Found\n";
		return -1;
	}
	else{
		cout << "Game Successfully Found!\n";
	}
	namedWindow("Win", 1);
	RECT winSize;

	int height, width;
	int unpressed = 0;
	GetClientRect(mineHandle, &winSize);
	height = winSize.bottom;
	width = winSize.right;

	frame.create(height, width, CV_8UC4);
	Point pt;
	pt.x = 0;
	pt.y = 0;

	Mat temp = imread("Images//square2.jpg", CV_LOAD_IMAGE_COLOR);
	Mat oneTemp = imread("Images//one3.jpg", CV_LOAD_IMAGE_COLOR);
	Mat twoTemp = imread("Images//two.jpg", CV_LOAD_IMAGE_COLOR);
	Mat threeTemp = imread("Images//three.jpg", CV_LOAD_IMAGE_COLOR);
	Mat fourTemp = imread("Images//four.jpg", CV_LOAD_IMAGE_COLOR);
	//cvtColor(temp, temp, CV_8UC4,0);
	//Mat result;
	//Mat oneResult;

	//----------------------------------------------------------------------------
	//Initial read to define co-ordinates

	Mat gridResult;
	vector<Point> gridMap;
	captureFrame(frame, mineHandle, height, width);
	gridResult.create(frame.cols - temp.cols + 1, frame.rows - temp.rows + 1, CV_32FC1);
	//unPressedMat = frame.clone();
	countSquares(frame, temp, gridResult, 0.920, gridMap, Scalar(0, 255, 255));
	cout << "Unpressed Squares: " << gridResult.size() << "\n";
	printSquares(gridMap);
	cv::imshow("Win", frame);
	gridResult.release();

	sortGrid(gridMap);
	printSquares(gridMap);
//	for (int i = 0; i < gridMap.size; i++){

//	}
	//Sleep(1000 * 5);
	//----------------------------------------------------------------------------

	//imwrite("Images//Master.jpg", frame);
	//result.create(frame.cols - temp.cols + 1, frame.rows - temp.rows + 1, CV_32FC1);
	char **grid = (char **)calloc(9, sizeof(char));
	for (int k = 0; k < 9; k++){
		grid[k] = (char*)calloc(9, sizeof(char));
	}
//	char grid[9][9] = { 0 };
	vector<Point> unsquare;
	vector<Point> oneSquares;
	vector<Point> twoSquares;
	vector<Point> threeSquares;
	vector<Point> fourSquares;
	Mat unPressedMat;
	Mat oneMat;
	Mat twoMat;
	Mat threeMat;
	Mat fourMat;
	until endOfTime{
		if (captureFrame(frame, mineHandle,height,width)==TRUE){
			if (!frame.empty()){
				//matchTemplate(frame, temp, result, TM_CCOEFF_NORMED);
				Mat result;
				result.create(frame.cols - temp.cols + 1, frame.rows - temp.rows + 1, CV_32FC1);
				//unPressedMat = frame.clone();
				countSquares(frame, temp, result,0.920, unsquare, Scalar(0,255, 255));
				cout << "Unpressed Squares: " << unsquare.size() << "\n";
				//printSquares(unsquare);
				result.release();
				if (unsquare.size() != 81){
					Mat oneResult;
					oneResult.create(frame.cols - oneTemp.cols + 1, frame.rows - oneTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, oneTemp, oneResult, 0.9, oneSquares, Scalar(255, 0, 0));
					cout << "One Squares: " << oneSquares.size() << "\n";
					oneResult.release();

					Mat twoResult;
					twoResult.create(frame.cols - twoTemp.cols + 1, frame.rows - twoTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, twoTemp, twoResult, 0.9, twoSquares, Scalar(255, 0, 0));
					cout << "Two Squares: " << twoSquares.size() << "\n";
					twoResult.release();

					Mat threeResult;
					threeResult.create(frame.cols - threeTemp.cols + 1, frame.rows - threeTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, threeTemp, threeResult, 0.9, threeSquares, Scalar(255, 0, 0));
					cout << "Three Squares: " << threeSquares.size() << "\n";
					threeResult.release();

					Mat fourResult;
					fourResult.create(frame.cols - fourTemp.cols + 1, frame.rows - fourTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, fourTemp, fourResult, 0.9, fourSquares, Scalar(255, 0, 0));
					cout << "Four Squares: " << fourSquares.size() << "\n";
					fourResult.release();
				}
				//update grid
				updateGrid(grid, unsquare, gridMap, 0);
				updateGrid(grid, oneSquares, gridMap, 1);
				updateGrid(grid, twoSquares, gridMap, 2);
				updateGrid(grid, threeSquares, gridMap, 3);
				printGrid(grid);
				cv::imshow("Win", frame);
				//imshow("One", oneMat);
				Sleep(2000);
			}
		}
		if (waitKey(30) >= 0) break;
	}
	return 0;
}<commit_msg>Clears grid every iteration of the loop<commit_after>#include <iostream>
#include <Windows.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <algorithm>
#include <string.h>
/*
mineBot.cpp
T.Lloyd

An attempt at an openCV minesweeper bot...

*/
using namespace cv;
using namespace std;

#define until for
#define endOfTime (;;)

BOOL captureFrame(Mat &f,HWND mineHandle,int height, int width){
	HDC mineHDC, mineCompat;
	HBITMAP mineBit;
	BITMAP b;
	BITMAPINFOHEADER mineH;
	if (mineHandle == NULL){
		cout << "Game Not Found\n";
		return FALSE;
	}
	mineHDC = GetDC(mineHandle);
	mineCompat = CreateCompatibleDC(mineHDC);
	if (!mineCompat){
		cout << "Error creating compatible DC\n";
		return FALSE;
	}
	//SetStretchBltMode(mineCompat, HALFTONE);
	SetStretchBltMode(mineCompat, HALFTONE);

	mineBit = CreateCompatibleBitmap(mineHDC, width, height);
	if (mineBit == NULL){
		cout << "Bitmap Creation Failed!\n";
		return FALSE;
	}
	mineH.biSize = sizeof(BITMAPINFOHEADER);
	mineH.biPlanes = 1;
	mineH.biWidth = width;
	mineH.biHeight = -height;
	mineH.biBitCount = 32;
	mineH.biCompression = BI_RGB;

	SelectObject(mineCompat, mineBit);
	if (!StretchBlt(mineCompat, 0, 0, width, height, mineHDC, 0, 0, width, height, SRCCOPY)){
		cout << "Error Stretch BLT\n";
		return FALSE;
	}

	//BitBlt(mineCompat, 0, 0, width, height, mineHDC, 0, 0, SRCCOPY);
	//GetObject(mineBit, sizeof(BITMAP), &b);
	//GetDIBits(mineHDC, mineBit, 0, height, frame.data, (BITMAPINFO*)&mineH, DIB_RGB_COLORS);
	GetDIBits(mineCompat, mineBit, 0, height, f.data, (BITMAPINFO*)&mineH, DIB_RGB_COLORS);

	DeleteObject(mineBit);
	DeleteDC(mineCompat);
	ReleaseDC(mineHandle, mineHDC);

	return TRUE;
}

BOOL countSquares(Mat &f,Mat &t, Mat &r,double threshold,vector<Point> &squares,Scalar colour){
	//Frame,Template,Result,Number of squares
	Mat greysrc = f.clone();
	Mat greyTemp = t.clone();
	cvtColor(f, greysrc, COLOR_BGR2GRAY);
	cvtColor(t, greyTemp, COLOR_BGR2GRAY);

	matchTemplate(greysrc, greyTemp, r, TM_CCOEFF_NORMED);
	normalize(r, r, 0, 1, NORM_MINMAX, -1, Mat());

	double minVal;
	double maxVal;
	Point minLoc;
	Point maxLoc;
	Point matchLoc;
	Point prevMatchLoc;
	squares.clear();
	bool edge = FALSE;
	int dup = 0; //count duplicates
	for (int i = 0, j = 0; i < 81; i++){
		//minesweeper has gradient so only detects two of the squares.
		minMaxLoc(r, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
		//if (maxVal > 0.87){
		if ((maxVal > threshold)){
			matchLoc = maxLoc;
			for (int k = 0; k < squares.size(); k++){
				if (((abs(matchLoc.y - squares[k].y) <= 3) && (abs(matchLoc.x - squares[k].x) <= 3))){
					//cout << "!";
					dup++;
				}
			}
			if (matchLoc.x > 30){
				edge = TRUE;
			}
			else{
				edge = FALSE;
			}
				//cout << "Duplicates=" << dup << "\n";
				//dup = 0;
				if ((dup == 0)&&(edge==TRUE)){
					squares.push_back(matchLoc);
					rectangle(r, matchLoc, Point(matchLoc.x + t.cols, matchLoc.y + t.rows), Scalar(0, 0, 0), CV_FILLED, 8, 0);
					rectangle(f, matchLoc, Point(matchLoc.x + t.cols, matchLoc.y + t.rows), colour, 1, 8, 0);
				}
			//}
			//}
		}
	}
	greysrc.release();
	greyTemp.release();
	//cout << "Vector Size=" << squares.size() << "\n";
	return TRUE;
}

void printSquares(vector<Point> &p){
	for (int k = 0; k < p.size(); k++){
		cout << "(" << p[k].x << "," << p[k].y << ")\n";
	}
}

bool sortX(Point p1, Point p2){return (p1.x < p2.x);}
bool sortY(Point p1, Point p2){ return (p1.y < p2.y); }

void sortGrid(vector<Point> &p){
	//9x9 Grid Sorting Algorithm
	std::sort(p.begin(), p.end(), sortX);
	for (int i = 0; i < 9; i++){
		std::sort(p.begin() + (i * 9), p.begin() + ((i + 1) * 9), sortY);
	}
}
void printGrid(char** &g){
	for (int j = 0; j < 9; j++){
		for (int k = 0; k < 9; k++){
			cout << g[k][j];
		}
		cout << "\n";
	}
}

void updateGrid(char** &g,vector<Point>&s,vector<Point>&masterGrid,char value){
	for (int j = 0; j < s.size(); j++){
		for (int k = 0; k < masterGrid.size(); k++){
			if ((s[j].x >= masterGrid[k].x) && (s[j].x <=(masterGrid[k].x + 16)) && (s[j].y >= masterGrid[k].y) && (s[j].y <= (masterGrid[k].y + 16))){
				int xpos = (int)(k / 9);
				int ypos = (int)(k % 9);
				g[xpos][ypos] = value;
			}
		}
	}
}

void clearGrid(char** &g){
	for (int i = 0; i < 9; i++){
		for (int k = 0; k < 9; k++){
			g[i][k] = 0;
		}
	}
}

int main(void){
	std::cout << "mineBot\nT.Lloyd\n";
	Mat frame;
	HWND mineHandle = FindWindow(NULL,L"Minesweeper");
	if (mineHandle == NULL){
		cout << "Game Not Found\n";
		return -1;
	}
	else{
		cout << "Game Successfully Found!\n";
	}
	namedWindow("Win", 1);
	RECT winSize;

	int height, width;
	int unpressed = 0;
	GetClientRect(mineHandle, &winSize);
	height = winSize.bottom;
	width = winSize.right;

	frame.create(height, width, CV_8UC4);
	Point pt;
	pt.x = 0;
	pt.y = 0;

	Mat temp = imread("Images//square2.jpg", CV_LOAD_IMAGE_COLOR);
	Mat oneTemp = imread("Images//one3.jpg", CV_LOAD_IMAGE_COLOR);
	Mat twoTemp = imread("Images//two.jpg", CV_LOAD_IMAGE_COLOR);
	Mat threeTemp = imread("Images//three.jpg", CV_LOAD_IMAGE_COLOR);
	Mat fourTemp = imread("Images//four.jpg", CV_LOAD_IMAGE_COLOR);
	//cvtColor(temp, temp, CV_8UC4,0);
	//Mat result;
	//Mat oneResult;

	//----------------------------------------------------------------------------
	//Initial read to define co-ordinates

	Mat gridResult;
	vector<Point> gridMap;
	captureFrame(frame, mineHandle, height, width);
	gridResult.create(frame.cols - temp.cols + 1, frame.rows - temp.rows + 1, CV_32FC1);
	//unPressedMat = frame.clone();
	countSquares(frame, temp, gridResult, 0.920, gridMap, Scalar(0, 255, 255));
	cout << "Unpressed Squares: " << gridResult.size() << "\n";
	printSquares(gridMap);
	cv::imshow("Win", frame);
	gridResult.release();

	sortGrid(gridMap);
	printSquares(gridMap);
//	for (int i = 0; i < gridMap.size; i++){

//	}
	//Sleep(1000 * 5);
	//----------------------------------------------------------------------------

	//imwrite("Images//Master.jpg", frame);
	//result.create(frame.cols - temp.cols + 1, frame.rows - temp.rows + 1, CV_32FC1);
	char **grid = (char **)calloc(9, sizeof(char));
	for (int k = 0; k < 9; k++){
		grid[k] = (char*)calloc(9, sizeof(char));
	}
//	char grid[9][9] = { 0 };
	vector<Point> unsquare;
	vector<Point> oneSquares;
	vector<Point> twoSquares;
	vector<Point> threeSquares;
	vector<Point> fourSquares;
	Mat unPressedMat;
	Mat oneMat;
	Mat twoMat;
	Mat threeMat;
	Mat fourMat;
	until endOfTime{
		clearGrid(grid);
		if (captureFrame(frame, mineHandle,height,width)==TRUE){
			if (!frame.empty()){
				//matchTemplate(frame, temp, result, TM_CCOEFF_NORMED);
				Mat result;
				result.create(frame.cols - temp.cols + 1, frame.rows - temp.rows + 1, CV_32FC1);
				//unPressedMat = frame.clone();
				countSquares(frame, temp, result,0.920, unsquare, Scalar(0,255, 255));
				cout << "Unpressed Squares: " << unsquare.size() << "\n";
				//printSquares(unsquare);
				result.release();
				if (unsquare.size() != 81){
					Mat oneResult;
					oneResult.create(frame.cols - oneTemp.cols + 1, frame.rows - oneTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, oneTemp, oneResult, 0.9, oneSquares, Scalar(255, 0, 0));
					cout << "One Squares: " << oneSquares.size() << "\n";
					oneResult.release();

					Mat twoResult;
					twoResult.create(frame.cols - twoTemp.cols + 1, frame.rows - twoTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, twoTemp, twoResult, 0.9, twoSquares, Scalar(255, 255, 0));
					cout << "Two Squares: " << twoSquares.size() << "\n";
					twoResult.release();

					Mat threeResult;
					threeResult.create(frame.cols - threeTemp.cols + 1, frame.rows - threeTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, threeTemp, threeResult, 0.9, threeSquares, Scalar(255, 0, 255));
					cout << "Three Squares: " << threeSquares.size() << "\n";
					threeResult.release();

					Mat fourResult;
					fourResult.create(frame.cols - fourTemp.cols + 1, frame.rows - fourTemp.rows + 1, CV_32FC1);
					//oneMat = frame.clone();
					countSquares(frame, fourTemp, fourResult, 0.9, fourSquares, Scalar(255, 0, 0));
					cout << "Four Squares: " << fourSquares.size() << "\n";
					fourResult.release();
				}
				//update grid
				updateGrid(grid, unsquare, gridMap, 'U');
				updateGrid(grid, oneSquares, gridMap, '1');
				updateGrid(grid, twoSquares, gridMap, '2');
				updateGrid(grid, threeSquares, gridMap, '3');
				printGrid(grid);
				cv::imshow("Win", frame);
				//imshow("One", oneMat);
				Sleep(1000);
			}
		}
		if (waitKey(30) >= 0) break;
	}
	return 0;
}<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "RTShaderSRSTexturedFog.h"
#include "OgreShaderFFPRenderState.h"
#include "OgreShaderProgram.h"
#include "OgreShaderParameter.h"
#include "OgreShaderProgramSet.h"
#include "OgreGpuProgram.h"
#include "OgrePass.h"
#include "OgreShaderGenerator.h"

#define FFP_FUNC_PIXELFOG_POSITION_DEPTH                        "FFP_PixelFog_PositionDepth"

using namespace Ogre;
using namespace RTShader;
/************************************************************************/
/*                                                                      */
/************************************************************************/
String RTShaderSRSTexturedFog::Type = "TexturedFog";

//-----------------------------------------------------------------------
RTShaderSRSTexturedFog::RTShaderSRSTexturedFog(RTShaderSRSTexturedFogFactory* factory)
{
    mFactory = factory;
    mFogMode                = FOG_NONE;
    mPassOverrideParams     = false;
}

//-----------------------------------------------------------------------
const String& RTShaderSRSTexturedFog::getType() const
{
    return Type;
}

//-----------------------------------------------------------------------
int RTShaderSRSTexturedFog::getExecutionOrder() const
{
    return FFP_FOG;
}
//-----------------------------------------------------------------------
void RTShaderSRSTexturedFog::updateGpuProgramsParams(Renderable* rend, Pass* pass, const AutoParamDataSource* source,
                                     const LightList* pLightList)
{
    if (mFogMode == FOG_NONE)
        return;

    FogMode fogMode;
    Real newFogStart, newFogEnd, newFogDensity;

    //Check if this is an overlay element if so disable fog
    if ((rend->getUseIdentityView() == true) && (rend->getUseIdentityProjection() == true))
    {
        fogMode         = FOG_NONE;
        newFogStart     = 100000000;
        newFogEnd       = 200000000;
        newFogDensity   = 0;
    }
    else
    {
        if (mPassOverrideParams)
        {
            fogMode         = pass->getFogMode();
            newFogStart     = pass->getFogStart();
            newFogEnd       = pass->getFogEnd();
            newFogDensity   = pass->getFogDensity();
        }
        else
        {
            SceneManager* sceneMgr = ShaderGenerator::getSingleton().getActiveSceneManager();

            fogMode         = sceneMgr->getFogMode();
            newFogStart     = sceneMgr->getFogStart();
            newFogEnd       = sceneMgr->getFogEnd();
            newFogDensity   = sceneMgr->getFogDensity();
        }
    }

    // Set fog properties.
    setFogProperties(fogMode, newFogStart, newFogEnd, newFogDensity);

    mFogParams->setGpuParameter(mFogParamsValue);
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::resolveParameters(ProgramSet* programSet)
{
    if (mFogMode == FOG_NONE)
        return true;

    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);
    Function* vsMain = vsProgram->getEntryPointFunction();
    Function* psMain = psProgram->getEntryPointFunction();

    // Resolve world view matrix.
    mWorldMatrix = vsProgram->resolveParameter(GpuProgramParameters::ACT_WORLD_MATRIX);
    if (mWorldMatrix.get() == NULL)
        return false;

    // Resolve world view matrix.
    mCameraPos = vsProgram->resolveParameter(GpuProgramParameters::ACT_CAMERA_POSITION);
    if (mCameraPos.get() == NULL)
        return false;

    // Resolve vertex shader input position.
    mVSInPos = vsMain->resolveInputParameter(Parameter::SPC_POSITION_OBJECT_SPACE);
    if (mVSInPos.get() == NULL)
        return false;

        // Resolve fog colour.
    mFogColour = psMain->resolveLocalParameter("FogColor", GCT_FLOAT4);
    if (mFogColour.get() == NULL)
        return false;

    // Resolve pixel shader output diffuse color.
    mPSOutDiffuse = psMain->resolveOutputParameter(Parameter::SPC_COLOR_DIFFUSE);
    if (mPSOutDiffuse.get() == NULL)
        return false;

    // Resolve fog params.
    mFogParams = psProgram->resolveParameter(GCT_FLOAT4, -1, (uint16)GPV_GLOBAL, "gFogParams");
    if (mFogParams.get() == NULL)
        return false;

    // Resolve vertex shader output depth.
    mVSOutPosView = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_VIEW_SPACE);
    if (mVSOutPosView.get() == NULL)
        return false;

    // Resolve pixel shader input depth.
    mPSInPosView = psMain->resolveInputParameter(mVSOutPosView);
    if (mPSInPosView.get() == NULL)
        return false;

    // Resolve vertex shader output depth.
    mVSOutDepth = vsMain->resolveOutputParameter(Parameter::SPC_DEPTH_VIEW_SPACE);
    if (mVSOutDepth.get() == NULL)
        return false;

    // Resolve pixel shader input depth.
    mPSInDepth = psMain->resolveInputParameter(mVSOutDepth);
    if (mPSInDepth.get() == NULL)
        return false;

    // Resolve texture sampler parameter.
    mBackgroundTextureSampler = psProgram->resolveParameter(GCT_SAMPLERCUBE, mBackgroundSamplerIndex, (uint16)GPV_GLOBAL, "FogBackgroundSampler");
    if (mBackgroundTextureSampler.get() == NULL)
        return false;

    return true;
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::resolveDependencies(ProgramSet* programSet)
{
    if (mFogMode == FOG_NONE)
        return true;

    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);

    vsProgram->addDependency(FFP_LIB_FOG);
    psProgram->addDependency(FFP_LIB_COMMON);

    psProgram->addDependency(FFP_LIB_FOG);
    psProgram->addDependency(FFP_LIB_TEXTURING);

    return true;
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::addFunctionInvocations(ProgramSet* programSet)
{
    if (mFogMode == FOG_NONE)
        return true;

    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);
    Function* vsMain = vsProgram->getEntryPointFunction();
    Function* psMain = psProgram->getEntryPointFunction();

    vsMain->getStage(FFP_VS_FOG)
        .callFunction(FFP_FUNC_PIXELFOG_POSITION_DEPTH,
                      {In(mWorldMatrix), In(mCameraPos), In(mVSInPos), Out(mVSOutPosView), Out(mVSOutDepth)});

    auto psStage = psMain->getStage(FFP_PS_FOG);
    psStage.sampleTexture(mBackgroundTextureSampler, mPSInPosView, mFogColour);

    const char* fogFunc = NULL;
    switch (mFogMode)
    {
    case FOG_LINEAR:
        fogFunc = FFP_FUNC_PIXELFOG_LINEAR;
        break;
    case FOG_EXP:
        fogFunc = FFP_FUNC_PIXELFOG_EXP;
        break;
    case FOG_EXP2:
        fogFunc = FFP_FUNC_PIXELFOG_EXP2;
        break;
    case FOG_NONE:
       break;
    }

    psStage.callFunction(fogFunc,
                         {In(mPSInDepth), In(mFogParams), In(mFogColour), In(mPSOutDiffuse), Out(mPSOutDiffuse)});
    return true;
}

//-----------------------------------------------------------------------
void RTShaderSRSTexturedFog::copyFrom(const SubRenderState& rhs)
{
    const RTShaderSRSTexturedFog& rhsFog = static_cast<const RTShaderSRSTexturedFog&>(rhs);

    mFogMode            = rhsFog.mFogMode;
    mFogParamsValue     = rhsFog.mFogParamsValue;
    mFactory            = rhsFog.mFactory;
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::preAddToRenderState(const RenderState* renderState, Pass* srcPass, Pass* dstPass)
{
    if (mFactory == NULL)
        return false;

    FogMode fogMode;
    ColourValue newFogColour;
    Real newFogStart, newFogEnd, newFogDensity;

    if (srcPass->getFogOverride())
    {
        fogMode         = srcPass->getFogMode();
        newFogStart     = srcPass->getFogStart();
        newFogEnd       = srcPass->getFogEnd();
        newFogDensity   = srcPass->getFogDensity();
        mPassOverrideParams = true;
    }
    else
    {
        SceneManager* sceneMgr = ShaderGenerator::getSingleton().getActiveSceneManager();

        if (sceneMgr == NULL)
        {
            fogMode         = FOG_NONE;
            newFogStart     = 0.0;
            newFogEnd       = 0.0;
            newFogDensity   = 0.0;
        }
        else
        {
            fogMode         = sceneMgr->getFogMode();
            newFogStart     = sceneMgr->getFogStart();
            newFogEnd       = sceneMgr->getFogEnd();
            newFogDensity   = sceneMgr->getFogDensity();
        }
        mPassOverrideParams = false;
    }

    // Set fog properties.
    setFogProperties(fogMode, newFogStart, newFogEnd, newFogDensity);

    // Override scene fog since it will happen in shader.
    dstPass->setFog(true, FOG_NONE, ColourValue::White, newFogDensity, newFogStart, newFogEnd);

    TextureUnitState* tus = dstPass->createTextureUnitState(mFactory->getBackgroundTextureName());
    tus->setCubicTextureName(mFactory->getBackgroundTextureName(), true);
    mBackgroundSamplerIndex = dstPass->getNumTextureUnitStates() - 1;

    return true;
}

//-----------------------------------------------------------------------
void RTShaderSRSTexturedFog::setFogProperties(FogMode fogMode,
                             float fogStart,
                             float fogEnd,
                             float fogDensity)
{
    mFogMode            = fogMode;
    mFogParamsValue.x   = fogDensity;
    mFogParamsValue.y   = fogStart;
    mFogParamsValue.z   = fogEnd;
    mFogParamsValue.w   = fogEnd != fogStart ? 1 / (fogEnd - fogStart) : 0;
}

//-----------------------------------------------------------------------
const String& RTShaderSRSTexturedFogFactory::getType() const
{
    return RTShaderSRSTexturedFog::Type;
}

//-----------------------------------------------------------------------
SubRenderState* RTShaderSRSTexturedFogFactory::createInstanceImpl()
{
    return OGRE_NEW RTShaderSRSTexturedFog(this);
}
<commit_msg>Samples: TexturedFog - fix errors with strict mode<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "RTShaderSRSTexturedFog.h"
#include "OgreShaderFFPRenderState.h"
#include "OgreShaderProgram.h"
#include "OgreShaderParameter.h"
#include "OgreShaderProgramSet.h"
#include "OgreGpuProgram.h"
#include "OgrePass.h"
#include "OgreShaderGenerator.h"
#include "OgreTextureManager.h"

#define FFP_FUNC_PIXELFOG_POSITION_DEPTH                        "FFP_PixelFog_PositionDepth"

using namespace Ogre;
using namespace RTShader;
/************************************************************************/
/*                                                                      */
/************************************************************************/
String RTShaderSRSTexturedFog::Type = "TexturedFog";

//-----------------------------------------------------------------------
RTShaderSRSTexturedFog::RTShaderSRSTexturedFog(RTShaderSRSTexturedFogFactory* factory)
{
    mFactory = factory;
    mFogMode                = FOG_NONE;
    mPassOverrideParams     = false;
}

//-----------------------------------------------------------------------
const String& RTShaderSRSTexturedFog::getType() const
{
    return Type;
}

//-----------------------------------------------------------------------
int RTShaderSRSTexturedFog::getExecutionOrder() const
{
    return FFP_FOG;
}
//-----------------------------------------------------------------------
void RTShaderSRSTexturedFog::updateGpuProgramsParams(Renderable* rend, Pass* pass, const AutoParamDataSource* source,
                                     const LightList* pLightList)
{
    if (mFogMode == FOG_NONE)
        return;

    FogMode fogMode;
    Real newFogStart, newFogEnd, newFogDensity;

    //Check if this is an overlay element if so disable fog
    if ((rend->getUseIdentityView() == true) && (rend->getUseIdentityProjection() == true))
    {
        fogMode         = FOG_NONE;
        newFogStart     = 100000000;
        newFogEnd       = 200000000;
        newFogDensity   = 0;
    }
    else
    {
        if (mPassOverrideParams)
        {
            fogMode         = pass->getFogMode();
            newFogStart     = pass->getFogStart();
            newFogEnd       = pass->getFogEnd();
            newFogDensity   = pass->getFogDensity();
        }
        else
        {
            SceneManager* sceneMgr = ShaderGenerator::getSingleton().getActiveSceneManager();

            fogMode         = sceneMgr->getFogMode();
            newFogStart     = sceneMgr->getFogStart();
            newFogEnd       = sceneMgr->getFogEnd();
            newFogDensity   = sceneMgr->getFogDensity();
        }
    }

    // Set fog properties.
    setFogProperties(fogMode, newFogStart, newFogEnd, newFogDensity);

    mFogParams->setGpuParameter(mFogParamsValue);
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::resolveParameters(ProgramSet* programSet)
{
    if (mFogMode == FOG_NONE)
        return true;

    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);
    Function* vsMain = vsProgram->getEntryPointFunction();
    Function* psMain = psProgram->getEntryPointFunction();

    // Resolve world view matrix.
    mWorldMatrix = vsProgram->resolveParameter(GpuProgramParameters::ACT_WORLD_MATRIX);
    if (mWorldMatrix.get() == NULL)
        return false;

    // Resolve world view matrix.
    mCameraPos = vsProgram->resolveParameter(GpuProgramParameters::ACT_CAMERA_POSITION);
    if (mCameraPos.get() == NULL)
        return false;

    // Resolve vertex shader input position.
    mVSInPos = vsMain->resolveInputParameter(Parameter::SPC_POSITION_OBJECT_SPACE);
    if (mVSInPos.get() == NULL)
        return false;

        // Resolve fog colour.
    mFogColour = psMain->resolveLocalParameter("FogColor", GCT_FLOAT4);
    if (mFogColour.get() == NULL)
        return false;

    // Resolve pixel shader output diffuse color.
    mPSOutDiffuse = psMain->resolveOutputParameter(Parameter::SPC_COLOR_DIFFUSE);
    if (mPSOutDiffuse.get() == NULL)
        return false;

    // Resolve fog params.
    mFogParams = psProgram->resolveParameter(GCT_FLOAT4, -1, (uint16)GPV_GLOBAL, "gFogParams");
    if (mFogParams.get() == NULL)
        return false;

    // Resolve vertex shader output depth.
    mVSOutPosView = vsMain->resolveOutputParameter(Parameter::SPC_POSITION_VIEW_SPACE);
    if (mVSOutPosView.get() == NULL)
        return false;

    // Resolve pixel shader input depth.
    mPSInPosView = psMain->resolveInputParameter(mVSOutPosView);
    if (mPSInPosView.get() == NULL)
        return false;

    // Resolve vertex shader output depth.
    mVSOutDepth = vsMain->resolveOutputParameter(Parameter::SPC_DEPTH_VIEW_SPACE);
    if (mVSOutDepth.get() == NULL)
        return false;

    // Resolve pixel shader input depth.
    mPSInDepth = psMain->resolveInputParameter(mVSOutDepth);
    if (mPSInDepth.get() == NULL)
        return false;

    // Resolve texture sampler parameter.
    mBackgroundTextureSampler = psProgram->resolveParameter(GCT_SAMPLERCUBE, mBackgroundSamplerIndex, (uint16)GPV_GLOBAL, "FogBackgroundSampler");
    if (mBackgroundTextureSampler.get() == NULL)
        return false;

    return true;
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::resolveDependencies(ProgramSet* programSet)
{
    if (mFogMode == FOG_NONE)
        return true;

    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);

    vsProgram->addDependency(FFP_LIB_FOG);
    psProgram->addDependency(FFP_LIB_COMMON);

    psProgram->addDependency(FFP_LIB_FOG);
    psProgram->addDependency(FFP_LIB_TEXTURING);

    return true;
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::addFunctionInvocations(ProgramSet* programSet)
{
    if (mFogMode == FOG_NONE)
        return true;

    Program* vsProgram = programSet->getCpuProgram(GPT_VERTEX_PROGRAM);
    Program* psProgram = programSet->getCpuProgram(GPT_FRAGMENT_PROGRAM);
    Function* vsMain = vsProgram->getEntryPointFunction();
    Function* psMain = psProgram->getEntryPointFunction();

    vsMain->getStage(FFP_VS_FOG)
        .callFunction(FFP_FUNC_PIXELFOG_POSITION_DEPTH,
                      {In(mWorldMatrix), In(mCameraPos), In(mVSInPos), Out(mVSOutPosView), Out(mVSOutDepth)});

    auto psStage = psMain->getStage(FFP_PS_FOG);
    psStage.sampleTexture(mBackgroundTextureSampler, mPSInPosView, mFogColour);

    const char* fogFunc = NULL;
    switch (mFogMode)
    {
    case FOG_LINEAR:
        fogFunc = FFP_FUNC_PIXELFOG_LINEAR;
        break;
    case FOG_EXP:
        fogFunc = FFP_FUNC_PIXELFOG_EXP;
        break;
    case FOG_EXP2:
        fogFunc = FFP_FUNC_PIXELFOG_EXP2;
        break;
    case FOG_NONE:
       break;
    }

    psStage.callFunction(fogFunc,
                         {In(mPSInDepth), In(mFogParams), In(mFogColour), In(mPSOutDiffuse), Out(mPSOutDiffuse)});
    return true;
}

//-----------------------------------------------------------------------
void RTShaderSRSTexturedFog::copyFrom(const SubRenderState& rhs)
{
    const RTShaderSRSTexturedFog& rhsFog = static_cast<const RTShaderSRSTexturedFog&>(rhs);

    mFogMode            = rhsFog.mFogMode;
    mFogParamsValue     = rhsFog.mFogParamsValue;
    mFactory            = rhsFog.mFactory;
}

//-----------------------------------------------------------------------
bool RTShaderSRSTexturedFog::preAddToRenderState(const RenderState* renderState, Pass* srcPass, Pass* dstPass)
{
    if (mFactory == NULL)
        return false;

    FogMode fogMode;
    ColourValue newFogColour;
    Real newFogStart, newFogEnd, newFogDensity;

    if (srcPass->getFogOverride())
    {
        fogMode         = srcPass->getFogMode();
        newFogStart     = srcPass->getFogStart();
        newFogEnd       = srcPass->getFogEnd();
        newFogDensity   = srcPass->getFogDensity();
        mPassOverrideParams = true;
    }
    else
    {
        SceneManager* sceneMgr = ShaderGenerator::getSingleton().getActiveSceneManager();

        if (sceneMgr == NULL)
        {
            fogMode         = FOG_NONE;
            newFogStart     = 0.0;
            newFogEnd       = 0.0;
            newFogDensity   = 0.0;
        }
        else
        {
            fogMode         = sceneMgr->getFogMode();
            newFogStart     = sceneMgr->getFogStart();
            newFogEnd       = sceneMgr->getFogEnd();
            newFogDensity   = sceneMgr->getFogDensity();
        }
        mPassOverrideParams = false;
    }

    // Set fog properties.
    setFogProperties(fogMode, newFogStart, newFogEnd, newFogDensity);

    // Override scene fog since it will happen in shader.
    dstPass->setFog(true, FOG_NONE, ColourValue::White, newFogDensity, newFogStart, newFogEnd);

    TextureUnitState* tus = dstPass->createTextureUnitState();
    auto tex = TextureManager::getSingleton().load(
        mFactory->getBackgroundTextureName(), RGN_DEFAULT, TEX_TYPE_CUBE_MAP);
    tus->setTexture(tex);
    mBackgroundSamplerIndex = dstPass->getNumTextureUnitStates() - 1;

    return true;
}

//-----------------------------------------------------------------------
void RTShaderSRSTexturedFog::setFogProperties(FogMode fogMode,
                             float fogStart,
                             float fogEnd,
                             float fogDensity)
{
    mFogMode            = fogMode;
    mFogParamsValue.x   = fogDensity;
    mFogParamsValue.y   = fogStart;
    mFogParamsValue.z   = fogEnd;
    mFogParamsValue.w   = fogEnd != fogStart ? 1 / (fogEnd - fogStart) : 0;
}

//-----------------------------------------------------------------------
const String& RTShaderSRSTexturedFogFactory::getType() const
{
    return RTShaderSRSTexturedFog::Type;
}

//-----------------------------------------------------------------------
SubRenderState* RTShaderSRSTexturedFogFactory::createInstanceImpl()
{
    return OGRE_NEW RTShaderSRSTexturedFog(this);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
using namespace std;

int main(int argc, char *argv[])
{
    cout << "|";
    for (int x = 1; x<=12; ++x)
    {
        cout <<x <<"|";

    }
    cout << endl;

    for( int x = 0; x<=12; ++x)
    {
        cout << "+";
    }
    cout << endl;

    for( int y = 1; y<=12; ++y)
    {
        cout<< y << "|";

        for (int x=1; x<=12; ++x)
        {
            cout<<x*y << "|";
        }
        cout<< endl;

        for(int x =0; x<=12; ++x)
        {
            cout << "----+";
        }
        cout <<endl;
    }

}
<commit_msg>fixed output off xtable.closes #35<commit_after>#include <iostream>
#include <iomanip>
using namespace std;

int main(int argc, char *argv[])
{
    cout << "      |";
    for (int x = 1; x<=12; ++x)
    {
        cout <<setw(5)<< x <<"|";

    }
    cout << endl;

    for( int x = 0; x<=12; ++x)
    {
        cout << "-----+";
    }
    cout << endl;

    for( int y = 1; y<=12; ++y)
    {
        cout<<setw(5)<< y << "|";

        for (int x=1; x<=12; ++x)
        {
            cout<<setw(5)<<x*y << "|";
        }
        cout<< endl;

        for(int x =0; x<=12; ++x)
        {
            cout << "-----+";
        }
        cout <<endl;
    }

}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2012
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#define __STDC_CONSTANT_MACROS 1

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_network.h>
#include <vlc_services_discovery.h>

#include <functional>
#include <unordered_map>
#include <sstream>

#include "discovery.h"
#include "helper.h"
#include "htsmessage.h"
#include "sha1.h"

struct tmp_channel
{
    std::string name;
    uint32_t cid;
    uint32_t cnum;
    std::string url;
    input_item_t *item;
    std::list<std::string> tags;
};

struct services_discovery_sys_t : public sys_common_t
{
    services_discovery_sys_t()
        :thread(0)
    {}

    vlc_thread_t thread;
    std::unordered_map<uint32_t, tmp_channel> channelMap;
};

bool ConnectSD(services_discovery_t *sd)
{
    services_discovery_sys_t *sys = sd->p_sys;

    const char *host = var_GetString(sd, CFG_PREFIX"host");
    int port = var_GetInteger(sd, CFG_PREFIX"port");

    if(host == 0 || host[0] == 0)
        host = "localhost";

    if(port == 0)
        port = 9982;

    sys->netfd = net_ConnectTCP(sd, host, port);

    if(sys->netfd < 0)
    {
        msg_Err(sd, "net_ConnectTCP failed");
        return false;
    }

    HtsMap map;
    map.setData("method", "hello");
    map.setData("clientname", "VLC media player");
    map.setData("htspversion", HTSP_PROTO_VERSION);

    HtsMessage m = ReadResult(sd, sys, map.makeMsg());
    if(!m.isValid())
    {
        msg_Err(sd, "No valid hello response");
        return false;
    }

    uint32_t chall_len;
    void * chall;
    m.getRoot()->getBin("challenge", &chall_len, &chall);

    std::string serverName = m.getRoot()->getStr("servername");
    std::string serverVersion = m.getRoot()->getStr("serverversion");
    uint32_t protoVersion = m.getRoot()->getU32("htspversion");

    msg_Info(sd, "Connected to HTSP Server %s, version %s, protocol %d", serverName.c_str(), serverVersion.c_str(), protoVersion);
    if(protoVersion < HTSP_PROTO_VERSION)
    {
        msg_Warn(sd, "TVHeadend is running an older version of HTSP(v%d) than we are(v%d). No effort was made to keep compatible with older versions, update tvh before reporting problems!", protoVersion, HTSP_PROTO_VERSION);
    }
    else if(protoVersion > HTSP_PROTO_VERSION)
    {
        msg_Info(sd, "TVHeadend is running a more recent version of HTSP(v%d) than we are(v%d). Check if there is an update available!", protoVersion, HTSP_PROTO_VERSION);
    }

    const char *user = var_GetString(sd, CFG_PREFIX"user");
    const char *pass = var_GetString(sd, CFG_PREFIX"pass");
    if(user == 0 || user[0] == 0)
        return true;

    map = HtsMap();
    map.setData("method", "authenticate");
    map.setData("username", user);

    if(pass != 0 && pass[0] != 0 && chall)
    {
        msg_Info(sd, "Authenticating as '%s' with a password", user);

        HTSSHA1 *shactx = (HTSSHA1*)malloc(hts_sha1_size);
        uint8_t d[20];
        hts_sha1_init(shactx);
        hts_sha1_update(shactx, (const uint8_t *)pass, strlen(pass));
        hts_sha1_update(shactx, (const uint8_t *)chall, chall_len);
        hts_sha1_final(shactx, d);

        std::shared_ptr<HtsBin> bin = std::make_shared<HtsBin>();
        bin->setBin(20, d);
        map.setData("digest", bin);

        free(shactx);
    }
    else
        msg_Info(sd, "Authenticating as '%s' without a password", user);

    if(chall)
        free(chall);

    bool res = ReadSuccess(sd, sys, map.makeMsg(), "authenticate");
    if(res)
        msg_Info(sd, "Successfully authenticated!");
    else
        msg_Err(sd, "Authentication failed!");
    return res;
}

bool GetChannels(services_discovery_t *sd)
{
    services_discovery_sys_t *sys = sd->p_sys;

    HtsMap map;
    map.setData("method", "enableAsyncMetadata");
    if(!ReadSuccess(sd, sys, map.makeMsg(), "enable async metadata"))
        return false;

    std::list<uint32_t> channelIds;
    std::unordered_map<uint32_t, tmp_channel> channels;

    HtsMessage m;
    while((m = ReadMessage(sd, sys)).isValid())
    {
        std::string method = m.getRoot()->getStr("method");
        if(method.empty() || method == "initialSyncCompleted")
        {
            msg_Info(sd, "Finished getting initial metadata sync");
            break;
        }

        if(method == "channelAdd")
        {
            if(!m.getRoot()->contains("channelId"))
                continue;
            uint32_t cid = m.getRoot()->getU32("channelId");

            std::string cname = m.getRoot()->getStr("channelName");
            if(cname.empty())
            {
                std::ostringstream ss;
                ss << "Channel " << cid;
                cname = ss.str();
            }

            uint32_t cnum = m.getRoot()->getU32("channelNumber");

            std::ostringstream oss;
            oss << "htsp://";

            char *user = var_GetString(sd, CFG_PREFIX"user");
            char *pass = var_GetString(sd, CFG_PREFIX"pass");
            if(user != 0 && user[0] != 0 && pass != 0 && pass[0] != 0)
                oss << user << ":" << pass << "@";
            else if(user != 0 && user[0] != 0)
                oss << user << "@";

            const char *host = var_GetString(sd, CFG_PREFIX"host");
            if(host == 0 || host[0] == 0)
                host = "localhost";
            int port = var_GetInteger(sd, CFG_PREFIX"port");
            if(port == 0)
                port = 9982;
            oss << host << ":" << port << "/" << cid;

            channels[cid].name = cname;
            channels[cid].cid = cid;
            channels[cid].cnum = cnum;
            channels[cid].url = oss.str();

            channelIds.push_back(cid);
        }
        else if(method == "tagAdd" || method == "tagUpdate")
        {
            if(!m.getRoot()->contains("tagId") || !m.getRoot()->contains("tagName"))
                continue;

            std::string tagName = m.getRoot()->getStr("tagName");

            std::shared_ptr<HtsList> chList = m.getRoot()->getList("members");
            for(uint32_t i = 0; i < chList->count(); ++i)
                channels[chList->getData(i)->getU32()].tags.push_back(tagName);
        }
    }

    channelIds.sort([&](const uint32_t &first, const uint32_t &second) {
        return channels[first].cnum < channels[second].cnum;
    });

    while(channelIds.size() > 0)
    {
        tmp_channel ch = channels[channelIds.front()];
        channelIds.pop_front();

        ch.item = input_item_New(ch.url.c_str(), ch.name.c_str());
        if(unlikely(ch.item == 0))
            return false;

        ch.item->i_type = ITEM_TYPE_NET;
        for(std::string tag: ch.tags)
            services_discovery_AddItem(sd, ch.item, tag.c_str());

        services_discovery_AddItem(sd, ch.item, "All Channels");

        sys->channelMap[ch.cid] = ch;
    }

    return true;
}

void * RunSD(void *obj)
{
    services_discovery_t *sd = (services_discovery_t *)obj;
    services_discovery_sys_t *sys = sd->p_sys;

    if(!ConnectSD(sd))
    {
        msg_Err(sd, "Connecting to HTS Failed!");
        return 0;
    }

    GetChannels(sd);

    for(;;)
    {
        HtsMessage msg = ReadMessage(sd, sys);
        if(!msg.isValid())
            return 0;

        std::string method = msg.getRoot()->getStr("method");
        if(method.empty())
            return 0;

        msg_Dbg(sd, "Got Message with method %s", method.c_str());
    }

    return 0;
}

int OpenSD(vlc_object_t *obj)
{
    services_discovery_t *sd = (services_discovery_t *)obj;
    services_discovery_sys_t *sys = new services_discovery_sys_t;
    if(unlikely(sys == NULL))
        return VLC_ENOMEM;
    sd->p_sys = sys;

    config_ChainParse(sd, CFG_PREFIX, cfg_options, sd->p_cfg);

    if(vlc_clone(&sys->thread, RunSD, sd, VLC_THREAD_PRIORITY_LOW))
    {
        delete sys;
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

void CloseSD(vlc_object_t *obj)
{
    services_discovery_t *sd = (services_discovery_t *)obj;
    services_discovery_sys_t *sys = sd->p_sys;

    if(!sys)
        return;

    if(sys->thread)
    {
        vlc_cancel(sys->thread);
        vlc_join(sys->thread, 0);
        sys->thread = 0;
    }

    delete sys;
    sys = sd->p_sys = 0;
}
<commit_msg>Fix a small leak<commit_after>/*****************************************************************************
 * Copyright (C) 2012
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#define __STDC_CONSTANT_MACROS 1

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_network.h>
#include <vlc_services_discovery.h>

#include <functional>
#include <unordered_map>
#include <sstream>

#include "discovery.h"
#include "helper.h"
#include "htsmessage.h"
#include "sha1.h"

struct tmp_channel
{
    std::string name;
    uint32_t cid;
    uint32_t cnum;
    std::string url;
    input_item_t *item;
    std::list<std::string> tags;
};

struct services_discovery_sys_t : public sys_common_t
{
    services_discovery_sys_t()
        :thread(0)
    {}

    vlc_thread_t thread;
    std::unordered_map<uint32_t, tmp_channel> channelMap;
};

bool ConnectSD(services_discovery_t *sd)
{
    services_discovery_sys_t *sys = sd->p_sys;

    const char *host = var_GetString(sd, CFG_PREFIX"host");
    int port = var_GetInteger(sd, CFG_PREFIX"port");

    if(host == 0 || host[0] == 0)
        host = "localhost";

    if(port == 0)
        port = 9982;

    sys->netfd = net_ConnectTCP(sd, host, port);

    if(sys->netfd < 0)
    {
        msg_Err(sd, "net_ConnectTCP failed");
        return false;
    }

    HtsMap map;
    map.setData("method", "hello");
    map.setData("clientname", "VLC media player");
    map.setData("htspversion", HTSP_PROTO_VERSION);

    HtsMessage m = ReadResult(sd, sys, map.makeMsg());
    if(!m.isValid())
    {
        msg_Err(sd, "No valid hello response");
        return false;
    }

    uint32_t chall_len;
    void * chall;
    m.getRoot()->getBin("challenge", &chall_len, &chall);

    std::string serverName = m.getRoot()->getStr("servername");
    std::string serverVersion = m.getRoot()->getStr("serverversion");
    uint32_t protoVersion = m.getRoot()->getU32("htspversion");

    msg_Info(sd, "Connected to HTSP Server %s, version %s, protocol %d", serverName.c_str(), serverVersion.c_str(), protoVersion);
    if(protoVersion < HTSP_PROTO_VERSION)
    {
        msg_Warn(sd, "TVHeadend is running an older version of HTSP(v%d) than we are(v%d). No effort was made to keep compatible with older versions, update tvh before reporting problems!", protoVersion, HTSP_PROTO_VERSION);
    }
    else if(protoVersion > HTSP_PROTO_VERSION)
    {
        msg_Info(sd, "TVHeadend is running a more recent version of HTSP(v%d) than we are(v%d). Check if there is an update available!", protoVersion, HTSP_PROTO_VERSION);
    }

    const char *user = var_GetString(sd, CFG_PREFIX"user");
    const char *pass = var_GetString(sd, CFG_PREFIX"pass");
    if(user == 0 || user[0] == 0)
        return true;

    map = HtsMap();
    map.setData("method", "authenticate");
    map.setData("username", user);

    if(pass != 0 && pass[0] != 0 && chall)
    {
        msg_Info(sd, "Authenticating as '%s' with a password", user);

        HTSSHA1 *shactx = (HTSSHA1*)malloc(hts_sha1_size);
        uint8_t d[20];
        hts_sha1_init(shactx);
        hts_sha1_update(shactx, (const uint8_t *)pass, strlen(pass));
        hts_sha1_update(shactx, (const uint8_t *)chall, chall_len);
        hts_sha1_final(shactx, d);

        std::shared_ptr<HtsBin> bin = std::make_shared<HtsBin>();
        bin->setBin(20, d);
        map.setData("digest", bin);

        free(shactx);
    }
    else
        msg_Info(sd, "Authenticating as '%s' without a password", user);

    if(user)
        free(user);
    if(pass)
        free(pass);
    if(chall)
        free(chall);

    bool res = ReadSuccess(sd, sys, map.makeMsg(), "authenticate");
    if(res)
        msg_Info(sd, "Successfully authenticated!");
    else
        msg_Err(sd, "Authentication failed!");
    return res;
}

bool GetChannels(services_discovery_t *sd)
{
    services_discovery_sys_t *sys = sd->p_sys;

    HtsMap map;
    map.setData("method", "enableAsyncMetadata");
    if(!ReadSuccess(sd, sys, map.makeMsg(), "enable async metadata"))
        return false;

    std::list<uint32_t> channelIds;
    std::unordered_map<uint32_t, tmp_channel> channels;

    HtsMessage m;
    while((m = ReadMessage(sd, sys)).isValid())
    {
        std::string method = m.getRoot()->getStr("method");
        if(method.empty() || method == "initialSyncCompleted")
        {
            msg_Info(sd, "Finished getting initial metadata sync");
            break;
        }

        if(method == "channelAdd")
        {
            if(!m.getRoot()->contains("channelId"))
                continue;
            uint32_t cid = m.getRoot()->getU32("channelId");

            std::string cname = m.getRoot()->getStr("channelName");
            if(cname.empty())
            {
                std::ostringstream ss;
                ss << "Channel " << cid;
                cname = ss.str();
            }

            uint32_t cnum = m.getRoot()->getU32("channelNumber");

            std::ostringstream oss;
            oss << "htsp://";

            char *user = var_GetString(sd, CFG_PREFIX"user");
            char *pass = var_GetString(sd, CFG_PREFIX"pass");
            if(user != 0 && user[0] != 0 && pass != 0 && pass[0] != 0)
                oss << user << ":" << pass << "@";
            else if(user != 0 && user[0] != 0)
                oss << user << "@";

            const char *host = var_GetString(sd, CFG_PREFIX"host");
            if(host == 0 || host[0] == 0)
                host = "localhost";
            int port = var_GetInteger(sd, CFG_PREFIX"port");
            if(port == 0)
                port = 9982;
            oss << host << ":" << port << "/" << cid;

            channels[cid].name = cname;
            channels[cid].cid = cid;
            channels[cid].cnum = cnum;
            channels[cid].url = oss.str();

            channelIds.push_back(cid);
        }
        else if(method == "tagAdd" || method == "tagUpdate")
        {
            if(!m.getRoot()->contains("tagId") || !m.getRoot()->contains("tagName"))
                continue;

            std::string tagName = m.getRoot()->getStr("tagName");

            std::shared_ptr<HtsList> chList = m.getRoot()->getList("members");
            for(uint32_t i = 0; i < chList->count(); ++i)
                channels[chList->getData(i)->getU32()].tags.push_back(tagName);
        }
    }

    channelIds.sort([&](const uint32_t &first, const uint32_t &second) {
        return channels[first].cnum < channels[second].cnum;
    });

    while(channelIds.size() > 0)
    {
        tmp_channel ch = channels[channelIds.front()];
        channelIds.pop_front();

        ch.item = input_item_New(ch.url.c_str(), ch.name.c_str());
        if(unlikely(ch.item == 0))
            return false;

        ch.item->i_type = ITEM_TYPE_NET;
        for(std::string tag: ch.tags)
            services_discovery_AddItem(sd, ch.item, tag.c_str());

        services_discovery_AddItem(sd, ch.item, "All Channels");

        sys->channelMap[ch.cid] = ch;
    }

    return true;
}

void * RunSD(void *obj)
{
    services_discovery_t *sd = (services_discovery_t *)obj;
    services_discovery_sys_t *sys = sd->p_sys;

    if(!ConnectSD(sd))
    {
        msg_Err(sd, "Connecting to HTS Failed!");
        return 0;
    }

    GetChannels(sd);

    for(;;)
    {
        HtsMessage msg = ReadMessage(sd, sys);
        if(!msg.isValid())
            return 0;

        std::string method = msg.getRoot()->getStr("method");
        if(method.empty())
            return 0;

        msg_Dbg(sd, "Got Message with method %s", method.c_str());
    }

    return 0;
}

int OpenSD(vlc_object_t *obj)
{
    services_discovery_t *sd = (services_discovery_t *)obj;
    services_discovery_sys_t *sys = new services_discovery_sys_t;
    if(unlikely(sys == NULL))
        return VLC_ENOMEM;
    sd->p_sys = sys;

    config_ChainParse(sd, CFG_PREFIX, cfg_options, sd->p_cfg);

    if(vlc_clone(&sys->thread, RunSD, sd, VLC_THREAD_PRIORITY_LOW))
    {
        delete sys;
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

void CloseSD(vlc_object_t *obj)
{
    services_discovery_t *sd = (services_discovery_t *)obj;
    services_discovery_sys_t *sys = sd->p_sys;

    if(!sys)
        return;

    if(sys->thread)
    {
        vlc_cancel(sys->thread);
        vlc_join(sys->thread, 0);
        sys->thread = 0;
    }

    delete sys;
    sys = sd->p_sys = 0;
}
<|endoftext|>