<commit_before>/*
 * tblf
 * A delimiter-seperated data file formatter in C++.
 *
 * Copyright (c) 2012 Wander Nauta, wandernauta.nl
 *
 *
 * 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 <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
#include <algorithm> // For min_element/max_element

#include <cstdlib>

typedef unsigned int uint;
typedef std::vector< std::vector <std::string> > table;
typedef std::vector< int > intvec;
typedef std::map< char, intvec > countmap;
typedef countmap::iterator cmit;

// Find out if a string represents a number.
bool isnum(std::string in) {
  std::istringstream ins(in);
  double test;
  ins >> test;

  if (!ins) return false;
  return (ins.rdbuf()->in_avail() == 0);
}

// Return the string version of an integer value.
std::string strval(int i) {
  std::ostringstream out;
  out << i;
  return out.str();
}

// Compare two integers.
char intcmp(int a, int b) {
  return (a==b);
}

// A UTF-8 strlen function. Also works for ASCII.
uint strlen_utf8(std::string s) {
  uint i = 0, j = 0, sz = s.size();
  while (i < sz) {
    if ((s[i] & 0xc0) != 0x80) j++;
    i++;
  }
  return j;
}

// Try to find which seperator is the most probable.
char probable_sep(std::istream &in) {
  countmap counts;
  counts['\t'] = intvec();
  counts[','] = intvec();
  counts[';'] = intvec();
  counts[':'] = intvec();
  counts['|'] = intvec();

  std::string line;
  char c;

  while (in.good()) {
    getline(in, line);
    if (line == "") continue;

    // Add a new zero to every counts vector
    for (cmit it = counts.begin(); it != counts.end(); ++it) {
      it->second.push_back(0);
    }

    // Consume the line char by char
    std::istringstream lines(line);
    while (lines.good()) {
      lines.get(c);

      if (c == '\t' or c == ';' or c == ':' or c == '|' or c == ',') {
        int lastidx = counts[c].size() - 1;
        counts[c][lastidx] += 1;
      }
    }
  }

  // Check which count vector has identical non-zero values

  for (cmit it = counts.begin(); it != counts.end(); ++it) {
    intvec vec = it->second;

    if (!vec.size()) break; // No rows! Bail.

    int min = *std::min_element(vec.begin(), vec.end());
    int max = *std::max_element(vec.begin(), vec.end());

    if (min == max && min != 0) {
      in.clear();
      return it->first;
    }
  }

  // No plausible seperator found, return something that won't collide
  return '\0';
}

// Enlarge a vector of ints to size `count`, adding zero's if necessary
void ensure_sz(std::vector<uint> & vec, uint count) {
  if (vec.size() < count) {
    vec.resize(count, 0);
  }
}

// Return the length of the longest value for each column in a table.
std::vector<uint> col_widths(table &tblf) {
  std::vector<uint> w;

  for (uint row = 0; row < tblf.size(); row++) {
    for (uint col = 0; col < tblf[row].size(); col++) {
      ensure_sz(w, col+1);
      uint width = strlen_utf8(tblf[row][col]);
      if (w[col] < width) {
        w[col] = width;
      }
    }
  }

  return w;
}

// Format an istream table onto stdout.
int tblf(std::istream & f, char sep, bool want_zebra, bool want_right, bool want_lineno) {
  std::string line;
  table rows;

  if (sep == '\0') {
    sep = probable_sep(f);
    f.seekg(0, std::ios::beg);
  }

  int lineno = 1;

  while (f.good()) {
    getline(f, line);
    std::vector<std::string> row;
    std::string val;
    if (line == "") continue; // Collapse empty lines

    if (want_lineno) row.push_back(strval(lineno));

    std::istringstream lines(line);
    while (lines.good()) {
      getline(lines, val, sep);
      row.push_back(val);
    }
    rows.push_back(row);
    lineno++;
  }

  std::vector<uint> widths = col_widths(rows);

  // If something went wrong during the parsing stage, bail.
  if (!rows.size()) {
    std::cerr << "tblf: Misformed or empty data file, quitting." << std::endl;
    return 1;
  }

  for (uint row = 0; row < rows.size(); row++) {
    if (want_zebra and (row % 2 == 1)) std::cout << "\x1b[1m";

    for (uint col = 0; col < rows[row].size(); col++) {
      std::string val = rows[row][col];
      int len = strlen_utf8(val);
      int width = widths[col];
      int pad = (width - len);

      if (want_right and isnum(val)) {
        std::cout << std::string(pad, ' ') << val;
      } else {
        std::cout << val << std::string(pad, ' ');
      }

      std::cout << "  ";
    }

    if (want_zebra and (row % 2 == 1)) std::cout << "\x1b[0m";
    std::cout << std::endl;
  }

  return 0;
}

// It's quite obvious what this thing does.
int main(int argc, char* argv[]) {
  char sep = '\0';
  bool want_zebra = false;  // Do I want zebra striping?
  bool want_right = true;   // Do I want right-alignment of numbers?
  bool want_lineno = false; // Do I want line numbers?
  int c;

  while ((c = getopt (argc, argv, "d:zlrn")) != -1) {
    switch (c) {
      case 'd':
        sep = optarg[0];
        break;
      case 'z':
        want_zebra = true; // Yes, I want zebra striping!
        break;
      case 'l':
        want_right = false; // Left-align numeric columns
        break;
      case 'r':
        want_right = true; // Right-align numeric columns
        break;
      case 'n':
        want_lineno = true; // Yes, I want line numbering!
        break;
    }
  }

  if (!argv[optind]) {
    std::cerr << "usage: tblf [-lrnz] [-d delimiter] FILE" << std::endl;
    std::cerr << "       tblf [-lrnz] [-d delimiter] -" << std::endl;
    return 1;
  }

  std::string file = std::string(argv[optind]);

  if (file == "-") {
    // Use stdin
    std::stringstream ss;
    ss << std::cin.rdbuf();
    return tblf(ss, sep, want_zebra, want_right, want_lineno);
  } else {
    // Open a file and use that
    std::ifstream f(file.c_str());
    return tblf(f, sep, want_zebra, want_right, want_lineno);
  }
}

<commit_msg>Minor cleanup<commit_after>/*
 * tblf
 * A delimiter-seperated data file formatter in C++.
 *
 * Copyright (c) 2012 Wander Nauta, wandernauta.nl
 *
 *
 * 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 <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
#include <algorithm> // For min_element/max_element

#include <cstdlib>

typedef unsigned int uint;
typedef std::vector< std::vector <std::string> > table;
typedef std::vector< int > intvec;
typedef std::map< char, intvec > countmap;
typedef countmap::iterator cmit;

// Find out if a string represents a number.
bool isnum(std::string in) {
  std::istringstream ins(in);
  double test;
  ins >> test;

  if (!ins) return false;
  return (ins.rdbuf()->in_avail() == 0);
}

// Return the string version of an integer value.
std::string strval(int i) {
  std::ostringstream out;
  out << i;
  return out.str();
}

// A UTF-8 strlen function. Also works for ASCII.
uint strlen_utf8(std::string s) {
  uint i = 0, j = 0, sz = s.size();
  while (i < sz) {
    if ((s[i] & 0xc0) != 0x80) j++;
    i++;
  }
  return j;
}

// Try to find which seperator is the most probable.
char probable_sep(std::istream &in) {
  countmap counts;
  counts['\t'] = intvec();
  counts[','] = intvec();
  counts[';'] = intvec();
  counts[':'] = intvec();
  counts['|'] = intvec();

  std::string line;
  char c;

  while (in.good()) {
    getline(in, line);
    if (line == "") continue;

    // Add a new zero to every counts vector
    for (cmit it = counts.begin(); it != counts.end(); ++it) {
      it->second.push_back(0);
    }

    // Consume the line char by char
    std::istringstream lines(line);
    while (lines.good()) {
      lines.get(c);

      if (c == '\t' or c == ';' or c == ':' or c == '|' or c == ',') {
        int lastidx = counts[c].size() - 1;
        counts[c][lastidx] += 1;
      }
    }
  }

  // Check which count vector has identical non-zero values

  for (cmit it = counts.begin(); it != counts.end(); ++it) {
    intvec vec = it->second;

    if (vec.empty()) break; // No rows! Bail.

    int min = *std::min_element(vec.begin(), vec.end());
    int max = *std::max_element(vec.begin(), vec.end());

    if (min == max && min != 0) {
      in.clear();
      return it->first;
    }
  }

  // No plausible seperator found, return something that won't collide
  return '\0';
}

// Enlarge a vector of ints to size `count`, adding zero's if necessary
void ensure_sz(std::vector<uint> & vec, uint count) {
  if (vec.size() < count) {
    vec.resize(count, 0);
  }
}

// Return the length of the longest value for each column in a table.
std::vector<uint> col_widths(table &tblf) {
  std::vector<uint> w;

  for (uint row = 0; row < tblf.size(); row++) {
    for (uint col = 0; col < tblf[row].size(); col++) {
      ensure_sz(w, col+1);
      uint width = strlen_utf8(tblf[row][col]);
      if (w[col] < width) {
        w[col] = width;
      }
    }
  }

  return w;
}

// Format an istream table onto stdout.
int tblf(std::istream & f, char sep, bool want_zebra, bool want_right, bool want_lineno) {
  std::string line;
  table rows;

  if (sep == '\0') {
    sep = probable_sep(f);
    f.seekg(0, std::ios::beg);
  }

  int lineno = 1;

  while (f.good()) {
    getline(f, line);
    std::vector<std::string> row;
    std::string val;
    if (line == "") continue; // Collapse empty lines

    if (want_lineno) row.push_back(strval(lineno));

    std::istringstream lines(line);
    while (lines.good()) {
      getline(lines, val, sep);
      row.push_back(val);
    }
    rows.push_back(row);
    lineno++;
  }

  std::vector<uint> widths = col_widths(rows);

  // If something went wrong during the parsing stage, bail.
  if (rows.empty()) {
    std::cerr << "tblf: Misformed or empty data file, quitting." << std::endl;
    return 1;
  }

  for (uint row = 0; row < rows.size(); row++) {
    if (want_zebra and (row % 2 == 1)) std::cout << "\x1b[1m";

    for (uint col = 0; col < rows[row].size(); col++) {
      std::string val = rows[row][col];
      int len = strlen_utf8(val);
      int width = widths[col];
      int pad = (width - len);

      if (want_right and isnum(val)) {
        std::cout << std::string(pad, ' ') << val;
      } else {
        std::cout << val << std::string(pad, ' ');
      }

      std::cout << "  ";
    }

    if (want_zebra and (row % 2 == 1)) std::cout << "\x1b[0m";
    std::cout << std::endl;
  }

  return 0;
}

// It's quite obvious what this thing does.
int main(int argc, char* argv[]) {
  char sep = '\0';
  bool want_zebra = false;  // Do I want zebra striping?
  bool want_right = true;   // Do I want right-alignment of numbers?
  bool want_lineno = false; // Do I want line numbers?
  int c;

  while ((c = getopt (argc, argv, "d:zlrn")) != -1) {
    switch (c) {
      case 'd':
        sep = optarg[0];
        break;
      case 'z':
        want_zebra = true; // Yes, I want zebra striping!
        break;
      case 'l':
        want_right = false; // Left-align numeric columns
        break;
      case 'r':
        want_right = true; // Right-align numeric columns
        break;
      case 'n':
        want_lineno = true; // Yes, I want line numbering!
        break;
    }
  }

  if (!argv[optind]) {
    std::cerr << "usage: tblf [-lrnz] [-d delimiter] FILE" << std::endl;
    std::cerr << "       tblf [-lrnz] [-d delimiter] -" << std::endl;
    return 1;
  }

  std::string file = std::string(argv[optind]);

  if (file == "-") {
    // Use stdin
    std::stringstream ss;
    ss << std::cin.rdbuf();
    return tblf(ss, sep, want_zebra, want_right, want_lineno);
  } else {
    // Open a file and use that
    std::ifstream f(file.c_str());
    return tblf(f, sep, want_zebra, want_right, want_lineno);
  }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <unistd.h>
#include "cmdAnd.h"
#include "cmdOr.h"
#include "cmdBase.h"
#include "cmdSemi.h"
#include "cmdExecutable.h"

using namespace std;

// prints the prompt for the user
// displays the user name and host name
void printPrompt()
{
    char *User;
    char host[30];

    User = getlogin( );
    gethostname( host, 30 );

    cout << User << "@" << host << "$ ";
}

//takes in user input and returns the char*
char* getInput()
{
    //takes in user input as string w/ getline
    string temp;

    getline(cin, temp);

    //if user entered nothing
    //print the prompt and wait for user input
    //checks for syntax error when the connectors
    //are the first inputs
    while ( temp.empty( ) || temp[0] == '&' ||
            temp[0] == '|' || temp[0] == ';')
    {
        if (temp[0] == '&' || temp[0] == '|' || temp[0] == ';')
        {
            cout << "syntax error near unexpected token '"
                << temp[0];

            if ( temp[0] != ';' )
                cout << " " << temp[1] << "'" << endl;
            else
                cout << "'" << endl;

        }

        printPrompt();
        getline( cin, temp );
    }

    //creates char array and sets it equal to string
    char* input = new char[temp.size()];

    for (int i = 0, n = temp.size(); i < n; i++)
    {
        input[i] = temp.at(i);
    }

    input[temp.size()] = '\0'; //adds NULL to end of char array
    return input;
}

//creates tree of command connectors by parsing the entered line
cmdBase* parse(char* input)
{
    char* command1 = strtok(input, "#"); //removes everything thats a comment

    command1 = strtok(command1, ";"); //finds first semicolon

    char* command2 = strtok(NULL, "\0");

    if (command2 != NULL) //if semicolon was found
    {
        if (command2[0] == '&' || command2[1] == '&' ||
                command2[0] == '|' || command2[1] == '|'
                || command2[0] == ';')
        {
            cout  << "syntax error near unexpected token '"
                                  << ';'  << "'" << endl;
            cmdExecutable* tmp = new cmdExecutable( NULL );
            return tmp;
        }
        //create semi connector by parsing left side and right side
        cmdSemi* tmp = new cmdSemi(parse(command1), parse(command2));
        return tmp;
    }
    else //no semicolon found
    {
        //tree must be built with last connector having highest priority
        char* lastAnd = strrchr(command1, '&'); //returns ptr to last &
        char* lastOr = strrchr(command1, '|'); //returns ptr to last |

        //if there is && but no || or if && is after ||
        if (lastAnd != '\0' && (lastOr == '\0' || strlen(lastAnd)
                    < strlen(lastOr)))
        {
            //checks if two connectors are in a row and prints error if so
            if (lastAnd[-2] == '&' || lastAnd[-3] == '&' ||
                lastAnd[-1] == '|' || lastAnd[-2] == '|'
                || lastAnd[-1] == ';' || lastAnd[-2] == ';')
            {
                cout  << "syntax error near unexpected token '"
                    << lastAnd[0] << "'" << endl;
                cmdExecutable* tmp = new cmdExecutable( NULL );
                return tmp;
            }

            lastAnd[-1] = '\0'; //make last && into NULL
            lastAnd[0] = '\0';

            command2 = &lastAnd[1]; //set right side to after last &

            cmdAnd* tmp = new cmdAnd(parse(command1), parse(command2));

            return tmp;
        }

        //if there is || but no && or if || is after &&
        else if (lastOr != '\0' && (lastAnd == '\0'
                    || strlen(lastOr) < strlen(lastAnd)))
        {
            //checks if two connectors are in a row and prints error if so
            if (lastOr[-1] == '&' || lastOr[-2] == '&' ||
                lastOr[-2] == '|' || lastOr[-3] == '|'
                || lastOr[-1] == ';' || lastOr[-2] == ';')
            {
                cout  << "syntax error near unexpected token '"
                    << lastOr[0] << "'" << endl;
                cmdExecutable* tmp = new cmdExecutable( NULL );
                return tmp;
            }

            lastOr[-1] = '\0'; //make last || into NULL
            lastOr[0] = '\0';

            command2 = &lastOr[1]; //set right side to after last |

            cmdOr* tmp = new cmdOr(parse(command1), parse(command2));

            return tmp;
        }

        //if no && or || commands found
        else //if (lastAnd == '\0' && lastOr == '\0')
        {
            cmdExecutable* tmp = new cmdExecutable(command1);
            return tmp;
        }
    }
}

int main()
{
    while(true)
    {
        printPrompt();

        char* userInput = getInput();

        cmdBase* head = parse(userInput);

        head->execute( );
        delete head;
    }
}
<commit_msg>fixed spaces between connectors<commit_after>#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <unistd.h>
#include "cmdAnd.h"
#include "cmdOr.h"
#include "cmdBase.h"
#include "cmdSemi.h"
#include "cmdExecutable.h"

using namespace std;

// prints the prompt for the user
// displays the user name and host name
void printPrompt()
{
    char *User;
    char host[30];

    User = getlogin( );
    gethostname( host, 30 );

    cout << User << "@" << host << "$ ";
}

//takes in user input and returns the char*
char* getInput()
{
    //takes in user input as string w/ getline
    string temp;

    getline(cin, temp);

    //if user entered nothing
    //print the prompt and wait for user input
    //checks for syntax error when the connectors
    //are the first inputs
    while ( temp.empty( ) || temp[0] == '&' ||
            temp[0] == '|' || temp[0] == ';')
    {
        if (temp[0] == '&' || temp[0] == '|' || temp[0] == ';')
        {
            cout << "syntax error near unexpected token '"
                << temp[0];

            if ( temp[0] != ';' )
                cout << temp[1] << "'" << endl;
            else
                cout << "'" << endl;

        }

        printPrompt();
        getline( cin, temp );
    }

    if ( temp.find("&& ||") != std::string::npos )
    {
        cout << "syntax error near unexpected token ||" << endl;

        printPrompt( );
        getline( cin, temp );
    }

    else if ( temp.find( "|| &&" ) != std::string::npos )
    {
        cout << "syntax error near unexpected token &&" << endl;
        printPrompt( );
        getline( cin, temp );
    }

    //creates char array and sets it equal to string
    char* input = new char[temp.size()];

    for (int i = 0, n = temp.size(); i < n; i++)
    {
        input[i] = temp.at(i);
    }

    input[temp.size()] = '\0'; //adds NULL to end of char array
    return input;
}

//creates tree of command connectors by parsing the entered line
cmdBase* parse(char* input)
{
    char* command1 = strtok(input, "#"); //removes everything thats a comment

    command1 = strtok(command1, ";"); //finds first semicolon

    char* command2 = strtok(NULL, "\0");

    if (command2 != NULL) //if semicolon was found
    {
        if (command2[0] == '&' || command2[1] == '&' ||
                command2[0] == '|' || command2[1] == '|'
                || command2[0] == ';')
        {
            cout  << "syntax error near unexpected token '"
                                  << ';'  << "'" << endl;
            cmdExecutable* tmp = new cmdExecutable( NULL );
            return tmp;
        }
        //create semi connector by parsing left side and right side
        cmdSemi* tmp = new cmdSemi(parse(command1), parse(command2));
        return tmp;
    }
    else //no semicolon found
    {
        //tree must be built with last connector having highest priority
        char* lastAnd = strrchr(command1, '&'); //returns ptr to last &
        char* lastOr = strrchr(command1, '|'); //returns ptr to last |

        //if there is && but no || or if && is after ||
        if (lastAnd != '\0' && (lastOr == '\0' || strlen(lastAnd)
                    < strlen(lastOr)))
        {
            //checks if two connectors are in a row and prints error if so
            if (lastAnd[-2] == '&' || lastAnd[-3] == '&' ||
                lastAnd[-1] == '|' || lastAnd[-2] == '|'
                || lastAnd[-1] == ';' || lastAnd[-2] == ';')
            {
                cout  << "syntax error near unexpected token '"
                    << lastAnd[0] << "'" << endl;
                cmdExecutable* tmp = new cmdExecutable( NULL );
                return tmp;
            }

            lastAnd[-1] = '\0'; //make last && into NULL
            lastAnd[0] = '\0';

            command2 = &lastAnd[1]; //set right side to after last &

            cmdAnd* tmp = new cmdAnd(parse(command1), parse(command2));

            return tmp;
        }

        //if there is || but no && or if || is after &&
        else if (lastOr != '\0' && (lastAnd == '\0'
                    || strlen(lastOr) < strlen(lastAnd)))
        {
            //checks if two connectors are in a row and prints error if so
            if (lastOr[-1] == '&' || lastOr[-2] == '&' ||
                lastOr[-2] == '|' || lastOr[-3] == '|'
                || lastOr[-1] == ';' || lastOr[-2] == ';')
            {
                cout  << "syntax error near unexpected token '"
                    << lastOr[0] << "'" << endl;
                cmdExecutable* tmp = new cmdExecutable( NULL );
                return tmp;
            }

            lastOr[-1] = '\0'; //make last || into NULL
            lastOr[0] = '\0';

            command2 = &lastOr[1]; //set right side to after last |

            cmdOr* tmp = new cmdOr(parse(command1), parse(command2));

            return tmp;
        }

        //if no && or || commands found
        else //if (lastAnd == '\0' && lastOr == '\0')
        {
            cmdExecutable* tmp = new cmdExecutable(command1);
            return tmp;
        }
    }
}

int main()
{
    while(true)
    {
        printPrompt();

        char* userInput = getInput();

        cmdBase* head = parse(userInput);

        head->execute( );
        delete head;
    }
}
<|endoftext|>


<commit_before>/*
 *  This file is part of SKATRAK Playground.
 *
 *  SKATRAK Playground 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, see <http://www.gnu.org/licenses/> or
 *  write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 *  Floor, Boston, MA 02110-1301 USA
 *
 *  Sergio M. Afonso Fumero <theSkatrak@gmail.com>
 */

#include <SKATRAK_PLAYGROUND.hpp>

/**
 * @brief Constructor. Inicializa los valores de las variables e inicia SDL_TTF si no se ha iniciado.
 */
font_t::font_t(): font(NULL), rendered(NULL), fontName(""), fontSize(DEFAULT_FONT_SIZE), fontStyle(DEFAULT_FONT_STYLE), fontText(""), fontAlpha(SDL_ALPHA_OPAQUE), changed(true) {
	sistema->initSubsystems(SYS_SUBST_TTF);
	setColor(0, 0, 0);
}

/**
 * @brief Constructor de copia. Inicializa los valores de las variables e inicia SDL_TTF si no se ha iniciado.
 * @param copy Instancia de font_t que se desea copiar.
 */
font_t::font_t(font_t& copy): font(NULL), rendered(NULL), fontName(""), fontSize(copy.fontSize), fontStyle(copy.fontStyle), fontText(""), fontAlpha(SDL_ALPHA_OPAQUE), changed(true) {
	if(sistema->initSubsystems(SYS_SUBST_TTF) & SYS_SUBST_TTF)
		open(copy.fontName);
	fontColor = copy.fontColor;
}

/**
 * @brief Constructor. Inicializa los valores de las variables e inicia SDL_TTF si no se ha iniciado.
 * @param path Ruta del archivo de fuentes .ttf o .fon que contiene la fuente a utilizar.
 */
font_t::font_t(string path): font(NULL), rendered(NULL), fontName(path), fontSize(DEFAULT_FONT_SIZE), fontStyle(DEFAULT_FONT_STYLE), fontText(""), fontAlpha(SDL_ALPHA_OPAQUE), changed(true) {
	if(sistema->initSubsystems(SYS_SUBST_TTF) & SYS_SUBST_TTF)
		open(path);
	setColor(0, 0, 0);
}

/**
 * @brief Destructor. Libera la memoria reservada.
 */
font_t::~font_t(){
	if(font != NULL)
		TTF_CloseFont(font);
	if(rendered != NULL)
		SDL_FreeSurface(rendered);
}

/**
 * @brief Abre un archivo de fuentes .ttf o .fon.
 */
void font_t::open(string path){
	fontName = FONT_PATH;
	fontName += path;

	if(font != NULL){
		TTF_CloseFont(font);
		font = NULL;
	}
	font = TTF_OpenFont(fontName.c_str(), fontSize);
	if(font == NULL)
		fprintf(stderr, "font_t::open: No se ha podido abrir \"%s\": %s.\n", fontName.c_str(), TTF_GetError());
	changed = true;
	fontName = path;	// Hay que resetear la variable, porque si no se va aadiendo FONT_PATH al principio todo el rato
}

/**
 * @brief Cambia el tamao de la fuente cargada. Se puede utilizar antes de cargar la fuente tambin.
 * @param size Tamao de la fuente.
 */
void font_t::setSize(int size){
	if(size != fontSize){
		changed = true;
		fontSize = size;
		open(fontName);
	}
}

/**
 * @brief Cambia el estilo de la fuente.
 * @param style Mscara de bits que especifica las propiedades del estilo.
 *
 * Las posibles mscaras son:
 * TTF_STYLE_BOLD,
 * TTF_STYLE_ITALIC,
 * TTF_STYLE_UNDERLINE,
 * TTF_STYLE_STRIKETHROUGH,
 * TTF_STYLE_NORMAL
 */
void font_t::setStyle(int style){
	if(style != fontStyle){
		changed = true;
		fontStyle = style;
	}
}

/**
 * @brief Especifica el texto que se desea renderizar.
 * @param text Texto a renderizar.
 */
void font_t::setText(string text){
	if(text != fontText){
		changed = true;
		fontText = text;
	}
}

/**
 * @brief Cambia el color de la fuente.
 * @param R Valor entre 0 y 255 que representa la cantidad de Rojo que se desea.
 * @param G Valor entre 0 y 255 que representa la cantidad de Verde que se desea.
 * @param B Valor entre 0 y 255 que representa la cantidad de Azul que se desea.
 */
void font_t::setColor(int R, int G, int B){
	if(fontColor.r != R || fontColor.g != G || fontColor.b != B){
		changed = true;
		fontColor.r = R;
		fontColor.g = G;
		fontColor.b = B;
	}
}

/**
 * @brief Cambia la transparencia de la fuente al imprimirla por pantalla.
 * @param alpha Valor de transparencia que se desea poner. Debe estar entre 0 (SDL_ALPHA_TRANSPARENT) y 255 (SDL_ALPHA_OPAQUE).
 */
void font_t::setAlpha(int alpha){
	if(alpha >= SDL_ALPHA_TRANSPARENT && alpha <= SDL_ALPHA_OPAQUE && alpha != fontAlpha){
		fontAlpha = alpha;
		changed = true;
	}
}

/**
 * @brief Imprime la fuente por la pantalla
 * @param x Posicin X donde se imprime
 * @param y Posicin Y donde se imprime
 * @param screen Superficie sobre la que se har el blitting.
 */
void font_t::blit(int x, int y, SDL_Surface* screen){
	if(font != NULL){
		if(changed){
			TTF_SetFontStyle(font, fontStyle);
			if(rendered != NULL){
				SDL_FreeSurface(rendered);
				rendered = NULL;
			}
			if(fontAlpha == SDL_ALPHA_OPAQUE){
				rendered = TTF_RenderText_Blended(font, fontText.c_str(), fontColor);
				if(rendered == NULL)
					fprintf(stderr, "font_t::blit: No se ha podido renderizar: %s.\n", TTF_GetError());
			}
			else {
				rendered = TTF_RenderText_Solid(font, fontText.c_str(), fontColor);
				if(rendered == NULL)
					fprintf(stderr, "font_t::blit: No se ha podido renderizar: %s.\n", TTF_GetError());
				else
					SDL_SetAlpha(rendered, SDL_SRCALPHA | SDL_RLEACCEL, fontAlpha);
			}
			if(rendered != NULL){
				changed = false;
				SDL_Surface* temp = NULL;
				temp = SDL_DisplayFormatAlpha(rendered);
				if(temp == NULL)
					fprintf(stderr, "font_t::blit: No se ha podido optimizar el formato: %s.\n", SDL_GetError());
				else {
					SDL_FreeSurface(rendered);
					rendered = temp;
				}
			}
		}
		int tmp = 0;
		TTF_GlyphMetrics(font, 'l', NULL, NULL, NULL, &tmp, NULL);
		SDL_Rect dest = {x, y - TTF_FontAscent(font) + tmp, 0, 0};
		SDL_BlitSurface(rendered, NULL, screen, &dest);
	}
	else
		fprintf(stderr, "font_t::blit: No se puede imprimir por pantalla porque no se ha cargado.\n");
}

/**
 * @return Anchura en pxeles del texto cargado actualmente con la fuente actual.
 */
int font_t::width(){
	if(font == NULL)
		return 0;
	int retVal = 0;
	TTF_SizeText(font, fontText.c_str(), &retVal, NULL);
	return retVal;
}

/**
 * @return Altura en pxeles mxima que puede alcanzar la fuente actual.
 */
int font_t::height(){
	if(font == NULL)
		return 0;

	int miny = 0, maxy = 0;
	// Hago este truco porque usando las medidas por defecto de las fuentes quedan poco ajustadas
	TTF_GlyphMetrics(font, 'l', NULL, NULL, NULL, &maxy, NULL); // Una letra larga por arriba
	TTF_GlyphMetrics(font, 'p', NULL, NULL, &miny, NULL, NULL); // Una letra larga por abajo
	return maxy - miny;
}
<commit_msg>Mensaje de error redundante y molesto eliminado<commit_after>/*
 *  This file is part of SKATRAK Playground.
 *
 *  SKATRAK Playground 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, see <http://www.gnu.org/licenses/> or
 *  write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 *  Floor, Boston, MA 02110-1301 USA
 *
 *  Sergio M. Afonso Fumero <theSkatrak@gmail.com>
 */

#include <SKATRAK_PLAYGROUND.hpp>

/**
 * @brief Constructor. Inicializa los valores de las variables e inicia SDL_TTF si no se ha iniciado.
 */
font_t::font_t(): font(NULL), rendered(NULL), fontName(""), fontSize(DEFAULT_FONT_SIZE), fontStyle(DEFAULT_FONT_STYLE), fontText(""), fontAlpha(SDL_ALPHA_OPAQUE), changed(true) {
	sistema->initSubsystems(SYS_SUBST_TTF);
	setColor(0, 0, 0);
}

/**
 * @brief Constructor de copia. Inicializa los valores de las variables e inicia SDL_TTF si no se ha iniciado.
 * @param copy Instancia de font_t que se desea copiar.
 */
font_t::font_t(font_t& copy): font(NULL), rendered(NULL), fontName(""), fontSize(copy.fontSize), fontStyle(copy.fontStyle), fontText(""), fontAlpha(SDL_ALPHA_OPAQUE), changed(true) {
	if(sistema->initSubsystems(SYS_SUBST_TTF) & SYS_SUBST_TTF)
		open(copy.fontName);
	fontColor = copy.fontColor;
}

/**
 * @brief Constructor. Inicializa los valores de las variables e inicia SDL_TTF si no se ha iniciado.
 * @param path Ruta del archivo de fuentes .ttf o .fon que contiene la fuente a utilizar.
 */
font_t::font_t(string path): font(NULL), rendered(NULL), fontName(path), fontSize(DEFAULT_FONT_SIZE), fontStyle(DEFAULT_FONT_STYLE), fontText(""), fontAlpha(SDL_ALPHA_OPAQUE), changed(true) {
	if(sistema->initSubsystems(SYS_SUBST_TTF) & SYS_SUBST_TTF)
		open(path);
	setColor(0, 0, 0);
}

/**
 * @brief Destructor. Libera la memoria reservada.
 */
font_t::~font_t(){
	if(font != NULL)
		TTF_CloseFont(font);
	if(rendered != NULL)
		SDL_FreeSurface(rendered);
}

/**
 * @brief Abre un archivo de fuentes .ttf o .fon.
 */
void font_t::open(string path){
	fontName = FONT_PATH;
	fontName += path;

	if(font != NULL){
		TTF_CloseFont(font);
		font = NULL;
	}
	font = TTF_OpenFont(fontName.c_str(), fontSize);
	if(font == NULL)
		fprintf(stderr, "font_t::open: No se ha podido abrir \"%s\": %s.\n", fontName.c_str(), TTF_GetError());
	changed = true;
	fontName = path;	// Hay que resetear la variable, porque si no se va aadiendo FONT_PATH al principio todo el rato
}

/**
 * @brief Cambia el tamao de la fuente cargada. Se puede utilizar antes de cargar la fuente tambin.
 * @param size Tamao de la fuente.
 */
void font_t::setSize(int size){
	if(size != fontSize){
		changed = true;
		fontSize = size;
		open(fontName);
	}
}

/**
 * @brief Cambia el estilo de la fuente.
 * @param style Mscara de bits que especifica las propiedades del estilo.
 *
 * Las posibles mscaras son:
 * TTF_STYLE_BOLD,
 * TTF_STYLE_ITALIC,
 * TTF_STYLE_UNDERLINE,
 * TTF_STYLE_STRIKETHROUGH,
 * TTF_STYLE_NORMAL
 */
void font_t::setStyle(int style){
	if(style != fontStyle){
		changed = true;
		fontStyle = style;
	}
}

/**
 * @brief Especifica el texto que se desea renderizar.
 * @param text Texto a renderizar.
 */
void font_t::setText(string text){
	if(text != fontText){
		changed = true;
		fontText = text;
	}
}

/**
 * @brief Cambia el color de la fuente.
 * @param R Valor entre 0 y 255 que representa la cantidad de Rojo que se desea.
 * @param G Valor entre 0 y 255 que representa la cantidad de Verde que se desea.
 * @param B Valor entre 0 y 255 que representa la cantidad de Azul que se desea.
 */
void font_t::setColor(int R, int G, int B){
	if(fontColor.r != R || fontColor.g != G || fontColor.b != B){
		changed = true;
		fontColor.r = R;
		fontColor.g = G;
		fontColor.b = B;
	}
}

/**
 * @brief Cambia la transparencia de la fuente al imprimirla por pantalla.
 * @param alpha Valor de transparencia que se desea poner. Debe estar entre 0 (SDL_ALPHA_TRANSPARENT) y 255 (SDL_ALPHA_OPAQUE).
 */
void font_t::setAlpha(int alpha){
	if(alpha >= SDL_ALPHA_TRANSPARENT && alpha <= SDL_ALPHA_OPAQUE && alpha != fontAlpha){
		fontAlpha = alpha;
		changed = true;
	}
}

/**
 * @brief Imprime la fuente por la pantalla
 * @param x Posicin X donde se imprime
 * @param y Posicin Y donde se imprime
 * @param screen Superficie sobre la que se har el blitting.
 */
void font_t::blit(int x, int y, SDL_Surface* screen){
	if(font != NULL){
		if(changed){
			TTF_SetFontStyle(font, fontStyle);
			if(rendered != NULL){
				SDL_FreeSurface(rendered);
				rendered = NULL;
			}
			if(fontAlpha == SDL_ALPHA_OPAQUE){
				rendered = TTF_RenderText_Blended(font, fontText.c_str(), fontColor);
				if(rendered == NULL)
					fprintf(stderr, "font_t::blit: No se ha podido renderizar: %s.\n", TTF_GetError());
			}
			else {
				rendered = TTF_RenderText_Solid(font, fontText.c_str(), fontColor);
				if(rendered == NULL)
					fprintf(stderr, "font_t::blit: No se ha podido renderizar: %s.\n", TTF_GetError());
				else
					SDL_SetAlpha(rendered, SDL_SRCALPHA | SDL_RLEACCEL, fontAlpha);
			}
			if(rendered != NULL){
				changed = false;
				SDL_Surface* temp = NULL;
				temp = SDL_DisplayFormatAlpha(rendered);
				if(temp == NULL)
					fprintf(stderr, "font_t::blit: No se ha podido optimizar el formato: %s.\n", SDL_GetError());
				else {
					SDL_FreeSurface(rendered);
					rendered = temp;
				}
			}
		}
		int tmp = 0;
		TTF_GlyphMetrics(font, 'l', NULL, NULL, NULL, &tmp, NULL);
		SDL_Rect dest = {x, y - TTF_FontAscent(font) + tmp, 0, 0};
		SDL_BlitSurface(rendered, NULL, screen, &dest);
	}
}

/**
 * @return Anchura en pxeles del texto cargado actualmente con la fuente actual.
 */
int font_t::width(){
	if(font == NULL)
		return 0;
	int retVal = 0;
	TTF_SizeText(font, fontText.c_str(), &retVal, NULL);
	return retVal;
}

/**
 * @return Altura en pxeles mxima que puede alcanzar la fuente actual.
 */
int font_t::height(){
	if(font == NULL)
		return 0;

	int miny = 0, maxy = 0;
	// Hago este truco porque usando las medidas por defecto de las fuentes quedan poco ajustadas
	TTF_GlyphMetrics(font, 'l', NULL, NULL, NULL, &maxy, NULL); // Una letra larga por arriba
	TTF_GlyphMetrics(font, 'p', NULL, NULL, &miny, NULL, NULL); // Una letra larga por abajo
	return maxy - miny;
}
<|endoftext|>


<commit_before>#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <array>
#include <iomanip>
#include <cfloat>
#include "immintrin.h"
#include "vec.h"
#include "color.h"
#include "render_target.h"

struct Sphere {
	float x, y, z, radius;

	Sphere(float x, float y, float z, float radius) : x(x), y(y), z(z), radius(radius) {}
	// Test 8 rays against the sphere, returns masks for the hits (0xff) and misses (0x00)
	__m256 intersect(Ray8 &ray) const {
		const auto center = Vec3f_8{x, y, z};
		const auto d = center - ray.o;
		const auto a = ray.d.length_sqr();
		const auto b = _mm256_mul_ps(ray.d.dot(d), _mm256_set1_ps(-2.f));
		const auto c = _mm256_sub_ps(d.dot(d), _mm256_mul_ps(_mm256_set1_ps(radius),
					_mm256_set1_ps(radius)));
		// Solve the quadratic equation and store the mask of potential hits
		// We'll update this mask as we discard other potential hits, eg. due to
		// the hit being beyond the ray's t value
		std::cout << "a = " << a
			<< "\nb = " << b
			<< "\nc = " << c << std::endl;
		__m256 t0, t1;
		auto hits = solve_quadratic(a, b, c, t0, t1);
		std::cout << "solved quadratic:"
			<< "\nhits = " << hits
			<< "\nt0 = " << t0
			<< "\nt1 = " << t1 << std::endl;
		// We want t0 to hold the nearest t value that is greater than ray.t_min
		auto swap_t = _mm256_cmp_ps(t0, ray.t_min, _CMP_LT_OQ);
		t0 = _mm256_blendv_ps(t0, t1, swap_t);
		// Check which rays are within the ray's t range
		auto in_range = _mm256_and_ps(_mm256_cmp_ps(t0, ray.t_min, _CMP_GT_OQ),
				_mm256_cmp_ps(t0, ray.t_max, _CMP_LT_OQ));
		hits = _mm256_and_ps(hits, in_range);
		// Check if all rays miss the sphere
		if ((_mm256_movemask_ps(hits) & 255) == 0){
			return hits;
		}
		// Update t values for rays that did hit
		ray.t_max = _mm256_blendv_ps(ray.t_max, t0, hits);
		return hits;
	}
};

// Simple perspective camera. Perhaps later switch to have transformation matrices?
// would make it easier to have interactive rendering and could add in my glt arball camera
struct PerspectiveCamera {
	// dir_top_left is the direction from the camera to the top left of the image
	Vec3f pos, dir, up, dir_top_left, screen_du, screen_dv;

	PerspectiveCamera(Vec3f pos, Vec3f center, Vec3f up, float fovy, float aspect)
		: pos(pos), dir((center - pos).normalized()), up(up)
	{
		Vec3f dz = dir.normalized();
		Vec3f dx = -dz.cross(up).normalized();
		Vec3f dy = dx.cross(dz).normalized();
		float dim_y = 2.f * std::sin((fovy / 2.f) * (M_PI / 180.f));
		float dim_x = dim_y * aspect;
		dir_top_left = dz - 0.5f * dim_x * dx - 0.5f * dim_y * dy;
		screen_du = dx * dim_x;
		screen_dv = dy * dim_y;
		std::cout << "dir_top_left = " << dir_top_left
			<< "\nscreen_du = " << screen_du
			<< "\nscreen_dv = " << screen_dv
			<< "\ndx = " << dx
			<< "\ndim_x = " << dim_x
			<< "\ndy = " << dy
			<< "\ndim_y = " << dim_y << "\n";
	}
	// Generate a ray packet sampling the 8 screen positions passed
	void generate_rays(Ray8 &rays, const Vec2f_8 &samples) const {
		rays.o = Vec3f_8{pos.x, pos.y, pos.z};
		rays.d = Vec3f_8{dir_top_left.x, dir_top_left.y, dir_top_left.z};
		const auto u_step = samples.x * Vec3f_8{screen_du.x, screen_du.y, screen_du.z};
		const auto v_step = samples.y * Vec3f_8{screen_dv.x, screen_dv.y, screen_dv.z};
		std::cout << "u_step = " << u_step
			<< "\nv_step = " << v_step
			<< "\nrays.d = " << rays.d << "\n";
		rays.d = rays.d + u_step + v_step;
		std::cout << "final (not normalized ray dir) = " << rays.d << "\n";
		rays.d.normalize();
		rays.t_min = _mm256_set1_ps(0);
		rays.t_max = _mm256_set1_ps(INFINITY);
	}
};

int main(int, char**){
	const auto sphere = Sphere{0, 0, 0, 1.25};
	const auto camera = PerspectiveCamera{Vec3f{0, 0, -3}, Vec3f{0, 0, 0}, Vec3f{0, 1, 0}, 60.f, 1.f};
	auto target = RenderTarget{4, 4};
	std::array<float, 16> pixel_x, pixel_y;
	for (int i = 0; i < 16; ++i){
		pixel_x[i] = 0.5 + i % 4;
		pixel_y[i] = 0.5 + i / 4;
	}
	const auto img_dim = Vec2f_8{4, 4};
	const auto samples_top = Vec2f_8{_mm256_loadu_ps(pixel_x.data()),
		_mm256_loadu_ps(pixel_y.data())};
	const auto samples_bot = Vec2f_8{_mm256_loadu_ps(pixel_x.data() + 8),
		_mm256_loadu_ps(pixel_y.data() + 8)};
	std::cout << "samples_top = " << samples_top
	   << "\nsamples_bot = " << samples_bot << "\n";
	// packet_top tests the upper 4x2 region while packet_bot checks the lower 4x2 region
	Ray8 packet_top, packet_bot;
	std::cout << "Making ray packet for top 4x2 region\n";
	camera.generate_rays(packet_top, samples_top / img_dim);
	std::cout << "Making ray packet for bottom 4x2 region\n";
	camera.generate_rays(packet_bot, samples_bot / img_dim);
	std::cout << "packet_top = " << packet_top
	   << "\npacket_bot = " << packet_bot << std::endl;
	// We're rendering a 4x4 'image'
	std::array<char, 4 * 4> image;
	image.fill(' ');
	{
		std::cout << "Checking top hits\n";
		auto hits = sphere.intersect(packet_top);
		target.write_samples(samples_top, Colorf_8{1}, hits);
		std::cout << "Actual hits = " << hits << std::endl;
		std::cout << "packet post hit: " << packet_top << std::endl;

		int hit_mask = _mm256_movemask_ps(hits);
		std::cout << "hit mask = " << std::hex << hit_mask << std::dec << std::endl;
		for (int mask = 1, i = 0; i < 8; mask <<= 1, ++i){
			std::cout << "checking for hit at index " << i
				<< ", using mask " << std::hex << mask << std::dec << std::endl;
			if (hit_mask & mask){
				const float *x = (const float*)&samples_top.x;
				const float *y = (const float*)&samples_top.y;
				std::cout << "there was a hit for pixel { " << x[i] << ", " << y[i] << " }\n";
				const int px_x = clamp(x[i], 0.f, 4.f);
				const int px_y = clamp(y[i], 0.f, 4.f);
				image[px_y * 4 + px_x] = 'X';
			}
		}
	}
	{
		std::cout << "Checking bot hits\n";
		auto hits = sphere.intersect(packet_bot);
		target.write_samples(samples_bot, Colorf_8{1}, hits);
		std::cout << "Actual hits = " << hits << std::endl;
		std::cout << "packet post hit: " << packet_bot << std::endl;

		int hit_mask = _mm256_movemask_ps(hits);
		std::cout << "hit mask = " << std::hex << hit_mask << std::dec << std::endl;
		for (int mask = 1, i = 0; i < 8; mask <<= 1, ++i){
			std::cout << "checking for hit at index " << i
				<< ", using mask " << std::hex << mask << std::dec << std::endl;
			if (hit_mask & mask){
				const float *x = (const float*)&samples_bot.x;
				const float *y = (const float*)&samples_bot.y;
				std::cout << "there was a hit for pixel { " << x[i] << ", " << y[i] << " }\n";
				const int px_x = clamp(x[i], 0.f, 4.f);
				const int px_y = clamp(y[i], 0.f, 4.f);
				image[px_y * 4 + px_x] = 'X';
			}
		}
	}
	for (int y = 0; y < 4; ++y){
		for (int x = 0; x < 4; ++x){
			std::cout << image[y * 4 + x];
		}
		std::cout << "\n";
	}
	target.save_image("out.bmp");
}

<commit_msg>Now just render to the image and render bigger<commit_after>#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <array>
#include <iomanip>
#include <cfloat>
#include "immintrin.h"
#include "vec.h"
#include "color.h"
#include "render_target.h"

struct Sphere {
	float x, y, z, radius;

	Sphere(float x, float y, float z, float radius) : x(x), y(y), z(z), radius(radius) {}
	// Test 8 rays against the sphere, returns masks for the hits (0xff) and misses (0x00)
	__m256 intersect(Ray8 &ray) const {
		const auto center = Vec3f_8{x, y, z};
		const auto d = center - ray.o;
		const auto a = ray.d.length_sqr();
		const auto b = _mm256_mul_ps(ray.d.dot(d), _mm256_set1_ps(-2.f));
		const auto c = _mm256_sub_ps(d.dot(d), _mm256_mul_ps(_mm256_set1_ps(radius),
					_mm256_set1_ps(radius)));
		// Solve the quadratic equation and store the mask of potential hits
		// We'll update this mask as we discard other potential hits, eg. due to
		// the hit being beyond the ray's t value
		__m256 t0, t1;
		auto hits = solve_quadratic(a, b, c, t0, t1);
		// We want t0 to hold the nearest t value that is greater than ray.t_min
		auto swap_t = _mm256_cmp_ps(t0, ray.t_min, _CMP_LT_OQ);
		t0 = _mm256_blendv_ps(t0, t1, swap_t);
		// Check which rays are within the ray's t range
		auto in_range = _mm256_and_ps(_mm256_cmp_ps(t0, ray.t_min, _CMP_GT_OQ),
				_mm256_cmp_ps(t0, ray.t_max, _CMP_LT_OQ));
		hits = _mm256_and_ps(hits, in_range);
		// Check if all rays miss the sphere
		if (_mm256_movemask_ps(hits) == 0){
			return hits;
		}
		// Update t values for rays that did hit
		ray.t_max = _mm256_blendv_ps(ray.t_max, t0, hits);
		return hits;
	}
};

// Simple perspective camera. Perhaps later switch to have transformation matrices?
// would make it easier to have interactive rendering and could add in my glt arball camera
struct PerspectiveCamera {
	// dir_top_left is the direction from the camera to the top left of the image
	Vec3f pos, dir, up, dir_top_left, screen_du, screen_dv;

	PerspectiveCamera(Vec3f pos, Vec3f center, Vec3f up, float fovy, float aspect)
		: pos(pos), dir((center - pos).normalized()), up(up)
	{
		Vec3f dz = dir.normalized();
		Vec3f dx = -dz.cross(up).normalized();
		Vec3f dy = dx.cross(dz).normalized();
		float dim_y = 2.f * std::sin((fovy / 2.f) * (M_PI / 180.f));
		float dim_x = dim_y * aspect;
		dir_top_left = dz - 0.5f * dim_x * dx - 0.5f * dim_y * dy;
		screen_du = dx * dim_x;
		screen_dv = dy * dim_y;
	}
	// Generate a ray packet sampling the 8 screen positions passed
	void generate_rays(Ray8 &rays, const Vec2f_8 &samples) const {
		rays.o = Vec3f_8{pos.x, pos.y, pos.z};
		rays.d = Vec3f_8{dir_top_left.x, dir_top_left.y, dir_top_left.z};
		const auto u_step = samples.x * Vec3f_8{screen_du.x, screen_du.y, screen_du.z};
		const auto v_step = samples.y * Vec3f_8{screen_dv.x, screen_dv.y, screen_dv.z};
		rays.d = rays.d + u_step + v_step;
		rays.d.normalize();
		rays.t_min = _mm256_set1_ps(0);
		rays.t_max = _mm256_set1_ps(INFINITY);
	}
};

int main(int, char**){
	const uint32_t width = 800;
	const uint32_t height = 600;
	const auto sphere = Sphere{0, 0, 0, 1.25};
	const auto camera = PerspectiveCamera{Vec3f{0, 0, -3}, Vec3f{0, 0, 0}, Vec3f{0, 1, 0},
		60.f, static_cast<float>(width) / height};
	auto target = RenderTarget{width, height};
	const auto img_dim = Vec2f_8{width, height};
	// TODO: Z-order 4x4 blocks
	const int n_pixels = width * height;
	for (int i = 0; i < n_pixels; i += 8){
		std::array<float, 8> pixel_x, pixel_y;
		for (int j = 0; j < 8; ++j){
			pixel_x[j] = 0.5 + i % width + j;
			pixel_y[j] = 0.5 + i / width;
		}
		const auto samples = Vec2f_8{_mm256_loadu_ps(pixel_x.data()),
			_mm256_loadu_ps(pixel_y.data())};
		Ray8 packet;
		camera.generate_rays(packet, samples / img_dim);

		auto hits = sphere.intersect(packet);
		target.write_samples(samples, Colorf_8{1}, hits);
	}
	target.save_image("out.bmp");
}

<|endoftext|>


<commit_before>/*
 * JeezyAI is a rap bot that emulates Young Jeezy.
 *
 * Given a bar, JeezyAI will return a rhyme on beat. The AI is trained on a
 * bank of Jeezy lyrics, so it spits like Jeezy.
 *
 * Cameron Matson, Clayton Gentry
 */

#include <iostream>
#include <fstream>
#include <string>

#include "battle.h"
#include "denouncer.h"
#include "model.h"
#include "nouncer.h"
#include "utils.h"
#include "word.h"
#include "wordList.h"

#define LYRICS_FILE "lyrics/lyrics.txt"
#define TEST_FILE   "lyrics/test.txt"

/*
 * Parses a line
 *
 * Each new unique word is appended to the adjacency list
 * as a base word, and its preceding word is instantiated
 * as a node in its leaders vector. If the leader has already
 * been instantiated, its frequency is updated.
 *
 * Lines are processed individually to ensure the model
 * doesn't assume false positive adjacency between the
 * last word of a preceding line and the first word of
 * its successor.
 */
void parseLine(std::string in, Model* model, Nouncer* nouncer, Denouncer* denouncer) {
  std::istringstream ss(Utils::flip(in));
  std::string temp;
  std::string pronunciation;

  Word* current = nullptr;
  Word* leader  = nullptr;

  // TODO: Make this not spaghetti.
  while (ss >> temp) {
    pronunciation = *(nouncer->lookUp(temp));
    denouncer->addPronunciation(temp, pronunciation);

    current = new Word(temp);
    model->addOrUpdate(current);

    // if first word on (reversed) line
    if (leader == nullptr) {
      leader = current;
    }
    else {
      WordList* list_ptr = model -> find(leader);

      if (list_ptr != nullptr) {
        (*list_ptr).add_leader(*current);
        leader = current;
      }
      else {
        std::cerr << "Could not get leader." << std::endl;
      }
    }
  }
}

void parseFile(std::string filename, Model* model, Nouncer* nouncer, Denouncer* denouncer) {
  std::string line;
  std::ifstream file(filename);

  if (file) {
    while(getline(file, line)) {
      parseLine(line, model, nouncer, denouncer);
    }

    file.close();
  }
  else {
    std::cerr << "Could not load lyrics file" << std::endl;
  }

  std::cout << "Model ready!" << std::endl;
}

void rap(std::string bar, Model* model, Nouncer* nouncer) {
  if (bar == "exit") {
    return;
  }
  else {
    Battle* battle = new Battle(bar, model, nouncer);
    battle -> spit();

    std::getline(std::cin, bar);
    rap(bar, model, nouncer);
  }
}

int main(int argc, char *argv[]) {
  Model* model         = new Model();
  Nouncer* nouncer     = new Nouncer();
  Denouncer* denouncer = new Denouncer();
  parseFile(LYRICS_FILE, model, nouncer, denouncer);

  std::string bar;
  std::cout << "Gimme a bar" << std::endl;
  std::getline(std::cin, bar);

  rap(bar, model, nouncer);
}
<commit_msg>add docs<commit_after>/*
 * JeezyAI is a rap bot that emulates Young Jeezy.
 *
 * Given a bar, JeezyAI will return a rhyme on beat. The AI is trained on a
 * bank of Jeezy lyrics, so it spits like Jeezy.
 *
 * Cameron Matson, Clayton Gentry
 */

#include <iostream>
#include <fstream>
#include <string>

#include "battle.h"
#include "denouncer.h"
#include "model.h"
#include "nouncer.h"
#include "utils.h"
#include "word.h"
#include "wordList.h"

#define LYRICS_FILE "lyrics/lyrics.txt"
#define TEST_FILE   "lyrics/test.txt"

/*
 * Parses a line
 *
 * Each new unique word is appended to the adjacency list
 * as a base word, and its preceding word is instantiated
 * as a node in its leaders vector. If the leader has already
 * been instantiated, its frequency is updated.
 *
 * Lines are processed individually to ensure the model
 * doesn't assume false positive adjacency between the
 * last word of a preceding line and the first word of
 * its successor.
 */
void parseLine(std::string in, Model* model, Nouncer* nouncer, Denouncer* denouncer) {
  std::istringstream ss(Utils::flip(in));
  std::string temp;
  std::string pronunciation;

  Word* current = nullptr;
  Word* leader  = nullptr;

  // TODO: Make this not spaghetti.
  while (ss >> temp) {
    pronunciation = *(nouncer->lookUp(temp));
    denouncer->addPronunciation(temp, pronunciation);

    current = new Word(temp);
    model->addOrUpdate(current);

    // if first word on (reversed) line
    if (leader == nullptr) {
      leader = current;
    }
    else {
      WordList* list_ptr = model -> find(leader);

      if (list_ptr != nullptr) {
        (*list_ptr).add_leader(*current);
        leader = current;
      }
      else {
        std::cerr << "Could not get leader." << std::endl;
      }
    }
  }
}

/*
 * Parses a text file of lyrics
 *
 * Iterates through each line of the file, passing references to
 * the data structures to be constructed during analysis.
 */
void parseFile(std::string filename, Model* model, Nouncer* nouncer, Denouncer* denouncer) {
  std::string line;
  std::ifstream file(filename);

  if (file) {
    while(getline(file, line)) {
      parseLine(line, model, nouncer, denouncer);
    }

    file.close();
  }
  else {
    std::cerr << "Could not load lyrics file" << std::endl;
  }

  std::cout << "Model ready!" << std::endl;
}

/*
 * Defines the recursive functionality to consume a given bar and respond.
 */
void rap(std::string bar, Model* model, Nouncer* nouncer) {
  if (bar == "exit") {
    return;
  }
  else {
    Battle* battle = new Battle(bar, model, nouncer);
    battle -> spit();

    std::getline(std::cin, bar);
    rap(bar, model, nouncer);
  }
}

int main(int argc, char *argv[]) {
  Model* model         = new Model();
  Nouncer* nouncer     = new Nouncer();
  Denouncer* denouncer = new Denouncer();
  parseFile(LYRICS_FILE, model, nouncer, denouncer);

  std::string bar;
  std::cout << "Gimme a bar" << std::endl;
  std::getline(std::cin, bar);

  rap(bar, model, nouncer);
}
<|endoftext|>


<commit_before>#include <SFML/Graphics.hpp>
#include "PhysSystem.h"
#include <sstream>
#include <iomanip>
#include <string.h>

sf::Vector2f ConvertVector(Vector2f vec)
{
    return sf::Vector2f(vec.x, vec.y);
}

void RenderBox(std::vector<sf::Vertex>& vertices, Coords2f coords, Vector2f size, sf::Color color)
{
    Vector2f axisX = coords.xVector * size.x;
    Vector2f axisY = coords.yVector * size.y;

    sf::Vertex v;

    v.color = color;

    v.position = ConvertVector(coords.pos - axisX - axisY);
    vertices.push_back(v);

    v.position = ConvertVector(coords.pos + axisX - axisY);
    vertices.push_back(v);

    v.position = ConvertVector(coords.pos + axisX + axisY);
    vertices.push_back(v);

    v.position = ConvertVector(coords.pos - axisX + axisY);
    vertices.push_back(v);
}

float random(float min, float max)
{
    return min + (max - min) * (float(rand()) / float(RAND_MAX));
}

const struct
{
    PhysSystem::SolveMode mode;
    const char* name;
} kModes[] =
    {
     {PhysSystem::Solve_Baseline, "Baseline"},
     {PhysSystem::Solve_AoS, "AoS"},
     {PhysSystem::Solve_SoA_Scalar, "SoA Scalar"},
     {PhysSystem::Solve_SoA_SSE2, "SoA SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoA_AVX2, "SoA AVX2"},
#endif

     {PhysSystem::Solve_SoAPacked_Scalar, "SoA Packed Scalar"},
     {PhysSystem::Solve_SoAPacked_SSE2, "SoA Packed SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoAPacked_AVX2, "SoA Packed AVX2"},
#endif

#if defined(__AVX2__) && defined(__FMA__)
     {PhysSystem::Solve_SoAPacked_FMA, "SoA Packed FMA"},
#endif
};

int main(int argc, char** argv)
{
    int windowWidth = 1280, windowHeight = 1024;

    std::unique_ptr<WorkQueue> queue(new WorkQueue(WorkQueue::getIdealWorkerCount()));

    PhysSystem physSystem;
    RigidBody* groundBody = physSystem.AddBody(Coords2f(Vector2f(windowWidth * 0.5f, windowHeight * 0.95f), 0.0f), Vector2f(windowWidth * 10.45f, 10.0f));
    groundBody->invInertia = 0.0f;
    groundBody->invMass = 0.0f;

    int currentMode = sizeof(kModes) / sizeof(kModes[0]) - 1;

    const float gravity = 200.0f;
    const float integrationTime = 1 / 60.f;
    const int contactIterationsCount = 15;
    const int penetrationIterationsCount = 15;

    float physicsTime = 0.0f;

    RigidBody* draggedBody = physSystem.AddBody(
        Coords2f(Vector2f(windowWidth * 0.1f, windowHeight * 0.7f), 0.0f), Vector2f(30.0f, 30.0f));

    float bodyRadius = 2.f;
    int bodyCount = 10000;

    for (int bodyIndex = 0; bodyIndex < bodyCount; bodyIndex++)
    {
        RigidBody* testBody = physSystem.AddBody(
            Coords2f(Vector2f(windowWidth * 0.5f, windowHeight * 0.6f) + Vector2f(random(-250.0f, 250.0f), random(-650.0f, 250.0f)), 0.0f), Vector2f(bodyRadius * 2.f, bodyRadius * 2.f));
        //testBody->invInertia = 0;
        testBody->velocity = Vector2f(10.0f, 0.0f);
    }

    if (argc > 1 && strcmp(argv[1], "profile") == 0)
    {
        for (int mode = 0; mode < sizeof(kModes) / sizeof(kModes[0]); ++mode)
        {
            PhysSystem testSystem;

            for (int i = 0; i < physSystem.GetBodiesCount(); ++i)
            {
                RigidBody* body = physSystem.GetBody(i);

                RigidBody* testBody = testSystem.AddBody(body->coords, body->geom.size);
                testBody->velocity = body->velocity;
            }

            double collisionTime = 0;
            double mergeTime = 0;
            double solveTime = 0;
            float iterations = 0;

            for (int i = 0; i < 10; ++i)
            {
                testSystem.Update(*queue, 1.f / 60.f, kModes[mode].mode, contactIterationsCount, penetrationIterationsCount);

                collisionTime += testSystem.collisionTime;
                mergeTime += testSystem.mergeTime;
                solveTime += testSystem.solveTime;
                iterations += testSystem.iterations;
            }

            printf("%s: collision %.2f ms, merge %.2f ms, solve %.2f ms, %.2f iterations\n", kModes[mode].name, collisionTime * 1000, mergeTime * 1000, solveTime * 1000, iterations);
        }

        return 0;
    }

    sf::Font font;
    font.loadFromFile("DroidSansMono.ttf");

    sf::RenderWindow* window = new sf::RenderWindow(sf::VideoMode(windowWidth, windowHeight), "This is awesome!");

    sf::Clock clock;

    float prevUpdateTime = 0.0f;

    bool paused = 0;

    std::vector<sf::Vertex> vertices;

    while (window->isOpen())
    {
        sf::Event event;
        while (window->pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window->close();
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::M)
                currentMode = (currentMode + 1) % (sizeof(kModes) / sizeof(kModes[0]));
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::P)
                paused = !paused;
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::C)
            {
                size_t workers = queue->getWorkerCount();
                workers *= 2;
                if (workers > WorkQueue::getIdealWorkerCount())
                    workers = 1;
                queue.reset(new WorkQueue(workers));
            }
        }
        Vector2f mousePos = Vector2f(sf::Mouse::getPosition(*window).x, sf::Mouse::getPosition(*window).y);
        window->clear(sf::Color(50, 50, 50, 255));
        vertices.clear();
        if (clock.getElapsedTime().asSeconds() > prevUpdateTime + integrationTime)
        {
            sf::Clock physicsClock;
            prevUpdateTime += integrationTime;
            float time = 0;
            if (!paused || sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
                time = integrationTime;
            {
                for (size_t bodyIndex = 0; bodyIndex < physSystem.GetBodiesCount(); bodyIndex++)
                {
                    physSystem.GetBody(bodyIndex)->acceleration = Vector2f(0.0f, 0.0f);
                    physSystem.GetBody(bodyIndex)->angularAcceleration = 0.0f;
                }
                for (size_t bodyIndex = 0; bodyIndex < physSystem.GetBodiesCount(); bodyIndex++)
                {
                    RigidBody* body = physSystem.GetBody(bodyIndex);
                    if (body->invMass > 0.0f)
                    {
                        physSystem.GetBody(bodyIndex)->acceleration += Vector2f(0.0f, gravity);
                    }
                }
                RigidBody* draggedBody = physSystem.GetBody(1);
                Vector2f dstVelocity = (mousePos - draggedBody->coords.pos) * 5e1f;
                draggedBody->acceleration += (dstVelocity - draggedBody->velocity) * 5e0;

                physSystem.Update(*queue, time, kModes[currentMode].mode, contactIterationsCount, penetrationIterationsCount);
                physicsTime = physicsClock.getElapsedTime().asSeconds();
            }
        }

        for (size_t bodyIndex = 0; bodyIndex < physSystem.GetBodiesCount(); bodyIndex++)
        {
            RigidBody* body = physSystem.GetBody(bodyIndex);
            Coords2f bodyCoords = body->coords;
            Vector2f size = body->geom.size;

            float colorMult = float(bodyIndex) / float(physSystem.GetBodiesCount()) * 0.5f + 0.5f;
            sf::Color color = sf::Color(char(50 * colorMult), char(125 * colorMult), char(218 * colorMult));

            if (bodyIndex == 1) //dragged body
            {
                color = sf::Color(242, 236, 164, 255);
            }

            RenderBox(vertices, bodyCoords, size, color);
        }

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::V))
            for (size_t manifoldIndex = 0; manifoldIndex < physSystem.GetCollider()->manifolds.size(); manifoldIndex++)
            {
                Manifold& man = physSystem.GetCollider()->manifolds[manifoldIndex];

                for (int collisionNumber = 0; collisionNumber < man.collisionsCount; collisionNumber++)
                {
                    Coords2f coords = Coords2f(Vector2f(0.0f, 0.0f), 3.1415f / 4.0f);

                    coords.pos = man.body1->coords.pos + man.collisions[collisionNumber].delta1;

                    float redMult = 1.0f;
                    if (man.collisions[collisionNumber].isNewlyCreated)
                        redMult = 0.5f;

                    sf::Color color1(100, char(100 * redMult), char(100 * redMult), 100);
                    RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), color1);

                    coords.pos = man.body2->coords.pos + man.collisions[collisionNumber].delta2;
                    sf::Color color2(150, char(150 * redMult), char(150 * redMult), 100);

                    RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), color2);
                }
            }

        if (vertices.size() > 0)
            window->draw(&vertices[0], vertices.size(), sf::Quads);

        std::stringstream debugTextStream;
        debugTextStream.precision(2);
        debugTextStream
            << "Bodies: " << physSystem.GetBodiesCount()
            << " Contacts: " << physSystem.GetJointsCount()
            << " Iterations: " << physSystem.iterations;
        sf::Text text(debugTextStream.str().c_str(), font, 20);
        text.setPosition(sf::Vector2f(10.0f, 30.0f));
        window->draw(text);

        std::stringstream debugTextStream2;
        debugTextStream2 << std::fixed;
        debugTextStream2.precision(2);
        debugTextStream2
            << queue->getWorkerCount() << " cores; "
            << "Mode: " << kModes[currentMode].name << "; "
            << "Physics time: " << std::setw(5) << physicsTime * 1000.0f << "ms (c: " << std::setw(5) << physSystem.collisionTime * 1000.0f << "ms, m: " << std::setw(5) << physSystem.mergeTime * 1000.0f << "ms, s: " << std::setw(5) << physSystem.solveTime * 1000.0f << "ms)";
        sf::Text text2(debugTextStream2.str().c_str(), font, 20);
        text2.setPosition(sf::Vector2f(10.0f, 50.0f));
        window->draw(text2);

        window->display();
    }
}<commit_msg>Handle window resizing<commit_after>#include <SFML/Graphics.hpp>
#include "PhysSystem.h"
#include <sstream>
#include <iomanip>
#include <string.h>

sf::Vector2f ConvertVector(Vector2f vec)
{
    return sf::Vector2f(vec.x, vec.y);
}

void RenderBox(std::vector<sf::Vertex>& vertices, Coords2f coords, Vector2f size, sf::Color color)
{
    Vector2f axisX = coords.xVector * size.x;
    Vector2f axisY = coords.yVector * size.y;

    sf::Vertex v;

    v.color = color;

    v.position = ConvertVector(coords.pos - axisX - axisY);
    vertices.push_back(v);

    v.position = ConvertVector(coords.pos + axisX - axisY);
    vertices.push_back(v);

    v.position = ConvertVector(coords.pos + axisX + axisY);
    vertices.push_back(v);

    v.position = ConvertVector(coords.pos - axisX + axisY);
    vertices.push_back(v);
}

float random(float min, float max)
{
    return min + (max - min) * (float(rand()) / float(RAND_MAX));
}

const struct
{
    PhysSystem::SolveMode mode;
    const char* name;
} kModes[] =
    {
     {PhysSystem::Solve_Baseline, "Baseline"},
     {PhysSystem::Solve_AoS, "AoS"},
     {PhysSystem::Solve_SoA_Scalar, "SoA Scalar"},
     {PhysSystem::Solve_SoA_SSE2, "SoA SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoA_AVX2, "SoA AVX2"},
#endif

     {PhysSystem::Solve_SoAPacked_Scalar, "SoA Packed Scalar"},
     {PhysSystem::Solve_SoAPacked_SSE2, "SoA Packed SSE2"},

#ifdef __AVX2__
     {PhysSystem::Solve_SoAPacked_AVX2, "SoA Packed AVX2"},
#endif

#if defined(__AVX2__) && defined(__FMA__)
     {PhysSystem::Solve_SoAPacked_FMA, "SoA Packed FMA"},
#endif
};

int main(int argc, char** argv)
{
    int windowWidth = 1280, windowHeight = 1024;

    std::unique_ptr<WorkQueue> queue(new WorkQueue(WorkQueue::getIdealWorkerCount()));

    PhysSystem physSystem;
    RigidBody* groundBody = physSystem.AddBody(Coords2f(Vector2f(windowWidth * 0.5f, windowHeight * 0.95f), 0.0f), Vector2f(windowWidth * 10.45f, 10.0f));
    groundBody->invInertia = 0.0f;
    groundBody->invMass = 0.0f;

    int currentMode = sizeof(kModes) / sizeof(kModes[0]) - 1;

    const float gravity = 200.0f;
    const float integrationTime = 1 / 60.f;
    const int contactIterationsCount = 15;
    const int penetrationIterationsCount = 15;

    float physicsTime = 0.0f;

    RigidBody* draggedBody = physSystem.AddBody(
        Coords2f(Vector2f(windowWidth * 0.1f, windowHeight * 0.7f), 0.0f), Vector2f(30.0f, 30.0f));

    float bodyRadius = 2.f;
    int bodyCount = 10000;

    for (int bodyIndex = 0; bodyIndex < bodyCount; bodyIndex++)
    {
        RigidBody* testBody = physSystem.AddBody(
            Coords2f(Vector2f(windowWidth * 0.5f, windowHeight * 0.6f) + Vector2f(random(-250.0f, 250.0f), random(-650.0f, 250.0f)), 0.0f), Vector2f(bodyRadius * 2.f, bodyRadius * 2.f));
        //testBody->invInertia = 0;
        testBody->velocity = Vector2f(10.0f, 0.0f);
    }

    if (argc > 1 && strcmp(argv[1], "profile") == 0)
    {
        for (int mode = 0; mode < sizeof(kModes) / sizeof(kModes[0]); ++mode)
        {
            PhysSystem testSystem;

            for (int i = 0; i < physSystem.GetBodiesCount(); ++i)
            {
                RigidBody* body = physSystem.GetBody(i);

                RigidBody* testBody = testSystem.AddBody(body->coords, body->geom.size);
                testBody->velocity = body->velocity;
            }

            double collisionTime = 0;
            double mergeTime = 0;
            double solveTime = 0;
            float iterations = 0;

            for (int i = 0; i < 10; ++i)
            {
                testSystem.Update(*queue, 1.f / 60.f, kModes[mode].mode, contactIterationsCount, penetrationIterationsCount);

                collisionTime += testSystem.collisionTime;
                mergeTime += testSystem.mergeTime;
                solveTime += testSystem.solveTime;
                iterations += testSystem.iterations;
            }

            printf("%s: collision %.2f ms, merge %.2f ms, solve %.2f ms, %.2f iterations\n", kModes[mode].name, collisionTime * 1000, mergeTime * 1000, solveTime * 1000, iterations);
        }

        return 0;
    }

    sf::Font font;
    font.loadFromFile("DroidSansMono.ttf");

    sf::RenderWindow* window = new sf::RenderWindow(sf::VideoMode(windowWidth, windowHeight), "This is awesome!");

    sf::Clock clock;

    float prevUpdateTime = 0.0f;

    bool paused = 0;

    std::vector<sf::Vertex> vertices;

    while (window->isOpen())
    {
        sf::Event event;
        while (window->pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window->close();
            else if (event.type == sf::Event::Resized)
            {
                sf::Vector2u size = window->getSize();

                window->setView(sf::View(sf::FloatRect(0.f, 0.f, static_cast<float>(size.x), static_cast<float>(size.y))));
            }
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::M)
                currentMode = (currentMode + 1) % (sizeof(kModes) / sizeof(kModes[0]));
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::P)
                paused = !paused;
            else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::C)
            {
                size_t workers = queue->getWorkerCount();
                workers *= 2;
                if (workers > WorkQueue::getIdealWorkerCount())
                    workers = 1;
                queue.reset(new WorkQueue(workers));
            }
        }
        Vector2f mousePos = Vector2f(sf::Mouse::getPosition(*window).x, sf::Mouse::getPosition(*window).y);
        window->clear(sf::Color(50, 50, 50, 255));
        vertices.clear();
        if (clock.getElapsedTime().asSeconds() > prevUpdateTime + integrationTime)
        {
            sf::Clock physicsClock;
            prevUpdateTime += integrationTime;
            float time = 0;
            if (!paused || sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
                time = integrationTime;
            {
                for (size_t bodyIndex = 0; bodyIndex < physSystem.GetBodiesCount(); bodyIndex++)
                {
                    physSystem.GetBody(bodyIndex)->acceleration = Vector2f(0.0f, 0.0f);
                    physSystem.GetBody(bodyIndex)->angularAcceleration = 0.0f;
                }
                for (size_t bodyIndex = 0; bodyIndex < physSystem.GetBodiesCount(); bodyIndex++)
                {
                    RigidBody* body = physSystem.GetBody(bodyIndex);
                    if (body->invMass > 0.0f)
                    {
                        physSystem.GetBody(bodyIndex)->acceleration += Vector2f(0.0f, gravity);
                    }
                }
                RigidBody* draggedBody = physSystem.GetBody(1);
                Vector2f dstVelocity = (mousePos - draggedBody->coords.pos) * 5e1f;
                draggedBody->acceleration += (dstVelocity - draggedBody->velocity) * 5e0;

                physSystem.Update(*queue, time, kModes[currentMode].mode, contactIterationsCount, penetrationIterationsCount);
                physicsTime = physicsClock.getElapsedTime().asSeconds();
            }
        }

        for (size_t bodyIndex = 0; bodyIndex < physSystem.GetBodiesCount(); bodyIndex++)
        {
            RigidBody* body = physSystem.GetBody(bodyIndex);
            Coords2f bodyCoords = body->coords;
            Vector2f size = body->geom.size;

            float colorMult = float(bodyIndex) / float(physSystem.GetBodiesCount()) * 0.5f + 0.5f;
            sf::Color color = sf::Color(char(50 * colorMult), char(125 * colorMult), char(218 * colorMult));

            if (bodyIndex == 1) //dragged body
            {
                color = sf::Color(242, 236, 164, 255);
            }

            RenderBox(vertices, bodyCoords, size, color);
        }

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::V))
            for (size_t manifoldIndex = 0; manifoldIndex < physSystem.GetCollider()->manifolds.size(); manifoldIndex++)
            {
                Manifold& man = physSystem.GetCollider()->manifolds[manifoldIndex];

                for (int collisionNumber = 0; collisionNumber < man.collisionsCount; collisionNumber++)
                {
                    Coords2f coords = Coords2f(Vector2f(0.0f, 0.0f), 3.1415f / 4.0f);

                    coords.pos = man.body1->coords.pos + man.collisions[collisionNumber].delta1;

                    float redMult = 1.0f;
                    if (man.collisions[collisionNumber].isNewlyCreated)
                        redMult = 0.5f;

                    sf::Color color1(100, char(100 * redMult), char(100 * redMult), 100);
                    RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), color1);

                    coords.pos = man.body2->coords.pos + man.collisions[collisionNumber].delta2;
                    sf::Color color2(150, char(150 * redMult), char(150 * redMult), 100);

                    RenderBox(vertices, coords, Vector2f(3.0f, 3.0f), color2);
                }
            }

        if (vertices.size() > 0)
            window->draw(&vertices[0], vertices.size(), sf::Quads);

        std::stringstream debugTextStream;
        debugTextStream.precision(2);
        debugTextStream
            << "Bodies: " << physSystem.GetBodiesCount()
            << " Contacts: " << physSystem.GetJointsCount()
            << " Iterations: " << physSystem.iterations;
        sf::Text text(debugTextStream.str().c_str(), font, 20);
        text.setPosition(sf::Vector2f(10.0f, 30.0f));
        window->draw(text);

        std::stringstream debugTextStream2;
        debugTextStream2 << std::fixed;
        debugTextStream2.precision(2);
        debugTextStream2
            << queue->getWorkerCount() << " cores; "
            << "Mode: " << kModes[currentMode].name << "; "
            << "Physics time: " << std::setw(5) << physicsTime * 1000.0f << "ms (c: " << std::setw(5) << physSystem.collisionTime * 1000.0f << "ms, m: " << std::setw(5) << physSystem.mergeTime * 1000.0f << "ms, s: " << std::setw(5) << physSystem.solveTime * 1000.0f << "ms)";
        sf::Text text2(debugTextStream2.str().c_str(), font, 20);
        text2.setPosition(sf::Vector2f(10.0f, 50.0f));
        window->draw(text2);

        window->display();
    }
}<|endoftext|>


<commit_before>#include "include/ctre.hpp"
#include "include/ctre/first.hpp"
#include <iostream>

template <typename T> struct identify;

int main() {
	ctre::point_set<4> set;
	set.insert(1,10);
	set.insert(5,20);

	std::cout << set.check(2,3) << "\n";

	constexpr auto lhs = ctre::calculate_first(ctre::plus<ctre::char_range<'a','z'>>{});
	constexpr auto rhs = ctre::calculate_first(ctre::back_reference<1>{});
	//identify<decltype(lhs)> i_lhs;
	//identify<decltype(rhs)> i_rhs;

	static_assert(ctre::collides(lhs, rhs));

	//auto out = ctre::first(ctll::list<>{}, ctll::list<ctre::select<ctre::string<'a','l','o','h','a'>, ctre::string<'h','a','n','a'>, ctre::character<'a'>> >{});
	//identify<decltype(out)> i;
}

//bool match2(std::string_view subject) {
//	return ctre::match<LR"(^([-dlsDLS][-rwxstlRWXSTL]{9}[+]?)\s+(\d+)?\s+(\S+)?\s+(.*?)?\s+(\d+)\s+(\d{1,2}).\s([^\s,.]{3,4}).?,?\s((\d{4,4})|(\d{1,2}):(\d{2,2}))\s)">(subject);
//}
//
//bool match(std::string_view subject){
//    return ctre::match<LR"(^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s*$)">(subject);
//}

static constexpr auto pattern = ctll::fixed_string(LR"(^([-dlsDLS][-rwxstlRWXSTL]{9}[+]?)\s*(\d+)?\s+(\S+)?\s+(.*?)?\s+(\d+|\d+.\d+\S)\s+([A-Za-z][a-z][a-z])\s+(\d{1,2})\s+((\d{4,4})|(\d{1,2}):.)\s)");

bool match3(std::string_view subject) {
	return ctre::search<pattern>(subject);
}<commit_msg>remove file<commit_after><|endoftext|>


<commit_before>#include "game.h"

#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>

using namespace space_invaders;

Game::Game(int width, int height) : mState(State::NOT_INITED), mRenderer(nullptr), mWindow(nullptr)
{
  // initialize all SDL2 framework systems.
  if (SDL_Init(SDL_INIT_EVERYTHING) == -1) {
    std::cerr << "Unable to initialize SDL: " << SDL_GetError() << std::endl;
    return;
  }

  // initialize TTF system for text rendering.
  if (TTF_Init() == -1) {
    std::cerr << "Unable to initialize TTF: " << TTF_GetError() << std::endl;
    return;
  }

  // create the main window for the application.
  mWindow = SDL_CreateWindow("SDL2 - Space Invaders", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);
  if (mWindow == nullptr) {
    std::cerr << "Unable to create SDL window: " << SDL_GetError() << std::endl;
    return;
  }

  // create the renderer for the main window.
  mRenderer = SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
  if (mRenderer == nullptr) {
    std::cerr << "Unable to create SDL renderer: " << SDL_GetError() << std::endl;
    return;
  }

  // define the game as ready-to-go!
  mState = State::INITED;
}

Game::~Game()
{
  SDL_DestroyRenderer(mRenderer);
  SDL_DestroyWindow(mWindow);
  TTF_Quit();
  SDL_Quit();
}

int Game::run()
{
  SDL_Event event;
  mState = State::RUNNING;
  while (mState == State::RUNNING) {
    // poll and handle events from the SDL.
    while (SDL_PollEvent(&event) != 0) {
      switch (event.type) {
      case SDL_QUIT:
        mState = State::STOPPED;
        break;
      }
    }

    // clear the rendering context with the black color.
    SDL_SetRenderDrawColor(mRenderer, 0x00, 0x00, 0x00, 0xff);
    SDL_RenderClear(mRenderer);

    // ... TODO render the scene contents into the back buffer

    // present the rendered buffer.
    SDL_RenderPresent(mRenderer);
  }

  return 0;
}<commit_msg>Added an sanity check for the game state before proceeding further in the Game#run function.<commit_after>#include "game.h"

#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>

using namespace space_invaders;

Game::Game(int width, int height) : mState(State::NOT_INITED), mRenderer(nullptr), mWindow(nullptr)
{
  // initialize all SDL2 framework systems.
  if (SDL_Init(SDL_INIT_EVERYTHING) == -1) {
    std::cerr << "Unable to initialize SDL: " << SDL_GetError() << std::endl;
    return;
  }

  // initialize TTF system for text rendering.
  if (TTF_Init() == -1) {
    std::cerr << "Unable to initialize TTF: " << TTF_GetError() << std::endl;
    return;
  }

  // create the main window for the application.
  mWindow = SDL_CreateWindow("SDL2 - Space Invaders", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);
  if (mWindow == nullptr) {
    std::cerr << "Unable to create SDL window: " << SDL_GetError() << std::endl;
    return;
  }

  // create the renderer for the main window.
  mRenderer = SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
  if (mRenderer == nullptr) {
    std::cerr << "Unable to create SDL renderer: " << SDL_GetError() << std::endl;
    return;
  }

  // define the game as ready-to-go!
  mState = State::INITED;
}

Game::~Game()
{
  SDL_DestroyRenderer(mRenderer);
  SDL_DestroyWindow(mWindow);
  TTF_Quit();
  SDL_Quit();
}

int Game::run()
{
  // return with an error code if we do not have a good game state.
  if (mState != State::INITED && mState != State::STOPPED) {
    std::cerr << "Uanble to run the game as the game state is " << (int)mState << std::endl;
    return -1;
  }

  SDL_Event event;
  mState = State::RUNNING;
  while (mState == State::RUNNING) {
    // poll and handle events from the SDL.
    while (SDL_PollEvent(&event) != 0) {
      switch (event.type) {
      case SDL_QUIT:
        mState = State::STOPPED;
        break;
      }
    }

    // clear the rendering context with the black color.
    SDL_SetRenderDrawColor(mRenderer, 0x00, 0x00, 0x00, 0xff);
    SDL_RenderClear(mRenderer);

    // ... TODO render the scene contents into the back buffer

    // present the rendered buffer.
    SDL_RenderPresent(mRenderer);
  }

  return 0;
}<|endoftext|>


<commit_before>/// @provides in    ferred types for elementary functions

#include <boost/integer/static_min_max.hpp>
#include <boost/integer/static_log2.hpp>

namespace core {
    namespace {
        using boost::mpl::eval_if;
        using boost::mpl::and_;
        using boost::static_unsigned_max;

        using boost::static_log2;
    }

/// LOG
    template<typename T, size_t n, size_t f, class op, class up>
    class fixed_point;

    template<typename T>
    class get_
    {
    public:
        typedef double log_type;
        typedef double sqrt_type;
        typedef double max_signed_type;

        typedef double sin_type;
        typedef sin_type cos_type;
        typedef double tan_type;

        typedef double arc_type;
    };

    template<typename T, size_t n, size_t f, class op, class up>
    class get_<fixed_point<T, n, f, op, up> >
    {
        typedef fixed_point<T, n, f, op, up> operand_type;

        struct sqrt_info
        {
            static size_t const integer_bits =
                ((n - f) & 1u)? ((n - f)/2u) + 1u : (n - f)/2u;
            static size_t const fractional_bits =
                (f & 1u)? (f/2u) + 1u : (f/2u);
            static size_t const total_bits = integer_bits + fractional_bits;
        };

        struct log_info
        {
            static size_t const extra_bits =
                static_unsigned_max<static_log2<f>::value + 1u, n + static_log2<n>::value + 1u>::value;

            struct can_expand
            {
                enum { value = (f != 0) &&
                    (n + log_info::extra_bits + 1u < std::numeric_limits<boost::intmax_t>::digits) };
            };

            struct expanded
            {
                typedef fixed_point<
                    typename boost::int_t<n + extra_bits + 1u>::least,
                    n + extra_bits,
                    f,
                    op,
                    up
                > type;
            };

            struct same
            {
                typedef operand_type type;
            };
        };

        struct sin_info
        {
            struct can_expand
            {
                enum { value = (f + 1u + 1u < std::numeric_limits<boost::intmax_t>::digits) };
            };

            struct expanded
            {
                typedef fixed_point<
                    typename boost::int_t<f + 1u + 1u>::least,
                    f + 1u,
                    f,
                    op,
                    up
                > type;
            };

            struct reduced
            {
                typedef fixed_point<
                    typename boost::int_t<f + 1u>::least,
                    f,
                    f - 1u,
                    op,
                    up
                > type;
            };
        };

        struct asin_info
        {
            static size_t const available_bits = std::numeric_limits<boost::intmax_t>::digits - f;

            struct can_expand
            {
                enum { value = (available_bits > 2u) };
            };

            struct expanded
            {
                typedef fixed_point<
                    typename boost::int_t<f + 2u + 1u>::least,
                    f + 2u,
                    f,
                    op,
                    up
                > type;
            };

            struct reduced
            {
                typedef fixed_point<
                    typename boost::int_t<f + 2u>::least,
                    f + available_bits,
                    f + available_bits - 2u,
                    op,
                    up
                > type;
            };
        };

        struct acos_info
        {
            static size_t const available_bits = std::numeric_limits<boost::intmax_t>::digits - f;

            struct can_expand
            {
                enum { value = (available_bits > 3u) };
            };

            struct expanded
            {
                typedef fixed_point<
                    typename boost::int_t<f + 3u + 1u>::least,
                    f + 3u,
                    f,
                    op,
                    up
                > type;
            };

            struct reduced
            {
                typedef fixed_point<
                    typename boost::int_t<f + 3u>::least,
                    f + available_bits,
                    f + available_bits - 3u,
                    op,
                    up
                > type;
            };
        };

    public:
        typedef typename eval_if<
            typename log_info::can_expand,
            typename log_info::expanded,
            typename log_info::same
        >::type log_type;

        // exists always
        typedef fixed_point<
            typename boost::uint_t<sqrt_info::total_bits>::least,
            sqrt_info::total_bits,
            sqrt_info::fractional_bits,
            op,
            up
        > sqrt_type;

        typedef fixed_point<boost::uintmax_t,
            std::numeric_limits<boost::uintmax_t>::digits, f, op, up> max_unsigned_type;

        typedef fixed_point<boost::intmax_t,
            std::numeric_limits<boost::intmax_t>::digits, f, op, up> max_signed_type;

        typedef typename eval_if<
            typename sin_info::can_expand,
            typename sin_info::expanded,
            typename sin_info::reduced
        >::type sin_type;
        typedef sin_type cos_type;
        typedef typename quotient<sin_type, cos_type>::type tan_type;

        typedef max_unsigned_type exp_type;

        typedef typename eval_if<
            typename asin_info::can_expand,
            typename asin_info::expanded,
            typename asin_info::reduced
        >::type asin_type;
        typedef asin_type atan_type;

        typedef typename eval_if<
            typename acos_info::can_expand,
            typename acos_info::expanded,
            typename acos_info::reduced
        >::type acos_type;

        typedef typename get_<operand_type>::log_type asinh_type;
    };
}
<commit_msg>get_.hpp: deletion<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   TeapotNet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "html.h"
#include "exception.h"

namespace tpot
{

Html::Html(Stream *stream) :
		mStream(stream)
{

}

Html::~Html(void)
{

}

void Html::header(const String &title, bool blank, const String &redirect)
{
	*mStream<<"<!DOCTYPE html>\n";
	*mStream<<"\n";
	*mStream<<"\n";
	if(blank) *mStream<<"<title>"<<title<<"</title>\n";
	else *mStream<<"<title>"<<title<<" - "<<APPNAME<<"</title>\n";
	*mStream<<"<meta http-equiv=\"content-type\" content=\"text/html;charset=UTF-8\">\n";
	*mStream<<"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\n";
	*mStream<<"<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/favicon.ico\">\n";
	if(!redirect.empty()) *mStream<<"<meta http-equiv=\"refresh\" content=\"5;URL='"+redirect+"'\">\n";
	*mStream<<"\n";
	*mStream<<"\n";
	*mStream<<"\n";
	*mStream<<"\n";

	if(!blank)
	{
		open("div","panel");
		openLink("/"); image("/logo.png", APPNAME, "logo"); closeLink();
		close("div");
		open("div","bar");
		link(SOURCELINK, "Source code", "", true);
		close("div");
	}
}

void Html::footer(void)
{
	*mStream<<"\n";
	*mStream<<"\n";
}

void Html::raw(const String &str)
{
	mStream->write(str);
}

void Html::text(const String &str)
{
	for(int i=0; i<str.size(); ++i)
	{
		char chr = str[i];
		switch(chr)
		{
		case '"': 	mStream->write(""");	break;
		case '\'': 	mStream->write("'");	break;
		case '<': 	mStream->write("<");		break;
		case '>': 	mStream->write(">");		break;
		case '&': 	mStream->write("&");	break;
		default:	mStream->put(chr);		break;
		}
	}
}

void Html::object(const Serializable &s)
{
	// TODO
	open("span");
	mStream->write(s.toString());
	close("span");
}

void Html::open(const String &type, String id)
{
	assert(!type.empty());
	String cl = id.cut('.');
	*mStream<<"<"<<type;
	if(!id.empty()) *mStream<<" id=\""<<id<<"\"";
	if(!cl.empty()) *mStream<<" class=\""<<cl<<"\"";
	*mStream<<">";
}

void Html::close(const String &type)
{
	assert(!type.empty());
	*mStream<<"</"<<type<<">\n";
}

void Html::openLink(const String &url, String id, bool newTab)
{
	String cl = id.cut('.');
	*mStream<<"<a href=\""<<url<<"\"";
	if(!id.empty()) *mStream<<" id=\""<<id<<"\"";
	if(!cl.empty()) *mStream<<" class=\""<<cl<<"\"";
	if(newTab) *mStream<<" target=\"_blank\"";
	*mStream<<">";
}

void Html::closeLink(void)
{
	*mStream<<"";
}

void Html::span(const String &txt, String id)
{
 	open("span",id);
	text(txt);
	close("span");
}

void Html::div(const String &txt, String id)
{
	open("div",id);
	text(txt);
	close("div");
}

void Html::link(	const String &url,
			const String &txt,
			String id,
			bool newTab)
{
	openLink(url, id, newTab);
	text(txt);
	closeLink();
}

void Html::image(	const String &url,
			const String &alt,
			String id)
{
	String cl = id.cut('.');
	*mStream<<"<img src=\""<<url<<"\"";
	if(!alt.empty()) *mStream<<" alt=\""<<alt<<"\"";
	if(!id.empty())  *mStream<<" id=\""<<id<<"\"";
	if(!cl.empty())  *mStream<<" class=\""<<cl<<"\"";
	*mStream<<"/>\n";
}

void Html::space(void)
{
	*mStream<<' ';
}

void Html::br(void)
{
	*mStream<<"
\n";
}

void Html::openForm(	const String &action,
			const String &method,
		     	const String &name,
			bool multipart)
{
	String enctype;
	if(multipart) enctype = "multipart/form-data";
	else enctype = "application/x-www-form-urlencoded";

	*mStream<<"<form";
	if(!name.empty()) *mStream<<" name=\""<<name<<"\"";
	*mStream<<" action=\""<<action<<"\" method=\""<<method<<"\"";
	if(method == "post") *mStream<<" enctype=\""<<enctype<<"\"";
	*mStream<<">\n";
}

void Html::closeForm(void)
{
	*mStream<<"</form>\n";
}

void Html::openFieldset(const String &legend)
{
	open("fieldset");
	open("legend");
	text(legend);
	close("legend");
}

void Html::closeFieldset(void)
{
  	close("fieldset");
}

void Html::label(const String &name, const String &label)
{
	*mStream<<"<label for=\""<<name<<"\">"<<label<<"\n";
}

void Html::input(const String &type, const String &name, const String &value)
{
	String t(type);
	if(t == "button") t = "submit";
 	*mStream<<"<input type=\""<<t<<"\" class=\""<<name<<"\" name=\""<<name<<"\" value=\""<<value<<"\">\n";
}

void Html::checkbox(const String &name, const String &value, bool checked)
{
 	*mStream<<"<span class=\""<<name<<"\"><input type=\"checkbox\" value=\"1\" name=\""<<name<<"\" "<<(checked ? "checked" : "")<<">";
 	text(value);
 	*mStream<<"\n";
}

void Html::textarea(const String &name, const String &value)
{
	*mStream<<"<textarea class=\""<<name<<"\" name=\""<<name<<"\">";
	text(value);
	*mStream<<"</textarea>\n";
}

void Html::select(const String &name, const StringMap &options, const String &def)
{
	*mStream<<"<select name=\""<<name<<"\">\n";
	for(StringMap::const_iterator it=options.begin(); it!=options.end(); ++it)
	{
		 *mStream<<"<option ";
		 if(def == it->first) *mStream<<"selected ";
		 *mStream<<"value=\""<<it->first<<"\">";
		 text(it->second);
		 *mStream<<"</option>\n";
	}
	*mStream<<"</select>\n";
}

void Html::button(const String &name, const String &text)
{
  	if(text.empty()) input("submit", name, name);
	else input("submit", name, text);
}

void Html::file(const String &name)
{
 	*mStream<<"<input type=\"file\" class=\""<<name<<"\" name=\""<<name<<"\" size="30">\n";
}

Stream *Html::stream(void)
{
	return mStream;
}

}
<commit_msg>Missing escaping<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   TeapotNet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "html.h"
#include "exception.h"

namespace tpot
{

Html::Html(Stream *stream) :
		mStream(stream)
{

}

Html::~Html(void)
{

}

void Html::header(const String &title, bool blank, const String &redirect)
{
	*mStream<<"<!DOCTYPE html>\n";
	*mStream<<"\n";
	*mStream<<"\n";
	if(blank) *mStream<<"<title>"<<title<<"</title>\n";
	else *mStream<<"<title>"<<title<<" - "<<APPNAME<<"</title>\n";
	*mStream<<"<meta http-equiv=\"content-type\" content=\"text/html;charset=UTF-8\">\n";
	*mStream<<"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\n";
	*mStream<<"<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/favicon.ico\">\n";
	if(!redirect.empty()) *mStream<<"<meta http-equiv=\"refresh\" content=\"5;URL='"+redirect+"'\">\n";
	*mStream<<"\n";
	*mStream<<"\n";
	*mStream<<"\n";
	*mStream<<"\n";

	if(!blank)
	{
		open("div","panel");
		openLink("/"); image("/logo.png", APPNAME, "logo"); closeLink();
		close("div");
		open("div","bar");
		link(SOURCELINK, "Source code", "", true);
		close("div");
	}
}

void Html::footer(void)
{
	*mStream<<"\n";
	*mStream<<"\n";
}

void Html::raw(const String &str)
{
	mStream->write(str);
}

void Html::text(const String &str)
{
	for(int i=0; i<str.size(); ++i)
	{
		char chr = str[i];
		switch(chr)
		{
		case '"': 	mStream->write(""");	break;
		case '\'': 	mStream->write("'");	break;
		case '<': 	mStream->write("<");		break;
		case '>': 	mStream->write(">");		break;
		case '&': 	mStream->write("&");	break;
		default:	mStream->put(chr);		break;
		}
	}
}

void Html::object(const Serializable &s)
{
	// TODO
	open("span");
	mStream->write(s.toString());
	close("span");
}

void Html::open(const String &type, String id)
{
	assert(!type.empty());
	String cl = id.cut('.');
	*mStream<<"<"<<type;
	if(!id.empty()) *mStream<<" id=\""<<id<<"\"";
	if(!cl.empty()) *mStream<<" class=\""<<cl<<"\"";
	*mStream<<">";
}

void Html::close(const String &type)
{
	assert(!type.empty());
	*mStream<<"</"<<type<<">\n";
}

void Html::openLink(const String &url, String id, bool newTab)
{
	String cl = id.cut('.');
	*mStream<<"<a href=\""<<url<<"\"";
	if(!id.empty()) *mStream<<" id=\""<<id<<"\"";
	if(!cl.empty()) *mStream<<" class=\""<<cl<<"\"";
	if(newTab) *mStream<<" target=\"_blank\"";
	*mStream<<">";
}

void Html::closeLink(void)
{
	*mStream<<"";
}

void Html::span(const String &txt, String id)
{
 	open("span",id);
	text(txt);
	close("span");
}

void Html::div(const String &txt, String id)
{
	open("div",id);
	text(txt);
	close("div");
}

void Html::link(	const String &url,
			const String &txt,
			String id,
			bool newTab)
{
	openLink(url, id, newTab);
	text(txt);
	closeLink();
}

void Html::image(	const String &url,
			const String &alt,
			String id)
{
	String cl = id.cut('.');
	*mStream<<"<img src=\""<<url<<"\"";
	if(!alt.empty()) *mStream<<" alt=\""<<alt<<"\"";
	if(!id.empty())  *mStream<<" id=\""<<id<<"\"";
	if(!cl.empty())  *mStream<<" class=\""<<cl<<"\"";
	*mStream<<"/>\n";
}

void Html::space(void)
{
	*mStream<<' ';
}

void Html::br(void)
{
	*mStream<<"
\n";
}

void Html::openForm(	const String &action,
			const String &method,
		     	const String &name,
			bool multipart)
{
	String enctype;
	if(multipart) enctype = "multipart/form-data";
	else enctype = "application/x-www-form-urlencoded";

	*mStream<<"<form";
	if(!name.empty()) *mStream<<" name=\""<<name<<"\"";
	*mStream<<" action=\""<<action<<"\" method=\""<<method<<"\"";
	if(method == "post") *mStream<<" enctype=\""<<enctype<<"\"";
	*mStream<<">\n";
}

void Html::closeForm(void)
{
	*mStream<<"</form>\n";
}

void Html::openFieldset(const String &legend)
{
	open("fieldset");
	open("legend");
	text(legend);
	close("legend");
}

void Html::closeFieldset(void)
{
  	close("fieldset");
}

void Html::label(const String &name, const String &label)
{
	*mStream<<"<label for=\""<<name<<"\">"<<label<<"\n";
}

void Html::input(const String &type, const String &name, const String &value)
{
	String t(type);
	if(t == "button") t = "submit";
 	*mStream<<"<input type=\""<<t<<"\" class=\""<<name<<"\" name=\""<<name<<"\" value=\""<<value<<"\">\n";
}

void Html::checkbox(const String &name, const String &value, bool checked)
{
 	*mStream<<"<span class=\""<<name<<"\"><input type=\"checkbox\" value=\"1\" name=\""<<name<<"\" "<<(checked ? "checked" : "")<<">";
 	text(value);
 	*mStream<<"\n";
}

void Html::textarea(const String &name, const String &value)
{
	*mStream<<"<textarea class=\""<<name<<"\" name=\""<<name<<"\">";
	text(value);
	*mStream<<"</textarea>\n";
}

void Html::select(const String &name, const StringMap &options, const String &def)
{
	*mStream<<"<select name=\""<<name<<"\">\n";
	for(StringMap::const_iterator it=options.begin(); it!=options.end(); ++it)
	{
		 *mStream<<"<option ";
		 if(def == it->first) *mStream<<"selected ";
		 *mStream<<"value=\""<<it->first<<"\">";
		 text(it->second);
		 *mStream<<"</option>\n";
	}
	*mStream<<"</select>\n";
}

void Html::button(const String &name, const String &text)
{
  	if(text.empty()) input("submit", name, name);
	else input("submit", name, text);
}

void Html::file(const String &name)
{
 	*mStream<<"<input type=\"file\" class=\""<<name<<"\" name=\""<<name<<"\" size=\"30\">\n";
}

Stream *Html::stream(void)
{
	return mStream;
}

}
<|endoftext|>