//############################################################################ // // LaserBoy !!! // // by James Lehman // Extra Stimulus Inc. // james@akrobiz.com // // began: October 2003 // // Copyright 2003 to 2025 James Lehman. // This source is distributed under the terms of the GNU General Public License. // // LaserBoy_common.cpp is part of LaserBoy. // // LaserBoy is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // LaserBoy 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with LaserBoy. If not, see . // //############################################################################ #include "LaserBoy_common.hpp" #include //############################################################################ LaserBoy_TUI* p_space = (LaserBoy_TUI*)0; //############################################################################ const double pi = (4 * atan(1.00)); const double two_pi = (pi * 2.00 ) ; const double quarter_pi = (pi / 4.00 ) ; const double half_pi = (pi / 2.00 ) ; const double three_quarters_pi = (pi * 0.75 ) ; const double pi_and_a_half = (pi * 1.50 ) ; const double one_degree = (pi / 180.0) ; const double one_radian = (180.0 / pi) ; const double _e_ = std::exp(1.0) ; //############################################################################ const u_short short_bit_mask[16] = { (u_short)0xffff, // 1111 1111 1111 1111 (u_short)0xfffe, // 1111 1111 1111 1110 (u_short)0xfffc, // 1111 1111 1111 1100 (u_short)0xfff8, // 1111 1111 1111 1000 (u_short)0xfff0, // 1111 1111 1111 0000 (u_short)0xffe0, // 1111 1111 1110 0000 (u_short)0xffc0, // 1111 1111 1100 0000 (u_short)0xff80, // 1111 1111 1000 0000 (u_short)0xff00, // 1111 1111 0000 0000 (u_short)0xfe00, // 1111 1110 0000 0000 (u_short)0xfc00, // 1111 1100 0000 0000 (u_short)0xf800, // 1111 1000 0000 0000 (u_short)0xf000, // 1111 0000 0000 0000 (u_short)0xe000, // 1110 0000 0000 0000 (u_short)0xc000, // 1100 0000 0000 0000 (u_short)0x8000 // 1000 0000 0000 0000 }; //############################################################################ string GUID8char() { time_t now = time(NULL); string P_name; static u_short new_palette_id = 0; static const string sixty_four_glyphs = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789"; // 1111 1100 0000 0000 6 bits of new_palette_id P_name += sixty_four_glyphs.at(((new_palette_id & 0xfc00) >> 10)); // 0000 0011 1111 0000 P_name += sixty_four_glyphs.at(((new_palette_id & 0x03f0) >> 4)); // 0000 0000 0000 1111 4 bits of new_palette_id // 1100 0000 0000 0000 0000 0000 0000 0000 2 bits of now P_name += sixty_four_glyphs.at( ((new_palette_id & 0x000f) << 2) | ((now & 0xc0000000) >> 30) ); // 0011 1111 0000 0000 0000 0000 0000 0000 6 bits of now P_name += sixty_four_glyphs.at((now & 0x3f000000) >> 24); // 0000 0000 1111 1100 0000 0000 0000 0000 P_name += sixty_four_glyphs.at((now & 0x00fc0000) >> 18); // 0000 0000 0000 0011 1111 0000 0000 0000 P_name += sixty_four_glyphs.at((now & 0x0003f000) >> 12); // 0000 0000 0000 0000 0000 1111 1100 0000 P_name += sixty_four_glyphs.at((now & 0x00000fc0) >> 6); // 0000 0000 0000 0000 0000 0000 0011 1111 P_name += sixty_four_glyphs.at( now & 0x0000003f ); new_palette_id++; if(new_palette_id == 32768) // 1000 0000 0000 0000 { // 32768 new palettes names in one second is quite a lot! new_palette_id = 0; while(now == time(NULL)){/* wait for next second */}; } return P_name; } //############################################################################ // delta_02, delta_01, delta_12, double delta_angle(double a, double b, double c) // sss triangle { // returns the simple angle in the three vertices 0, 1, 2 double angle; //------------------------------------------------------------------------ if( b == 0.0 || c == 0.0 ) angle = 0; //------------------------------------------------------------------------ else if(a == 0.0) angle = pi; //------------------------------------------------------------------------ else if(a >= b + c) angle = 0.0; //------------------------------------------------------------------------ else angle = pi - acos((b*b + c*c - a*a)/(2*b*c)); //------------------------------------------------------------------------ return angle; } //############################################################################ double simple_2D_angle(double x1, double y1, double x2, double y2) { return atan2(y2 - y1, x2 - x1); } //############################################################################ u_char rescale_to_index(const u_short* rescale, u_short value) { u_int i; value &= 0xfffe; // remove possible LSB tag for(i = 0; i < 256; i++) if(rescale[i] == value) return (u_char)i; return 0x00; } //############################################################################ int greatest_common_devisor(int x, int y) { x = abs(x); y = abs(y); int z; while(y != 0) { z = x % y; x = y; y = z; } return x; } //############################################################################ int lowest_common_denominator(int x, int y) { int z, min = x > y ? y : x; for(z = 2; z < min; z++) if(((x % z) == 0) && ((y % z) == 0)) break; if(z == min) return y; return z; } //############################################################################ bool file_exists(const string& file) { std::ifstream in; in.open(file.c_str(), ios::in); if(in.is_open()) { in.close(); return true; } return false; } //############################################################################ bool directory_exists(const string& dir, const string& home) { if(exists((home + dir).c_str())) return true; return false; } //############################################################################ string time_as_string(double seconds) { if(seconds >= 0) { char buffer[256]; string time_string; int hh, mm, ss; double sec; hh = (int)(seconds / 3600); mm = (int)((seconds - hh * 3600) / 60); ss = (int)(seconds - (hh * 3600 + mm * 60)); sec = seconds - (hh * 3600 + mm * 60 + ss); sprintf(buffer, "%02d:%02d:%02d", hh, mm, ss); time_string = buffer; sprintf(buffer, "%lf", sec); time_string += &(buffer[1]); // ignore the leading zero! return time_string; } return string("??:??:??"); } //############################################################################ double random_01() // returns a double between 0 & 1. { return ((double)(rand()) / (double)RAND_MAX); } //############################################################################ double random_neg_to_pos_1() // returns a double between -1 & 1. { return random_01() - random_01(); } //############################################################################ void txt_tag(std::ofstream& out) { out << "# This file was generated by " LASERBOY_VERSION " !!!\n" "#\n" "# the free, multiplatform laser display application\n" "# by James Lehman \n" "# Extra Stimulus Inc., Akron, Ohio USA\n" "# http://laserboy.org/\n\n" "# ASCII format version: " LASERBOY_TXT_VERSION "\n" << ENDL; return; } //############################################################################ bool get_dxf_pair(std::ifstream& in, int& group_code, string& entity_string) { char line[256]; in >> group_code; if(group_code != -1) { while(isspace(in.peek())) in.get(); // eat the '\r''\n' in.getline(line, 255); entity_string = line; int i = entity_string.size() - 1; while(!isgraph(entity_string[i])) i--; entity_string = entity_string.substr(0, i + 1); } return (group_code != 0 && in.good()); } //############################################################################ bool get_dxf_pair(std::ifstream& in, int& group_code, char entity_string[256]) { in >> group_code; if(group_code != -1) { while(isspace(in.peek())) in.get(); // eat the '\r''\n' in.getline(entity_string, 255); } return (group_code != 0 && in.good()); } //############################################################################ bool clear_to_alpha(std::ifstream& in, int& line_number) { u_int next_char = '\0'; while(in.good()) { next_char = in.peek(); if(!isalpha(next_char)) { in.get(); // eat it! if(next_char == '\n') // end of the line! { line_number++; } if(next_char == '#') // comment { in.ignore(99999, '\n'); line_number++; } } else // next_char is alpha break; } return in.good(); } //############################################################################ bool clear_to_digit(std::ifstream& in, int& line_number) { u_int next_char = '\0'; while(in.good()) { next_char = in.peek(); if( !isdigit(next_char) && next_char != '.' && next_char != '-' && next_char != '+' ) { in.get(); // eat it! if(next_char == '\n') // end of the line! { line_number++; } if(next_char == '#') // comment { in.ignore(99999, '\n'); line_number++; } } else // next_char is digit '.' '+' or '-' break; } return in.good(); } //############################################################################ bool clear_to_token(std::ifstream& in, int& line_number) { while(in.good()) { int next_char = in.peek(); if( !isalnum(next_char) && next_char != '.' && next_char != '-' && next_char != '+' ) { in.get(); // eat it! if(next_char == '\n') // end of the line! line_number++; if(next_char == '#') // comment { in.ignore(99999, '\n'); line_number++; } } else // next_char is alpha, digit '.' '+' or '-' break; } return in.good(); } //############################################################################ bool clear_to_token(std::ifstream& in, int& next_char, int& line_number) { while(in.good()) { next_char = in.peek(); if( !isalnum(next_char) && next_char != '.' && next_char != '-' && next_char != '+' ) { in.get(); // eat it! if(next_char == '\n') // end of the line! line_number++; if(next_char == '#') // comment { in.ignore(99999, '\n'); line_number++; } } else // next_char is alpha, digit '.' '+' or '-' break; } return in.good(); } //############################################################################ bool clear_through_string(std::ifstream& in, const string& token, int& line_number) { string word; while(in.good() && word.substr(0, token.size()) != token) get_next_token(in, word, line_number); return in.good(); } //############################################################################ bool get_next_token(std::ifstream& in, string& word, int& line_number) { int next_char = '\0'; while(in.good()) { next_char = in.peek(); if(!isgraph(next_char)) { if(next_char == '\n') // end of the line! line_number++; in.get(); // eat it! } else // next_char isgraph break; } in >> word; return in.good(); } //############################################################################ bool get_next_word(std::ifstream& in, string& word, int& line_number) { u_int next_char = '\0'; //------------------------------------------------------------------------ while(in.good()) { next_char = in.peek(); if(isspace(next_char)) { if(next_char == '\n') // end of the line! { in.get(); // eat it! line_number++; return false; } in.get(); // eat it! } else // it is not a white space character break; } //------------------------------------------------------------------------ if( isalpha(next_char) || next_char == '.' || next_char == '+' || next_char == '-' || next_char == '_' || next_char == '<' ) { in >> word; return true; } return false; } //############################################################################ bool get_next_number(std::ifstream& in, double& number, int& line_number) { bool negate = false; u_int next_char = '\0'; char* nada = {0}; string numstr; //------------------------------------------------------------------------ while(in.good()) { next_char = in.peek(); if(isspace(next_char)) { if(next_char == '\n') // end of the line! { in.get(); // eat it! line_number++; return false; } in.get(); // eat it! } else // it is not a white space character break; } //------------------------------------------------------------------------ if(next_char == '-') { in.get(); // eat it! negate = true; next_char = in.peek(); } //------------------------------------------------------------------------ if( isdigit(next_char) || next_char == '+' || next_char == '.' ) { in >> numstr; number = strtod(numstr.c_str(), &nada); if(negate) number = -number; return true; } //------------------------------------------------------------------------ else if(isalpha(next_char)) { in >> numstr; if (numstr == "pi") number = pi; else if(numstr == "two_pi") number = two_pi; else if(numstr == "half_pi") number = half_pi; else if(numstr == "quarter_pi") number = quarter_pi; else if(numstr == "three_quarters_pi") number = three_quarters_pi; else if(numstr == "pi_and_a_half") number = pi_and_a_half; else if(numstr == "e") number = _e_; else if(numstr == "one_third") number = 1.0 / 3.0; else if(numstr == "two_thirds") number = 2.0 / 3.0; else if(numstr == "true") number = 1.0; else if(numstr == "yes") number = 1.0; else if(numstr == "on") number = 1.0; else if(numstr == "false") number = 0.0; else if(numstr == "no") number = 0.0; else if(numstr == "off") number = 0.0; else return false; if(negate) number = -number; return true; } //------------------------------------------------------------------------ return false; } //############################################################################ bool get_next_hex(std::ifstream& in, double& number, int& line_number) { u_int next_char = '\0'; while(in.good()) { next_char = in.peek(); if(isspace(next_char)) { if(next_char == '\n') // end of the line! { in.get(); // eat it! line_number++; return false; } in.get(); // eat it! } else // it is not a white space character break; } //------------------------------------------------------------------------ if( isxdigit(next_char) || next_char == '+' || next_char == '-' ) { string token, chopped; char** junk = NULL; in >> token; if(token == "-1") { number = -1; return true; } chopped = token; if( token.substr(0, 2) == "0x" || token.substr(0, 2) == "0X" ) { chopped = token.substr(2); } for(size_t i = 0; i < chopped.size(); i++) if(!isxdigit(chopped[i])) return false; number = (int)(strtol(chopped.c_str(), junk, 16)); return true; } //------------------------------------------------------------------------ return false; } //############################################################################ bool hex_string(const string& token, double& number) { string chopped = token; char** junk = NULL; if(token == "-1") { number = -1; return true; } if( token.substr(0, 2) == "0x" || token.substr(0, 2) == "0X" ) { chopped = token.substr(2); } for(size_t i = 0; i < chopped.size(); i++) if(!isxdigit(chopped[i])) return false; number = (int)(strtol(chopped.c_str(), junk, 16)); return true; } //############################################################################ string as_hex_string(const char32_t& utf32) { std::stringstream ss; ss << setfill('0') << setw(8) << std::hex << utf32; return ss.str(); } //############################################################################ bool get_next_line(std::ifstream& in, string& line, int& line_number) { getline(in, line); line_number++; return in.good(); } //############################################################################ bool get_next_visible_line(std::ifstream& in, string& line, int& line_number) { u_int next_char = '\0'; //------------------------------------------------------------------------ while(in.good()) { next_char = in.peek(); if(isspace(next_char)) { if(next_char == '\n') // end of the line! line_number++; in.get(); // eat it! } else // it is not a white space character break; } getline(in, line); line_number++; return in.good(); } //############################################################################ char* char_utf32_to_utf8(const char32_t& utf32, const char* buffer) { char* end = const_cast(buffer); if(utf32 < 0x7F) *(end++) = static_cast(utf32); else if(utf32 < 0x7FF) { *(end++) = 0b1100'0000 + static_cast(utf32 >> 6); *(end++) = 0b1000'0000 + static_cast(utf32 & 0b0011'1111); } else if(utf32 < 0x10000) { *(end++) = 0b1110'0000 + static_cast( utf32 >> 12); *(end++) = 0b1000'0000 + static_cast((utf32 >> 6 ) & 0b0011'1111); *(end++) = 0b1000'0000 + static_cast( utf32 & 0b0011'1111); } else if(utf32 < 0x110000) { *(end++) = 0b1111'0000 + static_cast( utf32 >> 18); *(end++) = 0b1000'0000 + static_cast((utf32 >> 12) & 0b0011'1111); *(end++) = 0b1000'0000 + static_cast((utf32 >> 6 ) & 0b0011'1111); *(end++) = 0b1000'0000 + static_cast( utf32 & 0b0011'1111); } *end = '\0'; return end; } //############################################################################ bool is_orientation(const char32_t& utf32) { switch(utf32) { case 0x00000001: return true; case 0x00000002: return true; case 0x00000003: return true; default: return false; } return false; } //############################################################################ bool is_super_diacritic(const char32_t& utf32) { switch(utf32) { case 0x000002c6: case 0x000002c7: case 0x000002c9: case 0x000002d8: case 0x000002d9: case 0x000002da: case 0x000002dc: case 0x000002dd: case 0x00000300: case 0x00000301: case 0x00000302: case 0x00000303: case 0x00000304: case 0x00000305: case 0x00000306: case 0x00000307: case 0x00000308: case 0x00000309: case 0x0000030a: case 0x0000030b: case 0x0000030c: case 0x0000030d: case 0x0000030e: case 0x0000030f: case 0x00000310: case 0x00000311: case 0x00000313: case 0x00000314: case 0x00000315: case 0x0000033d: case 0x0000033e: case 0x00000343: case 0x0000034a: case 0x0000034b: case 0x0000034c: case 0x00000352: case 0x0000035b: case 0x00000385: return true; default: return false; } return false; } //############################################################################ bool is_sub_diacritic(const char32_t& utf32) { switch(utf32) { case 0x000000b8: case 0x000002db: case 0x00000316: case 0x00000317: case 0x00000318: case 0x00000319: case 0x0000031c: case 0x0000031d: case 0x0000031e: case 0x0000031f: case 0x00000320: case 0x00000323: case 0x00000324: case 0x00000325: case 0x00000326: case 0x00000327: case 0x00000328: case 0x00000329: case 0x0000032a: case 0x0000032b: case 0x0000032c: case 0x0000032d: case 0x0000032e: case 0x0000032f: case 0x00000330: case 0x00000331: case 0x00000339: case 0x0000033a: case 0x0000033b: case 0x0000033c: case 0x00000345: case 0x00000347: case 0x00000348: case 0x00000349: case 0x00000353: case 0x00000354: case 0x00000355: case 0x00000356: case 0x00000359: case 0x0000035a: return true; default: return false; } return false; } //############################################################################ bool is_diacritic(const char32_t& utf32) { return is_super_diacritic(utf32) || is_sub_diacritic(utf32); } //############################################################################ bool get_utf8_index(u32string& characters, const string &font_name) { wstring_convert, char32_t> conv_utf8_utf32; string word; u32string unicode; std::ifstream in(font_name, ios::in); // not binary! //------------------------------------------------------------------------ while(in.good()) { getline(in, word); unicode = conv_utf8_utf32.from_bytes(word); characters.clear(); for(size_t i = 0; i < unicode.size(); i++) if(unicode.at(i) > 0x000020) characters += unicode[i]; in.close(); return true; } //------------------------------------------------------------------------ in.close(); return false; } //############################################################################ string dots_setting_id_to_name(const int& id) { switch(id) { case LASERBOY_DOTS_IGNORE: return "ignore dots"; break; //---------------------------------------------------------------- case LASERBOY_DOTS_REMOVE: return "remove dots"; break; //---------------------------------------------------------------- case LASERBOY_DOTS_ENHANCE: return "enhance dots"; break; //---------------------------------------------------------------- } return ""; } //############################################################################ string wav_LSB_tag_to_name(const u_short& LSB_tag) { switch(LSB_tag) { default: case LASERBOY_LSB_NOT_USED: return " "; break; //---------------------------------------------------------------- case LASERBOY_LSB_BLANKING: return "BLANKING "; break; //---------------------------------------------------------------- case LASERBOY_LSB_END_OF_FRAME: return "END OF FRAME"; break; //---------------------------------------------------------------- case LASERBOY_LSB_UNIQUE_FRAME: return "UNIQUE FRAME"; break; //---------------------------------------------------------------- case LASERBOY_LSB_UNIQUE_VERTEX: return "UNIQUE VERTX"; break; //---------------------------------------------------------------- } return ""; } //############################################################################ string wav_signal_id_to_name(const short& signal_id) { switch((int)abs(signal_id)) // sign indicates polarity of channel data { default: case LASERBOY_NO_SIGNAL: return "NO SIGNAL "; //---------------------------------------------------------------- case LASERBOY_SIGNAL_UNDEFINED: return "UNDEF SIGNAL"; //---------------------------------------------------------------- case LASERBOY_SIGNAL_X_POSITION: return "X POSITION "; //---------------------------------------------------------------- case LASERBOY_SIGNAL_Y_POSITION: return "Y POSITION "; //---------------------------------------------------------------- case LASERBOY_SIGNAL_Z_POSITION: return "Z POSITION "; //---------------------------------------------------------------- case LASERBOY_SIGNAL_RED_ANALOG: return "RED ANALOG"; //---------------------------------------------------------------- case LASERBOY_SIGNAL_GREEN_ANALOG: return "GREEN ANALOG"; //---------------------------------------------------------------- case LASERBOY_SIGNAL_BLUE_ANALOG: return "BLUE ANALOG"; //---------------------------------------------------------------- case LASERBOY_SIGNAL_MONO_TTL: return "MONO TTL "; //---------------------------------------------------------------- case LASERBOY_SIGNAL_MONO_AVG_ANALOG: return "MONO ANL AVG"; //---------------------------------------------------------------- case LASERBOY_SIGNAL_MONO_OR_ANALOG: return "MONO ANLG OR"; //---------------------------------------------------------------- case LASERBOY_SIGNAL_MONO_WEIGHTED_ANALOG: return "MONO ANL WTD"; //---------------------------------------------------------------- case LASERBOY_SIGNAL_MONO_O_SCOPE: return "MONO O-SCOPE"; //---------------------------------------------------------------- } return ""; } //############################################################################ int LaserBoy_version_check(string& version_string, string install_GUID, u_int app_runs_count) { using boost::asio::ip::tcp; try { boost::asio::io_context io_context; tcp::resolver resolver(io_context); auto endpoints = resolver.resolve("laserboy.org", "http"); tcp::socket socket(io_context); boost::asio::connect(socket, endpoints); boost::asio::streambuf request; ostream request_stream(&request); request_stream << "POST /cgi-bin/laserboy_version?" << LASERBOY_VERSION << '+' << install_GUID << '+' << app_runs_count << " HTTP/1.0\r\n"; //---------------------------------------------------------------- request_stream << "Host: laserboy.org\r\n"; request_stream << "Accept: */*\r\n"; request_stream << "Connection: close\r\n\r\n"; //---------------------------------------------------------------- boost::asio::write(socket, request); boost::asio::streambuf response; boost::asio::read_until(socket, response, "\r\n"); std::istream response_stream(&response); std::string http_version; response_stream >> http_version; u_int status_code; response_stream >> status_code; std::string status_message; std::getline(response_stream, status_message); if(!response_stream || http_version.substr(0, 5) != "HTTP/") return 1; if(status_code != 200) return 1; boost::asio::read_until(socket, response, "\r\n\r\n"); std::string header; while(std::getline(response_stream, header) && header != "\r") {} std::ostringstream ostringstream_buffer; string version_string_buffer; if(response.size() > 0) { ostringstream_buffer << &response; version_string_buffer = ostringstream_buffer.str(); } for(size_t i = 0; i < version_string_buffer.size(); i++) if(!strchr(" \t\r\n\0", version_string_buffer.at(i))) version_string += version_string_buffer.at(i); boost::system::error_code error; while(boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error)) cout << &response; if(error != boost::asio::error::eof) throw boost::system::system_error(error); } catch(std::exception& e) { return 1; } return 0; } //############################################################################ ////////////////////////////////////////////////////////////////////////////// //############################################################################