<commit_before>#include <GLUL/G2D/Point.h>
#include <GLUL/G2D/Quad.h>

namespace GLUL {

    namespace G2D {

        Point::Point(unsigned int size) : _color(glm::vec4 { 1.0f }), size(size) { }

        Point::Point(const glm::vec2& position, unsigned int size) : Point(size) {
            setPosition(position);
        }

        Point& Point::operator=(const glm::vec2& position) {
            setPosition(position);

            return *this;
        }

        void Point::setPosition(const glm::vec2& position) {
            _position = position;
        }

        void Point::setPosition(const Point& point) {
            _position = point.getPosition();
        }

        const glm::vec2& Point::getPosition() const {
            return _position;
        }

        void Point::setColor(const glm::vec4& color) {
            _color = color;
        }

        const glm::vec4& Point::getColor() const {
            return _color;
        }

        void Point::_pushToBatch(GeometryBatch& geometryBatch) const {
            Quad quad;
            Point bottomLeftPoint = *this;

            bottomLeftPoint.setPosition(getPosition() - glm::vec2 { static_cast<float>((size / 2)) });
            quad.setSquare(bottomLeftPoint, static_cast<float>(size));

            geometryBatch.addPrimitive(quad);
        }

    }

}
<commit_msg>[#64] Fixed warning in G2D::Point constructor.<commit_after>#include <GLUL/G2D/Point.h>
#include <GLUL/G2D/Quad.h>

namespace GLUL {

    namespace G2D {

        Point::Point(unsigned int size) : size(size), _color({ 1.0f })  { }

        Point::Point(const glm::vec2& position, unsigned int size) : Point(size) {
            setPosition(position);
        }

        Point& Point::operator=(const glm::vec2& position) {
            setPosition(position);

            return *this;
        }

        void Point::setPosition(const glm::vec2& position) {
            _position = position;
        }

        void Point::setPosition(const Point& point) {
            _position = point.getPosition();
        }

        const glm::vec2& Point::getPosition() const {
            return _position;
        }

        void Point::setColor(const glm::vec4& color) {
            _color = color;
        }

        const glm::vec4& Point::getColor() const {
            return _color;
        }

        void Point::_pushToBatch(GeometryBatch& geometryBatch) const {
            Quad quad;
            Point bottomLeftPoint = *this;

            bottomLeftPoint.setPosition(getPosition() - glm::vec2 { static_cast<float>((size / 2)) });
            quad.setSquare(bottomLeftPoint, static_cast<float>(size));

            geometryBatch.addPrimitive(quad);
        }

    }

}
<|endoftext|>


<commit_before>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

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

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

Author(s) / Copyright (s): Damon Hart-Davis 2016
*/

/*
 * OpenTRV radiator valve physical UI controls and output as an actuator.
 *
 * A base class, a null class, and one or more implementations are provided
 * for different stock behaviour with different hardware.
 *
 * A mixture of template and constructor parameters
 * is used to configure the different types.
 */

#include <stddef.h>
#include <stdint.h>
#include <OTV0p2Base.h>

#include <OTRadValve_ActuatorPhysicalUI.h>

// Use namespaces to help avoid collisions.
namespace OTRadValve
    {

#if defined(ModeButtonAndPotActuatorPhysicalUI_DEFINED)
//// Use WDT-based timer for xxxPause() routines.
//// Very tiny low-power sleep.
//static const uint8_t VERYTINY_PAUSE_MS = 5;
//static void inline veryTinyPause() { OTV0P2BASE::sleepLowPowerMs(VERYTINY_PAUSE_MS); }
//// Tiny low-power sleep to approximately match the PICAXE V0.09 routine of the same name.
//static const uint8_t TINY_PAUSE_MS = 15;
//static void inline tinyPause() { OTV0P2BASE::nap(WDTO_15MS); } // 15ms vs 18ms nominal for PICAXE V0.09 impl.
//// Small low-power sleep.
//static const uint8_t SMALL_PAUSE_MS = 30;
//static void inline smallPause() { OTV0P2BASE::nap(WDTO_30MS); }
//// Medium low-power sleep to approximately match the PICAXE V0.09 routine of the same name.
//// Premature wakeups MAY be allowed to avoid blocking I/O polling for too long.
//static const uint8_t MEDIUM_PAUSE_MS = 60;
//static void inline mediumPause() { OTV0P2BASE::nap(WDTO_60MS); } // 60ms vs 144ms nominal for PICAXE V0.09 impl.
//// Big low-power sleep to approximately match the PICAXE V0.09 routine of the same name.
//// Premature wakeups MAY be allowed to avoid blocking I/O polling for too long.
//static const uint8_t BIG_PAUSE_MS = 120;
//static void inline bigPause() { OTV0P2BASE::nap(WDTO_120MS); } // 120ms vs 288ms nominal for PICAXE V0.09 impl.
//
//// Pause between flashes to allow them to be distinguished (>100ms); was mediumPause() for PICAXE V0.09 impl.
//static void inline offPause()
//  {
//  bigPause(); // 120ms, was V0.09 144ms mediumPause() for PICAXE V0.09 impl.
////  pollIO(); // Slip in an I/O poll.
//  }

// Record local manual operation of a physical UI control, eg not remote or via CLI.
// Marks room as occupied amongst other things.
// To be thread-/ISR- safe, everything that this touches or calls must be.
// Thread-safe.
void ModeButtonAndPotActuatorPhysicalUI::markUIControlUsed()
    {
    statusChange = true; // Note user interaction with the system.
    uiTimeoutM = UI_DEFAULT_RECENT_USE_TIMEOUT_M; // Ensure that UI controls are kept 'warm' for a little while.
// FIXME
//  #if defined(ENABLE_UI_WAKES_CLI)
//    // Make CLI active for a while (at some slight possibly-significant energy cost).
//    resetCLIActiveTimer(); // Thread-safe.
//  #endif
    // User operation of physical controls is strong indication of presence.
    occupancy->markAsOccupied(); // Thread-safe.
    }

// Record significant local manual operation of a physical UI control, eg not remote or via CLI.
// Marks room as occupied amongst other things.
// As markUIControlUsed() but likely to generate some feedback to the user, ASAP.
// Thread-safe.
void ModeButtonAndPotActuatorPhysicalUI::markUIControlUsedSignificant()
    {
    // Provide some instant visual feedback if possible.
    if(NULL != safeISRLEDonOpt) { safeISRLEDonOpt(); }
    // Flag up need for feedback.
    significantUIOp = true;
    // Do main UI-touched work.
    markUIControlUsed();
    }

// Call this nominally on even numbered seconds to allow the UI to operate.
// In practice call early once per 2s major cycle.
// Should never be skipped, so as to allow the UI to remain responsive.
// Runs in 350ms or less; usually takes only a few milliseconds or microseconds.
// Returns a non-zero value iff the user interacted with the system, and maybe caused a status change.
// NOTE: since this is on the minimum idle-loop code path, minimise CPU cycles, esp in frost mode.
// Replaces: bool tickUI(uint_fast8_t sec).
uint8_t ModeButtonAndPotActuatorPhysicalUI::read()
    {
    // True on every 4th tick/call, ie every ~8 seconds.
    const bool forthTick = !((++tickCount) & 3); // True on every 4th tick.

    // Perform any once-per-minute-ish operations, every 32 ticks.
    const bool sec0 = (0 == (tickCount & 0x1f));
    if(sec0)
      {
      ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
        {
        // Run down UI interaction timer if need be, one tick per minute(ish).
        if(uiTimeoutM > 0) { --uiTimeoutM; }
        }
      }

//    const bool reportedRecently = occupancy->reportedRecently();

    // Provide enhanced feedback when the has been very recent interaction with the UI,
    // since the user is still quite likely to be continuing.
    const bool enhancedUIFeedback = veryRecentUIControlUse();

    if(NULL != tempPotOpt)
        {
        // Force relatively-frequent re-read of temp pot UI device
        // and if there has been recent UI manual controls activity,
        // to keep the valve UI responsive.
    //  #if !defined(ENABLE_FAST_TEMP_POT_SAMPLING) || !defined(ENABLE_OCCUPANCY_SUPPORT)
    //    if(enhancedUIFeedback || forthTick)
    //  #else
    //    // Even more responsive at some possible energy cost...
        // Polls pot on every tick unless the room has been vacant for a day or two or is in FROST mode.
        if(enhancedUIFeedback || forthTick || (valveMode->inWarmMode() && !occupancy->longLongVacant()))
    //  #endif
          {
          tempPotOpt->read();
      #if 0 && defined(DEBUG)
            DEBUG_SERIAL_PRINT_FLASHSTRING("TP");
            DEBUG_SERIAL_PRINT(TempPot.getRaw());
            DEBUG_SERIAL_PRINTLN();
      #endif
          // Force to FROST mode (and cancel any erroneous BAKE, etc) when at FROST end of dial.
          const bool isLo = tempPotOpt->isAtLoEndStop();
          if(isLo) { valveMode->setWarmModeDebounced(false); }
          // Feed back significant change in pot position, ie at temperature boundaries.
          // Synthesise a 'warm' target temp that distinguishes the end stops...
          const uint8_t nominalWarmTarget = isLo ? 1 :
              (tempPotOpt->isAtHiEndStop() ? 99 :
              tempControl->getWARMTargetC());
          // Record of 'last' nominalWarmTarget; initially 0.
          static uint8_t lastNominalWarmTarget;
          if(nominalWarmTarget != lastNominalWarmTarget)
            {
            // Note if a boundary was crossed, ignoring any false 'start-up' transient.
            if(0 != lastNominalWarmTarget) { significantUIOp = true; }
      #if 1 && defined(DEBUG)
            DEBUG_SERIAL_PRINT_FLASHSTRING("WT");
            DEBUG_SERIAL_PRINT(nominalWarmTarget);
            DEBUG_SERIAL_PRINTLN();
      #endif
            lastNominalWarmTarget = nominalWarmTarget;
            }
          }
      }

    // Provide extra user feedback for significant UI actions...
    if(significantUIOp) { userOpFeedback(); }

    // Support cycling through modes polling the MODE button.
    // If MODE button is active skip normal LED UI activity.
    if(!pollMODEButton())
      {
      // Keep reporting UI status if the user has just touched the unit in some way or UI feedback is enhanced.
      const bool justTouched = statusChange || enhancedUIFeedback;

      // Mode button not pressed: indicate current mode with flash(es); more flashes if actually calling for heat.
      // Force display while UI controls are being used, eg to indicate temp pot position.
      if(justTouched || valveMode->inWarmMode()) // Generate flash(es) if in WARM mode or fiddling with UI other than Mode button.
        {
        // DHD20131223: only flash if the room not known to be dark so as to save energy and avoid disturbing sleep, etc.
        // In this case force resample of light level frequently in case user turns light on eg to operate unit.
        // Do show LED flash if user has recently operated controls (other than mode button) manually.
        // Flash infrequently if no recently operated controls and not in BAKE mode and not actually calling for heat;
        // this is to conserve batteries for those people who leave the valves in WARM mode all the time.
        if(justTouched ||
           ((forthTick
               || valveController->isCallingForHeat()
               || valveMode->inBakeMode()) && !ambLight->isRoomDark()))
          {
          // First flash to indicate WARM mode (or pot being twiddled).
          LEDon();
          // LED on stepwise proportional to temp pot setting.
          // Small number of steps (3) should help make positioning more obvious.
          const uint8_t wt = tempControl->getWARMTargetC();
          // Makes vtiny|tiny|medium flash for cool|OK|warm temperature target.
          // Stick to minimum length flashes to save energy unless just touched.
          if(!justTouched || tempControl->isEcoTemperature(wt)) { veryTinyPause(); }
          else if(!tempControl->isComfortTemperature(wt)) { tinyPause(); }
          else { mediumPause(); }

          // Second flash to indicate actually calling for heat,
          // or likely to be calling for heat while interacting with the controls, to give fast user feedback (TODO-695).
          if((enhancedUIFeedback && valveController->isUnderTarget()) ||
              valveController->isCallingForHeat() ||
              valveMode->inBakeMode())
            {
            LEDoff();
            offPause(); // V0.09 was mediumPause().
            LEDon(); // flash
            // Stick to minimum length flashes to save energy unless just touched.
            if(!justTouched || tempControl->isEcoTemperature(wt)) { veryTinyPause(); }
            else if(!tempControl->isComfortTemperature(wt)) { OTV0P2BASE::sleepLowPowerMs((VERYTINY_PAUSE_MS + TINY_PAUSE_MS) / 2); }
            else { tinyPause(); }

            if(valveMode->inBakeMode())
              {
              // Third (lengthened) flash to indicate BAKE mode.
              LEDoff();
              mediumPause(); // Note different flash off time to try to distinguish this last flash.
              LEDon();
              // Makes tiny|small|medium flash for eco|OK|comfort temperature target.
              // Stick to minimum length flashes to save energy unless just touched.
              if(!justTouched || tempControl->isEcoTemperature(wt)) { veryTinyPause(); }
              else if(!tempControl->isComfortTemperature(wt)) { smallPause(); }
              else { mediumPause(); }
              }
            }
          }
        }

      // Even in FROST mode, and if actually calling for heat (eg opening the rad valve significantly, etc)
      // then emit a tiny double flash on every 4th tick.
      // This call for heat may be frost protection or pre-warming / anticipating demand.
      // DHD20130528: new 4th-tick flash in FROST mode...
      // DHD20131223: only flash if the room is not dark (ie or if no working light sensor) so as to save energy and avoid disturbing sleep, etc.
      else if(forthTick &&
              !ambLight->isRoomDark() &&
              valveController->isCallingForHeat() /* &&
              NominalRadValve.isControlledValveReallyOpen() */ )
        {
        // Double flash every 4th tick indicates call for heat while in FROST MODE (matches call for heat in WARM mode).
        LEDon(); // flash
        veryTinyPause();
        LEDoff();
        offPause();
        LEDon(); // flash
        veryTinyPause();
        }

      }

    // Ensure that the LED forced off unconditionally at least once each cycle.
    LEDoff();

    // Handle LEARN buttons (etc) in derived classes.
    // Also can be used to handle any simple user schedules.
    handleOtherUserControls(statusChange);

    const bool statusChanged = statusChange;
    statusChange = false; // Potential race.
    return(statusChanged);
    }

#endif // ModeButtonAndPotActuatorPhysicalUI_DEFINED

    }
<commit_msg>tidyup<commit_after>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

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

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

Author(s) / Copyright (s): Damon Hart-Davis 2016
*/

/*
 * OpenTRV radiator valve physical UI controls and output as an actuator.
 *
 * A base class, a null class, and one or more implementations are provided
 * for different stock behaviour with different hardware.
 *
 * A mixture of template and constructor parameters
 * is used to configure the different types.
 */

#include <stddef.h>
#include <stdint.h>
#include <OTV0p2Base.h>

#include <OTRadValve_ActuatorPhysicalUI.h>

// Use namespaces to help avoid collisions.
namespace OTRadValve
    {

#if defined(ModeButtonAndPotActuatorPhysicalUI_DEFINED)
//// Use WDT-based timer for xxxPause() routines.
//// Very tiny low-power sleep.
//static const uint8_t VERYTINY_PAUSE_MS = 5;
//static void inline veryTinyPause() { OTV0P2BASE::sleepLowPowerMs(VERYTINY_PAUSE_MS); }
//// Tiny low-power sleep to approximately match the PICAXE V0.09 routine of the same name.
//static const uint8_t TINY_PAUSE_MS = 15;
//static void inline tinyPause() { OTV0P2BASE::nap(WDTO_15MS); } // 15ms vs 18ms nominal for PICAXE V0.09 impl.
//// Small low-power sleep.
//static const uint8_t SMALL_PAUSE_MS = 30;
//static void inline smallPause() { OTV0P2BASE::nap(WDTO_30MS); }
//// Medium low-power sleep to approximately match the PICAXE V0.09 routine of the same name.
//// Premature wakeups MAY be allowed to avoid blocking I/O polling for too long.
//static const uint8_t MEDIUM_PAUSE_MS = 60;
//static void inline mediumPause() { OTV0P2BASE::nap(WDTO_60MS); } // 60ms vs 144ms nominal for PICAXE V0.09 impl.
//// Big low-power sleep to approximately match the PICAXE V0.09 routine of the same name.
//// Premature wakeups MAY be allowed to avoid blocking I/O polling for too long.
//static const uint8_t BIG_PAUSE_MS = 120;
//static void inline bigPause() { OTV0P2BASE::nap(WDTO_120MS); } // 120ms vs 288ms nominal for PICAXE V0.09 impl.
//
//// Pause between flashes to allow them to be distinguished (>100ms); was mediumPause() for PICAXE V0.09 impl.
//static void inline offPause()
//  {
//  bigPause(); // 120ms, was V0.09 144ms mediumPause() for PICAXE V0.09 impl.
////  pollIO(); // Slip in an I/O poll.
//  }

// Record local manual operation of a physical UI control, eg not remote or via CLI.
// Marks room as occupied amongst other things.
// To be thread-/ISR- safe, everything that this touches or calls must be.
// Thread-safe.
void ModeButtonAndPotActuatorPhysicalUI::markUIControlUsed()
    {
    statusChange = true; // Note user interaction with the system.
    uiTimeoutM = UI_DEFAULT_RECENT_USE_TIMEOUT_M; // Ensure that UI controls are kept 'warm' for a little while.
// FIXME
//  #if defined(ENABLE_UI_WAKES_CLI)
//    // Make CLI active for a while (at some slight possibly-significant energy cost).
//    resetCLIActiveTimer(); // Thread-safe.
//  #endif
    // User operation of physical controls is strong indication of presence.
    occupancy->markAsOccupied(); // Thread-safe.
    }

// Record significant local manual operation of a physical UI control, eg not remote or via CLI.
// Marks room as occupied amongst other things.
// As markUIControlUsed() but likely to generate some feedback to the user, ASAP.
// Thread-safe.
void ModeButtonAndPotActuatorPhysicalUI::markUIControlUsedSignificant()
    {
    // Provide some instant visual feedback if possible.
    if(NULL != safeISRLEDonOpt) { safeISRLEDonOpt(); }
    // Flag up need for feedback.
    significantUIOp = true;
    // Do main UI-touched work.
    markUIControlUsed();
    }

// Call this nominally on even numbered seconds to allow the UI to operate.
// In practice call early once per 2s major cycle.
// Should never be skipped, so as to allow the UI to remain responsive.
// Runs in 350ms or less; usually takes only a few milliseconds or microseconds.
// Returns a non-zero value iff the user interacted with the system, and maybe caused a status change.
// NOTE: since this is on the minimum idle-loop code path, minimise CPU cycles, esp in frost mode.
// Replaces: bool tickUI(uint_fast8_t sec).
uint8_t ModeButtonAndPotActuatorPhysicalUI::read()
    {
    // True on every 4th tick/call, ie every ~8 seconds.
    const bool forthTick = !((++tickCount) & 3); // True on every 4th tick.

    // Perform any once-per-minute-ish operations, every 32 ticks.
    const bool sec0 = (0 == (tickCount & 0x1f));
    if(sec0)
      {
      ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
        {
        // Run down UI interaction timer if need be, one tick per minute(ish).
        if(uiTimeoutM > 0) { --uiTimeoutM; }
        }
      }

//    const bool reportedRecently = occupancy->reportedRecently();

    // Provide enhanced feedback when the has been very recent interaction with the UI,
    // since the user is still quite likely to be continuing.
    const bool enhancedUIFeedback = veryRecentUIControlUse();

    if(NULL != tempPotOpt)
        {
        // Force relatively-frequent re-read of temp pot UI device
        // and if there has been recent UI manual controls activity,
        // to keep the valve UI responsive.
    //  #if !defined(ENABLE_FAST_TEMP_POT_SAMPLING) || !defined(ENABLE_OCCUPANCY_SUPPORT)
    //    if(enhancedUIFeedback || forthTick)
    //  #else
    //    // Even more responsive at some possible energy cost...
        // Polls pot on every tick unless the room has been vacant for a day or two or is in FROST mode.
        if(enhancedUIFeedback || forthTick || (valveMode->inWarmMode() && !occupancy->longLongVacant()))
    //  #endif
          {
          tempPotOpt->read();
      #if 0 && defined(DEBUG)
            DEBUG_SERIAL_PRINT_FLASHSTRING("TP");
            DEBUG_SERIAL_PRINT(TempPot.getRaw());
            DEBUG_SERIAL_PRINTLN();
      #endif
          // Force to FROST mode (and cancel any erroneous BAKE, etc) when at FROST end of dial.
          const bool isLo = tempPotOpt->isAtLoEndStop();
          if(isLo) { valveMode->setWarmModeDebounced(false); }
          // Feed back significant change in pot position, ie at temperature boundaries.
          // Synthesise a 'hot' target temperature that distinguishes the end stops...
          const uint8_t nominalWarmTarget = isLo ? 1 :
              (tempPotOpt->isAtHiEndStop() ? 99 :
              tempControl->getWARMTargetC());
          // Record of 'last' nominalWarmTarget; initially 0.
          static uint8_t lastNominalWarmTarget;
          if(nominalWarmTarget != lastNominalWarmTarget)
            {
            // Note if a boundary was crossed, ignoring any false 'start-up' transient.
            if(0 != lastNominalWarmTarget) { significantUIOp = true; }
      #if 1 && defined(DEBUG)
            DEBUG_SERIAL_PRINT_FLASHSTRING("WT");
            DEBUG_SERIAL_PRINT(nominalWarmTarget);
            DEBUG_SERIAL_PRINTLN();
      #endif
            lastNominalWarmTarget = nominalWarmTarget;
            }
          }
      }

    // Provide extra user feedback for significant UI actions...
    if(significantUIOp) { userOpFeedback(); }

    // Support cycling through modes polling the MODE button.
    // If MODE button is active skip normal LED UI activity.
    if(!pollMODEButton())
      {
      // Keep reporting UI status if the user has just touched the unit in some way or UI feedback is enhanced.
      const bool justTouched = statusChange || enhancedUIFeedback;

      // Mode button not pressed: indicate current mode with flash(es); more flashes if actually calling for heat.
      // Force display while UI controls are being used, eg to indicate temp pot position.
      if(justTouched || valveMode->inWarmMode()) // Generate flash(es) if in WARM mode or fiddling with UI other than Mode button.
        {
        // DHD20131223: only flash if the room not known to be dark so as to save energy and avoid disturbing sleep, etc.
        // In this case force resample of light level frequently in case user turns light on eg to operate unit.
        // Do show LED flash if user has recently operated controls (other than mode button) manually.
        // Flash infrequently if no recently operated controls and not in BAKE mode and not actually calling for heat;
        // this is to conserve batteries for those people who leave the valves in WARM mode all the time.
        if(justTouched ||
           ((forthTick
               || valveController->isCallingForHeat()
               || valveMode->inBakeMode()) && !ambLight->isRoomDark()))
          {
          // First flash to indicate WARM mode (or pot being twiddled).
          LEDon();
          // LED on stepwise proportional to temp pot setting.
          // Small number of steps (3) should help make positioning more obvious.
          const uint8_t wt = tempControl->getWARMTargetC();
          // Makes vtiny|tiny|medium flash for cool|OK|warm temperature target.
          // Stick to minimum length flashes to save energy unless just touched.
          if(!justTouched || tempControl->isEcoTemperature(wt)) { veryTinyPause(); }
          else if(!tempControl->isComfortTemperature(wt)) { tinyPause(); }
          else { mediumPause(); }

          // Second flash to indicate actually calling for heat,
          // or likely to be calling for heat while interacting with the controls, to give fast user feedback (TODO-695).
          if((enhancedUIFeedback && valveController->isUnderTarget()) ||
              valveController->isCallingForHeat() ||
              valveMode->inBakeMode())
            {
            LEDoff();
            offPause(); // V0.09 was mediumPause().
            LEDon(); // flash
            // Stick to minimum length flashes to save energy unless just touched.
            if(!justTouched || tempControl->isEcoTemperature(wt)) { veryTinyPause(); }
            else if(!tempControl->isComfortTemperature(wt)) { OTV0P2BASE::sleepLowPowerMs((VERYTINY_PAUSE_MS + TINY_PAUSE_MS) / 2); }
            else { tinyPause(); }

            if(valveMode->inBakeMode())
              {
              // Third (lengthened) flash to indicate BAKE mode.
              LEDoff();
              mediumPause(); // Note different flash off time to try to distinguish this last flash.
              LEDon();
              // Makes tiny|small|medium flash for eco|OK|comfort temperature target.
              // Stick to minimum length flashes to save energy unless just touched.
              if(!justTouched || tempControl->isEcoTemperature(wt)) { veryTinyPause(); }
              else if(!tempControl->isComfortTemperature(wt)) { smallPause(); }
              else { mediumPause(); }
              }
            }
          }
        }

      // Even in FROST mode, and if actually calling for heat (eg opening the rad valve significantly, etc)
      // then emit a tiny double flash on every 4th tick.
      // This call for heat may be frost protection or pre-warming / anticipating demand.
      // DHD20130528: new 4th-tick flash in FROST mode...
      // DHD20131223: only flash if the room is not dark (ie or if no working light sensor) so as to save energy and avoid disturbing sleep, etc.
      else if(forthTick &&
              !ambLight->isRoomDark() &&
              valveController->isCallingForHeat() /* &&
              NominalRadValve.isControlledValveReallyOpen() */ )
        {
        // Double flash every 4th tick indicates call for heat while in FROST MODE (matches call for heat in WARM mode).
        LEDon(); // flash
        veryTinyPause();
        LEDoff();
        offPause();
        LEDon(); // flash
        veryTinyPause();
        }
      }

    // Ensure that the main UI LED is forced off unconditionally at least once each cycle.
    LEDoff();

    // Handle LEARN buttons (etc) in derived classes.
    // Also can be used to handle any simple user schedules.
    handleOtherUserControls(statusChange);

    const bool statusChanged = statusChange;
    statusChange = false; // Potential race.
    return(statusChanged);
    }

#endif // ModeButtonAndPotActuatorPhysicalUI_DEFINED

    }
<|endoftext|>


<commit_before>//---------------------------------------------------------
// Copyright 2018 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_vcf2fasta - write a new genome sequence
// by introducing variants from a set of vcf files
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <map>
#include <inttypes.h>
#include <assert.h>
#include <math.h>
#include <sys/time.h>
#include <algorithm>
#include <sstream>
#include <set>
#include <omp.h>
#include <getopt.h>
#include <fast5.hpp>
#include "htslib/faidx.h"
#include "nanopolish_common.h"
#include "nanopolish_variant.h"
#include "nanopolish_eventalign.h"
#include "nanopolish_haplotype.h"

//
// Getopt
//
#define SUBPROGRAM "vcf2fasta"

static const char *VCF2FASTA_VERSION_MESSAGE =
SUBPROGRAM " Version " PACKAGE_VERSION "\n"
"Written by Jared Simpson.\n"
"\n"
"Copyright 2018 Ontario Institute for Cancer Research\n";

static const char *VCF2FASTA_USAGE_MESSAGE =
"Usage: " PACKAGE_NAME " " SUBPROGRAM " [OPTIONS] segment1.vcf segment2.vcf ...\n"
"Write a new genome sequence by introducing variants from the input files\n"
"\n"
"  -v, --verbose                        display verbose output\n"
"      --version                        display version\n"
"      --help                           display this help and exit\n"
"  -g, --genome=FILE                    the input genome is in FILE\n"
"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";

namespace opt
{
    static unsigned int verbose;
    static std::vector<std::string> input_vcf_files;
    static std::string genome_file;
}

static const char* shortopts = "g:v";

enum { OPT_HELP = 1, OPT_VERSION };

static const struct option longopts[] = {
    { "verbose",     no_argument,       NULL, 'v' },
    { "help",        no_argument,       NULL, OPT_HELP },
    { "version",     no_argument,       NULL, OPT_VERSION },
    { "genome",      required_argument, NULL, 'g' },
    { NULL, 0, NULL, 0 }
};

void parse_vcf2fasta_options(int argc, char** argv)
{
    bool die = false;
    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
        std::istringstream arg(optarg != NULL ? optarg : "");
        switch (c) {
            case '?': die = true; break;
            case 'v': opt::verbose++; break;
            case 'g': arg >> opt::genome_file; break;
            case OPT_HELP:
                std::cout << VCF2FASTA_USAGE_MESSAGE;
                exit(EXIT_SUCCESS);
            case OPT_VERSION:
                std::cout << VCF2FASTA_VERSION_MESSAGE;
                exit(EXIT_SUCCESS);
        }
    }

    if (argc - optind < 1) {
        std::cerr << SUBPROGRAM ": not enough arguments\n";
        die = true;
    }

    if (die)
    {
        std::cout << "\n" << VCF2FASTA_USAGE_MESSAGE;
        exit(EXIT_FAILURE);
    }

    for(; optind < argc; ++optind) {
        opt::input_vcf_files.push_back(argv[optind]);
    }
}

int vcf2fasta_main(int argc, char** argv)
{
    parse_vcf2fasta_options(argc, argv);

    // Read genome file
    faidx_t *fai = fai_load(opt::genome_file.c_str());

    // Read VCF files and gather variants for each contig and the polishing window coordinates
    std::map<std::string, std::vector<Variant>> variants_by_contig;
    std::map<std::string, std::vector<std::pair<int, int>>> windows_by_contig;

    for(const auto& filename : opt::input_vcf_files) {

        std::string window_str;
        std::vector<Variant> out;
        std::ifstream infile(filename);
        std::string line;
        while(getline(infile, line)) {

            // parse header
            if(line[0] == '#') {

                // check for window coordinates
                if(line.find("nanopolish_window") != std::string::npos) {
                    std::vector<std::string> fields = split(line, '=');
                    assert(fields.size() == 2);
                    window_str = fields[1];
                }
            } else {
                Variant v(line);
                variants_by_contig[v.ref_name].push_back(v);
            }
        }

        if(window_str.empty()) {
            fprintf(stderr, "error: could not detect polishing window from input file %s\n", filename.c_str());
            exit(EXIT_FAILURE);
        }

        std::string window_contig;
        int window_start, window_end;
        parse_region_string(window_str, window_contig, window_start, window_end);
        windows_by_contig[window_contig].push_back(std::make_pair(window_start, window_end));
    }

    size_t n_contigs = faidx_nseq(fai);

    for(size_t contig_idx = 0; contig_idx < n_contigs; ++contig_idx) {
        std::string contig = faidx_iseq(fai, contig_idx);
        int contig_length = faidx_seq_len(fai, contig.c_str());

        // Confirm that all windows on this contig have been polished
        bool window_check_ok = true;
        auto& windows = windows_by_contig[contig];

        std::sort(windows.begin(), windows.end());
        if(windows[0].first != 0) {
            fprintf(stderr, "error: first %d bases are not covered by a polished window for contig %s.\n", windows[0].first, contig.c_str());
            window_check_ok = false;
        }

        for(size_t window_idx = 1; window_idx < windows.size(); ++window_idx) {
            int prev_start = windows[window_idx - 1].first;
            int prev_end = windows[window_idx - 1].second;
            int curr_start = windows[window_idx].first;
            int curr_end = windows[window_idx].second;
            if(curr_start > prev_end) {
                fprintf(stderr, "error: adjacent polishing windows do not overlap (%d-%d and %d-%d)\n", prev_start, prev_end, curr_start, curr_end);
                window_check_ok = false;
            }
        }

        int end_gap = contig_length - windows.back().second;
        if(end_gap > 500) {
            fprintf(stderr, "error: last %d bases are not covered by a polished window for contig %s.\n", end_gap, contig.c_str());
            window_check_ok = false;
        }

        if(!window_check_ok) {
            fprintf(stderr, "error: one or more polishing windows are missing. Please check that all nanopolish variants --consensus jobs ran to completion\n");
            exit(EXIT_FAILURE);
        }

        int length;
        char* seq = fai_fetch(fai, contig.c_str(), &length);
        if(length < 0) {
            fprintf(stderr, "error: could not fetch contig %s\n", contig.c_str());
            exit(EXIT_FAILURE);
        }

        auto& variants = variants_by_contig[contig];
        std::sort(variants.begin(), variants.end(), sortByPosition);

        // remove duplicate variants
        VariantKeyEqualityComp vkec;
        auto last = std::unique(variants.begin(), variants.end(), vkec);
        variants.erase(last, variants.end());

        assert(variants.size() < (1 << 30));
        uint32_t deleted_tag = 1 << 30;
        uint32_t variant_tag = 1 << 31;

        // make a vector holding either a literal character or an index to the variant that needs to be applied
        std::vector<uint32_t> consensus_record(length);
        for(size_t i = 0; i < length; ++i) {
            consensus_record[i] = seq[i];
        }

        size_t num_skipped = 0;
        size_t num_subs = 0;
        size_t num_insertions = 0;
        size_t num_deletions = 0;

        // update the consensus record according to the variants for this contig
        size_t applied_variants = 0;
        for(size_t variant_idx = 0; variant_idx < variants.size(); ++variant_idx) {
            const Variant& v = variants[variant_idx];

            // check if the variant record matches the reference sequence
            bool matches_ref = true;
            for(size_t i = 0; i < v.ref_seq.length(); ++i) {
                matches_ref = matches_ref && v.ref_seq[i] == consensus_record[v.ref_position + i];
            }

            if(!matches_ref) {
                num_skipped += 1;
                continue;
            }

            // mark the first base of the reference sequence as a variant and set the index
            consensus_record[v.ref_position] = variant_tag | variant_idx;

            // mark the subsequent bases of the reference as deleted
            for(size_t i = 1; i < v.ref_seq.length(); ++i) {
                consensus_record[v.ref_position + i] = deleted_tag;
            }

            num_subs += v.ref_seq.length() == v.alt_seq.length();
            num_insertions += v.ref_seq.length() < v.alt_seq.length();
            num_deletions += v.ref_seq.length() > v.alt_seq.length();
        }

        // write out the consensus record
        std::string out;
        out.reserve(length);
        for(size_t i = 0; i < length; ++i) {
            uint32_t r = consensus_record[i];
            if(r & variant_tag) {
                out.append(variants[r & ~variant_tag].alt_seq);
            } else if(r & ~deleted_tag) {
                out.append(1, r);
            } else {
                assert(r & deleted_tag);
            }
        }

        fprintf(stderr, "[vcf2fasta] rewrote contig %s with %zu subs, %zu ins, %zu dels (%zu skipped)\n", contig.c_str(), num_subs, num_insertions, num_deletions, num_skipped);
        fprintf(stdout, ">%s\n%s\n", contig.c_str(), out.c_str());

        free(seq);
        seq = NULL;
    }

    return 0;
}
<commit_msg>vcf2fasta: -g parameter is required<commit_after>//---------------------------------------------------------
// Copyright 2018 Ontario Institute for Cancer Research
// Written by Jared Simpson (jared.simpson@oicr.on.ca)
//---------------------------------------------------------
//
// nanopolish_vcf2fasta - write a new genome sequence
// by introducing variants from a set of vcf files
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <map>
#include <inttypes.h>
#include <assert.h>
#include <math.h>
#include <sys/time.h>
#include <algorithm>
#include <sstream>
#include <set>
#include <omp.h>
#include <getopt.h>
#include <fast5.hpp>
#include "htslib/faidx.h"
#include "nanopolish_common.h"
#include "nanopolish_variant.h"
#include "nanopolish_eventalign.h"
#include "nanopolish_haplotype.h"

//
// Getopt
//
#define SUBPROGRAM "vcf2fasta"

static const char *VCF2FASTA_VERSION_MESSAGE =
SUBPROGRAM " Version " PACKAGE_VERSION "\n"
"Written by Jared Simpson.\n"
"\n"
"Copyright 2018 Ontario Institute for Cancer Research\n";

static const char *VCF2FASTA_USAGE_MESSAGE =
"Usage: " PACKAGE_NAME " " SUBPROGRAM " -g draft.fa segment1.vcf segment2.vcf ...\n"
"Write a new genome sequence by introducing variants from the input files\n"
"\n"
"  -v, --verbose                        display verbose output\n"
"      --version                        display version\n"
"      --help                           display this help and exit\n"
"  -g, --genome=FILE                    the input genome is in FILE\n"
"\nReport bugs to " PACKAGE_BUGREPORT "\n\n";

namespace opt
{
    static unsigned int verbose;
    static std::vector<std::string> input_vcf_files;
    static std::string genome_file;
}

static const char* shortopts = "g:v";

enum { OPT_HELP = 1, OPT_VERSION };

static const struct option longopts[] = {
    { "verbose",     no_argument,       NULL, 'v' },
    { "help",        no_argument,       NULL, OPT_HELP },
    { "version",     no_argument,       NULL, OPT_VERSION },
    { "genome",      required_argument, NULL, 'g' },
    { NULL, 0, NULL, 0 }
};

void parse_vcf2fasta_options(int argc, char** argv)
{
    bool die = false;
    for (char c; (c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1;) {
        std::istringstream arg(optarg != NULL ? optarg : "");
        switch (c) {
            case '?': die = true; break;
            case 'v': opt::verbose++; break;
            case 'g': arg >> opt::genome_file; break;
            case OPT_HELP:
                std::cout << VCF2FASTA_USAGE_MESSAGE;
                exit(EXIT_SUCCESS);
            case OPT_VERSION:
                std::cout << VCF2FASTA_VERSION_MESSAGE;
                exit(EXIT_SUCCESS);
        }
    }

    if(opt::genome_file.empty()) {
        std::cerr << SUBPROGRAM ": -g/--genome file is required\n";
        die = true;
    }

    if (argc - optind < 1) {
        std::cerr << SUBPROGRAM ": not enough arguments\n";
        die = true;
    }

    if (die)
    {
        std::cout << "\n" << VCF2FASTA_USAGE_MESSAGE;
        exit(EXIT_FAILURE);
    }

    for(; optind < argc; ++optind) {
        opt::input_vcf_files.push_back(argv[optind]);
    }
}

int vcf2fasta_main(int argc, char** argv)
{
    parse_vcf2fasta_options(argc, argv);

    // Read genome file
    faidx_t *fai = fai_load(opt::genome_file.c_str());

    // Read VCF files and gather variants for each contig and the polishing window coordinates
    std::map<std::string, std::vector<Variant>> variants_by_contig;
    std::map<std::string, std::vector<std::pair<int, int>>> windows_by_contig;

    for(const auto& filename : opt::input_vcf_files) {

        std::string window_str;
        std::vector<Variant> out;
        std::ifstream infile(filename);
        std::string line;
        while(getline(infile, line)) {

            // parse header
            if(line[0] == '#') {

                // check for window coordinates
                if(line.find("nanopolish_window") != std::string::npos) {
                    std::vector<std::string> fields = split(line, '=');
                    assert(fields.size() == 2);
                    window_str = fields[1];
                }
            } else {
                Variant v(line);
                variants_by_contig[v.ref_name].push_back(v);
            }
        }

        if(window_str.empty()) {
            fprintf(stderr, "error: could not detect polishing window from input file %s\n", filename.c_str());
            exit(EXIT_FAILURE);
        }

        std::string window_contig;
        int window_start, window_end;
        parse_region_string(window_str, window_contig, window_start, window_end);
        windows_by_contig[window_contig].push_back(std::make_pair(window_start, window_end));
    }

    size_t n_contigs = faidx_nseq(fai);

    for(size_t contig_idx = 0; contig_idx < n_contigs; ++contig_idx) {
        std::string contig = faidx_iseq(fai, contig_idx);
        int contig_length = faidx_seq_len(fai, contig.c_str());

        // Confirm that all windows on this contig have been polished
        bool window_check_ok = true;
        auto& windows = windows_by_contig[contig];

        std::sort(windows.begin(), windows.end());
        if(windows[0].first != 0) {
            fprintf(stderr, "error: first %d bases are not covered by a polished window for contig %s.\n", windows[0].first, contig.c_str());
            window_check_ok = false;
        }

        for(size_t window_idx = 1; window_idx < windows.size(); ++window_idx) {
            int prev_start = windows[window_idx - 1].first;
            int prev_end = windows[window_idx - 1].second;
            int curr_start = windows[window_idx].first;
            int curr_end = windows[window_idx].second;
            if(curr_start > prev_end) {
                fprintf(stderr, "error: adjacent polishing windows do not overlap (%d-%d and %d-%d)\n", prev_start, prev_end, curr_start, curr_end);
                window_check_ok = false;
            }
        }

        int end_gap = contig_length - windows.back().second;
        if(end_gap > 500) {
            fprintf(stderr, "error: last %d bases are not covered by a polished window for contig %s.\n", end_gap, contig.c_str());
            window_check_ok = false;
        }

        if(!window_check_ok) {
            fprintf(stderr, "error: one or more polishing windows are missing. Please check that all nanopolish variants --consensus jobs ran to completion\n");
            exit(EXIT_FAILURE);
        }

        int length;
        char* seq = fai_fetch(fai, contig.c_str(), &length);
        if(length < 0) {
            fprintf(stderr, "error: could not fetch contig %s\n", contig.c_str());
            exit(EXIT_FAILURE);
        }

        auto& variants = variants_by_contig[contig];
        std::sort(variants.begin(), variants.end(), sortByPosition);

        // remove duplicate variants
        VariantKeyEqualityComp vkec;
        auto last = std::unique(variants.begin(), variants.end(), vkec);
        variants.erase(last, variants.end());

        assert(variants.size() < (1 << 30));
        uint32_t deleted_tag = 1 << 30;
        uint32_t variant_tag = 1 << 31;

        // make a vector holding either a literal character or an index to the variant that needs to be applied
        std::vector<uint32_t> consensus_record(length);
        for(size_t i = 0; i < length; ++i) {
            consensus_record[i] = seq[i];
        }

        size_t num_skipped = 0;
        size_t num_subs = 0;
        size_t num_insertions = 0;
        size_t num_deletions = 0;

        // update the consensus record according to the variants for this contig
        size_t applied_variants = 0;
        for(size_t variant_idx = 0; variant_idx < variants.size(); ++variant_idx) {
            const Variant& v = variants[variant_idx];

            // check if the variant record matches the reference sequence
            bool matches_ref = true;
            for(size_t i = 0; i < v.ref_seq.length(); ++i) {
                matches_ref = matches_ref && v.ref_seq[i] == consensus_record[v.ref_position + i];
            }

            if(!matches_ref) {
                num_skipped += 1;
                continue;
            }

            // mark the first base of the reference sequence as a variant and set the index
            consensus_record[v.ref_position] = variant_tag | variant_idx;

            // mark the subsequent bases of the reference as deleted
            for(size_t i = 1; i < v.ref_seq.length(); ++i) {
                consensus_record[v.ref_position + i] = deleted_tag;
            }

            num_subs += v.ref_seq.length() == v.alt_seq.length();
            num_insertions += v.ref_seq.length() < v.alt_seq.length();
            num_deletions += v.ref_seq.length() > v.alt_seq.length();
        }

        // write out the consensus record
        std::string out;
        out.reserve(length);
        for(size_t i = 0; i < length; ++i) {
            uint32_t r = consensus_record[i];
            if(r & variant_tag) {
                out.append(variants[r & ~variant_tag].alt_seq);
            } else if(r & ~deleted_tag) {
                out.append(1, r);
            } else {
                assert(r & deleted_tag);
            }
        }

        fprintf(stderr, "[vcf2fasta] rewrote contig %s with %zu subs, %zu ins, %zu dels (%zu skipped)\n", contig.c_str(), num_subs, num_insertions, num_deletions, num_skipped);
        fprintf(stdout, ">%s\n%s\n", contig.c_str(), out.c_str());

        free(seq);
        seq = NULL;
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "../stdafx.h"

#include "wcashjson.h"
#include "wpkistore.h"

void WCashJson::Init(v8::Handle<v8::Object> exports){
	METHOD_BEGIN();

	v8::Local<v8::String> className = Nan::New("CashJson").ToLocalChecked();

	// Basic instance setup
	v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);

	tpl->SetClassName(className);
	tpl->InstanceTemplate()->SetInternalFieldCount(1); // req'd by ObjectWrap

	Nan::SetPrototypeMethod(tpl, "import", Import);
	Nan::SetPrototypeMethod(tpl, "export", Export);

	// Store the constructor in the target bindings.
	constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());

	exports->Set(className, tpl->GetFunction());
}

NAN_METHOD(WCashJson::New){
	METHOD_BEGIN();

	try{
		WCashJson *obj = new WCashJson();

		if (info[0]->IsUndefined()){
			Nan::ThrowError("Parameter 1 is required");
			return;
		}
		else {
#if defined(OPENSSL_SYS_WINDOWS)
			LPCWSTR wCont = (LPCWSTR)* v8::String::Value(info[0]->ToString());

			int string_len = WideCharToMultiByte(CP_ACP, 0, wCont, -1, NULL, 0, NULL, NULL);
			if (!string_len) {
				Nan::ThrowError("Error WideCharToMultiByte");
			}

			char* converted = new char[string_len];
			if (!converted) {
				Nan::ThrowError("Error LocalAlloc");
			}

			string_len = WideCharToMultiByte(CP_ACP, 0, wCont, -1, converted, string_len, NULL, NULL);
			if (!string_len)
			{
				free(converted);
				Nan::ThrowError("Error WideCharToMultiByte");
			}

			std::string result = converted;

			delete[] converted;

			const char *json = result.c_str();
#else
			v8::String::Utf8Value v8Str(info[0]->ToString());
			char *json = *v8Str;
#endif // OPENSSL_SYS_WINDOWS
			obj->data_ = new CashJson(new std::string(json));

			obj->Wrap(info.This());

			info.GetReturnValue().Set(info.This());
			return;
		}
	}
	TRY_END();
}

NAN_METHOD(WCashJson::Import) {
	METHOD_BEGIN();

	try {
		LOGGER_ARG("items");
		WPkiItem * wItem = WPkiItem::Unwrap<WPkiItem>(info[0]->ToObject());

		UNWRAP_DATA(CashJson);

		_this->importJson(wItem->data_);
		return;
	}
	TRY_END();
}

NAN_METHOD(WCashJson::Export) {
	METHOD_BEGIN();

	try{
		UNWRAP_DATA(CashJson);

		Handle<PkiItemCollection> res = _this->exportJson();

		v8::Isolate* isolate = v8::Isolate::GetCurrent();

		v8::Local<v8::Array> array8 = v8::Array::New(isolate, res->length());

		for (int i = 0; i < res->length(); i++){
			v8::Local<v8::Object> tempObj = v8::Object::New(isolate);
			Handle<PkiItem> item = res->items(i);

			tempObj->Set(v8::String::NewFromUtf8(isolate, "type"),
				v8::String::NewFromUtf8(isolate, item->type->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "format"),
				v8::String::NewFromUtf8(isolate, item->format->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "provider"),
				v8::String::NewFromUtf8(isolate, item->provider->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "category"),
				v8::String::NewFromUtf8(isolate, item->category->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "uri"),
				v8::String::NewFromUtf8(isolate, item->uri->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "hash"),
				v8::String::NewFromUtf8(isolate, item->hash->c_str()));

			if (strcmp(item->type->c_str(), "CERTIFICATE") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectName"),
					v8::String::NewFromUtf8(isolate, item->certSubjectName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->certSubjectFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerName"),
					v8::String::NewFromUtf8(isolate, item->certIssuerName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->certIssuerFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "notBefore"),
					v8::String::NewFromUtf8(isolate, item->certNotBefore->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "notAfter"),
					v8::String::NewFromUtf8(isolate, item->certNotAfter->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "serial"),
					v8::String::NewFromUtf8(isolate, item->certSerial->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "key"),
					v8::String::NewFromUtf8(isolate, item->certKey->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "organizationName"),
					v8::String::NewFromUtf8(isolate, item->certOrganizationName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->certSignatureAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureDigestAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->certSignatureDigestAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "publicKeyAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->certPublicKeyAlgorithm->c_str()));

				array8->Set(i, tempObj);
				continue;
			}

			if (strcmp(item->type->c_str(), "CRL") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerName"),
					v8::String::NewFromUtf8(isolate, item->crlIssuerName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->crlIssuerFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "lastUpdate"),
					v8::String::NewFromUtf8(isolate, item->crlLastUpdate->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "nextUpdate"),
					v8::String::NewFromUtf8(isolate, item->crlNextUpdate->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->crlSignatureAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureDigestAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->crlSignatureDigestAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "authorityKeyid"),
					v8::String::NewFromUtf8(isolate, item->crlAuthorityKeyid->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "crlNumber"),
					v8::String::NewFromUtf8(isolate, item->crlCrlNumber->c_str()));

				array8->Set(i, tempObj);
				continue;
			}

			if (strcmp(item->type->c_str(), "REQUEST") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectName"),
					v8::String::NewFromUtf8(isolate, item->csrSubjectName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->csrSubjectFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "key"),
					v8::String::NewFromUtf8(isolate, item->csrKey->c_str()));

				array8->Set(i, tempObj);
				continue;
			}

			if (strcmp(item->type->c_str(), "KEY") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "encrypted"),
					v8::Boolean::New(isolate, item->keyEncrypted));

				array8->Set(i, tempObj);
				continue;
			}
		}

		info.GetReturnValue().Set(array8);
		return;
	}

	TRY_END();
}<commit_msg>fix memory released using the 'free' function<commit_after>#include "../stdafx.h"

#include "wcashjson.h"
#include "wpkistore.h"

void WCashJson::Init(v8::Handle<v8::Object> exports){
	METHOD_BEGIN();

	v8::Local<v8::String> className = Nan::New("CashJson").ToLocalChecked();

	// Basic instance setup
	v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);

	tpl->SetClassName(className);
	tpl->InstanceTemplate()->SetInternalFieldCount(1); // req'd by ObjectWrap

	Nan::SetPrototypeMethod(tpl, "import", Import);
	Nan::SetPrototypeMethod(tpl, "export", Export);

	// Store the constructor in the target bindings.
	constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());

	exports->Set(className, tpl->GetFunction());
}

NAN_METHOD(WCashJson::New){
	METHOD_BEGIN();

	try{
		WCashJson *obj = new WCashJson();

		if (info[0]->IsUndefined()){
			Nan::ThrowError("Parameter 1 is required");
			return;
		}
		else {
#if defined(OPENSSL_SYS_WINDOWS)
			LPCWSTR wCont = (LPCWSTR)* v8::String::Value(info[0]->ToString());

			int string_len = WideCharToMultiByte(CP_ACP, 0, wCont, -1, NULL, 0, NULL, NULL);
			if (!string_len) {
				Nan::ThrowError("Error WideCharToMultiByte");
			}

			char* converted = new char[string_len];
			if (!converted) {
				Nan::ThrowError("Error LocalAlloc");
			}

			string_len = WideCharToMultiByte(CP_ACP, 0, wCont, -1, converted, string_len, NULL, NULL);
			if (!string_len)
			{
				delete[] converted;
				Nan::ThrowError("Error WideCharToMultiByte");
			}

			std::string result = converted;

			delete[] converted;

			const char *json = result.c_str();
#else
			v8::String::Utf8Value v8Str(info[0]->ToString());
			char *json = *v8Str;
#endif // OPENSSL_SYS_WINDOWS
			obj->data_ = new CashJson(new std::string(json));

			obj->Wrap(info.This());

			info.GetReturnValue().Set(info.This());
			return;
		}
	}
	TRY_END();
}

NAN_METHOD(WCashJson::Import) {
	METHOD_BEGIN();

	try {
		LOGGER_ARG("items");
		WPkiItem * wItem = WPkiItem::Unwrap<WPkiItem>(info[0]->ToObject());

		UNWRAP_DATA(CashJson);

		_this->importJson(wItem->data_);
		return;
	}
	TRY_END();
}

NAN_METHOD(WCashJson::Export) {
	METHOD_BEGIN();

	try{
		UNWRAP_DATA(CashJson);

		Handle<PkiItemCollection> res = _this->exportJson();

		v8::Isolate* isolate = v8::Isolate::GetCurrent();

		v8::Local<v8::Array> array8 = v8::Array::New(isolate, res->length());

		for (int i = 0; i < res->length(); i++){
			v8::Local<v8::Object> tempObj = v8::Object::New(isolate);
			Handle<PkiItem> item = res->items(i);

			tempObj->Set(v8::String::NewFromUtf8(isolate, "type"),
				v8::String::NewFromUtf8(isolate, item->type->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "format"),
				v8::String::NewFromUtf8(isolate, item->format->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "provider"),
				v8::String::NewFromUtf8(isolate, item->provider->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "category"),
				v8::String::NewFromUtf8(isolate, item->category->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "uri"),
				v8::String::NewFromUtf8(isolate, item->uri->c_str()));

			tempObj->Set(v8::String::NewFromUtf8(isolate, "hash"),
				v8::String::NewFromUtf8(isolate, item->hash->c_str()));

			if (strcmp(item->type->c_str(), "CERTIFICATE") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectName"),
					v8::String::NewFromUtf8(isolate, item->certSubjectName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->certSubjectFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerName"),
					v8::String::NewFromUtf8(isolate, item->certIssuerName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->certIssuerFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "notBefore"),
					v8::String::NewFromUtf8(isolate, item->certNotBefore->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "notAfter"),
					v8::String::NewFromUtf8(isolate, item->certNotAfter->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "serial"),
					v8::String::NewFromUtf8(isolate, item->certSerial->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "key"),
					v8::String::NewFromUtf8(isolate, item->certKey->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "organizationName"),
					v8::String::NewFromUtf8(isolate, item->certOrganizationName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->certSignatureAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureDigestAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->certSignatureDigestAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "publicKeyAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->certPublicKeyAlgorithm->c_str()));

				array8->Set(i, tempObj);
				continue;
			}

			if (strcmp(item->type->c_str(), "CRL") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerName"),
					v8::String::NewFromUtf8(isolate, item->crlIssuerName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "issuerFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->crlIssuerFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "lastUpdate"),
					v8::String::NewFromUtf8(isolate, item->crlLastUpdate->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "nextUpdate"),
					v8::String::NewFromUtf8(isolate, item->crlNextUpdate->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->crlSignatureAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "signatureDigestAlgorithm"),
					v8::String::NewFromUtf8(isolate, item->crlSignatureDigestAlgorithm->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "authorityKeyid"),
					v8::String::NewFromUtf8(isolate, item->crlAuthorityKeyid->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "crlNumber"),
					v8::String::NewFromUtf8(isolate, item->crlCrlNumber->c_str()));

				array8->Set(i, tempObj);
				continue;
			}

			if (strcmp(item->type->c_str(), "REQUEST") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectName"),
					v8::String::NewFromUtf8(isolate, item->csrSubjectName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "subjectFriendlyName"),
					v8::String::NewFromUtf8(isolate, item->csrSubjectFriendlyName->c_str()));

				tempObj->Set(v8::String::NewFromUtf8(isolate, "key"),
					v8::String::NewFromUtf8(isolate, item->csrKey->c_str()));

				array8->Set(i, tempObj);
				continue;
			}

			if (strcmp(item->type->c_str(), "KEY") == 0){
				tempObj->Set(v8::String::NewFromUtf8(isolate, "encrypted"),
					v8::Boolean::New(isolate, item->keyEncrypted));

				array8->Set(i, tempObj);
				continue;
			}
		}

		info.GetReturnValue().Set(array8);
		return;
	}

	TRY_END();
}<|endoftext|>


<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include<atomic>
#include<mutex>
#include<sstream>
#include<string>

#include"ork/file_utils.hpp"
#include"ork/orientation.hpp"
#include"ork/tagger.hpp"

namespace ork {

class tagger_statics {
private:
	file::path _debug_root = { ORK("./debug") };//Global guarded by mutex
	std::mutex _mutex = { };
public:
	tagger_statics() {}
	ORK_NON_COPYABLE(tagger_statics)
public:
	file::path debug_root() {
		std::lock_guard<std::mutex> lock(_mutex);
		return _debug_root;
	}
	void set_debug_root(const file::path&directory) {
		std::lock_guard<std::mutex> lock(_mutex);
		_debug_root = directory;
	}
};
tagger_statics&g_tagger_statics() {
	static tagger_statics statics;
	return statics;
}

struct tagger::impl {
public:
	std::atomic<unsigned>count;//Local static
	const bool number_folder;//Local static constant
	const string tag;//Local static constant
public:
	impl(const string&tag)
		: count(0)
		, number_folder(true)
		, tag(tag)
	{}
	impl(const string&tag, const bool numbered_folders)
		: count(0)
		, number_folder(numbered_folders)
		, tag(tag)
	{}
	ORK_NON_COPYABLE(impl)
};

tagger::tagger(const string&tag) : _pimpl{ new impl(tag) } {}
tagger::tagger(const string&tag, bool numbered_folders) : _pimpl{ new impl(tag, numbered_folders) } {}
tagger::~tagger() {}

string tagger::sub_tag(const string&tag, size_t&index) {
	string_stream stream;
	stream << tag << index++ << ORK("_");
	return stream.str();
}

string tagger::operator()() {
	string_stream stream;
	file::path p(g_tagger_statics().debug_root());
	if(_pimpl->number_folder) {
		stream << _pimpl->tag << ORK("_") << _pimpl->count++ << ORK("/");
		p /= stream.str();
		return p.ORK_GEN_STR();
	}
	else {
		stream << _pimpl->tag << ORK("/");
		p /= stream.str();
		return p.ORK_GEN_STR() + std::to_string(_pimpl->count++) + ORK("_");
	}
}

unsigned tagger::count() {
	return _pimpl->count.load();
}

void tagger::set_debug_root(const string&directory) {
	g_tagger_statics().set_debug_root(directory);
}

void tagger::set_debug_root(const string&as_is_path, const string&to_be_path) {
	file::path directory(ORK("./debug/"));
	directory /= file::path(as_is_path).stem();
	directory /= file::path(to_be_path).stem();
	g_tagger_statics().set_debug_root(directory.ORK_GEN_STR() + ORK("/"));
}

struct setup_hierarchy::impl {
public:
	string setup_directory;
	bool cached;
	unsigned score;
	std::vector<orientation>setups;
public:
	impl()
		: setup_directory()
		, cached(false)
		, score(0)
		, setups()
	{}
};

setup_hierarchy::setup_hierarchy(const string&setup_root, const string&as_is_path, const string&to_be_path)
	: _pimpl{ new impl{ } }
{
	if(!file::ensure_directory(setup_root))ORK_THROW(ORK("Setup root could not be created: ") << setup_root);
	//if(!test_file(as_is_path))ORK_THROW(ORK("As-is file could not be found: ") << as_is_path);
	//if(!test_file(to_be_path))ORK_THROW(ORK("To-Be file could not be found: ") << to_be_path);

	const string as_is_name(file::path(as_is_path).stem().ORK_GEN_STR());
	const string to_be_name(file::path(to_be_path).stem().ORK_GEN_STR());

	file::path setup_path(setup_root);
	setup_path /= as_is_name + ORK("/");
	setup_path /= to_be_name + ORK("/");
	_pimpl->setup_directory = setup_path.ORK_GEN_STR();
}

file::path setup_hierarchy::get_subdirectory() {
	file::path setup_dir;
	if(!top_subdirectory(get_path(), setup_dir))ORK_THROW(ORK("Setup directory not found for root: ") << get_path());
	_pimpl->cached = false;//Dirty, in case the client fetches more than one setup
	return setup_dir /= ORK("/");
}

struct setup_match {
	string setups;
	file::path setup_dir;
	setup_match(const string&exact_setups) :setups(exact_setups), setup_dir() {}
	void operator()(const file::path&p) {
		if(!setup_dir.empty())return;//Already found (this could be a superstring, so find might work)
		if(!ext_file::is_directory(p))return;//Just in case
		const string dir_name(p.stem().ORK_GEN_STR());
		if(dir_name.find(setups) != string::npos)setup_dir = p;
	}
};

const string&setup_hierarchy::get_path() {
	return _pimpl->setup_directory;
}

file::path setup_hierarchy::get_subdirectory(const string&exact_setups) {
	setup_match match(exact_setups);
	iterate_directory<setup_match, flat_search, sorted>::run(get_path(), match);
	if(match.setup_dir.empty())ORK_THROW(ORK("Setup permutation not found: ") << exact_setups);
	_pimpl->cached = false;//Dirty, in case the client fetches more than one setup
	return match.setup_dir;
}

const std::vector<orientation>& setup_hierarchy::get_setups() {
	return do_get_setups(file::canonical_normalized_trimmed(get_subdirectory()).filename().ORK_GEN_STR());
}

const std::vector<orientation>& setup_hierarchy::get_setups(const string&exact_setups) {
	return do_get_setups(file::canonical_normalized_trimmed(get_subdirectory(exact_setups)).filename().ORK_GEN_STR());
}

const std::vector<orientation>&setup_hierarchy::do_get_setups(const string&setup_dir) {
	if(!_pimpl->cached) {
		//Directory format: score [orientation]+
		//TODO: abstract writing, reading setups into a utility (right now process_plan class does the writing, but uses ACIS)
		i_string_stream strm(setup_dir);
		strm >> _pimpl->score;

		string setup;
		strm >> setup;
		while(strm) {
			_pimpl->setups.push_back(string2orientation(setup));
			strm >> setup;
		}
		if(_pimpl->setups.empty())ORK_THROW(ORK("Setup directory not formatted correctly: ") << get_path() << ORK("/") << setup_dir);

		_pimpl->cached = true;
	}
	if(_pimpl->setups.empty())ORK_THROW(ORK("Setups not found for directory: ") << setup_dir);
	return _pimpl->setups;
}

}//namespace ork
<commit_msg>Tagger now uses string conversion for count<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include<atomic>
#include<mutex>
#include<sstream>
#include<string>

#include"ork/file_utils.hpp"
#include"ork/orientation.hpp"
#include"ork/string_utils.hpp"
#include"ork/tagger.hpp"

namespace ork {

class tagger_statics {
private:
	file::path _debug_root = { ORK("./debug") };//Global guarded by mutex
	std::mutex _mutex = { };
public:
	tagger_statics() {}
	ORK_NON_COPYABLE(tagger_statics)
public:
	file::path debug_root() {
		std::lock_guard<std::mutex> lock(_mutex);
		return _debug_root;
	}
	void set_debug_root(const file::path&directory) {
		std::lock_guard<std::mutex> lock(_mutex);
		_debug_root = directory;
	}
};
tagger_statics&g_tagger_statics() {
	static tagger_statics statics;
	return statics;
}

struct tagger::impl {
public:
	std::atomic<unsigned>count;//Local static
	const bool number_folder;//Local static constant
	const string tag;//Local static constant
public:
	impl(const string&tag)
		: count(0)
		, number_folder(true)
		, tag(tag)
	{}
	impl(const string&tag, const bool numbered_folders)
		: count(0)
		, number_folder(numbered_folders)
		, tag(tag)
	{}
	ORK_NON_COPYABLE(impl)
};

tagger::tagger(const string&tag) : _pimpl{ new impl(tag) } {}
tagger::tagger(const string&tag, bool numbered_folders) : _pimpl{ new impl(tag, numbered_folders) } {}
tagger::~tagger() {}

string tagger::sub_tag(const string&tag, size_t&index) {
	string_stream stream;
	stream << tag << index++ << ORK("_");
	return stream.str();
}

string tagger::operator()() {
	string_stream stream;
	file::path p(g_tagger_statics().debug_root());
	if(_pimpl->number_folder) {
		stream << _pimpl->tag << ORK("_") << _pimpl->count++ << ORK("/");
		p /= stream.str();
		return p.ORK_GEN_STR();
	}
	else {
		stream << _pimpl->tag << ORK("/");
		p /= stream.str();
		return p.ORK_GEN_STR() + to_string(_pimpl->count++) + ORK("_");
	}
}

unsigned tagger::count() {
	return _pimpl->count.load();
}

void tagger::set_debug_root(const string&directory) {
	g_tagger_statics().set_debug_root(directory);
}

void tagger::set_debug_root(const string&as_is_path, const string&to_be_path) {
	file::path directory(ORK("./debug/"));
	directory /= file::path(as_is_path).stem();
	directory /= file::path(to_be_path).stem();
	g_tagger_statics().set_debug_root(directory.ORK_GEN_STR() + ORK("/"));
}

struct setup_hierarchy::impl {
public:
	string setup_directory;
	bool cached;
	unsigned score;
	std::vector<orientation>setups;
public:
	impl()
		: setup_directory()
		, cached(false)
		, score(0)
		, setups()
	{}
};

setup_hierarchy::setup_hierarchy(const string&setup_root, const string&as_is_path, const string&to_be_path)
	: _pimpl{ new impl{ } }
{
	if(!file::ensure_directory(setup_root))ORK_THROW(ORK("Setup root could not be created: ") << setup_root);
	//if(!test_file(as_is_path))ORK_THROW(ORK("As-is file could not be found: ") << as_is_path);
	//if(!test_file(to_be_path))ORK_THROW(ORK("To-Be file could not be found: ") << to_be_path);

	const string as_is_name(file::path(as_is_path).stem().ORK_GEN_STR());
	const string to_be_name(file::path(to_be_path).stem().ORK_GEN_STR());

	file::path setup_path(setup_root);
	setup_path /= as_is_name + ORK("/");
	setup_path /= to_be_name + ORK("/");
	_pimpl->setup_directory = setup_path.ORK_GEN_STR();
}

file::path setup_hierarchy::get_subdirectory() {
	file::path setup_dir;
	if(!top_subdirectory(get_path(), setup_dir))ORK_THROW(ORK("Setup directory not found for root: ") << get_path());
	_pimpl->cached = false;//Dirty, in case the client fetches more than one setup
	return setup_dir /= ORK("/");
}

struct setup_match {
	string setups;
	file::path setup_dir;
	setup_match(const string&exact_setups) :setups(exact_setups), setup_dir() {}
	void operator()(const file::path&p) {
		if(!setup_dir.empty())return;//Already found (this could be a superstring, so find might work)
		if(!ext_file::is_directory(p))return;//Just in case
		const string dir_name(p.stem().ORK_GEN_STR());
		if(dir_name.find(setups) != string::npos)setup_dir = p;
	}
};

const string&setup_hierarchy::get_path() {
	return _pimpl->setup_directory;
}

file::path setup_hierarchy::get_subdirectory(const string&exact_setups) {
	setup_match match(exact_setups);
	iterate_directory<setup_match, flat_search, sorted>::run(get_path(), match);
	if(match.setup_dir.empty())ORK_THROW(ORK("Setup permutation not found: ") << exact_setups);
	_pimpl->cached = false;//Dirty, in case the client fetches more than one setup
	return match.setup_dir;
}

const std::vector<orientation>& setup_hierarchy::get_setups() {
	return do_get_setups(file::canonical_normalized_trimmed(get_subdirectory()).filename().ORK_GEN_STR());
}

const std::vector<orientation>& setup_hierarchy::get_setups(const string&exact_setups) {
	return do_get_setups(file::canonical_normalized_trimmed(get_subdirectory(exact_setups)).filename().ORK_GEN_STR());
}

const std::vector<orientation>&setup_hierarchy::do_get_setups(const string&setup_dir) {
	if(!_pimpl->cached) {
		//Directory format: score [orientation]+
		//TODO: abstract writing, reading setups into a utility (right now process_plan class does the writing, but uses ACIS)
		i_string_stream strm(setup_dir);
		strm >> _pimpl->score;

		string setup;
		strm >> setup;
		while(strm) {
			_pimpl->setups.push_back(string2orientation(setup));
			strm >> setup;
		}
		if(_pimpl->setups.empty())ORK_THROW(ORK("Setup directory not formatted correctly: ") << get_path() << ORK("/") << setup_dir);

		_pimpl->cached = true;
	}
	if(_pimpl->setups.empty())ORK_THROW(ORK("Setups not found for directory: ") << setup_dir);
	return _pimpl->setups;
}

}//namespace ork
<|endoftext|>


<commit_before>#include <pthread.h>
#include <cstddef>
#include <cstdio>
#include "thread.h"

/*
 * Initialize a thread object
 */
Thread::Thread() :
	state(INIT)
{
	// Initialize synchronization primitives
	pthread_attr_init(&attr);
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&start_signal, NULL);
	pthread_cond_init(&stop_signal, NULL);

	pthread_mutex_lock(&mutex);

	// Initialize some thread attributes
	pthread_attr_setstacksize(&attr, 16000);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

	// Try to create a thread
	if (pthread_create(&id, &attr, Thread::dispatch, (void*) this) == 0) {
		// Hold until the created thread reaches a certain execution point
		pthread_cond_wait(&stop_signal, &mutex);

		// Mark the thread as started
		state = STARTED;
	} else {

		// Mark the thread as failed
		state = STOPPED;
		// TODO: Add error handling if thread creation failed
		//pthread_mutex_unlock(&mutex);
		//throw "Failed to create thread";
	}
	pthread_mutex_unlock(&mutex);
}

/*
 * Destroy a thread object
 */
Thread::~Thread()
{
	// Call stop. Note that this will *not* call stop for a derived class.
	stop();

	// Destroy synchronization primitives
	pthread_attr_destroy(&attr);
	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&start_signal);
	pthread_cond_destroy(&stop_signal);
}

/*
 * Start the thread
 */
void Thread::start()
{
	pthread_mutex_lock(&mutex);
	if (state == STARTED) {
		// Mark the thread as good to go
		state = RUNNING;

		// Signal to the waiting thread that it's good to go
		pthread_cond_signal(&start_signal);
	}
	pthread_mutex_unlock(&mutex);
}

/*
 * Stop the thread
 */
void Thread::stop()
{
	pthread_mutex_lock(&mutex);
	if (state != STOPPED) {

		// The client hasn't called start(), signal to the waiting thread that
		// it should start and stop immediatly.
		if (state != RUNNING) {
			state = STOPPED;
			pthread_cond_signal(&start_signal);
		}

		// Wait for the thread to finish up, we assume that the derived class'
		// stop() implementation has been called, and that run() behaves properly.
		pthread_cond_wait(&stop_signal, &mutex);
		state = STOPPED;
	}
	pthread_mutex_unlock(&mutex);
}

/*
 * Invoke run on a derived class
 */
void* Thread::dispatch(void* object)
{
	Thread* thread = static_cast<Thread*>(object);

	pthread_mutex_lock(&thread->mutex);
	// Notify parent thread that we have been created
	pthread_cond_signal(&thread->stop_signal);

	// Wait until further notice
	pthread_cond_wait(&thread->start_signal, &thread->mutex);

	// Check if we are still good to go
	bool run = thread->state == RUNNING;
	pthread_mutex_unlock(&thread->mutex);

	// Call the run() method of the derived class
	if (run) {
		thread->run();
	}

	pthread_mutex_lock(&thread->mutex);
	// Notify parent thread that we are shutting down
	pthread_cond_broadcast(&thread->stop_signal);
	pthread_mutex_unlock(&thread->mutex);

	pthread_exit(NULL);
}
<commit_msg>refactored the threading class<commit_after>#include <pthread.h>
#include <cstddef>
#include "thread.h"

/*
 * Initialize a thread object
 */
Thread::Thread() :
	state(INIT)
{
	// Initialize synchronization primitives
	pthread_attr_init(&attr);
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&start_signal, NULL);
	pthread_cond_init(&stop_signal, NULL);

	pthread_mutex_lock(&mutex);

	// Initialize some thread attributes
	pthread_attr_setstacksize(&attr, 16000);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

	// Try to create a thread
	if (pthread_create(&id, &attr, Thread::dispatch, (void*) this) == 0) {
		// Hold until the created thread reaches a certain execution point
		pthread_cond_wait(&stop_signal, &mutex);

		// Mark the thread as started
		state = STARTED;
	} else {

		// Mark the thread as failed
		state = STOPPED;
		// TODO: Add error handling if thread creation failed
		//pthread_mutex_unlock(&mutex);
		//throw "Failed to create thread";
	}
	pthread_mutex_unlock(&mutex);
}

/*
 * Destroy a thread object
 */
Thread::~Thread()
{
	// Stop thread
	stop();

	// Destroy synchronization primitives
	pthread_attr_destroy(&attr);
	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&start_signal);
	pthread_cond_destroy(&stop_signal);
}

/*
 * Start the thread
 */
void Thread::start()
{
	pthread_mutex_lock(&mutex);
	if (state == STARTED) {
		// Mark the thread as good to go
		state = RUNNING;

		// Signal to the waiting thread that it's good to go
		pthread_cond_signal(&start_signal);
	}
	pthread_mutex_unlock(&mutex);
}

void Thread::stop()
{
	pthread_mutex_lock(&mutex);
	if (state != STOPPED) {

		// The client hasn't called start(), signal to the waiting thread that
		// it should start and stop immediatly.
		if (state != RUNNING) {
			state = STOPPED;
			pthread_cond_signal(&start_signal);
			pthread_cond_wait(&stop_signal, &mutex);
		}

		// Wait for the thread to finish up, we assume that the derived class'
		// stop() implementation has been called, and that run() behaves properly.
		state = STOPPED;
		pthread_join(id, NULL);
	}
	pthread_mutex_unlock(&mutex);
}

/*
 * Invoke run on a derived class
 */
void* Thread::dispatch(void* object)
{
	Thread* thread = static_cast<Thread*>(object);

	pthread_mutex_lock(&thread->mutex);
	// Notify parent thread that we have been created
	pthread_cond_signal(&thread->stop_signal);

	// Wait until further notice
	pthread_cond_wait(&thread->start_signal, &thread->mutex);

	// Check if we are still good to go
	bool run = thread->state == RUNNING;
	pthread_mutex_unlock(&thread->mutex);

	// Call the run() method of the derived class
	if (run) {
		thread->run();
	}

	pthread_cond_signal(&thread->stop_signal);
	pthread_exit(NULL);
}
<|endoftext|>


<commit_before>#include "saiga/opengl/shader/shader.h"
#include "saiga/opengl/texture/raw_texture.h"
#include "saiga/util/error.h"
#include <fstream>
#include <algorithm>
#include "saiga/util/assert.h"

GLuint Shader::boundShader = 0;

Shader::Shader(){
}

Shader::~Shader(){
	destroyProgram();
}

// ===================================== program stuff =====================================

GLuint Shader::createProgram(){

	program = glCreateProgram();

	//attach all shaders
	for (auto& sp : shaders){
		glAttachShader(program, sp->id);
	}
	assert_no_glerror();
	glLinkProgram(program);

	if (!printProgramLog()){
		return 0;
	}

	assert_no_glerror();
	for (auto& sp : shaders){
		sp->deleteGLShader();
	}

	assert_no_glerror();

	checkUniforms();

	assert_no_glerror();
	return program;
}

void Shader::destroyProgram()
{
	if (program != 0){
		glDeleteProgram(program);
		program = 0;
        assert_no_glerror();
	}
}

bool Shader::printProgramLog(){
	//Make sure name is shader
	if (glIsProgram(program) == GL_TRUE)
	{
		//Program log length
		int infoLogLength = 0;
		int maxLength = infoLogLength;

		//Get info std::string length
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

		//Allocate std::string
		char* infoLog = new char[maxLength];

		//Get info log
		glGetProgramInfoLog(program, maxLength, &infoLogLength, infoLog);
		if (infoLogLength > 0)
		{
			//Print Log
			std::cout << "program error:" << std::endl;
			std::cout << infoLog << std::endl;
		}
        assert_no_glerror();

		//Deallocate std::string
		delete[] infoLog;
		return infoLogLength == 0;
	}
	else
	{
		cout << "Name " << program << " is not a program" << endl;
		return false;
	}
}

void Shader::bind(){
	assert(program);
	//allow double bind
	assert(boundShader == program || boundShader == 0);
	boundShader = program;
	glUseProgram(program);
    assert_no_glerror();
}

void Shader::unbind(){
	//allow double unbind
	assert(boundShader == program || boundShader == 0);
	boundShader = 0;
#if defined(SAIGA_DEBUG)
	glUseProgram(0);
#endif
    assert_no_glerror();
}

bool Shader::isBound(){
	return boundShader == program;
}

// ===================================== Compute Shaders =====================================

glm::uvec3 Shader::getComputeWorkGroupSize()
{
	GLint work_size[3];
	glGetProgramiv(program, GL_COMPUTE_WORK_GROUP_SIZE, work_size);
    assert_no_glerror();
	return glm::uvec3(work_size[0], work_size[1], work_size[2]);
}

glm::uvec3 Shader::getNumGroupsCeil(const glm::uvec3 &problem_size)
{
	return getNumGroupsCeil(problem_size, getComputeWorkGroupSize());
}

glm::uvec3 Shader::getNumGroupsCeil(const glm::uvec3 &problem_size, const glm::uvec3 &work_group_size)
{
	//    glm::uvec3 ret = problem_size/work_group_size;
	//    glm::uvec3 rest = problem_size%work_group_size;

	//    ret.x += rest.x ? 1 : 0;
	//    ret.y += rest.y ? 1 : 0;
	//    ret.z += rest.z ? 1 : 0;

	//    return ret;

	return (problem_size + work_group_size - glm::uvec3(1)) / (work_group_size);
}

void Shader::dispatchCompute(const glm::uvec3 &num_groups)
{
	assert(isBound());
	dispatchCompute(num_groups.x, num_groups.y, num_groups.z);
    assert_no_glerror();
}

void Shader::dispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z)
{
	assert(isBound());
	glDispatchCompute(num_groups_x, num_groups_y, num_groups_z);
    assert_no_glerror();
}

void Shader::memoryBarrier(MemoryBarrierMask barriers)
{
	glMemoryBarrier(barriers);
    assert_no_glerror();
}

void Shader::memoryBarrierTextureFetch()
{
	memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
    assert_no_glerror();
}

void Shader::memoryBarrierImageAccess()
{
	memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
    assert_no_glerror();
}

// ===================================== uniforms =====================================

GLint Shader::getUniformLocation(const char* name){
	GLint i = glGetUniformLocation(program, name);
	return i;
}

void Shader::getUniformInfo(GLuint location){
	const GLsizei bufSize = 128;

	GLsizei length;
	GLint size;
	GLenum type;
	GLchar name[bufSize];

	glGetActiveUniform(program, location, bufSize, &length, &size, &type, name);

	cout << "uniform info " << location << endl;
	cout << "name " << name << endl;
	//    cout<<"length "<<length<<endl;
	cout << "size " << size << endl;
	cout << "type " << type << endl;
}

// ===================================== uniform blocks =====================================

GLuint Shader::getUniformBlockLocation(const char *name)
{
	GLuint blockIndex = glGetUniformBlockIndex(program, name);

	if (blockIndex == GL_INVALID_INDEX){
		std::cerr << "glGetUniformBlockIndex: uniform block invalid!" << endl;
	}
	return blockIndex;
}

void Shader::setUniformBlockBinding(GLuint blockLocation, GLuint bindingPoint)
{
	glUniformBlockBinding(program, blockLocation, bindingPoint);
}

GLint Shader::getUniformBlockSize(GLuint blockLocation)
{
	GLint ret;
	glGetActiveUniformBlockiv(program, blockLocation, GL_UNIFORM_BLOCK_DATA_SIZE, &ret);
	return ret;
}

std::vector<GLint> Shader::getUniformBlockIndices(GLuint blockLocation)
{
	GLint ret;
	glGetActiveUniformBlockiv(program, blockLocation, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ret);

	std::vector<GLint> indices(ret);
	glGetActiveUniformBlockiv(program, blockLocation, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &indices[0]);

	return indices;
}

std::vector<GLint> Shader::getUniformBlockSize(std::vector<GLint> indices)
{
	std::vector<GLint> ret(indices.size());
	glGetActiveUniformsiv(program, indices.size(), (GLuint*)indices.data(), GL_UNIFORM_SIZE, ret.data());
	return ret;
}

std::vector<GLint> Shader::getUniformBlockType(std::vector<GLint> indices)
{
	std::vector<GLint> ret(indices.size());
	glGetActiveUniformsiv(program, indices.size(), (GLuint*)indices.data(), GL_UNIFORM_TYPE, ret.data());
	return ret;
}

std::vector<GLint> Shader::getUniformBlockOffset(std::vector<GLint> indices)
{
	std::vector<GLint> ret(indices.size());
	glGetActiveUniformsiv(program, indices.size(), (GLuint*)indices.data(), GL_UNIFORM_OFFSET, ret.data());
	return ret;
}

// ===================================== uniform uploads =====================================

void Shader::upload(int location, const mat4 &m){
	assert(isBound());
	glUniformMatrix4fv(location, 1, GL_FALSE, (GLfloat*)&m[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const vec4 &v){
	assert(isBound());
	glUniform4fv(location, 1, (GLfloat*)&v[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const vec3 &v){
	assert(isBound());
	glUniform3fv(location, 1, (GLfloat*)&v[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const vec2 &v){
	assert(isBound());
	glUniform2fv(location, 1, (GLfloat*)&v[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const int &i){
	assert(isBound());
	glUniform1i(location, (GLint)i);
    assert_no_glerror();
}

void Shader::upload(int location, const float &f){
	assert(isBound());
	glUniform1f(location, (GLfloat)f);
    assert_no_glerror();
}

void Shader::upload(int location, int count, mat4* m){
	assert(isBound());
	glUniformMatrix4fv(location, count, GL_FALSE, (GLfloat*)m);
    assert_no_glerror();
}

void Shader::upload(int location, int count, vec4* v){
	assert(isBound());
	glUniform4fv(location, count, (GLfloat*)v);
    assert_no_glerror();
}

void Shader::upload(int location, int count, vec3* v){
	assert(isBound());
	glUniform3fv(location, count, (GLfloat*)v);
    assert_no_glerror();
}

void Shader::upload(int location, int count, vec2* v){
	assert(isBound());
	glUniform2fv(location, count, (GLfloat*)v);
    assert_no_glerror();
}

void Shader::upload(int location, raw_Texture *texture, int textureUnit)
{
	assert(isBound());
	texture->bind(textureUnit);
	Shader::upload(location, textureUnit);
    assert_no_glerror();
}
<commit_msg>added assert<commit_after>#include "saiga/opengl/shader/shader.h"
#include "saiga/opengl/texture/raw_texture.h"
#include "saiga/util/error.h"
#include <fstream>
#include <algorithm>
#include "saiga/util/assert.h"

GLuint Shader::boundShader = 0;

Shader::Shader(){
}

Shader::~Shader(){
	destroyProgram();
}

// ===================================== program stuff =====================================

GLuint Shader::createProgram(){

	program = glCreateProgram();

	//attach all shaders
	for (auto& sp : shaders){
		glAttachShader(program, sp->id);
	}
	assert_no_glerror();
	glLinkProgram(program);

	if (!printProgramLog()){
        assert(0);
		return 0;
	}

	assert_no_glerror();
	for (auto& sp : shaders){
		sp->deleteGLShader();
	}

	assert_no_glerror();

	checkUniforms();

	assert_no_glerror();
	return program;
}

void Shader::destroyProgram()
{
	if (program != 0){
		glDeleteProgram(program);
		program = 0;
        assert_no_glerror();
	}
}

bool Shader::printProgramLog(){
	//Make sure name is shader
	if (glIsProgram(program) == GL_TRUE)
	{
		//Program log length
		int infoLogLength = 0;
		int maxLength = infoLogLength;

		//Get info std::string length
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

		//Allocate std::string
		char* infoLog = new char[maxLength];

		//Get info log
		glGetProgramInfoLog(program, maxLength, &infoLogLength, infoLog);
		if (infoLogLength > 0)
		{
			//Print Log
			std::cout << "program error:" << std::endl;
			std::cout << infoLog << std::endl;
		}
        assert_no_glerror();

		//Deallocate std::string
		delete[] infoLog;
		return infoLogLength == 0;
	}
	else
	{
		cout << "Name " << program << " is not a program" << endl;
		return false;
	}
}

void Shader::bind(){
	assert(program);
	//allow double bind
	assert(boundShader == program || boundShader == 0);
	boundShader = program;
	glUseProgram(program);
    assert_no_glerror();
}

void Shader::unbind(){
	//allow double unbind
	assert(boundShader == program || boundShader == 0);
	boundShader = 0;
#if defined(SAIGA_DEBUG)
	glUseProgram(0);
#endif
    assert_no_glerror();
}

bool Shader::isBound(){
	return boundShader == program;
}

// ===================================== Compute Shaders =====================================

glm::uvec3 Shader::getComputeWorkGroupSize()
{
	GLint work_size[3];
	glGetProgramiv(program, GL_COMPUTE_WORK_GROUP_SIZE, work_size);
    assert_no_glerror();
	return glm::uvec3(work_size[0], work_size[1], work_size[2]);
}

glm::uvec3 Shader::getNumGroupsCeil(const glm::uvec3 &problem_size)
{
	return getNumGroupsCeil(problem_size, getComputeWorkGroupSize());
}

glm::uvec3 Shader::getNumGroupsCeil(const glm::uvec3 &problem_size, const glm::uvec3 &work_group_size)
{
	//    glm::uvec3 ret = problem_size/work_group_size;
	//    glm::uvec3 rest = problem_size%work_group_size;

	//    ret.x += rest.x ? 1 : 0;
	//    ret.y += rest.y ? 1 : 0;
	//    ret.z += rest.z ? 1 : 0;

	//    return ret;

	return (problem_size + work_group_size - glm::uvec3(1)) / (work_group_size);
}

void Shader::dispatchCompute(const glm::uvec3 &num_groups)
{
	assert(isBound());
	dispatchCompute(num_groups.x, num_groups.y, num_groups.z);
    assert_no_glerror();
}

void Shader::dispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z)
{
	assert(isBound());
	glDispatchCompute(num_groups_x, num_groups_y, num_groups_z);
    assert_no_glerror();
}

void Shader::memoryBarrier(MemoryBarrierMask barriers)
{
	glMemoryBarrier(barriers);
    assert_no_glerror();
}

void Shader::memoryBarrierTextureFetch()
{
	memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
    assert_no_glerror();
}

void Shader::memoryBarrierImageAccess()
{
	memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
    assert_no_glerror();
}

// ===================================== uniforms =====================================

GLint Shader::getUniformLocation(const char* name){
	GLint i = glGetUniformLocation(program, name);
	return i;
}

void Shader::getUniformInfo(GLuint location){
	const GLsizei bufSize = 128;

	GLsizei length;
	GLint size;
	GLenum type;
	GLchar name[bufSize];

	glGetActiveUniform(program, location, bufSize, &length, &size, &type, name);

	cout << "uniform info " << location << endl;
	cout << "name " << name << endl;
	//    cout<<"length "<<length<<endl;
	cout << "size " << size << endl;
	cout << "type " << type << endl;
}

// ===================================== uniform blocks =====================================

GLuint Shader::getUniformBlockLocation(const char *name)
{
	GLuint blockIndex = glGetUniformBlockIndex(program, name);

	if (blockIndex == GL_INVALID_INDEX){
		std::cerr << "glGetUniformBlockIndex: uniform block invalid!" << endl;
	}
	return blockIndex;
}

void Shader::setUniformBlockBinding(GLuint blockLocation, GLuint bindingPoint)
{
	glUniformBlockBinding(program, blockLocation, bindingPoint);
}

GLint Shader::getUniformBlockSize(GLuint blockLocation)
{
	GLint ret;
	glGetActiveUniformBlockiv(program, blockLocation, GL_UNIFORM_BLOCK_DATA_SIZE, &ret);
	return ret;
}

std::vector<GLint> Shader::getUniformBlockIndices(GLuint blockLocation)
{
	GLint ret;
	glGetActiveUniformBlockiv(program, blockLocation, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ret);

	std::vector<GLint> indices(ret);
	glGetActiveUniformBlockiv(program, blockLocation, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &indices[0]);

	return indices;
}

std::vector<GLint> Shader::getUniformBlockSize(std::vector<GLint> indices)
{
	std::vector<GLint> ret(indices.size());
	glGetActiveUniformsiv(program, indices.size(), (GLuint*)indices.data(), GL_UNIFORM_SIZE, ret.data());
	return ret;
}

std::vector<GLint> Shader::getUniformBlockType(std::vector<GLint> indices)
{
	std::vector<GLint> ret(indices.size());
	glGetActiveUniformsiv(program, indices.size(), (GLuint*)indices.data(), GL_UNIFORM_TYPE, ret.data());
	return ret;
}

std::vector<GLint> Shader::getUniformBlockOffset(std::vector<GLint> indices)
{
	std::vector<GLint> ret(indices.size());
	glGetActiveUniformsiv(program, indices.size(), (GLuint*)indices.data(), GL_UNIFORM_OFFSET, ret.data());
	return ret;
}

// ===================================== uniform uploads =====================================

void Shader::upload(int location, const mat4 &m){
	assert(isBound());
	glUniformMatrix4fv(location, 1, GL_FALSE, (GLfloat*)&m[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const vec4 &v){
	assert(isBound());
	glUniform4fv(location, 1, (GLfloat*)&v[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const vec3 &v){
	assert(isBound());
	glUniform3fv(location, 1, (GLfloat*)&v[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const vec2 &v){
	assert(isBound());
	glUniform2fv(location, 1, (GLfloat*)&v[0]);
    assert_no_glerror();
}

void Shader::upload(int location, const int &i){
	assert(isBound());
	glUniform1i(location, (GLint)i);
    assert_no_glerror();
}

void Shader::upload(int location, const float &f){
	assert(isBound());
	glUniform1f(location, (GLfloat)f);
    assert_no_glerror();
}

void Shader::upload(int location, int count, mat4* m){
	assert(isBound());
	glUniformMatrix4fv(location, count, GL_FALSE, (GLfloat*)m);
    assert_no_glerror();
}

void Shader::upload(int location, int count, vec4* v){
	assert(isBound());
	glUniform4fv(location, count, (GLfloat*)v);
    assert_no_glerror();
}

void Shader::upload(int location, int count, vec3* v){
	assert(isBound());
	glUniform3fv(location, count, (GLfloat*)v);
    assert_no_glerror();
}

void Shader::upload(int location, int count, vec2* v){
	assert(isBound());
	glUniform2fv(location, count, (GLfloat*)v);
    assert_no_glerror();
}

void Shader::upload(int location, raw_Texture *texture, int textureUnit)
{
	assert(isBound());
	texture->bind(textureUnit);
	Shader::upload(location, textureUnit);
    assert_no_glerror();
}
<|endoftext|>