<commit_before>/*
  Copyright 2019 Alain Dargelas

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*
 * File:   Cache.cpp
 * Author: alain
 *
 * Created on April 28, 2017, 9:32 PM
 */

#include <Surelog/Cache/Cache.h>
#include <Surelog/CommandLine/CommandLineParser.h>
#include <Surelog/Design/FileContent.h>
#include <Surelog/ErrorReporting/ErrorContainer.h>
#include <Surelog/SourceCompile/SymbolTable.h>
#include <flatbuffers/util.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <ctime>
#include <iostream>

namespace SURELOG {
namespace fs = std::filesystem;

const std::string& Cache::getExecutableTimeStamp() {
  static const std::string sExecTstamp(__DATE__ "-" __TIME__);
  return sExecTstamp;
}

time_t Cache::get_mtime(const fs::path& path) {
  std::string cpath = path.string();
  struct stat statbuf;
  if (stat(cpath.c_str(), &statbuf) == -1) {
    return -1;
  }
  return statbuf.st_mtime;
}

uint8_t* Cache::openFlatBuffers(const fs::path& cacheFileName) {
  const std::string filename = cacheFileName.string();
  FILE* file = fopen(filename.c_str(), "rb");
  if (file == nullptr) return nullptr;
  fseek(file, 0L, SEEK_END);
  unsigned int length = ftell(file);
  fseek(file, 0L, SEEK_SET);
  char* data = new char[length];
  size_t l = fread(data, sizeof(char), length, file);
  fclose(file);
  if (length != l) {
    delete[] data;
    return nullptr;
  }
  uint8_t* buffer_pointer = (uint8_t*)data;
  return buffer_pointer;
}

bool Cache::checkIfCacheIsValid(const SURELOG::CACHE::Header* header,
                                std::string_view schemaVersion,
                                const fs::path& cacheFileName) {
  /* Schema version */
  if (schemaVersion != header->flb_version()->c_str()) {
    return false;
  }

  /* Tool version */
  if (CommandLineParser::getVersionNumber() != header->sl_version()->c_str()) {
    return false;
  }

  /* Timestamp Tool that created Cache vs tool date */
  std::string execDate = getExecutableTimeStamp();
  if (execDate != header->sl_date_compiled()->c_str()) {
    return false;
  }

  /* Timestamp Cache vs Orig File */
  if (!cacheFileName.empty()) {
    time_t ct = get_mtime(cacheFileName);
    std::string fileName = header->file()->c_str();
    time_t ft = get_mtime(fileName.c_str());
    if (ft == -1) {
      return false;
    }
    if (ct == -1) {
      return false;
    }
    if (ct < ft) {
      return false;
    }
  }
  return true;
}

flatbuffers::Offset<SURELOG::CACHE::Header> Cache::createHeader(
    flatbuffers::FlatBufferBuilder& builder, std::string_view schemaVersion,
    const fs::path& origFileName) {
  auto fName = builder.CreateString(origFileName.string());
  auto sl_version = builder.CreateString(CommandLineParser::getVersionNumber());
  auto sl_build_date = builder.CreateString(getExecutableTimeStamp());
  auto sl_flb_version = builder.CreateString(schemaVersion);
  std::time_t t_result = std::time(nullptr);
  auto file_creation_date = builder.CreateString(std::to_string(t_result));
  auto header = CACHE::CreateHeader(builder, sl_version, sl_flb_version,
                                    sl_build_date, file_creation_date, fName);
  return header;
}

bool Cache::saveFlatbuffers(flatbuffers::FlatBufferBuilder& builder,
                            const fs::path& cacheFileName) {
  const std::string filename = cacheFileName.string();
  const unsigned char* buf = builder.GetBufferPointer();
  int size = builder.GetSize();
  bool status = flatbuffers::SaveFile(filename.c_str(), (char*)buf, size, true);
  return status;
}

std::pair<flatbuffers::Offset<Cache::VectorOffsetError>,
          flatbuffers::Offset<Cache::VectorOffsetString>>
Cache::cacheErrors(flatbuffers::FlatBufferBuilder& builder,
                   SymbolTable& canonicalSymbols,
                   ErrorContainer* errorContainer, SymbolTable* symbols,
                   SymbolId subjectId) {
  const std::vector<Error>& errors = errorContainer->getErrors();
  std::vector<flatbuffers::Offset<SURELOG::CACHE::Error>> error_vec;
  for (const Error& error : errors) {
    const std::vector<Location>& locs = error.getLocations();
    if (!locs.empty()) {
      bool matchSubject = false;
      for (const Location& loc : locs) {
        if (loc.m_fileId == subjectId) {
          matchSubject = true;
          break;
        }
      }
      if (matchSubject) {
        std::vector<flatbuffers::Offset<SURELOG::CACHE::Location>> location_vec;
        for (const Location& loc : locs) {
          SymbolId canonicalFileId =
              canonicalSymbols.registerSymbol(symbols->getSymbol(loc.m_fileId));
          SymbolId canonicalObjectId =
              canonicalSymbols.registerSymbol(symbols->getSymbol(loc.m_object));
          auto locflb =
              CACHE::CreateLocation(builder, canonicalFileId, loc.m_line,
                                    loc.m_column, canonicalObjectId);
          location_vec.push_back(locflb);
        }
        auto locvec = builder.CreateVector(location_vec);
        auto err = CACHE::CreateError(builder, locvec, error.getType());
        error_vec.push_back(err);
      }
    }
  }

  /* Cache all the symbols */
  for (const auto& s : symbols->getSymbols()) {
    canonicalSymbols.registerSymbol(s);
  }

  auto symbolVec = builder.CreateVectorOfStrings(canonicalSymbols.getSymbols());
  auto errvec = builder.CreateVector(error_vec);
  return std::make_pair(errvec, symbolVec);
}

void Cache::restoreErrors(const VectorOffsetError* errorsBuf,
                          const VectorOffsetString* symbolsBuf,
                          SymbolTable& canonicalSymbols,
                          ErrorContainer* errorContainer,
                          SymbolTable* symbols) {
  for (unsigned int i = 0; i < symbolsBuf->size(); i++) {
    const std::string symbol = symbolsBuf->Get(i)->c_str();
    canonicalSymbols.registerSymbol(symbol);
  }
  for (unsigned int i = 0; i < errorsBuf->size(); i++) {
    auto errorFlb = errorsBuf->Get(i);
    std::vector<Location> locs;
    for (unsigned int j = 0; j < errorFlb->locations()->size(); j++) {
      auto locFlb = errorFlb->locations()->Get(j);
      SymbolId translFileId = symbols->registerSymbol(
          canonicalSymbols.getSymbol(locFlb->file_id()));
      SymbolId translObjectId =
          symbols->registerSymbol(canonicalSymbols.getSymbol(locFlb->object()));
      Location loc(translFileId, locFlb->line(), locFlb->column(),
                   translObjectId);
      locs.push_back(loc);
    }
    Error err((ErrorDefinition::ErrorType)errorFlb->error_id(), locs);
    errorContainer->addError(err, false);
  }
}

std::vector<CACHE::VObject> Cache::cacheVObjects(FileContent* fcontent,
                                                 SymbolTable& canonicalSymbols,
                                                 SymbolTable& fileTable,
                                                 SymbolId fileId) {
  /* Cache the design objects */
  // std::vector<flatbuffers::Offset<PARSECACHE::VObject>> object_vec;
  std::vector<CACHE::VObject> object_vec;
  if (!fcontent) return object_vec;
  if (fcontent->getVObjects().size() > Capacity) {
    std::cout << "INTERNAL ERROR: Cache is saturated, Use -nocache option\n";
    return object_vec;
  }
  for (const VObject& object : fcontent->getVObjects()) {
    // Lets compress this struct into 20 and 16 bits fields:
    //  object_vec.push_back(PARSECACHE::CreateVObject(builder,
    //                                              canonicalSymbols.getId(m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol(object.m_name)),
    //                                              object.m_uniqueId,
    //                                              object.m_type,
    //                                              object.m_column,
    //                                              object.m_line,
    //                                              object.m_parent,
    //                                               object.m_definition,
    //                                               object.m_child,
    //                                               object.m_sibling));

    uint64_t field1 = 0;
    uint64_t field2 = 0;
    uint64_t field3 = 0;
    uint64_t field4 = 0;
    SymbolId name = canonicalSymbols.getId(fileTable.getSymbol(object.m_name));
    // clang-format off
    field1 |= 0x0000000000FFFFFF & (name);
    field1 |= 0x0000000FFF000000 & (((uint64_t)object.m_type)      << (24));
    field1 |= 0x0000FFF000000000 & (((uint64_t)object.m_column)    << (24 + 12));
    field1 |= 0xFFFF000000000000 & (((uint64_t)object.m_parent     << (24 + 12 + 12)));
    field2 |= 0x0000000000000FFF & (object.m_parent                >> (16));
    field2 |= 0x000000FFFFFFF000 & (((uint64_t)object.m_definition) << (12));
    field2 |= 0xFFFFFF0000000000 & (((uint64_t)object.m_child)     << (12 + 28));
    field3 |= 0x000000000000000F & (((uint64_t)object.m_child)     >> (24));
    field3 |= 0x00000000FFFFFFF0 & (object.m_sibling               << (4));
    field3 |= 0x00FFFFFF00000000 & (((uint64_t)object.m_fileId)    << (4 + 28));
    field3 |= 0xFF00000000000000 & (((uint64_t)object.m_line)      << (4 + 28 + 24));
    field4 |= 0x000000000000FFFF & (((uint64_t)object.m_line)      >> (8));
    field4 |= 0x000000FFFFFF0000 & (((uint64_t)object.m_endLine)   << (16));
    field4 |= 0x000FFF0000000000 & (((uint64_t)object.m_endColumn) << (16 + 24));
    // clang-format on

    object_vec.emplace_back(field1, field2, field3, field4);
  }
  // std::cout << "SAVE: " << cacheFileName << " "
  //          << fileTable.getSymbol(fileId)
  //          << " NB: " <<   fcontent->getVObjects().size()
  //         << std::endl;

  return object_vec;
}

void Cache::restoreVObjects(
    const flatbuffers::Vector<const SURELOG::CACHE::VObject*>* objects,
    SymbolTable& canonicalSymbols, SymbolTable& fileTable, SymbolId fileId,
    FileContent* fileContent) {
  /* Restore design objects */
  for (unsigned int i = 0; i < objects->size(); i++) {
    auto objectc = objects->Get(i);

    // VObject object
    // (m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol(canonicalSymbols.getSymbol(objectc->m_name())),
    //                (VObjectType) objectc->m_type(), objectc->m_uniqueId(),
    //                objectc->m_column(), objectc->m_line(),
    //                objectc->m_parent(), objectc->m_definition(),
    //               objectc->m_child(),  objectc->m_sibling());

    uint64_t field1 = objectc->field1();
    uint64_t field2 = objectc->field2();
    uint64_t field3 = objectc->field3();
    uint64_t field4 = objectc->field4();
    // Decode compression done when saving cache (see below)
    // clang-format off
    SymbolId name =            (field1 & 0x0000000000FFFFFF);
    unsigned short type =      (field1 & 0x0000000FFF000000) >> (24);
    unsigned short column =    (field1 & 0x0000FFF000000000) >> (24 + 12);
    NodeId parent         =    (field1 & 0xFFFF000000000000) >> (24 + 12 + 12);
    parent |=                  (field2 & 0x0000000000000FFF) << (16);
    NodeId definition =        (field2 & 0x000000FFFFFFF000) >> (12);
    NodeId child =             (field2 & 0xFFFFFF0000000000) >> (12 + 28);
    child  |=                  (field3 & 0x000000000000000F) << (24);
    NodeId sibling =           (field3 & 0x00000000FFFFFFF0) >> (4);
    SymbolId fileId =          (field3 & 0x00FFFFFF00000000) >> (4 + 28);
    unsigned int line =        (field3 & 0xFF00000000000000) >> (4 + 28 + 24);
    line |=                    (field4 & 0x000000000000FFFF) << (8);
    unsigned int endLine =     (field4 & 0x000000FFFFFF0000) >> (16);
    unsigned short endColumn = (field4 & 0x000FFF0000000000) >> (16 + 24);
    // clang-format on

    fileContent->getVObjects().emplace_back(
        fileTable.registerSymbol(canonicalSymbols.getSymbol(name)),
        fileTable.registerSymbol(canonicalSymbols.getSymbol(fileId)),
        (VObjectType)type, line, column, endLine, endColumn, parent, definition,
        child, sibling);
  }
}
}  // namespace SURELOG
<commit_msg>Atomically write cache in its entirety or not at all.<commit_after>/*
  Copyright 2019 Alain Dargelas

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/*
 * File:   Cache.cpp
 * Author: alain
 *
 * Created on April 28, 2017, 9:32 PM
 */

#include <Surelog/Cache/Cache.h>
#include <Surelog/CommandLine/CommandLineParser.h>
#include <Surelog/Design/FileContent.h>
#include <Surelog/ErrorReporting/ErrorContainer.h>
#include <Surelog/SourceCompile/SymbolTable.h>
#include <flatbuffers/util.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <ctime>
#include <iostream>

namespace SURELOG {
namespace fs = std::filesystem;

const std::string& Cache::getExecutableTimeStamp() {
  static const std::string sExecTstamp(__DATE__ "-" __TIME__);
  return sExecTstamp;
}

time_t Cache::get_mtime(const fs::path& path) {
  std::string cpath = path.string();
  struct stat statbuf;
  if (stat(cpath.c_str(), &statbuf) == -1) {
    return -1;
  }
  return statbuf.st_mtime;
}

uint8_t* Cache::openFlatBuffers(const fs::path& cacheFileName) {
  const std::string filename = cacheFileName.string();
  FILE* file = fopen(filename.c_str(), "rb");
  if (file == nullptr) return nullptr;
  fseek(file, 0L, SEEK_END);
  unsigned int length = ftell(file);
  fseek(file, 0L, SEEK_SET);
  char* data = new char[length];
  size_t l = fread(data, sizeof(char), length, file);
  fclose(file);
  if (length != l) {
    delete[] data;
    return nullptr;
  }
  uint8_t* buffer_pointer = (uint8_t*)data;
  return buffer_pointer;
}

bool Cache::checkIfCacheIsValid(const SURELOG::CACHE::Header* header,
                                std::string_view schemaVersion,
                                const fs::path& cacheFileName) {
  /* Schema version */
  if (schemaVersion != header->flb_version()->c_str()) {
    return false;
  }

  /* Tool version */
  if (CommandLineParser::getVersionNumber() != header->sl_version()->c_str()) {
    return false;
  }

  /* Timestamp Tool that created Cache vs tool date */
  std::string execDate = getExecutableTimeStamp();
  if (execDate != header->sl_date_compiled()->c_str()) {
    return false;
  }

  /* Timestamp Cache vs Orig File */
  if (!cacheFileName.empty()) {
    time_t ct = get_mtime(cacheFileName);
    std::string fileName = header->file()->c_str();
    time_t ft = get_mtime(fileName.c_str());
    if (ft == -1) {
      return false;
    }
    if (ct == -1) {
      return false;
    }
    if (ct < ft) {
      return false;
    }
  }
  return true;
}

flatbuffers::Offset<SURELOG::CACHE::Header> Cache::createHeader(
    flatbuffers::FlatBufferBuilder& builder, std::string_view schemaVersion,
    const fs::path& origFileName) {
  auto fName = builder.CreateString(origFileName.string());
  auto sl_version = builder.CreateString(CommandLineParser::getVersionNumber());
  auto sl_build_date = builder.CreateString(getExecutableTimeStamp());
  auto sl_flb_version = builder.CreateString(schemaVersion);
  std::time_t t_result = std::time(nullptr);
  auto file_creation_date = builder.CreateString(std::to_string(t_result));
  auto header = CACHE::CreateHeader(builder, sl_version, sl_flb_version,
                                    sl_build_date, file_creation_date, fName);
  return header;
}

bool Cache::saveFlatbuffers(flatbuffers::FlatBufferBuilder& builder,
                            const fs::path& cacheFileName) {
  const std::string tmp_name = cacheFileName.string() + ".tmp";
  const unsigned char* buf = builder.GetBufferPointer();
  const int size = builder.GetSize();
  bool success =
      flatbuffers::SaveFile(tmp_name.c_str(), (const char*)buf, size, true);
  if (success) {
    std::filesystem::rename(tmp_name, cacheFileName);
  } else {
    std::filesystem::remove(tmp_name);
  }
  return success;
}

std::pair<flatbuffers::Offset<Cache::VectorOffsetError>,
          flatbuffers::Offset<Cache::VectorOffsetString>>
Cache::cacheErrors(flatbuffers::FlatBufferBuilder& builder,
                   SymbolTable& canonicalSymbols,
                   ErrorContainer* errorContainer, SymbolTable* symbols,
                   SymbolId subjectId) {
  const std::vector<Error>& errors = errorContainer->getErrors();
  std::vector<flatbuffers::Offset<SURELOG::CACHE::Error>> error_vec;
  for (const Error& error : errors) {
    const std::vector<Location>& locs = error.getLocations();
    if (!locs.empty()) {
      bool matchSubject = false;
      for (const Location& loc : locs) {
        if (loc.m_fileId == subjectId) {
          matchSubject = true;
          break;
        }
      }
      if (matchSubject) {
        std::vector<flatbuffers::Offset<SURELOG::CACHE::Location>> location_vec;
        for (const Location& loc : locs) {
          SymbolId canonicalFileId =
              canonicalSymbols.registerSymbol(symbols->getSymbol(loc.m_fileId));
          SymbolId canonicalObjectId =
              canonicalSymbols.registerSymbol(symbols->getSymbol(loc.m_object));
          auto locflb =
              CACHE::CreateLocation(builder, canonicalFileId, loc.m_line,
                                    loc.m_column, canonicalObjectId);
          location_vec.push_back(locflb);
        }
        auto locvec = builder.CreateVector(location_vec);
        auto err = CACHE::CreateError(builder, locvec, error.getType());
        error_vec.push_back(err);
      }
    }
  }

  /* Cache all the symbols */
  for (const auto& s : symbols->getSymbols()) {
    canonicalSymbols.registerSymbol(s);
  }

  auto symbolVec = builder.CreateVectorOfStrings(canonicalSymbols.getSymbols());
  auto errvec = builder.CreateVector(error_vec);
  return std::make_pair(errvec, symbolVec);
}

void Cache::restoreErrors(const VectorOffsetError* errorsBuf,
                          const VectorOffsetString* symbolsBuf,
                          SymbolTable& canonicalSymbols,
                          ErrorContainer* errorContainer,
                          SymbolTable* symbols) {
  for (unsigned int i = 0; i < symbolsBuf->size(); i++) {
    const std::string symbol = symbolsBuf->Get(i)->c_str();
    canonicalSymbols.registerSymbol(symbol);
  }
  for (unsigned int i = 0; i < errorsBuf->size(); i++) {
    auto errorFlb = errorsBuf->Get(i);
    std::vector<Location> locs;
    for (unsigned int j = 0; j < errorFlb->locations()->size(); j++) {
      auto locFlb = errorFlb->locations()->Get(j);
      SymbolId translFileId = symbols->registerSymbol(
          canonicalSymbols.getSymbol(locFlb->file_id()));
      SymbolId translObjectId =
          symbols->registerSymbol(canonicalSymbols.getSymbol(locFlb->object()));
      Location loc(translFileId, locFlb->line(), locFlb->column(),
                   translObjectId);
      locs.push_back(loc);
    }
    Error err((ErrorDefinition::ErrorType)errorFlb->error_id(), locs);
    errorContainer->addError(err, false);
  }
}

std::vector<CACHE::VObject> Cache::cacheVObjects(FileContent* fcontent,
                                                 SymbolTable& canonicalSymbols,
                                                 SymbolTable& fileTable,
                                                 SymbolId fileId) {
  /* Cache the design objects */
  // std::vector<flatbuffers::Offset<PARSECACHE::VObject>> object_vec;
  std::vector<CACHE::VObject> object_vec;
  if (!fcontent) return object_vec;
  if (fcontent->getVObjects().size() > Capacity) {
    std::cout << "INTERNAL ERROR: Cache is saturated, Use -nocache option\n";
    return object_vec;
  }
  for (const VObject& object : fcontent->getVObjects()) {
    // Lets compress this struct into 20 and 16 bits fields:
    //  object_vec.push_back(PARSECACHE::CreateVObject(builder,
    //                                              canonicalSymbols.getId(m_parse->getCompileSourceFile()->getSymbolTable()->getSymbol(object.m_name)),
    //                                              object.m_uniqueId,
    //                                              object.m_type,
    //                                              object.m_column,
    //                                              object.m_line,
    //                                              object.m_parent,
    //                                               object.m_definition,
    //                                               object.m_child,
    //                                               object.m_sibling));

    uint64_t field1 = 0;
    uint64_t field2 = 0;
    uint64_t field3 = 0;
    uint64_t field4 = 0;
    SymbolId name = canonicalSymbols.getId(fileTable.getSymbol(object.m_name));
    // clang-format off
    field1 |= 0x0000000000FFFFFF & (name);
    field1 |= 0x0000000FFF000000 & (((uint64_t)object.m_type)      << (24));
    field1 |= 0x0000FFF000000000 & (((uint64_t)object.m_column)    << (24 + 12));
    field1 |= 0xFFFF000000000000 & (((uint64_t)object.m_parent     << (24 + 12 + 12)));
    field2 |= 0x0000000000000FFF & (object.m_parent                >> (16));
    field2 |= 0x000000FFFFFFF000 & (((uint64_t)object.m_definition) << (12));
    field2 |= 0xFFFFFF0000000000 & (((uint64_t)object.m_child)     << (12 + 28));
    field3 |= 0x000000000000000F & (((uint64_t)object.m_child)     >> (24));
    field3 |= 0x00000000FFFFFFF0 & (object.m_sibling               << (4));
    field3 |= 0x00FFFFFF00000000 & (((uint64_t)object.m_fileId)    << (4 + 28));
    field3 |= 0xFF00000000000000 & (((uint64_t)object.m_line)      << (4 + 28 + 24));
    field4 |= 0x000000000000FFFF & (((uint64_t)object.m_line)      >> (8));
    field4 |= 0x000000FFFFFF0000 & (((uint64_t)object.m_endLine)   << (16));
    field4 |= 0x000FFF0000000000 & (((uint64_t)object.m_endColumn) << (16 + 24));
    // clang-format on

    object_vec.emplace_back(field1, field2, field3, field4);
  }
  // std::cout << "SAVE: " << cacheFileName << " "
  //          << fileTable.getSymbol(fileId)
  //          << " NB: " <<   fcontent->getVObjects().size()
  //         << std::endl;

  return object_vec;
}

void Cache::restoreVObjects(
    const flatbuffers::Vector<const SURELOG::CACHE::VObject*>* objects,
    SymbolTable& canonicalSymbols, SymbolTable& fileTable, SymbolId fileId,
    FileContent* fileContent) {
  /* Restore design objects */
  for (unsigned int i = 0; i < objects->size(); i++) {
    auto objectc = objects->Get(i);

    // VObject object
    // (m_parse->getCompileSourceFile()->getSymbolTable()->registerSymbol(canonicalSymbols.getSymbol(objectc->m_name())),
    //                (VObjectType) objectc->m_type(), objectc->m_uniqueId(),
    //                objectc->m_column(), objectc->m_line(),
    //                objectc->m_parent(), objectc->m_definition(),
    //               objectc->m_child(),  objectc->m_sibling());

    uint64_t field1 = objectc->field1();
    uint64_t field2 = objectc->field2();
    uint64_t field3 = objectc->field3();
    uint64_t field4 = objectc->field4();
    // Decode compression done when saving cache (see below)
    // clang-format off
    SymbolId name =            (field1 & 0x0000000000FFFFFF);
    unsigned short type =      (field1 & 0x0000000FFF000000) >> (24);
    unsigned short column =    (field1 & 0x0000FFF000000000) >> (24 + 12);
    NodeId parent         =    (field1 & 0xFFFF000000000000) >> (24 + 12 + 12);
    parent |=                  (field2 & 0x0000000000000FFF) << (16);
    NodeId definition =        (field2 & 0x000000FFFFFFF000) >> (12);
    NodeId child =             (field2 & 0xFFFFFF0000000000) >> (12 + 28);
    child  |=                  (field3 & 0x000000000000000F) << (24);
    NodeId sibling =           (field3 & 0x00000000FFFFFFF0) >> (4);
    SymbolId fileId =          (field3 & 0x00FFFFFF00000000) >> (4 + 28);
    unsigned int line =        (field3 & 0xFF00000000000000) >> (4 + 28 + 24);
    line |=                    (field4 & 0x000000000000FFFF) << (8);
    unsigned int endLine =     (field4 & 0x000000FFFFFF0000) >> (16);
    unsigned short endColumn = (field4 & 0x000FFF0000000000) >> (16 + 24);
    // clang-format on

    fileContent->getVObjects().emplace_back(
        fileTable.registerSymbol(canonicalSymbols.getSymbol(name)),
        fileTable.registerSymbol(canonicalSymbols.getSymbol(fileId)),
        (VObjectType)type, line, column, endLine, endColumn, parent, definition,
        child, sibling);
  }
}
}  // namespace SURELOG
<|endoftext|>


<commit_before>#include "glcore.hpp"
#include <GL/gl3w.h>

#include <string>

#include <Scene/scene.hpp>
#include <Utilities/exceptions.hpp>
#include <Utilities/log.hpp>

GLCore::GLCore(int width, int height, std::string scene) {

    m_display = std::make_unique<Display>(width, height);

    // Log information about current context
    Log::getLog() << "\nInformation: \n";
    Log::getLog() << "\tGL Version: " << glGetString(GL_VERSION) << '\n';
    Log::getLog() << "\tDisplay Address: " << m_display.get() << "\n\n";

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glDepthFunc(GL_LESS);
    glClearColor(0.0f, 0.1f, 0.0f, 0.0f);

    Log::getLog() << Log::OUT_LOG << "GL Context created" << Log::OUT_LOG_CONS;

    initScene(scene);
    m_scene->start();
}

GLCore::~GLCore() {
    closeScene();
}

void GLCore::displayFunc() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    m_scene->gameLoop();
    m_display->getInputController()->callKeyLambdas();
}

void GLCore::inputFunc(int key, bool state) {
    m_display->getInputController()->updateKey(key, state);
}

void GLCore::mouseFunc(double xpos, double ypos) {
    m_display->getInputController()->updateMousePosition(xpos, ypos);
}

void GLCore::initScene(std::string scene) {
    m_luaState = luaL_newstate();
    luaL_openlibs(m_luaState);
    m_scene = std::make_unique<Scene>(m_display.get(), m_luaState, scene);
}

void GLCore::closeScene() {
    m_scene.reset(nullptr);
    lua_close(m_luaState);
}
<commit_msg>small change to log<commit_after>#include "glcore.hpp"
#include <GL/gl3w.h>

#include <string>

#include <Scene/scene.hpp>
#include <Utilities/exceptions.hpp>
#include <Utilities/log.hpp>

GLCore::GLCore(int width, int height, std::string scene) {

    m_display = std::make_unique<Display>(width, height);

    // Log information about current context
    Log::getLog() << "\nInformation: \n";
    Log::getLog() << "\tGL Version: " << glGetString(GL_VERSION) << '\n';
    Log::getLog() << "\tDisplay Address: " << m_display.get() << "\n\n";

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glDepthFunc(GL_LESS);
    glClearColor(0.0f, 0.1f, 0.0f, 0.0f);

    Log::getLog() << Log::OUT_LOG << "GL Context created\n";
    Log::getLog() << Log::OUT_LOG_CONS;

    initScene(scene);
    m_scene->start();
}

GLCore::~GLCore() {
    closeScene();
}

void GLCore::displayFunc() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    m_scene->gameLoop();
    m_display->getInputController()->callKeyLambdas();
}

void GLCore::inputFunc(int key, bool state) {
    m_display->getInputController()->updateKey(key, state);
}

void GLCore::mouseFunc(double xpos, double ypos) {
    m_display->getInputController()->updateMousePosition(xpos, ypos);
}

void GLCore::initScene(std::string scene) {
    m_luaState = luaL_newstate();
    luaL_openlibs(m_luaState);
    m_scene = std::make_unique<Scene>(m_display.get(), m_luaState, scene);
}

void GLCore::closeScene() {
    m_scene.reset(nullptr);
    lua_close(m_luaState);
}
<|endoftext|>


<commit_before>// CuttingTool.cpp
/*
 * Copyright (c) 2009, Dan Heeks, Perttu Ahola
 * This program is released under the BSD license. See the file COPYING for
 * details.
 */

#include "stdafx.h"
#include "CuttingTool.h"
#include "CNCConfig.h"
#include "ProgramCanvas.h"
#include "interface/HeeksObj.h"
#include "interface/PropertyInt.h"
#include "interface/PropertyDouble.h"
#include "interface/PropertyLength.h"
#include "interface/PropertyChoice.h"
#include "interface/PropertyString.h"
#include "tinyxml/tinyxml.h"

#include <sstream>

extern CHeeksCADInterface* heeksCAD;

void CCuttingToolParams::set_initial_values()
{
	CNCConfig config;
	config.Read(_T("m_diameter"), &m_diameter, 12.7);
	config.Read(_T("m_x_offset"), &m_x_offset, 0);
	config.Read(_T("m_tool_length_offset"), &m_tool_length_offset, 0);
	config.Read(_T("m_orientation"), &m_orientation, 9);
}

void CCuttingToolParams::write_values_to_config()
{
	CNCConfig config;

	// We ALWAYS write the parameters into the configuration file in mm (for consistency).
	// If we're now in inches then convert the values.
	// We're in mm already.
	config.Write(_T("m_diameter"), m_diameter);
	config.Write(_T("m_x_offset"), m_x_offset);
	config.Write(_T("m_tool_length_offset"), m_tool_length_offset);
	config.Write(_T("m_orientation"), m_orientation);
}

static void on_set_diameter(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_diameter = value;}
static void on_set_x_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_x_offset = value;}
static void on_set_tool_length_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_tool_length_offset = value;}
static void on_set_orientation(int value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_orientation = value;}

void CCuttingToolParams::GetProperties(CCuttingTool* parent, std::list<Property *> *list)
{
	list->push_back(new PropertyLength(_("diameter"), m_diameter, parent, on_set_diameter));
	list->push_back(new PropertyLength(_("x_offset"), m_x_offset, parent, on_set_x_offset));
	list->push_back(new PropertyLength(_("tool_length_offset"), m_x_offset, parent, on_set_tool_length_offset));
	list->push_back(new PropertyInt(_("orientation"), m_orientation, parent, on_set_orientation));
}

void CCuttingToolParams::WriteXMLAttributes(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "params" );
	root->LinkEndChild( element );

	element->SetDoubleAttribute("diameter", m_diameter);
	element->SetDoubleAttribute("x_offset", m_x_offset);
	element->SetDoubleAttribute("tool_length_offset", m_tool_length_offset);

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_orientation;
	element->SetAttribute("orientation", l_ossValue.str().c_str() );
}

void CCuttingToolParams::ReadParametersFromXMLElement(TiXmlElement* pElem)
{
	if (pElem->Attribute("diameter")) m_diameter = atof(pElem->Attribute("diameter"));
	if (pElem->Attribute("x_offset")) m_x_offset = atof(pElem->Attribute("x_offset"));
	if (pElem->Attribute("tool_length_offset")) m_tool_length_offset = atof(pElem->Attribute("tool_length_offset"));
	if (pElem->Attribute("orientation")) m_orientation = atoi(pElem->Attribute("orientation"));
}

/**
	This method is called when the CAD operator presses the Python button.  This method generates
	Python source code whose job will be to generate RS-274 GCode.  It's done in two steps so that
	the Python code can be configured to generate GCode suitable for various CNC interpreters.
 */
void CCuttingTool::AppendTextToProgram()
{

#ifdef UNICODE
	std::wostringstream ss;
#else
    std::ostringstream ss;
#endif
    ss.imbue(std::locale("C"));

	// The G10 command can be used (within EMC2) to add a tool to the tool
        // table from within a program.
        // G10 L1 P[tool number] R[radius] X[offset] Z[offset] Q[orientation]

	if (m_title.size() > 0)
	{
		ss << "#(" << m_title.c_str() << ")\n";
	} // End if - then

	ss << "tool_defn( id=" << m_tool_number << ", "
		<< "name=None, ";
	if (m_params.m_diameter > 0)
	{
		ss << "radius=" << m_params.m_diameter / 2 << ", ";
	} // End if - then
	else
	{
		ss << "radius=None, ";
	} // End if - else

	if (m_params.m_tool_length_offset > 0)
	{
		ss << "length=" << m_params.m_tool_length_offset;
	} // End if - then
	else
	{
		ss << "length=None";
	} // End if - else

	ss << ")\n";

	theApp.m_program_canvas->m_textCtrl->AppendText(ss.str().c_str());
}

static void on_set_tool_number(const int value, HeeksObj* object){((CCuttingTool*)object)->m_tool_number = value;}

/**
	NOTE: The m_title member is a special case.  The HeeksObj code looks for a 'GetShortDesc()' method.  If found, it
	adds a Property called 'Object Title'.  If the value is changed, it tries to call the 'OnEditString()' method.
	That's why the m_title value is not defined here
 */
void CCuttingTool::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyInt(_("tool_number"), m_tool_number, this, on_set_tool_number));

	m_params.GetProperties(this, list);
	HeeksObj::GetProperties(list);
}

HeeksObj *CCuttingTool::MakeACopy(void)const
{
	return new CCuttingTool(*this);
}

void CCuttingTool::CopyFrom(const HeeksObj* object)
{
	operator=(*((CCuttingTool*)object));
}

bool CCuttingTool::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == ToolsType;
}

void CCuttingTool::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element = new TiXmlElement( "CuttingTool" );
	root->LinkEndChild( element );
	element->SetAttribute("title", Ttc(m_title.c_str()));

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_tool_number;
	element->SetAttribute("tool_number", l_ossValue.str().c_str() );

	m_params.WriteXMLAttributes(element);
	WriteBaseXML(element);
}

// static member function
HeeksObj* CCuttingTool::ReadFromXMLElement(TiXmlElement* element)
{

	int tool_number = 0;
	if (element->Attribute("tool_number")) tool_number = atoi(element->Attribute("tool_number"));

	wxString title(Ctt(element->Attribute("title")));
	CCuttingTool* new_object = new CCuttingTool( title.c_str(), tool_number);

	// read point and circle ids
	for(TiXmlElement* pElem = TiXmlHandle(element).FirstChildElement().Element(); pElem; pElem = pElem->NextSiblingElement())
	{
		std::string name(pElem->Value());
		if(name == "params"){
			new_object->m_params.ReadParametersFromXMLElement(pElem);
		}
	}

	new_object->ReadBaseXML(element);

	return new_object;
}

void CCuttingTool::OnEditString(const wxChar* str){
        m_title.assign(str);
	heeksCAD->WasModified(this);
}

/**
 * Find the CuttingTool object whose tool number matches that passed in.
 */
int CCuttingTool::FindCuttingTool( const int tool_number )
{
        /* Can't make this work.  Need to figure out why */
        for (HeeksObj *ob = heeksCAD->GetFirstObject(); ob != NULL; ob = heeksCAD->GetNextObject())
        {
                if (ob->GetType() != CuttingToolType) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        // This is a hack but it works.  As long as we don't get more than 100 tools in the holder.
        for (int id=1; id<100; id++)
        {
                HeeksObj *ob = heeksCAD->GetIDObject( CuttingToolType, id );
                if (! ob) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        return(-1);

} // End FindCuttingTool() method

<commit_msg>added units<commit_after>// CuttingTool.cpp
/*
 * Copyright (c) 2009, Dan Heeks, Perttu Ahola
 * This program is released under the BSD license. See the file COPYING for
 * details.
 */

#include "stdafx.h"
#include "CuttingTool.h"
#include "CNCConfig.h"
#include "ProgramCanvas.h"
#include "interface/HeeksObj.h"
#include "interface/PropertyInt.h"
#include "interface/PropertyDouble.h"
#include "interface/PropertyLength.h"
#include "interface/PropertyChoice.h"
#include "interface/PropertyString.h"
#include "tinyxml/tinyxml.h"

#include <sstream>

extern CHeeksCADInterface* heeksCAD;

void CCuttingToolParams::set_initial_values()
{
	CNCConfig config;
	config.Read(_T("m_diameter"), &m_diameter, 12.7);
	config.Read(_T("m_x_offset"), &m_x_offset, 0);
	config.Read(_T("m_tool_length_offset"), &m_tool_length_offset, 0);
	config.Read(_T("m_orientation"), &m_orientation, 9);
}

void CCuttingToolParams::write_values_to_config()
{
	CNCConfig config;

	// We ALWAYS write the parameters into the configuration file in mm (for consistency).
	// If we're now in inches then convert the values.
	// We're in mm already.
	config.Write(_T("m_diameter"), m_diameter);
	config.Write(_T("m_x_offset"), m_x_offset);
	config.Write(_T("m_tool_length_offset"), m_tool_length_offset);
	config.Write(_T("m_orientation"), m_orientation);
}

static void on_set_diameter(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_diameter = value;}
static void on_set_x_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_x_offset = value;}
static void on_set_tool_length_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_tool_length_offset = value;}
static void on_set_orientation(int value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_orientation = value;}

void CCuttingToolParams::GetProperties(CCuttingTool* parent, std::list<Property *> *list)
{
	list->push_back(new PropertyLength(_("diameter"), m_diameter, parent, on_set_diameter));
	list->push_back(new PropertyLength(_("x_offset"), m_x_offset, parent, on_set_x_offset));
	list->push_back(new PropertyLength(_("tool_length_offset"), m_x_offset, parent, on_set_tool_length_offset));
	list->push_back(new PropertyInt(_("orientation"), m_orientation, parent, on_set_orientation));
}

void CCuttingToolParams::WriteXMLAttributes(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "params" );
	root->LinkEndChild( element );

	element->SetDoubleAttribute("diameter", m_diameter);
	element->SetDoubleAttribute("x_offset", m_x_offset);
	element->SetDoubleAttribute("tool_length_offset", m_tool_length_offset);

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_orientation;
	element->SetAttribute("orientation", l_ossValue.str().c_str() );
}

void CCuttingToolParams::ReadParametersFromXMLElement(TiXmlElement* pElem)
{
	if (pElem->Attribute("diameter")) m_diameter = atof(pElem->Attribute("diameter"));
	if (pElem->Attribute("x_offset")) m_x_offset = atof(pElem->Attribute("x_offset"));
	if (pElem->Attribute("tool_length_offset")) m_tool_length_offset = atof(pElem->Attribute("tool_length_offset"));
	if (pElem->Attribute("orientation")) m_orientation = atoi(pElem->Attribute("orientation"));
}

/**
	This method is called when the CAD operator presses the Python button.  This method generates
	Python source code whose job will be to generate RS-274 GCode.  It's done in two steps so that
	the Python code can be configured to generate GCode suitable for various CNC interpreters.
 */
void CCuttingTool::AppendTextToProgram()
{

#ifdef UNICODE
	std::wostringstream ss;
#else
    std::ostringstream ss;
#endif
    ss.imbue(std::locale("C"));

	// The G10 command can be used (within EMC2) to add a tool to the tool
        // table from within a program.
        // G10 L1 P[tool number] R[radius] X[offset] Z[offset] Q[orientation]

	if (m_title.size() > 0)
	{
		ss << "#(" << m_title.c_str() << ")\n";
	} // End if - then

	ss << "tool_defn( id=" << m_tool_number << ", "
		<< "name=None, ";
	if (m_params.m_diameter > 0)
	{
		ss << "radius=" << m_params.m_diameter / 2 /theApp.m_program->m_units << ", ";
	} // End if - then
	else
	{
		ss << "radius=None, ";
	} // End if - else

	if (m_params.m_tool_length_offset > 0)
	{
		ss << "length=" << m_params.m_tool_length_offset /theApp.m_program->m_units;
	} // End if - then
	else
	{
		ss << "length=None";
	} // End if - else

	ss << ")\n";

	theApp.m_program_canvas->m_textCtrl->AppendText(ss.str().c_str());
}

static void on_set_tool_number(const int value, HeeksObj* object){((CCuttingTool*)object)->m_tool_number = value;}

/**
	NOTE: The m_title member is a special case.  The HeeksObj code looks for a 'GetShortDesc()' method.  If found, it
	adds a Property called 'Object Title'.  If the value is changed, it tries to call the 'OnEditString()' method.
	That's why the m_title value is not defined here
 */
void CCuttingTool::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyInt(_("tool_number"), m_tool_number, this, on_set_tool_number));

	m_params.GetProperties(this, list);
	HeeksObj::GetProperties(list);
}

HeeksObj *CCuttingTool::MakeACopy(void)const
{
	return new CCuttingTool(*this);
}

void CCuttingTool::CopyFrom(const HeeksObj* object)
{
	operator=(*((CCuttingTool*)object));
}

bool CCuttingTool::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == ToolsType;
}

void CCuttingTool::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element = new TiXmlElement( "CuttingTool" );
	root->LinkEndChild( element );
	element->SetAttribute("title", Ttc(m_title.c_str()));

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_tool_number;
	element->SetAttribute("tool_number", l_ossValue.str().c_str() );

	m_params.WriteXMLAttributes(element);
	WriteBaseXML(element);
}

// static member function
HeeksObj* CCuttingTool::ReadFromXMLElement(TiXmlElement* element)
{

	int tool_number = 0;
	if (element->Attribute("tool_number")) tool_number = atoi(element->Attribute("tool_number"));

	wxString title(Ctt(element->Attribute("title")));
	CCuttingTool* new_object = new CCuttingTool( title.c_str(), tool_number);

	// read point and circle ids
	for(TiXmlElement* pElem = TiXmlHandle(element).FirstChildElement().Element(); pElem; pElem = pElem->NextSiblingElement())
	{
		std::string name(pElem->Value());
		if(name == "params"){
			new_object->m_params.ReadParametersFromXMLElement(pElem);
		}
	}

	new_object->ReadBaseXML(element);

	return new_object;
}

void CCuttingTool::OnEditString(const wxChar* str){
        m_title.assign(str);
	heeksCAD->WasModified(this);
}

/**
 * Find the CuttingTool object whose tool number matches that passed in.
 */
int CCuttingTool::FindCuttingTool( const int tool_number )
{
        /* Can't make this work.  Need to figure out why */
        for (HeeksObj *ob = heeksCAD->GetFirstObject(); ob != NULL; ob = heeksCAD->GetNextObject())
        {
                if (ob->GetType() != CuttingToolType) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        // This is a hack but it works.  As long as we don't get more than 100 tools in the holder.
        for (int id=1; id<100; id++)
        {
                HeeksObj *ob = heeksCAD->GetIDObject( CuttingToolType, id );
                if (! ob) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        return(-1);

} // End FindCuttingTool() method

<|endoftext|>


<commit_before>#include "Hymn.hpp"

#include "Util/FileSystem.hpp"
#include "Manager/Managers.hpp"
#include "Manager/RenderManager.hpp"
#include "Manager/PhysicsManager.hpp"
#include "Manager/ParticleManager.hpp"
#include "Manager/ScriptManager.hpp"
#include "Manager/SoundManager.hpp"
#include "Manager/DebugDrawingManager.hpp"
#include "Manager/ResourceManager.hpp"
#include "DefaultAlbedo.png.hpp"
#include "DefaultNormal.png.hpp"
#include "DefaultMetallic.png.hpp"
#include "DefaultRoughness.png.hpp"
#include "Geometry/Model.hpp"
#include <Video/Texture/Texture2D.hpp>
#include "Texture/TextureAsset.hpp"
#include "Input/Input.hpp"
#include "Script/ScriptFile.hpp"
#include "Util/Json.hpp"
#include <fstream>
#include "Util/Profiling.hpp"
#include "Util/GPUProfiling.hpp"

#include "Entity/Entity.hpp"
#include "Component/Animation.hpp"

using namespace std;

ActiveHymn::ActiveHymn() {
    defaultAlbedo = new TextureAsset();
    defaultAlbedo->GetTexture()->Load(DEFAULTALBEDO_PNG, DEFAULTALBEDO_PNG_LENGTH, true);
    defaultNormal = new TextureAsset();
    defaultNormal->GetTexture()->Load(DEFAULTNORMAL_PNG, DEFAULTNORMAL_PNG_LENGTH, false);
    defaultMetallic= new TextureAsset();
    defaultMetallic->GetTexture()->Load(DEFAULTMETALLIC_PNG, DEFAULTMETALLIC_PNG_LENGTH, false);
    defaultRoughness = new TextureAsset();
    defaultRoughness->GetTexture()->Load(DEFAULTROUGHNESS_PNG, DEFAULTROUGHNESS_PNG_LENGTH, false);

    Clear();
}

ActiveHymn& ActiveHymn::GetInstance() {
    static ActiveHymn ActiveHymn;

    return ActiveHymn;
}

void ActiveHymn::Clear() {
    path = "";
    startupScene = "";
    world.Clear();

    entityNumber = 1U;

    filterSettings.color = false;
    filterSettings.fog = false;
    filterSettings.fogDensity = 0.001f;
    filterSettings.fxaa = true;
    filterSettings.glow = true;
    filterSettings.glowBlurAmount = 1;

    for (ScriptFile* script : scripts) {
        Managers().resourceManager->FreeScriptFile(script);
    }
    scripts.clear();
    scriptNumber = 0U;
}

const string& ActiveHymn::GetPath() const {
    return path;
}

void ActiveHymn::SetPath(const string& path) {
    this->path = path;
    FileSystem::CreateDirectory(path.c_str());
    FileSystem::CreateDirectory((path + "/Resources").c_str());
}

std::string ActiveHymn::GetSavePath() const {
    return path + FileSystem::DELIMITER + "Hymn.json";
}

void ActiveHymn::Save() const {
    // Save to file.
    ofstream file(GetSavePath());
    file << ToJson();
    file.close();
}

void ActiveHymn::Load(const string& path) {
    Clear();
    this->path = path;

    // Load Json document from file.
    Json::Value root;
    ifstream file(GetSavePath());
    file >> root;
    file.close();

    FromJson(root);
}

Json::Value ActiveHymn::ToJson() const {
    Json::Value root;

    Json::Value inputNode;
    inputNode.append(Input::GetInstance().Save());
    root["input"] = inputNode;

    // Filter settings.
    Json::Value filtersNode;
    filtersNode["color"] = filterSettings.color;
    filtersNode["colorColor"] = Json::SaveVec3(filterSettings.colorColor);
    filtersNode["fog"] = filterSettings.fog;
    filtersNode["fogDensity"] = filterSettings.fogDensity;
    filtersNode["fogColor"] = Json::SaveVec3(filterSettings.fogColor);
    filtersNode["fxaa"] = filterSettings.fxaa;
    filtersNode["glow"] = filterSettings.glow;
    filtersNode["glowBlurAmount"] = filterSettings.glowBlurAmount;
    root["filters"] = filtersNode;

    // Save scripts.
    Json::Value scriptNode;
    for (ScriptFile* script : scripts) {
        scriptNode.append(script->path + script->name);
    }
    root["scripts"] = scriptNode;

    root["startupScene"] = startupScene;

    return root;
}

void ActiveHymn::FromJson(Json::Value root) {
    const Json::Value inputNode = root["input"];
    Input::GetInstance().Load(inputNode[0]);

    // Load filter settings.
    Json::Value filtersNode = root["filters"];
    filterSettings.color = filtersNode["color"].asBool();
    filterSettings.colorColor = Json::LoadVec3(filtersNode["colorColor"]);
    filterSettings.fog = filtersNode["fog"].asBool();
    filterSettings.fogDensity = filtersNode["fogDensity"].asFloat();
    filterSettings.fogColor = Json::LoadVec3(filtersNode["fogColor"]);
    filterSettings.fxaa = filtersNode["fxaa"].asBool();
    filterSettings.glow = filtersNode["glow"].asBool();
    filterSettings.glowBlurAmount = filtersNode["glowBlurAmount"].asInt();

    // Load scripts.
    const Json::Value scriptNode = root["scripts"];
    for (unsigned int i = 0; i < scriptNode.size(); ++i) {
        scripts.push_back(Managers().resourceManager->CreateScriptFile(scriptNode[i].asString()));
    }
    scriptNumber = scripts.size();

    startupScene = root["startupScene"].asString();
}

void ActiveHymn::Update(float deltaTime) {
    { PROFILE("Run scripts.");
        Managers().scriptManager->Update(world, deltaTime);
    }

    { PROFILE("Update physics");
        Managers().physicsManager->Update(deltaTime);
    }

    { PROFILE("Update animations");
        for (Entity* entity : world.GetEntities()) {
            if (entity->IsKilled() || !entity->enabled)
                continue;

            Component::Animation* anim = entity->GetComponent<Component::Animation>();
            if (anim != nullptr) {
                Geometry::Model* model = anim->riggedModel;
                /// @todo Fix animations.
            }
        }
    }

    { PROFILE("Update particles");
        Managers().particleManager->Update(world, deltaTime);
    }

    { PROFILE("Update sounds");
        Managers().soundManager->Update(deltaTime);
    }

    { PROFILE("Update debug drawing");
        Managers().debugDrawingManager->Update(deltaTime);
    }

    { PROFILE("Synchronize transforms");
        Managers().physicsManager->UpdateEntityTransforms();
    }

    { PROFILE("Clear killed entities/components");
        world.ClearKilled();
    }
}

void ActiveHymn::Render(Entity* camera, bool soundSources, bool particleEmitters, bool lightSources, bool cameras, bool physics) {
    { PROFILE("Render world");
    { GPUPROFILE("Render world", Video::Query::Type::TIME_ELAPSED);
        Managers().renderManager->Render(world, camera);
    }
    }

    if (soundSources || particleEmitters || lightSources || cameras || physics) {
        { PROFILE("Render editor entities");
        { GPUPROFILE("Render editor entities", Video::Query::Type::TIME_ELAPSED);
            Managers().renderManager->RenderEditorEntities(world, camera, soundSources, particleEmitters, lightSources, cameras, physics);
        }
        }
    }

    { PROFILE("Render debug entities");
    { GPUPROFILE("Render debug entities", Video::Query::Type::TIME_ELAPSED);
        Managers().debugDrawingManager->Render(camera);
    }
    }
}

ActiveHymn& Hymn() {
    return ActiveHymn::GetInstance();
}
<commit_msg>Update Hymn.cpp<commit_after>#include "Hymn.hpp"

#include "Util/FileSystem.hpp"
#include "Manager/Managers.hpp"
#include "Manager/RenderManager.hpp"
#include "Manager/PhysicsManager.hpp"
#include "Manager/ParticleManager.hpp"
#include "Manager/ScriptManager.hpp"
#include "Manager/SoundManager.hpp"
#include "Manager/DebugDrawingManager.hpp"
#include "Manager/ResourceManager.hpp"
#include "DefaultAlbedo.png.hpp"
#include "DefaultNormal.png.hpp"
#include "DefaultMetallic.png.hpp"
#include "DefaultRoughness.png.hpp"
#include "Geometry/Model.hpp"
#include <Video/Texture/Texture2D.hpp>
#include "Texture/TextureAsset.hpp"
#include "Input/Input.hpp"
#include "Script/ScriptFile.hpp"
#include "Util/Json.hpp"
#include <fstream>
#include "Util/Profiling.hpp"
#include "Util/GPUProfiling.hpp"

#include "Entity/Entity.hpp"
#include "Component/Animation.hpp"

using namespace std;

ActiveHymn::ActiveHymn() {
    defaultAlbedo = new TextureAsset();
    defaultAlbedo->GetTexture()->Load(DEFAULTALBEDO_PNG, DEFAULTALBEDO_PNG_LENGTH, true);
    defaultNormal = new TextureAsset();
    defaultNormal->GetTexture()->Load(DEFAULTNORMAL_PNG, DEFAULTNORMAL_PNG_LENGTH, false);
    defaultMetallic= new TextureAsset();
    defaultMetallic->GetTexture()->Load(DEFAULTMETALLIC_PNG, DEFAULTMETALLIC_PNG_LENGTH, false);
    defaultRoughness = new TextureAsset();
    defaultRoughness->GetTexture()->Load(DEFAULTROUGHNESS_PNG, DEFAULTROUGHNESS_PNG_LENGTH, false);

    Clear();
}

ActiveHymn& ActiveHymn::GetInstance() {
    static ActiveHymn ActiveHymn;

    return ActiveHymn;
}

void ActiveHymn::Clear() {
    path = "";
    startupScene = "";
    world.Clear();

    entityNumber = 1U;

    filterSettings.color = false;
    filterSettings.fog = false;
    filterSettings.fogDensity = 0.001f;
    filterSettings.fxaa = true;
    filterSettings.glow = true;
    filterSettings.glowBlurAmount = 1;

    for (ScriptFile* script : scripts) {
        Managers().resourceManager->FreeScriptFile(script);
    }
    scripts.clear();
    scriptNumber = 0U;
}

const string& ActiveHymn::GetPath() const {
    return path;
}

void ActiveHymn::SetPath(const string& path) {
    this->path = path;
    FileSystem::CreateDirectory(path.c_str());
    FileSystem::CreateDirectory((path + "/Resources").c_str());
}

std::string ActiveHymn::GetSavePath() const {
    return path + FileSystem::DELIMITER + "Hymn.json";
}

void ActiveHymn::Save() const {
    // Save to file.
    ofstream file(GetSavePath());
    file << ToJson();
    file.close();
}

void ActiveHymn::Load(const string& path) {
    Clear();
    this->path = path;

    // Load Json document from file.
    Json::Value root;
    ifstream file(GetSavePath());
    file >> root;
    file.close();

    FromJson(root);
}

Json::Value ActiveHymn::ToJson() const {
    Json::Value root;

    Json::Value inputNode;
    inputNode.append(Input::GetInstance().Save());
    root["input"] = inputNode;

    // Filter settings.
    Json::Value filtersNode;
    filtersNode["color"] = filterSettings.color;
    filtersNode["colorColor"] = Json::SaveVec3(filterSettings.colorColor);
    filtersNode["fog"] = filterSettings.fog;
    filtersNode["fogDensity"] = filterSettings.fogDensity;
    filtersNode["fogColor"] = Json::SaveVec3(filterSettings.fogColor);
    filtersNode["fxaa"] = filterSettings.fxaa;
    filtersNode["glow"] = filterSettings.glow;
    filtersNode["glowBlurAmount"] = filterSettings.glowBlurAmount;
    root["filters"] = filtersNode;

    // Save scripts.
    Json::Value scriptNode;
    for (ScriptFile* script : scripts) {
        scriptNode.append(script->path + script->name);
    }
    root["scripts"] = scriptNode;
    root["startupScene"] = startupScene;

    return root;
}

void ActiveHymn::FromJson(Json::Value root) {
    const Json::Value inputNode = root["input"];
    Input::GetInstance().Load(inputNode[0]);

    // Load filter settings.
    Json::Value filtersNode = root["filters"];
    filterSettings.color = filtersNode["color"].asBool();
    filterSettings.colorColor = Json::LoadVec3(filtersNode["colorColor"]);
    filterSettings.fog = filtersNode["fog"].asBool();
    filterSettings.fogDensity = filtersNode["fogDensity"].asFloat();
    filterSettings.fogColor = Json::LoadVec3(filtersNode["fogColor"]);
    filterSettings.fxaa = filtersNode["fxaa"].asBool();
    filterSettings.glow = filtersNode["glow"].asBool();
    filterSettings.glowBlurAmount = filtersNode["glowBlurAmount"].asInt();

    // Load scripts.
    const Json::Value scriptNode = root["scripts"];
    for (unsigned int i = 0; i < scriptNode.size(); ++i) {
        scripts.push_back(Managers().resourceManager->CreateScriptFile(scriptNode[i].asString()));
    }
    scriptNumber = scripts.size();

    startupScene = root["startupScene"].asString();
}

void ActiveHymn::Update(float deltaTime) {
    { PROFILE("Run scripts.");
        Managers().scriptManager->Update(world, deltaTime);
    }

    { PROFILE("Update physics");
        Managers().physicsManager->Update(deltaTime);
    }

    { PROFILE("Update animations");
        for (Entity* entity : world.GetEntities()) {
            if (entity->IsKilled() || !entity->enabled)
                continue;

            Component::Animation* anim = entity->GetComponent<Component::Animation>();
            if (anim != nullptr) {
                Geometry::Model* model = anim->riggedModel;
                /// @todo Fix animations.
            }
        }
    }

    { PROFILE("Update particles");
        Managers().particleManager->Update(world, deltaTime);
    }

    { PROFILE("Update sounds");
        Managers().soundManager->Update(deltaTime);
    }

    { PROFILE("Update debug drawing");
        Managers().debugDrawingManager->Update(deltaTime);
    }

    { PROFILE("Synchronize transforms");
        Managers().physicsManager->UpdateEntityTransforms();
    }

    { PROFILE("Clear killed entities/components");
        world.ClearKilled();
    }
}

void ActiveHymn::Render(Entity* camera, bool soundSources, bool particleEmitters, bool lightSources, bool cameras, bool physics) {
    { PROFILE("Render world");
    { GPUPROFILE("Render world", Video::Query::Type::TIME_ELAPSED);
        Managers().renderManager->Render(world, camera);
    }
    }

    if (soundSources || particleEmitters || lightSources || cameras || physics) {
        { PROFILE("Render editor entities");
        { GPUPROFILE("Render editor entities", Video::Query::Type::TIME_ELAPSED);
            Managers().renderManager->RenderEditorEntities(world, camera, soundSources, particleEmitters, lightSources, cameras, physics);
        }
        }
    }

    { PROFILE("Render debug entities");
    { GPUPROFILE("Render debug entities", Video::Query::Type::TIME_ELAPSED);
        Managers().debugDrawingManager->Render(camera);
    }
    }
}

ActiveHymn& Hymn() {
    return ActiveHymn::GetInstance();
}
<|endoftext|>


<commit_before>#include "Hymn.hpp"

#include "Util/FileSystem.hpp"
#include "Manager/Managers.hpp"
#include "Manager/RenderManager.hpp"
#include "Manager/PhysicsManager.hpp"
#include "Manager/ParticleManager.hpp"
#include "Manager/ScriptManager.hpp"
#include "Manager/SoundManager.hpp"
#include "Manager/DebugDrawingManager.hpp"
#include "Manager/ResourceManager.hpp"
#include "DefaultAlbedo.png.hpp"
#include "DefaultNormal.png.hpp"
#include "DefaultMetallic.png.hpp"
#include "DefaultRoughness.png.hpp"
#include "Geometry/Model.hpp"
#include <Video/Texture/Texture2D.hpp>
#include "Texture/TextureAsset.hpp"
#include "Input/Input.hpp"
#include "Script/ScriptFile.hpp"
#include "Util/Json.hpp"
#include <fstream>
#include "Util/Profiling.hpp"

#include "Entity/Entity.hpp"
#include "Component/Animation.hpp"

using namespace std;

ActiveHymn::ActiveHymn() {
    defaultAlbedo = new TextureAsset();
    defaultAlbedo->GetTexture()->Load(DEFAULTALBEDO_PNG, DEFAULTALBEDO_PNG_LENGTH, true);
    defaultNormal = new TextureAsset();
    defaultNormal->GetTexture()->Load(DEFAULTNORMAL_PNG, DEFAULTNORMAL_PNG_LENGTH, false);
    defaultMetallic= new TextureAsset();
    defaultMetallic->GetTexture()->Load(DEFAULTMETALLIC_PNG, DEFAULTMETALLIC_PNG_LENGTH, false);
    defaultRoughness = new TextureAsset();
    defaultRoughness->GetTexture()->Load(DEFAULTROUGHNESS_PNG, DEFAULTROUGHNESS_PNG_LENGTH, false);

    Clear();
}

ActiveHymn& ActiveHymn::GetInstance() {
    static ActiveHymn ActiveHymn;

    return ActiveHymn;
}

void ActiveHymn::Clear() {
    path = "";
    world.Clear();

    entityNumber = 1U;

    filterSettings.color = false;
    filterSettings.fog = false;
    filterSettings.fogDensity = 0.001f;
    filterSettings.fxaa = true;
    filterSettings.glow = true;
    filterSettings.glowBlurAmount = 1;

    for (ScriptFile* script : scripts) {
        Managers().resourceManager->FreeScriptFile(script);
    }
    scripts.clear();
    scriptNumber = 0U;
}

const string& ActiveHymn::GetPath() const {
    return path;
}

void ActiveHymn::SetPath(const string& path) {
    this->path = path;
    FileSystem::CreateDirectory(path.c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Models").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Scenes").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Scripts").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Sounds").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Textures").c_str());
}

void ActiveHymn::Save() const {
    // Save to file.
    ofstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file << ToJson();
    file.close();
}

void ActiveHymn::Load(const string& path) {
    Clear();
    this->path = path;

    // Load Json document from file.
    Json::Value root;
    ifstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file >> root;
    file.close();

    FromJson(root);
}

Json::Value ActiveHymn::ToJson() const {
    Json::Value root;

    Json::Value inputNode;
    inputNode.append(Input::GetInstance().Save());
    root["input"] = inputNode;

    // Filter settings.
    Json::Value filtersNode;
    filtersNode["color"] = filterSettings.color;
    filtersNode["colorColor"] = Json::SaveVec3(filterSettings.colorColor);
    filtersNode["fog"] = filterSettings.fog;
    filtersNode["fogDensity"] = filterSettings.fogDensity;
    filtersNode["fogColor"] = Json::SaveVec3(filterSettings.fogColor);
    filtersNode["fxaa"] = filterSettings.fxaa;
    filtersNode["glow"] = filterSettings.glow;
    filtersNode["glowBlurAmount"] = filterSettings.glowBlurAmount;
    root["filters"] = filtersNode;

    // Save scripts.
    Json::Value scriptNode;
    for (ScriptFile* script : scripts) {
        scriptNode.append(script->path + script->name);
    }
    root["scripts"] = scriptNode;

    return root;
}

void ActiveHymn::FromJson(Json::Value root) {
    const Json::Value inputNode = root["input"];
    Input::GetInstance().Load(inputNode[0]);

    // Load filter settings.
    Json::Value filtersNode = root["filters"];
    filterSettings.color = filtersNode["color"].asBool();
    filterSettings.colorColor = Json::LoadVec3(filtersNode["colorColor"]);
    filterSettings.fog = filtersNode["fog"].asBool();
    filterSettings.fogDensity = filtersNode["fogDensity"].asFloat();
    filterSettings.fogColor = Json::LoadVec3(filtersNode["fogColor"]);
    filterSettings.fxaa = filtersNode["fxaa"].asBool();
    filterSettings.glow = filtersNode["glow"].asBool();
    filterSettings.glowBlurAmount = filtersNode["glowBlurAmount"].asInt();

    // Load scripts.
    const Json::Value scriptNode = root["scripts"];
    for (unsigned int i = 0; i < scriptNode.size(); ++i) {
        scripts.push_back(Managers().resourceManager->CreateScriptFile(scriptNode[i].asString()));
    }
    scriptNumber = scripts.size();
}

void ActiveHymn::Update(float deltaTime) {
    { PROFILE("Run scripts.");
        Managers().scriptManager->Update(world, deltaTime);
    }

    { PROFILE("Update physics");
        Managers().physicsManager->Update(deltaTime);
    }

    { PROFILE("Update animations");
        for (Entity* entity : world.GetEntities()) {
            if (entity->IsKilled() || !entity->enabled)
                continue;

            Component::Animation* anim = entity->GetComponent<Component::Animation>();
            if (anim != nullptr) {
                Geometry::Model* model = anim->riggedModel;
                /// @todo Fix animations.
            }
        }
    }

    { PROFILE("Update particles");
        Managers().particleManager->Update(world, deltaTime);
    }

    { PROFILE("Update sounds");
        Managers().soundManager->Update();
    }

    { PROFILE("Update debug drawing");
        Managers().debugDrawingManager->Update(deltaTime);
    }

    { PROFILE("Synchronize transforms");
        Managers().physicsManager->UpdateEntityTransforms();
    }

    { PROFILE("Clear killed entities/components");
        world.ClearKilled();
    }
}

void ActiveHymn::Render(Entity* camera, bool soundSources, bool particleEmitters, bool lightSources, bool cameras, bool physics, bool showGridSettings) {
    { PROFILE("Render world");
        Managers().renderManager->Render(world, camera);
    }

    if (soundSources || particleEmitters || lightSources || cameras || physics) {
        { PROFILE("Render editor entities");
            Managers().renderManager->RenderEditorEntities(world, camera, soundSources, particleEmitters, lightSources, cameras, physics);
        }
    }
    if (showGridSettings)
    {
        ImGui::SetNextWindowPos(ImVec2(1275, 25));
        ImGui::SetNextWindowSizeConstraints(ImVec2(250, 50), ImVec2(250, 50));
        ImGui::Begin("Grid Settings", &showGridSettings, ImGuiWindowFlags_NoTitleBar);
        ImGui::DragInt("Grid Scale", &gridSettings.gridScale, 1.0f, 0, 100);
        ImGui::End();
    }

    { PROFILE("Render debug entities");
        CreateGrid(gridSettings.gridScale);
        Managers().debugDrawingManager->Render(camera);
    }
}

void ActiveHymn::CreateGrid(int scale)
{
    glm::vec2 gridWidthDepth(10.0f, 10.0f);
    gridWidthDepth.x = (gridWidthDepth.x * scale);
    gridWidthDepth.y = (gridWidthDepth.y * scale);

    float xStart = (-gridWidthDepth.x / 2);
    float xEnd = (gridWidthDepth.x / 2);
    float zStart = (-gridWidthDepth.y / 2);
    float zEnd = (gridWidthDepth.y / 2);

    if (scale <= 100 && scale > 0) {
        for (int i = 0; i < (scale + scale + 1); i++)
        {
            Managers().debugDrawingManager->AddLine(glm::vec3(xStart, 0.0f, -gridWidthDepth.y / (2)), glm::vec3(xStart, 0.0f, zEnd), glm::vec3(0.1f, 0.1f, 0.5f), 3.0f);
            Managers().debugDrawingManager->AddLine(glm::vec3(-gridWidthDepth.x / (2), 0.0f, zStart), glm::vec3(xEnd, 0.0f, zStart), glm::vec3(0.5f, 0.1f, 0.1f), 3.0f);
            xStart += (gridWidthDepth.x / 2) / scale;
            zStart += (gridWidthDepth.y / 2) / scale;
        }
    }
}

ActiveHymn& Hymn() {
    return ActiveHymn::GetInstance();
}
<commit_msg>Don't create unused directories<commit_after>#include "Hymn.hpp"

#include "Util/FileSystem.hpp"
#include "Manager/Managers.hpp"
#include "Manager/RenderManager.hpp"
#include "Manager/PhysicsManager.hpp"
#include "Manager/ParticleManager.hpp"
#include "Manager/ScriptManager.hpp"
#include "Manager/SoundManager.hpp"
#include "Manager/DebugDrawingManager.hpp"
#include "Manager/ResourceManager.hpp"
#include "DefaultAlbedo.png.hpp"
#include "DefaultNormal.png.hpp"
#include "DefaultMetallic.png.hpp"
#include "DefaultRoughness.png.hpp"
#include "Geometry/Model.hpp"
#include <Video/Texture/Texture2D.hpp>
#include "Texture/TextureAsset.hpp"
#include "Input/Input.hpp"
#include "Script/ScriptFile.hpp"
#include "Util/Json.hpp"
#include <fstream>
#include "Util/Profiling.hpp"

#include "Entity/Entity.hpp"
#include "Component/Animation.hpp"

using namespace std;

ActiveHymn::ActiveHymn() {
    defaultAlbedo = new TextureAsset();
    defaultAlbedo->GetTexture()->Load(DEFAULTALBEDO_PNG, DEFAULTALBEDO_PNG_LENGTH, true);
    defaultNormal = new TextureAsset();
    defaultNormal->GetTexture()->Load(DEFAULTNORMAL_PNG, DEFAULTNORMAL_PNG_LENGTH, false);
    defaultMetallic= new TextureAsset();
    defaultMetallic->GetTexture()->Load(DEFAULTMETALLIC_PNG, DEFAULTMETALLIC_PNG_LENGTH, false);
    defaultRoughness = new TextureAsset();
    defaultRoughness->GetTexture()->Load(DEFAULTROUGHNESS_PNG, DEFAULTROUGHNESS_PNG_LENGTH, false);

    Clear();
}

ActiveHymn& ActiveHymn::GetInstance() {
    static ActiveHymn ActiveHymn;

    return ActiveHymn;
}

void ActiveHymn::Clear() {
    path = "";
    world.Clear();

    entityNumber = 1U;

    filterSettings.color = false;
    filterSettings.fog = false;
    filterSettings.fogDensity = 0.001f;
    filterSettings.fxaa = true;
    filterSettings.glow = true;
    filterSettings.glowBlurAmount = 1;

    for (ScriptFile* script : scripts) {
        Managers().resourceManager->FreeScriptFile(script);
    }
    scripts.clear();
    scriptNumber = 0U;
}

const string& ActiveHymn::GetPath() const {
    return path;
}

void ActiveHymn::SetPath(const string& path) {
    this->path = path;
    FileSystem::CreateDirectory(path.c_str());
    FileSystem::CreateDirectory((path + "/Resources").c_str());
}

void ActiveHymn::Save() const {
    // Save to file.
    ofstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file << ToJson();
    file.close();
}

void ActiveHymn::Load(const string& path) {
    Clear();
    this->path = path;

    // Load Json document from file.
    Json::Value root;
    ifstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file >> root;
    file.close();

    FromJson(root);
}

Json::Value ActiveHymn::ToJson() const {
    Json::Value root;

    Json::Value inputNode;
    inputNode.append(Input::GetInstance().Save());
    root["input"] = inputNode;

    // Filter settings.
    Json::Value filtersNode;
    filtersNode["color"] = filterSettings.color;
    filtersNode["colorColor"] = Json::SaveVec3(filterSettings.colorColor);
    filtersNode["fog"] = filterSettings.fog;
    filtersNode["fogDensity"] = filterSettings.fogDensity;
    filtersNode["fogColor"] = Json::SaveVec3(filterSettings.fogColor);
    filtersNode["fxaa"] = filterSettings.fxaa;
    filtersNode["glow"] = filterSettings.glow;
    filtersNode["glowBlurAmount"] = filterSettings.glowBlurAmount;
    root["filters"] = filtersNode;

    // Save scripts.
    Json::Value scriptNode;
    for (ScriptFile* script : scripts) {
        scriptNode.append(script->path + script->name);
    }
    root["scripts"] = scriptNode;

    return root;
}

void ActiveHymn::FromJson(Json::Value root) {
    const Json::Value inputNode = root["input"];
    Input::GetInstance().Load(inputNode[0]);

    // Load filter settings.
    Json::Value filtersNode = root["filters"];
    filterSettings.color = filtersNode["color"].asBool();
    filterSettings.colorColor = Json::LoadVec3(filtersNode["colorColor"]);
    filterSettings.fog = filtersNode["fog"].asBool();
    filterSettings.fogDensity = filtersNode["fogDensity"].asFloat();
    filterSettings.fogColor = Json::LoadVec3(filtersNode["fogColor"]);
    filterSettings.fxaa = filtersNode["fxaa"].asBool();
    filterSettings.glow = filtersNode["glow"].asBool();
    filterSettings.glowBlurAmount = filtersNode["glowBlurAmount"].asInt();

    // Load scripts.
    const Json::Value scriptNode = root["scripts"];
    for (unsigned int i = 0; i < scriptNode.size(); ++i) {
        scripts.push_back(Managers().resourceManager->CreateScriptFile(scriptNode[i].asString()));
    }
    scriptNumber = scripts.size();
}

void ActiveHymn::Update(float deltaTime) {
    { PROFILE("Run scripts.");
        Managers().scriptManager->Update(world, deltaTime);
    }

    { PROFILE("Update physics");
        Managers().physicsManager->Update(deltaTime);
    }

    { PROFILE("Update animations");
        for (Entity* entity : world.GetEntities()) {
            if (entity->IsKilled() || !entity->enabled)
                continue;

            Component::Animation* anim = entity->GetComponent<Component::Animation>();
            if (anim != nullptr) {
                Geometry::Model* model = anim->riggedModel;
                /// @todo Fix animations.
            }
        }
    }

    { PROFILE("Update particles");
        Managers().particleManager->Update(world, deltaTime);
    }

    { PROFILE("Update sounds");
        Managers().soundManager->Update();
    }

    { PROFILE("Update debug drawing");
        Managers().debugDrawingManager->Update(deltaTime);
    }

    { PROFILE("Synchronize transforms");
        Managers().physicsManager->UpdateEntityTransforms();
    }

    { PROFILE("Clear killed entities/components");
        world.ClearKilled();
    }
}

void ActiveHymn::Render(Entity* camera, bool soundSources, bool particleEmitters, bool lightSources, bool cameras, bool physics, bool showGridSettings) {
    { PROFILE("Render world");
        Managers().renderManager->Render(world, camera);
    }

    if (soundSources || particleEmitters || lightSources || cameras || physics) {
        { PROFILE("Render editor entities");
            Managers().renderManager->RenderEditorEntities(world, camera, soundSources, particleEmitters, lightSources, cameras, physics);
        }
    }
    if (showGridSettings)
    {
        ImGui::SetNextWindowPos(ImVec2(1275, 25));
        ImGui::SetNextWindowSizeConstraints(ImVec2(250, 50), ImVec2(250, 50));
        ImGui::Begin("Grid Settings", &showGridSettings, ImGuiWindowFlags_NoTitleBar);
        ImGui::DragInt("Grid Scale", &gridSettings.gridScale, 1.0f, 0, 100);
        ImGui::End();
    }

    { PROFILE("Render debug entities");
        CreateGrid(gridSettings.gridScale);
        Managers().debugDrawingManager->Render(camera);
    }
}

void ActiveHymn::CreateGrid(int scale)
{
    glm::vec2 gridWidthDepth(10.0f, 10.0f);
    gridWidthDepth.x = (gridWidthDepth.x * scale);
    gridWidthDepth.y = (gridWidthDepth.y * scale);

    float xStart = (-gridWidthDepth.x / 2);
    float xEnd = (gridWidthDepth.x / 2);
    float zStart = (-gridWidthDepth.y / 2);
    float zEnd = (gridWidthDepth.y / 2);

    if (scale <= 100 && scale > 0) {
        for (int i = 0; i < (scale + scale + 1); i++)
        {
            Managers().debugDrawingManager->AddLine(glm::vec3(xStart, 0.0f, -gridWidthDepth.y / (2)), glm::vec3(xStart, 0.0f, zEnd), glm::vec3(0.1f, 0.1f, 0.5f), 3.0f);
            Managers().debugDrawingManager->AddLine(glm::vec3(-gridWidthDepth.x / (2), 0.0f, zStart), glm::vec3(xEnd, 0.0f, zStart), glm::vec3(0.5f, 0.1f, 0.1f), 3.0f);
            xStart += (gridWidthDepth.x / 2) / scale;
            zStart += (gridWidthDepth.y / 2) / scale;
        }
    }
}

ActiveHymn& Hymn() {
    return ActiveHymn::GetInstance();
}
<|endoftext|>


<commit_before>// Time:  O(|V| + |E|)
// Space: O(|E|)

/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */
// BFS
class Solution {
public:
    // @param graph: A list of Directed graph node
    // @return: Any topological order for the given graph.
    //
    vector<DirectedGraphNode *> topSort(vector<DirectedGraphNode*> graph) {
        vector<DirectedGraphNode *> output;

        // Find ancestors of each node by DFS
        unordered_set<DirectedGraphNode *> nodes;
        unordered_map<DirectedGraphNode *, int> ancestors;
        for (const auto& node :graph) {
            findDependencyBFS(node, nodes, ancestors);
        }

        // Output topological order by BFS
        topSortBFS(graph, ancestors, output);

        return output;
    }

private:
    void findDependencyBFS(DirectedGraphNode* node,
                           unordered_set<DirectedGraphNode *> &nodes,
                           unordered_map<DirectedGraphNode *, int> &ancestors) {
        if (nodes.emplace(node).second) {
            queue<DirectedGraphNode *> scheduled;
            scheduled.emplace(node);
            while (!scheduled.empty()) {
                DirectedGraphNode *node = scheduled.front();
                scheduled.pop();

                // Update in degree of neighbors.
                for (const auto& neighbor : node->neighbors) {
                    ++ancestors[neighbor];
                    if (nodes.emplace(neighbor).second) {
                        scheduled.emplace(neighbor);
                    }
                }
            }
        }
    }

    void topSortBFS(vector<DirectedGraphNode*>& graph,
                    unordered_map<DirectedGraphNode *, int> &ancestors,
                    vector<DirectedGraphNode *> &output) {
        // Find the nodes with 0 in degree.
        queue<DirectedGraphNode *> scheduled;
        for (const auto& node : graph) {
            if (ancestors[node] == 0) {
                scheduled.emplace(node);
            }
        }

        while (!scheduled.empty()) {
            DirectedGraphNode *node = scheduled.front();
            output.emplace_back(node);
            scheduled.pop();

            // Update in degree of neighbors.
            for (const auto& neighbor : node->neighbors) {
                --ancestors[neighbor];
                if (ancestors[neighbor] == 0) {
                    scheduled.emplace(neighbor);
                }
            }
        }
    }
};

// DFS
class Solution {
public:
    // @param graph: A list of Directed graph node
    // @return: Any topological order for the given graph.
    //
    vector<DirectedGraphNode *> topSort(vector<DirectedGraphNode*> graph) {
        vector<DirectedGraphNode *> output;

        // Find ancestors of each node by DFS
        unordered_set<DirectedGraphNode *> nodes;
        unordered_map<DirectedGraphNode *, vector<DirectedGraphNode *>> ancestors;
        for (const auto& node :graph) {
            findDependencyDFS(node, nodes, ancestors);
        }

        // Output topological order by DFS
        unordered_set<DirectedGraphNode *> scheduled;
        for (const auto& node : graph) {
            topSortDFS(node, ancestors, scheduled, output);
        }

        return output;
    }

private:
    void findDependencyDFS(DirectedGraphNode* node,
                           unordered_set<DirectedGraphNode *> &nodes,
                           unordered_map<DirectedGraphNode *, vector<DirectedGraphNode *>> &ancestors) {
        if (nodes.emplace(node).second) {
            for (const auto& neighbor : node->neighbors) {
                ancestors[neighbor].emplace_back(node);
                findDependencyDFS(neighbor, nodes, ancestors);
            }
        }
    }

    void topSortDFS(DirectedGraphNode *node,
                    unordered_map<DirectedGraphNode *, vector<DirectedGraphNode *>> &ancestors,
                    unordered_set<DirectedGraphNode *> &scheduled,
                    vector<DirectedGraphNode *> &output) {
        if (scheduled.emplace(node).second) {
            for (const auto& ancestor: ancestors[node]) {
                topSortDFS(ancestor, ancestors, scheduled, output);
            }
            output.emplace_back(node);
        }
    }
};
<commit_msg>Update topological-sorting.cpp<commit_after>// Time:  O(|V| + |E|)
// Space: O(|E|)

/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */
// BFS
class Solution {
public:
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */
    vector<DirectedGraphNode *> topSort(vector<DirectedGraphNode*> graph) {
        vector<DirectedGraphNode *> output;

        // Find ancestors of each node by DFS
        unordered_set<DirectedGraphNode *> nodes;
        unordered_map<DirectedGraphNode *, int> ancestors;
        for (const auto& node :graph) {
            findDependencyBFS(node, nodes, ancestors);
        }

        // Output topological order by BFS
        topSortBFS(graph, ancestors, output);

        return output;
    }

private:
    void findDependencyBFS(DirectedGraphNode* node,
                           unordered_set<DirectedGraphNode *> &nodes,
                           unordered_map<DirectedGraphNode *, int> &ancestors) {
        if (nodes.emplace(node).second) {
            queue<DirectedGraphNode *> scheduled;
            scheduled.emplace(node);
            while (!scheduled.empty()) {
                DirectedGraphNode *node = scheduled.front();
                scheduled.pop();

                // Update in degree of neighbors.
                for (const auto& neighbor : node->neighbors) {
                    ++ancestors[neighbor];
                    if (nodes.emplace(neighbor).second) {
                        scheduled.emplace(neighbor);
                    }
                }
            }
        }
    }

    void topSortBFS(vector<DirectedGraphNode*>& graph,
                    unordered_map<DirectedGraphNode *, int> &ancestors,
                    vector<DirectedGraphNode *> &output) {
        // Find the nodes with 0 in degree.
        queue<DirectedGraphNode *> scheduled;
        for (const auto& node : graph) {
            if (ancestors[node] == 0) {
                scheduled.emplace(node);
            }
        }

        while (!scheduled.empty()) {
            DirectedGraphNode *node = scheduled.front();
            output.emplace_back(node);
            scheduled.pop();

            // Update in degree of neighbors.
            for (const auto& neighbor : node->neighbors) {
                --ancestors[neighbor];
                if (ancestors[neighbor] == 0) {
                    scheduled.emplace(neighbor);
                }
            }
        }
    }
};

// DFS
class Solution2 {
public:
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */
    vector<DirectedGraphNode *> topSort(vector<DirectedGraphNode*> graph) {
        vector<DirectedGraphNode *> output;

        // Find ancestors of each node by DFS
        unordered_set<DirectedGraphNode *> nodes;
        unordered_map<DirectedGraphNode *, vector<DirectedGraphNode *>> ancestors;
        for (const auto& node :graph) {
            findDependencyDFS(node, nodes, ancestors);
        }

        // Output topological order by DFS
        unordered_set<DirectedGraphNode *> scheduled;
        for (const auto& node : graph) {
            topSortDFS(node, ancestors, scheduled, output);
        }

        return output;
    }

private:
    void findDependencyDFS(DirectedGraphNode* node,
                           unordered_set<DirectedGraphNode *> &nodes,
                           unordered_map<DirectedGraphNode *, vector<DirectedGraphNode *>> &ancestors) {
        if (nodes.emplace(node).second) {
            for (const auto& neighbor : node->neighbors) {
                ancestors[neighbor].emplace_back(node);
                findDependencyDFS(neighbor, nodes, ancestors);
            }
        }
    }

    void topSortDFS(DirectedGraphNode *node,
                    unordered_map<DirectedGraphNode *, vector<DirectedGraphNode *>> &ancestors,
                    unordered_set<DirectedGraphNode *> &scheduled,
                    vector<DirectedGraphNode *> &output) {
        if (scheduled.emplace(node).second) {
            for (const auto& ancestor: ancestors[node]) {
                topSortDFS(ancestor, ancestors, scheduled, output);
            }
            output.emplace_back(node);
        }
    }
};
<|endoftext|>