<commit_before>#pragma once
#include <bts/blockchain/types.hpp>
#include <bts/blockchain/operations.hpp>
#include <bts/blockchain/error_codes.hpp>
#include <fc/optional.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/io/raw.hpp>

#include <unordered_set>

namespace bts { namespace blockchain {

   class chain_interface;
   typedef std::shared_ptr<chain_interface> chain_interface_ptr;

   /**
    *  A transaction is a set of operations that are
    *  performed atomicly and must be internally consistant.
    *
    *  Every transaction votes for
    */
   struct transaction
   {
      transaction(){}

      digest_type                      digest()const;

      fc::optional<fc::time_point_sec> expiration;
      fc::optional<name_id_type>       delegate_id; // delegate being voted for in required payouts
      std::vector<operation>           operations;

      void withdraw( const account_id_type& account, share_type amount );
      void deposit( const address& addr, const asset& amount, name_id_type delegate_id );
      void reserve_name( const std::string& name, const std::string& json_data, const public_key_type& master, const public_key_type& active, bool as_delegate = false );
      void update_name( name_id_type name_id, const fc::optional<std::string>& json_data, const fc::optional<public_key_type>& active, bool as_delegate = false );
   };

   struct signed_transaction : public transaction
   {
      transaction_id_type                     id()const;
      size_t                                  data_size()const;
      void                                    sign( const fc::ecc::private_key& signer );

      std::vector<fc::ecc::compact_signature> signatures;
   };
   typedef std::vector<signed_transaction> signed_transactions;
   typedef fc::optional<signed_transaction> osigned_transaction;

   /**
    *  While evaluating a transaction there is a lot of intermediate
    *  state that must be tracked.  Any shares withdrawn from the
    *  database must be stored in the transaction state until they
    *  are sent back to the database as either new balances or
    *  as fees collected.
    *
    *  Some outputs such as markets, options, etc require certain
    *  payments to be made.  So payments made are tracked and
    *  compared against payments required.
    *
    */
   class transaction_evaluation_state
   {
      public:
         transaction_evaluation_state( const chain_interface_ptr& blockchain );
         transaction_evaluation_state(){};

         virtual ~transaction_evaluation_state();
         virtual share_type get_fees( asset_id_type id = 0)const;

         virtual void reset();

         virtual void evaluate( const signed_transaction& trx );
         virtual void evaluate_operation( const operation& op );

         /** perform any final operations based upon the current state of
          * the operation such as updating fees paid etc.
          */
         virtual void post_evaluate();
         /** can be specalized to handle many different forms of
          * fee payment.
          */
         virtual void validate_required_fee();
         /**
          * apply collected vote changes
          */
         virtual void update_delegate_votes();

         virtual void evaluate_withdraw( const withdraw_operation& op );
         virtual void evaluate_deposit( const deposit_operation& op );
         virtual void evaluate_reserve_name( const reserve_name_operation& op );
         virtual void evaluate_update_name( const update_name_operation& op );
         virtual void evaluate_create_asset( const create_asset_operation& op );
         virtual void evaluate_update_asset( const update_asset_operation& op );
         virtual void evaluate_issue_asset( const issue_asset_operation& op );

         virtual void fail( bts_error_code error_code, const fc::variant& data );

         bool check_signature( const address& a )const;
         void add_required_signature( const address& a );

         // steps performed as the transaction is validated

         /**
          *  subtracts amount from a withdraw_with_signature account with the
          *  owner_key and amount.asset_id and the delegate_id of the transaction.
          */
         void add_required_deposit( const address& owner_key, const asset& amount );

         /** contains address funds were deposited into for use in
          * incrementing required_deposits balance
          */
         void sub_balance( const account_id_type& addr, const asset& amount );
         void add_balance( const asset& amount );

         /** any time a balance is deposited increment the vote for the delegate,
          * if delegate_id then it is a vote against abs(delegate_id)
          */
         void add_vote( name_id_type delegate_id, share_type amount );
         void sub_vote( name_id_type delegate_id, share_type amount );

         signed_transaction                               trx;
         std::unordered_set<address>                      signed_keys;
         std::unordered_set<address>                      required_keys;

         // increases with funds are withdrawn, decreases when funds are deposited or fees paid
         uint32_t                                         validation_error_code;
         fc::variant                                      validation_error_data;

         /** every time a deposit is made this balance is increased
          *  every time a deposit is required this balance is decreased
          *
          *  This balance cannot be negative without an error.
          */
         std::unordered_map<account_id_type, asset>       required_deposits;
         std::unordered_map<account_id_type, asset>       provided_deposits;

         // track deposits and withdraws by asset type
         std::unordered_map<asset_id_type, asset>         deposits;
         std::unordered_map<asset_id_type, asset>         withdraws;

         /**
          *  As operation withdraw funds, input balance grows...
          *  As operations consume funds (deposit) input balance decreases
          *
          *  Any left-over input balance can be seen as fees
          *
          *  @note - this value should always equal the sum of deposits-withdraws
          *  and is maintained for the purpose of seralization.
          */
         std::unordered_map<asset_id_type, share_type>    balance;

         struct vote_state
         {
            vote_state():votes_for(0),votes_against(0){}

            int64_t votes_for;
            int64_t votes_against;
         };
         /**
          *  Tracks the votes for or against each delegate based upon
          *  the deposits and withdraws to addresses.
          */
         std::unordered_map<name_id_type, vote_state>     net_delegate_votes;
      protected:
         chain_interface_ptr                              _current_state;
   };

   typedef std::shared_ptr<transaction_evaluation_state> transaction_evaluation_state_ptr;

   struct transaction_location
   {
      transaction_location( uint32_t block_num = 0, uint32_t trx_num = 0 )
      :block_num(0),trx_num(0){}

      uint32_t block_num;
      uint32_t trx_num;
   };

   typedef fc::optional<transaction_location> otransaction_location;

} } // bts::blockchain

FC_REFLECT( bts::blockchain::transaction, (expiration)(delegate_id)(operations) )
FC_REFLECT_DERIVED( bts::blockchain::signed_transaction, (bts::blockchain::transaction), (signatures) )
FC_REFLECT( bts::blockchain::transaction_evaluation_state::vote_state, (votes_for)(votes_against) )
FC_REFLECT( bts::blockchain::transaction_evaluation_state,
           (trx)(signed_keys)(required_keys)
           (validation_error_code)
           (validation_error_data)
           (required_deposits)
           (provided_deposits)
           (deposits)(withdraws)(balance)(net_delegate_votes)(balance) )

FC_REFLECT( bts::blockchain::transaction_location, (block_num)(trx_num) )
<commit_msg>adding definition for transaction_summary<commit_after>#pragma once
#include <bts/blockchain/types.hpp>
#include <bts/blockchain/operations.hpp>
#include <bts/blockchain/error_codes.hpp>
#include <fc/optional.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/io/raw.hpp>

#include <unordered_set>

namespace bts { namespace blockchain {

   class chain_interface;
   typedef std::shared_ptr<chain_interface> chain_interface_ptr;

   /**
    *  A transaction is a set of operations that are
    *  performed atomicly and must be internally consistant.
    *
    *  Every transaction votes for
    */
   struct transaction
   {
      transaction(){}

      digest_type                      digest()const;

      fc::optional<fc::time_point_sec> expiration;
      fc::optional<name_id_type>       delegate_id; // delegate being voted for in required payouts
      std::vector<operation>           operations;

      void withdraw( const account_id_type& account, share_type amount );
      void deposit( const address& addr, const asset& amount, name_id_type delegate_id );
      void reserve_name( const std::string& name, const std::string& json_data, const public_key_type& master, const public_key_type& active, bool as_delegate = false );
      void update_name( name_id_type name_id, const fc::optional<std::string>& json_data, const fc::optional<public_key_type>& active, bool as_delegate = false );
   };
   struct transaction_summary_details
   {
      /**
       *  Bitcoin compatibility
       */
      ///@{
        std::string        account;
        std::string        category;
        std::string        address;
        share_type         amount;
      ///@}
   };

   struct transaction_summary
   {
      transaction_summary():amount(0),confirmations(0),blockindex(0){}

      /**
       *  Bitcoin compatibility
       */
      ///@{
      share_type                  amount;
      uint32_t                    confirmations;
      block_id_type               blockhash;
      uint32_t                    blockindex;
      fc::time_point_sec          blocktime;
      transaction_id_type         txid;
      fc::time_point_sec          time;
      fc::time_point_sec          timereceived;
      transaction_summary_details details;
      ///@}

      std::vector<asset>          fees;
      std::vector<asset>          amounts;
   };

   struct signed_transaction : public transaction
   {
      transaction_id_type                     id()const;
      size_t                                  data_size()const;
      void                                    sign( const fc::ecc::private_key& signer );

      std::vector<fc::ecc::compact_signature> signatures;
   };
   typedef std::vector<signed_transaction> signed_transactions;
   typedef fc::optional<signed_transaction> osigned_transaction;

   /**
    *  While evaluating a transaction there is a lot of intermediate
    *  state that must be tracked.  Any shares withdrawn from the
    *  database must be stored in the transaction state until they
    *  are sent back to the database as either new balances or
    *  as fees collected.
    *
    *  Some outputs such as markets, options, etc require certain
    *  payments to be made.  So payments made are tracked and
    *  compared against payments required.
    *
    */
   class transaction_evaluation_state
   {
      public:
         transaction_evaluation_state( const chain_interface_ptr& blockchain );
         transaction_evaluation_state(){};

         virtual ~transaction_evaluation_state();
         virtual share_type get_fees( asset_id_type id = 0)const;

         virtual void reset();

         virtual void evaluate( const signed_transaction& trx );
         virtual void evaluate_operation( const operation& op );

         /** perform any final operations based upon the current state of
          * the operation such as updating fees paid etc.
          */
         virtual void post_evaluate();
         /** can be specalized to handle many different forms of
          * fee payment.
          */
         virtual void validate_required_fee();
         /**
          * apply collected vote changes
          */
         virtual void update_delegate_votes();

         virtual void evaluate_withdraw( const withdraw_operation& op );
         virtual void evaluate_deposit( const deposit_operation& op );
         virtual void evaluate_reserve_name( const reserve_name_operation& op );
         virtual void evaluate_update_name( const update_name_operation& op );
         virtual void evaluate_create_asset( const create_asset_operation& op );
         virtual void evaluate_update_asset( const update_asset_operation& op );
         virtual void evaluate_issue_asset( const issue_asset_operation& op );

         virtual void fail( bts_error_code error_code, const fc::variant& data );

         bool check_signature( const address& a )const;
         void add_required_signature( const address& a );

         // steps performed as the transaction is validated

         /**
          *  subtracts amount from a withdraw_with_signature account with the
          *  owner_key and amount.asset_id and the delegate_id of the transaction.
          */
         void add_required_deposit( const address& owner_key, const asset& amount );

         /** contains address funds were deposited into for use in
          * incrementing required_deposits balance
          */
         void sub_balance( const account_id_type& addr, const asset& amount );
         void add_balance( const asset& amount );

         /** any time a balance is deposited increment the vote for the delegate,
          * if delegate_id then it is a vote against abs(delegate_id)
          */
         void add_vote( name_id_type delegate_id, share_type amount );
         void sub_vote( name_id_type delegate_id, share_type amount );

         signed_transaction                               trx;
         std::unordered_set<address>                      signed_keys;
         std::unordered_set<address>                      required_keys;

         // increases with funds are withdrawn, decreases when funds are deposited or fees paid
         uint32_t                                         validation_error_code;
         fc::variant                                      validation_error_data;

         /** every time a deposit is made this balance is increased
          *  every time a deposit is required this balance is decreased
          *
          *  This balance cannot be negative without an error.
          */
         std::unordered_map<account_id_type, asset>       required_deposits;
         std::unordered_map<account_id_type, asset>       provided_deposits;

         // track deposits and withdraws by asset type
         std::unordered_map<asset_id_type, asset>         deposits;
         std::unordered_map<asset_id_type, asset>         withdraws;

         /**
          *  As operation withdraw funds, input balance grows...
          *  As operations consume funds (deposit) input balance decreases
          *
          *  Any left-over input balance can be seen as fees
          *
          *  @note - this value should always equal the sum of deposits-withdraws
          *  and is maintained for the purpose of seralization.
          */
         std::unordered_map<asset_id_type, share_type>    balance;

         struct vote_state
         {
            vote_state():votes_for(0),votes_against(0){}

            int64_t votes_for;
            int64_t votes_against;
         };
         /**
          *  Tracks the votes for or against each delegate based upon
          *  the deposits and withdraws to addresses.
          */
         std::unordered_map<name_id_type, vote_state>     net_delegate_votes;
      protected:
         chain_interface_ptr                              _current_state;
   };

   typedef std::shared_ptr<transaction_evaluation_state> transaction_evaluation_state_ptr;

   struct transaction_location
   {
      transaction_location( uint32_t block_num = 0, uint32_t trx_num = 0 )
      :block_num(0),trx_num(0){}

      uint32_t block_num;
      uint32_t trx_num;
   };

   typedef fc::optional<transaction_location> otransaction_location;

} } // bts::blockchain

FC_REFLECT( bts::blockchain::transaction, (expiration)(delegate_id)(operations) )
FC_REFLECT_DERIVED( bts::blockchain::signed_transaction, (bts::blockchain::transaction), (signatures) )
FC_REFLECT( bts::blockchain::transaction_evaluation_state::vote_state, (votes_for)(votes_against) )
FC_REFLECT( bts::blockchain::transaction_evaluation_state,
           (trx)(signed_keys)(required_keys)
           (validation_error_code)
           (validation_error_data)
           (required_deposits)
           (provided_deposits)
           (deposits)(withdraws)(balance)(net_delegate_votes)(balance) )

FC_REFLECT( bts::blockchain::transaction_location, (block_num)(trx_num) )
FC_REFLECT( bts::blockchain::transaction_summary_details, (account)(category)(address)(amount) )
FC_REFLECT( bts::blockchain::transaction_summary, (amount)(confirmations)(blockhash)(blockindex)(blocktime)(txid)(time)(timereceived)(details)(fees)(amounts) )

<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit https://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2019 Luke Wilimitis, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "pixelerroraov.h"

// appleseed.renderer headers.
#include "renderer/kernel/aov/aovaccumulator.h"
#include "renderer/modeling/aov/aov.h"
#include "renderer/modeling/frame/frame.h"

// appleseed.foundation headers.
#include "foundation/image/analysis.h"
#include "foundation/image/color.h"
#include "foundation/image/image.h"
#include "foundation/utility/api/specializedapiarrays.h"
#include "foundation/utility/containers/dictionary.h"

// Standard headers.
#include <algorithm>
#include <cstddef>
#include <memory>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Pixel Error AOV.
    //

    const char* PixelErrorAOVModel = "pixel_error_aov";

    class PixelErrorAOV
      : public UnfilteredAOV
    {
      public:
        explicit PixelErrorAOV(const ParamArray& params)
          : UnfilteredAOV("pixel_error", params)
        {
        }

        const char* get_model() const override
        {
            return PixelErrorAOVModel;
        }

        void post_process_image(const Frame& frame) override
        {
            if (!frame.has_valid_ref_image())
                return;

            // TODO: Convert to inferno color map.
            static const Color3f Blue(0.0f, 0.0f, 1.0f);
            static const Color3f Red(1.0f, 0.0f, 0.0f);

            const AABB2u& crop_window = frame.get_crop_window();

            float max_error = 0.0f;

            for (size_t y = crop_window.min.y; y <= crop_window.max.y; ++y)
            {
                for (size_t x = crop_window.min.x; x <= crop_window.max.x; ++x)
                {
                    Color3f image_color;
                    frame.image().get_pixel(x, y, image_color);

                    Color3f ref_color;
                    frame.ref_image()->get_pixel(x, y, ref_color);

                    const float error = sqrt(compute_error_squared(image_color, ref_color));
                    max_error = max(max_error, error);

                    m_image->set_pixel(x, y, &error, 1);
                }
            }

            if (max_error == 0.0f)
                return;

            for (size_t y = crop_window.min.y; y <= crop_window.max.y; ++y)
            {
                for (size_t x = crop_window.min.x; x <= crop_window.max.x; ++x)
                {
                    float error;
                    m_image->get_pixel(x, y, &error, 1);

                    const float k = fit(error, 0.0f, max_error, 0.0f, 1.0f);
                    assert(k >= 0.0f && k <= 1.0f);

                    m_image->set_pixel(x, y, lerp(Blue, Red, k));
                }
            }
        }

      private:
        auto_release_ptr<AOVAccumulator> create_accumulator() const override
        {
            return auto_release_ptr<AOVAccumulator>(new AOVAccumulator());
        }
    };
}

//
// PixelErrorAOVFactory class implementation.
//

void PixelErrorAOVFactory::release()
{
    delete this;
}

const char* PixelErrorAOVFactory::get_model() const
{
    return PixelErrorAOVModel;
}

Dictionary PixelErrorAOVFactory::get_model_metadata() const
{
    return
        Dictionary()
            .insert("name", PixelErrorAOVModel)
            .insert("label", "Pixel Error");
}

DictionaryArray PixelErrorAOVFactory::get_input_metadata() const
{
    DictionaryArray metadata;
    return metadata;
}

auto_release_ptr<AOV> PixelErrorAOVFactory::create(const ParamArray& params) const
{
    return auto_release_ptr<AOV>(new PixelErrorAOV(params));
}

}   // namespace renderer
<commit_msg>Use Inferno color map in Pixel Error AOV<commit_after>
//
// This source file is part of appleseed.
// Visit https://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2019 Luke Wilimitis, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "pixelerroraov.h"

// appleseed.renderer headers.
#include "renderer/kernel/aov/aovaccumulator.h"
#include "renderer/modeling/aov/aov.h"
#include "renderer/modeling/frame/frame.h"

// appleseed.foundation headers.
#include "foundation/image/analysis.h"
#include "foundation/image/color.h"
#include "foundation/image/colormap.h"
#include "foundation/image/colormapdata.h"
#include "foundation/image/image.h"
#include "foundation/utility/api/specializedapiarrays.h"
#include "foundation/utility/containers/dictionary.h"

// Standard headers.
#include <algorithm>
#include <cstddef>
#include <memory>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Pixel Error AOV.
    //

    const char* PixelErrorAOVModel = "pixel_error_aov";

    class PixelErrorAOV
      : public UnfilteredAOV
    {
      public:
        explicit PixelErrorAOV(const ParamArray& params)
          : UnfilteredAOV("pixel_error", params)
        {
        }

        const char* get_model() const override
        {
            return PixelErrorAOVModel;
        }

        void post_process_image(const Frame& frame) override
        {
            if (!frame.has_valid_ref_image())
                return;

            ColorMap color_map;
            color_map.set_palette_from_array(InfernoColorMapLinearRGB, countof(InfernoColorMapLinearRGB) / 3);

            const AABB2u& crop_window = frame.get_crop_window();

            float max_error = 0.0f;

            for (size_t y = crop_window.min.y; y <= crop_window.max.y; ++y)
            {
                for (size_t x = crop_window.min.x; x <= crop_window.max.x; ++x)
                {
                    Color3f image_color;
                    frame.image().get_pixel(x, y, image_color);

                    Color3f ref_color;
                    frame.ref_image()->get_pixel(x, y, ref_color);

                    const float error = sqrt(compute_error_squared(image_color, ref_color));
                    max_error = max(max_error, error);

                    m_image->set_pixel(x, y, &error, 1);
                }
            }

            if (max_error == 0.0f)
                return;

            color_map.remap_red_channel(*m_image, crop_window, 0.0f, max_error);
        }

      private:
        auto_release_ptr<AOVAccumulator> create_accumulator() const override
        {
            return auto_release_ptr<AOVAccumulator>(new AOVAccumulator());
        }
    };
}

//
// PixelErrorAOVFactory class implementation.
//

void PixelErrorAOVFactory::release()
{
    delete this;
}

const char* PixelErrorAOVFactory::get_model() const
{
    return PixelErrorAOVModel;
}

Dictionary PixelErrorAOVFactory::get_model_metadata() const
{
    return
        Dictionary()
            .insert("name", PixelErrorAOVModel)
            .insert("label", "Pixel Error");
}

DictionaryArray PixelErrorAOVFactory::get_input_metadata() const
{
    DictionaryArray metadata;
    return metadata;
}

auto_release_ptr<AOV> PixelErrorAOVFactory::create(const ParamArray& params) const
{
    return auto_release_ptr<AOV>(new PixelErrorAOV(params));
}

}   // namespace renderer
<|endoftext|>


<commit_before>/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __STOUT_FLAGS_PARSE_HPP__
#define __STOUT_FLAGS_PARSE_HPP__

#include <sstream> // For istringstream.
#include <string>

#include <stout/duration.hpp>
#include <stout/error.hpp>
#include <stout/json.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>

#include <stout/os/read.hpp>

namespace flags {

template <typename T>
Try<T> parse(const std::string& value)
{
  T t;
  std::istringstream in(value);
  in >> t;
  if (!in.good() && !in.eof()) {
    return Error("Failed to convert into required type");
  }
  return t;
}

template <>
inline Try<std::string> parse(const std::string& value)
{
  return value;
}

template <>
inline Try<bool> parse(const std::string& value)
{
  if (value == "true" || value == "1") {
    return true;
  } else if (value == "false" || value == "0") {
    return false;
  }
  return Error("Expecting a boolean (e.g., true or false)");
}

template <>
inline Try<Duration> parse(const std::string& value)
{
  return Duration::parse(value);
}

template <>
inline Try<Bytes> parse(const std::string& value)
{
  return Bytes::parse(value);
}

template <>
inline Try<JSON::Object> parse(const std::string& value)
{
  // If the flag value corresponds to a file parse the contents of the
  // file as JSON.
  // TODO(vinod): We do not support relative paths because it is
  // tricky to figure out if a flag value corresponds to a relative
  // path or a JSON string. For example, "{", "  {" and "  \n {" are
  // all valid prefixes of a JSON string.
  if (strings::startsWith(value, "/") ||
      strings::startsWith(value, "file://")) {

    const std::string& path =
      strings::remove(value, "file://", strings::PREFIX);

    Try<std::string> read = os::read(path);
    if (read.isError()) {
      return Error("Error reading file '" + path + "': " + read.error());
    }

    return JSON::parse<JSON::Object>(read.get());
  }

  return JSON::parse<JSON::Object>(value);
}

} // namespace flags {

#endif // __STOUT_FLAGS_PARSE_HPP__
<commit_msg>Fixed blank line in flags/parse.hpp.<commit_after>/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __STOUT_FLAGS_PARSE_HPP__
#define __STOUT_FLAGS_PARSE_HPP__

#include <sstream> // For istringstream.
#include <string>

#include <stout/duration.hpp>
#include <stout/error.hpp>
#include <stout/json.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>

#include <stout/os/read.hpp>

namespace flags {

template <typename T>
Try<T> parse(const std::string& value)
{
  T t;
  std::istringstream in(value);
  in >> t;
  if (!in.good() && !in.eof()) {
    return Error("Failed to convert into required type");
  }
  return t;
}

template <>
inline Try<std::string> parse(const std::string& value)
{
  return value;
}

template <>
inline Try<bool> parse(const std::string& value)
{
  if (value == "true" || value == "1") {
    return true;
  } else if (value == "false" || value == "0") {
    return false;
  }
  return Error("Expecting a boolean (e.g., true or false)");
}

template <>
inline Try<Duration> parse(const std::string& value)
{
  return Duration::parse(value);
}

template <>
inline Try<Bytes> parse(const std::string& value)
{
  return Bytes::parse(value);
}

template <>
inline Try<JSON::Object> parse(const std::string& value)
{
  // If the flag value corresponds to a file parse the contents of the
  // file as JSON.
  // TODO(vinod): We do not support relative paths because it is
  // tricky to figure out if a flag value corresponds to a relative
  // path or a JSON string. For example, "{", "  {" and "  \n {" are
  // all valid prefixes of a JSON string.
  if (strings::startsWith(value, "/") ||
      strings::startsWith(value, "file://")) {
    const std::string& path =
      strings::remove(value, "file://", strings::PREFIX);

    Try<std::string> read = os::read(path);
    if (read.isError()) {
      return Error("Error reading file '" + path + "': " + read.error());
    }

    return JSON::parse<JSON::Object>(read.get());
  }

  return JSON::parse<JSON::Object>(value);
}

} // namespace flags {

#endif // __STOUT_FLAGS_PARSE_HPP__
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2013 - 2017)
//   Rene Milk       (2014, 2016 - 2018)
//   Sven Kaulmann   (2014)
//   Tobias Leibner  (2014, 2016 - 2017)

#ifndef DUNE_GDT_SPACES_INTERFACE_HH
#define DUNE_GDT_SPACES_INTERFACE_HH

#include <dune/geometry/type.hh>

#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/local/finite-elements/interfaces.hh>
#include <dune/gdt/spaces/basis/interface.hh>
#include <dune/gdt/spaces/mapper/interfaces.hh>
#include <dune/gdt/spaces/parallel/communication.hh>
#include <dune/gdt/type_traits.hh>

namespace Dune {
namespace GDT {

template <class GridView, size_t range_dim, size_t range_dim_columns = 1, class RangeField = double>
class SpaceInterface
{
  static_assert(XT::Grid::is_view<GridView>::value, "");

public:
  using GridViewType = GridView;
  using GV = GridViewType;
  using D = typename GridViewType::ctype;
  static const constexpr size_t d = GridViewType::dimension;
  using R = RangeField;
  static const constexpr size_t r = range_dim;
  static const constexpr size_t rC = range_dim_columns;

  using GlobalBasisType = GlobalBasisInterface<GridViewType, r, rC, R>;
  using MapperType = MapperInterface<GridViewType>;
  using FiniteElementType = LocalFiniteElementInterface<D, d, R, r, rC>;

  using DofCommunicatorType = typename DofCommunicationChooser<GridViewType>::Type;

  SpaceInterface()
    : dof_communicator_(nullptr)
  {
  }

  virtual ~SpaceInterface() = default;

  virtual const GridViewType& grid_view() const = 0;

  /**
   * \name These methods provide the actual functionality, they have to be implemented.
   * \{
   **/

  virtual const MapperType& mapper() const = 0;

  virtual const GlobalBasisType& basis() const = 0;

  virtual const FiniteElementType& finite_element(const GeometryType& geometry_type) const = 0;

  /// \}

  /**
   * \name These methods help to identify the space, they have to be implemented.
   * \{
   **/

  virtual SpaceType type() const = 0;

  virtual int min_polorder() const = 0;

  virtual int max_polorder() const = 0;

  /**
   * To query if elements of this space (functions) are continuous (i.e., in C^0), use `continuous(0)`.
   */
  virtual bool continuous(const int diff_order) const = 0;

  virtual bool continuous_normal_components() const = 0;

  /**
   * If this returns true, every finite_element() is expected to provide lagrange_points().
   */
  virtual bool is_lagrangian() const = 0;

  /// \}

  /**
   * \name These methods are required for MPI communication, they are provided.
   * \{
   */

  virtual const DofCommunicatorType& dof_communicator() const
  {
    if (!dof_communicator_)
      DUNE_THROW(Exceptions::space_error,
                 "The actual space has to either implement its own dof_communicator() or call "
                 "create_communicator() in the ctor!");
    return *dof_communicator_;
  }

  /// \}

protected:
  void create_communicator()
  {
    if (!dof_communicator_) {
      dof_communicator_ =
          std::shared_ptr<DofCommunicatorType>(DofCommunicationChooser<GridViewType>::create(grid_view()));
      DofCommunicationChooser<GridViewType>::prepare(*this, *dof_communicator_);
    }
  }

private:
  std::shared_ptr<DofCommunicatorType> dof_communicator_;
}; // class SpaceInterface

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_INTERFACE_HH
<commit_msg>[spaces.interface] let range_dim default to 1<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2013 - 2017)
//   Rene Milk       (2014, 2016 - 2018)
//   Sven Kaulmann   (2014)
//   Tobias Leibner  (2014, 2016 - 2017)

#ifndef DUNE_GDT_SPACES_INTERFACE_HH
#define DUNE_GDT_SPACES_INTERFACE_HH

#include <dune/geometry/type.hh>

#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/local/finite-elements/interfaces.hh>
#include <dune/gdt/spaces/basis/interface.hh>
#include <dune/gdt/spaces/mapper/interfaces.hh>
#include <dune/gdt/spaces/parallel/communication.hh>
#include <dune/gdt/type_traits.hh>

namespace Dune {
namespace GDT {

template <class GridView, size_t range_dim = 1, size_t range_dim_columns = 1, class RangeField = double>
class SpaceInterface
{
  static_assert(XT::Grid::is_view<GridView>::value, "");

public:
  using GridViewType = GridView;
  using GV = GridViewType;
  using D = typename GridViewType::ctype;
  static const constexpr size_t d = GridViewType::dimension;
  using R = RangeField;
  static const constexpr size_t r = range_dim;
  static const constexpr size_t rC = range_dim_columns;

  using GlobalBasisType = GlobalBasisInterface<GridViewType, r, rC, R>;
  using MapperType = MapperInterface<GridViewType>;
  using FiniteElementType = LocalFiniteElementInterface<D, d, R, r, rC>;

  using DofCommunicatorType = typename DofCommunicationChooser<GridViewType>::Type;

  SpaceInterface()
    : dof_communicator_(nullptr)
  {
  }

  virtual ~SpaceInterface() = default;

  virtual const GridViewType& grid_view() const = 0;

  /**
   * \name These methods provide the actual functionality, they have to be implemented.
   * \{
   **/

  virtual const MapperType& mapper() const = 0;

  virtual const GlobalBasisType& basis() const = 0;

  virtual const FiniteElementType& finite_element(const GeometryType& geometry_type) const = 0;

  /// \}

  /**
   * \name These methods help to identify the space, they have to be implemented.
   * \{
   **/

  virtual SpaceType type() const = 0;

  virtual int min_polorder() const = 0;

  virtual int max_polorder() const = 0;

  /**
   * To query if elements of this space (functions) are continuous (i.e., in C^0), use `continuous(0)`.
   */
  virtual bool continuous(const int diff_order) const = 0;

  virtual bool continuous_normal_components() const = 0;

  /**
   * If this returns true, every finite_element() is expected to provide lagrange_points().
   */
  virtual bool is_lagrangian() const = 0;

  /// \}

  /**
   * \name These methods are required for MPI communication, they are provided.
   * \{
   */

  virtual const DofCommunicatorType& dof_communicator() const
  {
    if (!dof_communicator_)
      DUNE_THROW(Exceptions::space_error,
                 "The actual space has to either implement its own dof_communicator() or call "
                 "create_communicator() in the ctor!");
    return *dof_communicator_;
  }

  /// \}

protected:
  void create_communicator()
  {
    if (!dof_communicator_) {
      dof_communicator_ =
          std::shared_ptr<DofCommunicatorType>(DofCommunicationChooser<GridViewType>::create(grid_view()));
      DofCommunicationChooser<GridViewType>::prepare(*this, *dof_communicator_);
    }
  }

private:
  std::shared_ptr<DofCommunicatorType> dof_communicator_;
}; // class SpaceInterface

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_INTERFACE_HH
<|endoftext|>


<commit_before>//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "CompiledShaders\StateMachineLib.h"

namespace FallbackLayer
{
    void CompilePSO(ID3D12Device *pDevice, D3D12_SHADER_BYTECODE shaderByteCode, const StateObjectCollection &stateObjectCollection, ID3D12PipelineState **ppPipelineState)
    {
        D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
        psoDesc.CS = CD3DX12_SHADER_BYTECODE(shaderByteCode);
        psoDesc.NodeMask = stateObjectCollection.m_nodeMask;
        psoDesc.pRootSignature = stateObjectCollection.m_pGlobalRootSignature;

        ThrowInternalFailure(pDevice->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(ppPipelineState)));
    }

    StateIdentifier UberShaderRaytracingProgram::GetStateIdentfier(LPCWSTR pExportName)
    {
        StateIdentifier id = 0;
        if (pExportName)
        {
            auto shaderIdentifier = m_ExportNameToShaderIdentifier.find(pExportName);
            if (shaderIdentifier != m_ExportNameToShaderIdentifier.end())
            {
                id = shaderIdentifier->second.StateId;
            }
            else
            {
                ThrowFailure(E_INVALIDARG, L"Hit group is referring to a shader name that wasn't found in the state object");
            }
        }
        return id;
    }

    UberShaderRaytracingProgram::UberShaderRaytracingProgram(ID3D12Device *pDevice, DxilShaderPatcher &dxilShaderPatcher, const StateObjectCollection &stateObjectCollection) :
        m_DxilShaderPatcher(dxilShaderPatcher)
    {
        UINT numLibraries = (UINT)stateObjectCollection.m_dxilLibraries.size();

        UINT numShaders = 0;
        for (auto &lib : stateObjectCollection.m_dxilLibraries)
        {
            numShaders += lib.NumExports;
        }

        std::vector<DxilLibraryInfo> librariesInfo;
        std::vector<LPCWSTR> exportNames;

        std::vector<CComPtr<IDxcBlob>> patchedBlobList;

        UINT cbvSrvUavHandleSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
        UINT samplerHandleSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
        for (UINT i = 0; i < numLibraries; i++)
        {
            auto &library = stateObjectCollection.m_dxilLibraries[i];
            if (library.NumExports > 0)
            {
                DxilLibraryInfo outputLibInfo((void *)library.DXILLibrary.pShaderBytecode, (UINT)library.DXILLibrary.BytecodeLength);
                CComPtr<IDxcBlob> pOutputBlob;
                for (UINT exportIndex = 0; exportIndex < library.NumExports; exportIndex++)
                {
                    std::wstring exportName = library.pExports[exportIndex].Name;
                    auto pShaderAssociation = stateObjectCollection.m_shaderAssociations.find(exportName);

                    if (pShaderAssociation == stateObjectCollection.m_shaderAssociations.end())
                    {
                        for (auto &hitgroup : stateObjectCollection.m_hitGroups)
                        {
                            LPCWSTR imports[] = {
                                hitgroup.second.ClosestHitShaderImport,
                                hitgroup.second.AnyHitShaderImport,
                                hitgroup.second.IntersectionShaderImport
                            };
                            for(auto hitgroupImport : imports)
                            {
                                if (hitgroupImport && exportName == std::wstring(hitgroupImport))
                                {
                                    pShaderAssociation = stateObjectCollection.m_shaderAssociations.find(hitgroup.first);
                                }
                            }
                        }
                    }

                    if (pShaderAssociation != stateObjectCollection.m_shaderAssociations.end() && pShaderAssociation->second.m_pRootSignature)
                    {
                        CComPtr<ID3D12VersionedRootSignatureDeserializer> pDeserializer;
                        ShaderInfo shaderInfo;
                        shaderInfo.pRootSignatureDesc = GetDescFromRootSignature(pShaderAssociation->second.m_pRootSignature, pDeserializer);

                        if (GetNumParameters(*shaderInfo.pRootSignatureDesc) > 0)
                        {
                            shaderInfo.SamplerDescriptorSizeInBytes = samplerHandleSize;
                            shaderInfo.SrvCbvUavDescriptorSizeInBytes = cbvSrvUavHandleSize;
                            shaderInfo.ShaderRecordIdentifierSizeInBytes = sizeof(ShaderIdentifier);
                            shaderInfo.ExportName = exportName.c_str();

                            CComPtr<IDxcBlob> pPatchedBlob;
                            m_DxilShaderPatcher.PatchShaderBindingTables(
                                (const BYTE *)outputLibInfo.pByteCode,
                                (UINT)outputLibInfo.BytecodeLength,
                                &shaderInfo,
                                &pPatchedBlob);

                            pOutputBlob = pPatchedBlob;
                            outputLibInfo = DxilLibraryInfo(pOutputBlob->GetBufferPointer(), pOutputBlob->GetBufferSize());
                        }
                    }
                }
                patchedBlobList.push_back(pOutputBlob);
                librariesInfo.emplace_back(outputLibInfo);

            }

            for(UINT exportIndex = 0; exportIndex < library.NumExports; exportIndex++)
              exportNames.push_back(library.pExports[exportIndex].Name);
        }

        {
            auto &traversalShader = stateObjectCollection.m_traversalShader.DXILLibrary;
            librariesInfo.emplace_back((void *)traversalShader.pShaderBytecode, traversalShader.BytecodeLength);
            exportNames.push_back(L"Fallback_TraceRay");
        }

        {
            librariesInfo.emplace_back((void *)g_pStateMachineLib, ARRAYSIZE(g_pStateMachineLib));
        }

        std::vector<FallbackLayer::StateIdentifier> stateIdentifiers;
        CComPtr<IDxcBlob> pLinkedBlob;
        m_DxilShaderPatcher.LinkShaders((UINT)stateObjectCollection.m_pipelineStackSize, librariesInfo, exportNames, stateIdentifiers, &pLinkedBlob);

        for (size_t i = 0; i < exportNames.size(); ++i)
        {
            m_ExportNameToShaderIdentifier[exportNames[i]] = { stateIdentifiers[i], 0 };
        }

        for (auto &hitGroupMapEntry : stateObjectCollection.m_hitGroups)
        {
            auto closestHitName = hitGroupMapEntry.second.ClosestHitShaderImport;
            auto anyHitName = hitGroupMapEntry.second.AnyHitShaderImport;
            auto intersectionName = hitGroupMapEntry.second.IntersectionShaderImport;

            ShaderIdentifier shaderId = {};
            shaderId.StateId = GetStateIdentfier(closestHitName);
            shaderId.AnyHitId = GetStateIdentfier(anyHitName);
            shaderId.IntersectionShaderId = GetStateIdentfier(intersectionName);

            auto hitGroupName = hitGroupMapEntry.first;
            m_ExportNameToShaderIdentifier[hitGroupName] = shaderId;
        }

        CompilePSO(
            pDevice,
            CD3DX12_SHADER_BYTECODE(pLinkedBlob->GetBufferPointer(), pLinkedBlob->GetBufferSize()),
            stateObjectCollection,
            &m_pRayTracePSO);

        UINT sizeOfParamterStart = sizeof(m_patchRootSignatureParameterStart);
        ThrowFailure(stateObjectCollection.m_pGlobalRootSignature->GetPrivateData(
            FallbackLayerPatchedParameterStartGUID,
            &sizeOfParamterStart,
            &m_patchRootSignatureParameterStart),
            L"Root signatures in a state object must be created through "
            L"Fallback Layer-specific interaces. Either use RaytracingDevice::D3D12SerializeRootSignature "
            L"or RaytracingDevice::D3D12SerializeFallbackRootSignature and create with "
            L"RaytracingDevice::CreateRootSignature");
    }

    ShaderIdentifier *UberShaderRaytracingProgram::GetShaderIdentifier(LPCWSTR pExportName)
    {
        auto pEntry = m_ExportNameToShaderIdentifier.find(pExportName);
        if (pEntry == m_ExportNameToShaderIdentifier.end())
        {
            return nullptr;
        }
        else
        {
            // Handing out this pointer is safe because the map is read-only at this point
            return &pEntry->second;
        }
    }

    void UberShaderRaytracingProgram::DispatchRays(
        ID3D12GraphicsCommandList *pCommandList,
        ID3D12DescriptorHeap *pSrvCbvUavDescriptorHeap,
        ID3D12DescriptorHeap *pSamplerDescriptorHeap,
        const std::unordered_map<UINT, WRAPPED_GPU_POINTER> &boundAccelerationStructures,
        const D3D12_FALLBACK_DISPATCH_RAYS_DESC &desc)
    {
        assert(pSrvCbvUavDescriptorHeap);
        pCommandList->SetComputeRootDescriptorTable(m_patchRootSignatureParameterStart + CbvSrvUavDescriptorHeapAliasedTables, pSrvCbvUavDescriptorHeap->GetGPUDescriptorHandleForHeapStart());

        if (pSamplerDescriptorHeap)
        {
            pCommandList->SetComputeRootDescriptorTable(m_patchRootSignatureParameterStart + SamplerDescriptorHeapAliasedTables, pSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
        }
        if (desc.HitGroupTable.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + HitGroupRecord, desc.HitGroupTable.StartAddress);
        }
        if (desc.MissShaderTable.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + MissShaderRecord, desc.MissShaderTable.StartAddress);
        }
        if (desc.RayGenerationShaderRecord.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + RayGenShaderRecord, desc.RayGenerationShaderRecord.StartAddress);
        }
        if (desc.CallableShaderTable.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + CallableShaderRecord, desc.CallableShaderTable.StartAddress);
        }

        DispatchRaysConstants constants;
        constants.RayDispatchDimensionsWidth = desc.Width;
        constants.RayDispatchDimensionsHeight = desc.Height;
        constants.HitGroupShaderRecordStride = static_cast<UINT>(desc.HitGroupTable.StrideInBytes);
        constants.MissShaderRecordStride = static_cast<UINT>(desc.MissShaderTable.StrideInBytes);
        constants.SrvCbvUavDescriptorHeapStart = pSrvCbvUavDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr;
        constants.SamplerDescriptorHeapStart = pSamplerDescriptorHeap ? pSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr : 0;

        pCommandList->SetComputeRoot32BitConstants(m_patchRootSignatureParameterStart + DispatchConstants, SizeOfInUint32(DispatchRaysConstants), &constants, 0);

        UINT entriesAdded = 0;
        std::vector<WRAPPED_GPU_POINTER> AccelerationStructuresEntries(boundAccelerationStructures.size());
        for (auto &entry : boundAccelerationStructures)
        {
            AccelerationStructuresEntries[entriesAdded++] = entry.second;
        }

        pCommandList->SetComputeRoot32BitConstants(
            m_patchRootSignatureParameterStart + AccelerationStructuresList, (UINT)(AccelerationStructuresEntries.size() * (SizeOfInUint32(*AccelerationStructuresEntries.data()))), AccelerationStructuresEntries.data(), 0);

#ifdef DEBUG
        m_pPredispatchCallback(pCommandList, m_patchRootSignatureParameterStart);
#endif

        UINT dispatchWidth = DivideAndRoundUp<UINT>(desc.Width, THREAD_GROUP_WIDTH);
        UINT dispatchHeight = DivideAndRoundUp<UINT>(desc.Height, THREAD_GROUP_HEIGHT);

        pCommandList->SetPipelineState(m_pRayTracePSO);
        pCommandList->Dispatch(dispatchWidth, dispatchHeight, 1);
    }
}
<commit_msg>  Adding workaround to enable recursion to work well when the intersection/anyhit shader is active<commit_after>//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "CompiledShaders\StateMachineLib.h"

namespace FallbackLayer
{
    void CompilePSO(ID3D12Device *pDevice, D3D12_SHADER_BYTECODE shaderByteCode, const StateObjectCollection &stateObjectCollection, ID3D12PipelineState **ppPipelineState)
    {
        D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
        psoDesc.CS = CD3DX12_SHADER_BYTECODE(shaderByteCode);
        psoDesc.NodeMask = stateObjectCollection.m_nodeMask;
        psoDesc.pRootSignature = stateObjectCollection.m_pGlobalRootSignature;

        ThrowInternalFailure(pDevice->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(ppPipelineState)));
    }

    StateIdentifier UberShaderRaytracingProgram::GetStateIdentfier(LPCWSTR pExportName)
    {
        StateIdentifier id = 0;
        if (pExportName)
        {
            auto shaderIdentifier = m_ExportNameToShaderIdentifier.find(pExportName);
            if (shaderIdentifier != m_ExportNameToShaderIdentifier.end())
            {
                id = shaderIdentifier->second.StateId;
            }
            else
            {
                ThrowFailure(E_INVALIDARG, L"Hit group is referring to a shader name that wasn't found in the state object");
            }
        }
        return id;
    }

    UberShaderRaytracingProgram::UberShaderRaytracingProgram(ID3D12Device *pDevice, DxilShaderPatcher &dxilShaderPatcher, const StateObjectCollection &stateObjectCollection) :
        m_DxilShaderPatcher(dxilShaderPatcher)
    {
        UINT numLibraries = (UINT)stateObjectCollection.m_dxilLibraries.size();

        UINT numShaders = 0;
        for (auto &lib : stateObjectCollection.m_dxilLibraries)
        {
            numShaders += lib.NumExports;
        }

        std::vector<DxilLibraryInfo> librariesInfo;
        std::vector<LPCWSTR> exportNames;

        std::vector<CComPtr<IDxcBlob>> patchedBlobList;

        UINT cbvSrvUavHandleSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
        UINT samplerHandleSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
        for (UINT i = 0; i < numLibraries; i++)
        {
            auto &library = stateObjectCollection.m_dxilLibraries[i];
            if (library.NumExports > 0)
            {
                DxilLibraryInfo outputLibInfo((void *)library.DXILLibrary.pShaderBytecode, (UINT)library.DXILLibrary.BytecodeLength);
                CComPtr<IDxcBlob> pOutputBlob;
                for (UINT exportIndex = 0; exportIndex < library.NumExports; exportIndex++)
                {
                    std::wstring exportName = library.pExports[exportIndex].Name;
                    auto pShaderAssociation = stateObjectCollection.m_shaderAssociations.find(exportName);

                    if (pShaderAssociation == stateObjectCollection.m_shaderAssociations.end())
                    {
                        for (auto &hitgroup : stateObjectCollection.m_hitGroups)
                        {
                            LPCWSTR imports[] = {
                                hitgroup.second.ClosestHitShaderImport,
                                hitgroup.second.AnyHitShaderImport,
                                hitgroup.second.IntersectionShaderImport
                            };
                            for(auto hitgroupImport : imports)
                            {
                                if (hitgroupImport && exportName == std::wstring(hitgroupImport))
                                {
                                    pShaderAssociation = stateObjectCollection.m_shaderAssociations.find(hitgroup.first);
                                }
                            }
                        }
                    }

                    if (pShaderAssociation != stateObjectCollection.m_shaderAssociations.end() && pShaderAssociation->second.m_pRootSignature)
                    {
                        CComPtr<ID3D12VersionedRootSignatureDeserializer> pDeserializer;
                        ShaderInfo shaderInfo;
                        shaderInfo.pRootSignatureDesc = GetDescFromRootSignature(pShaderAssociation->second.m_pRootSignature, pDeserializer);

                        if (GetNumParameters(*shaderInfo.pRootSignatureDesc) > 0)
                        {
                            shaderInfo.SamplerDescriptorSizeInBytes = samplerHandleSize;
                            shaderInfo.SrvCbvUavDescriptorSizeInBytes = cbvSrvUavHandleSize;
                            shaderInfo.ShaderRecordIdentifierSizeInBytes = sizeof(ShaderIdentifier);
                            shaderInfo.ExportName = exportName.c_str();

                            CComPtr<IDxcBlob> pPatchedBlob;
                            m_DxilShaderPatcher.PatchShaderBindingTables(
                                (const BYTE *)outputLibInfo.pByteCode,
                                (UINT)outputLibInfo.BytecodeLength,
                                &shaderInfo,
                                &pPatchedBlob);

                            pOutputBlob = pPatchedBlob;
                            outputLibInfo = DxilLibraryInfo(pOutputBlob->GetBufferPointer(), pOutputBlob->GetBufferSize());
                        }
                    }
                }
                patchedBlobList.push_back(pOutputBlob);
                librariesInfo.emplace_back(outputLibInfo);

            }

            for(UINT exportIndex = 0; exportIndex < library.NumExports; exportIndex++)
              exportNames.push_back(library.pExports[exportIndex].Name);
        }

        {
            auto &traversalShader = stateObjectCollection.m_traversalShader.DXILLibrary;
            librariesInfo.emplace_back((void *)traversalShader.pShaderBytecode, traversalShader.BytecodeLength);
            exportNames.push_back(L"Fallback_TraceRay");
        }

        {
            librariesInfo.emplace_back((void *)g_pStateMachineLib, ARRAYSIZE(g_pStateMachineLib));
        }

        std::vector<FallbackLayer::StateIdentifier> stateIdentifiers;
        CComPtr<IDxcBlob> pLinkedBlob;
        UINT stackSize = (UINT)stateObjectCollection.m_pipelineStackSize;
        if (stackSize == 0 && (stateObjectCollection.IsUsingAnyHit || stateObjectCollection.IsUsingIntersection))
        {
            // TODO: The stack size used by the traversal shader is high when it's split by a continuation from the
            // Intersection shader or the Anyhit. Currently setting a higher hard-coded value, this can go-away
            // once API-specified stack-sizes are supported
            stackSize = 2048;
        }

        m_DxilShaderPatcher.LinkShaders(stackSize, librariesInfo, exportNames, stateIdentifiers, &pLinkedBlob);

        for (size_t i = 0; i < exportNames.size(); ++i)
        {
            m_ExportNameToShaderIdentifier[exportNames[i]] = { stateIdentifiers[i], 0 };
        }

        for (auto &hitGroupMapEntry : stateObjectCollection.m_hitGroups)
        {
            auto closestHitName = hitGroupMapEntry.second.ClosestHitShaderImport;
            auto anyHitName = hitGroupMapEntry.second.AnyHitShaderImport;
            auto intersectionName = hitGroupMapEntry.second.IntersectionShaderImport;

            ShaderIdentifier shaderId = {};
            shaderId.StateId = GetStateIdentfier(closestHitName);
            shaderId.AnyHitId = GetStateIdentfier(anyHitName);
            shaderId.IntersectionShaderId = GetStateIdentfier(intersectionName);

            auto hitGroupName = hitGroupMapEntry.first;
            m_ExportNameToShaderIdentifier[hitGroupName] = shaderId;
        }

        CompilePSO(
            pDevice,
            CD3DX12_SHADER_BYTECODE(pLinkedBlob->GetBufferPointer(), pLinkedBlob->GetBufferSize()),
            stateObjectCollection,
            &m_pRayTracePSO);

        UINT sizeOfParamterStart = sizeof(m_patchRootSignatureParameterStart);
        ThrowFailure(stateObjectCollection.m_pGlobalRootSignature->GetPrivateData(
            FallbackLayerPatchedParameterStartGUID,
            &sizeOfParamterStart,
            &m_patchRootSignatureParameterStart),
            L"Root signatures in a state object must be created through "
            L"Fallback Layer-specific interaces. Either use RaytracingDevice::D3D12SerializeRootSignature "
            L"or RaytracingDevice::D3D12SerializeFallbackRootSignature and create with "
            L"RaytracingDevice::CreateRootSignature");
    }

    ShaderIdentifier *UberShaderRaytracingProgram::GetShaderIdentifier(LPCWSTR pExportName)
    {
        auto pEntry = m_ExportNameToShaderIdentifier.find(pExportName);
        if (pEntry == m_ExportNameToShaderIdentifier.end())
        {
            return nullptr;
        }
        else
        {
            // Handing out this pointer is safe because the map is read-only at this point
            return &pEntry->second;
        }
    }

    void UberShaderRaytracingProgram::DispatchRays(
        ID3D12GraphicsCommandList *pCommandList,
        ID3D12DescriptorHeap *pSrvCbvUavDescriptorHeap,
        ID3D12DescriptorHeap *pSamplerDescriptorHeap,
        const std::unordered_map<UINT, WRAPPED_GPU_POINTER> &boundAccelerationStructures,
        const D3D12_FALLBACK_DISPATCH_RAYS_DESC &desc)
    {
        assert(pSrvCbvUavDescriptorHeap);
        pCommandList->SetComputeRootDescriptorTable(m_patchRootSignatureParameterStart + CbvSrvUavDescriptorHeapAliasedTables, pSrvCbvUavDescriptorHeap->GetGPUDescriptorHandleForHeapStart());

        if (pSamplerDescriptorHeap)
        {
            pCommandList->SetComputeRootDescriptorTable(m_patchRootSignatureParameterStart + SamplerDescriptorHeapAliasedTables, pSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
        }
        if (desc.HitGroupTable.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + HitGroupRecord, desc.HitGroupTable.StartAddress);
        }
        if (desc.MissShaderTable.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + MissShaderRecord, desc.MissShaderTable.StartAddress);
        }
        if (desc.RayGenerationShaderRecord.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + RayGenShaderRecord, desc.RayGenerationShaderRecord.StartAddress);
        }
        if (desc.CallableShaderTable.StartAddress)
        {
            pCommandList->SetComputeRootShaderResourceView(m_patchRootSignatureParameterStart + CallableShaderRecord, desc.CallableShaderTable.StartAddress);
        }

        DispatchRaysConstants constants;
        constants.RayDispatchDimensionsWidth = desc.Width;
        constants.RayDispatchDimensionsHeight = desc.Height;
        constants.HitGroupShaderRecordStride = static_cast<UINT>(desc.HitGroupTable.StrideInBytes);
        constants.MissShaderRecordStride = static_cast<UINT>(desc.MissShaderTable.StrideInBytes);
        constants.SrvCbvUavDescriptorHeapStart = pSrvCbvUavDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr;
        constants.SamplerDescriptorHeapStart = pSamplerDescriptorHeap ? pSamplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr : 0;

        pCommandList->SetComputeRoot32BitConstants(m_patchRootSignatureParameterStart + DispatchConstants, SizeOfInUint32(DispatchRaysConstants), &constants, 0);

        UINT entriesAdded = 0;
        std::vector<WRAPPED_GPU_POINTER> AccelerationStructuresEntries(boundAccelerationStructures.size());
        for (auto &entry : boundAccelerationStructures)
        {
            AccelerationStructuresEntries[entriesAdded++] = entry.second;
        }

        pCommandList->SetComputeRoot32BitConstants(
            m_patchRootSignatureParameterStart + AccelerationStructuresList, (UINT)(AccelerationStructuresEntries.size() * (SizeOfInUint32(*AccelerationStructuresEntries.data()))), AccelerationStructuresEntries.data(), 0);

#ifdef DEBUG
        m_pPredispatchCallback(pCommandList, m_patchRootSignatureParameterStart);
#endif

        UINT dispatchWidth = DivideAndRoundUp<UINT>(desc.Width, THREAD_GROUP_WIDTH);
        UINT dispatchHeight = DivideAndRoundUp<UINT>(desc.Height, THREAD_GROUP_HEIGHT);

        pCommandList->SetPipelineState(m_pRayTracePSO);
        pCommandList->Dispatch(dispatchWidth, dispatchHeight, 1);
    }
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2009, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <iterator>
#include <fstream>

#include "boost/bind.hpp"
#include "boost/version.hpp"
#if BOOST_VERSION >= 103600
#define BOOST_SPIRIT_USE_OLD_NAMESPACE
#include "boost/spirit/include/classic.hpp"
#else
#include "boost/spirit.hpp"
#endif

#include "IECore/OBJReader.h"
#include "IECore/CompoundData.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/VectorTypedData.h"
#include "IECore/MessageHandler.h"
#include "IECore/NumericParameter.h"
#include "IECore/TypedParameter.h"
#include "IECore/MeshPrimitive.h"
#include "IECore/CompoundParameter.h"
#include "IECore/FileNameParameter.h"
#include "IECore/ObjectParameter.h"
#include "IECore/NullObject.h"

using namespace std;
using namespace IECore;
using namespace Imath;
using namespace boost;
using namespace boost::spirit;

IE_CORE_DEFINERUNTIMETYPED(OBJReader);

// syntactic sugar for specifying our grammar
typedef boost::spirit::rule<boost::spirit::phrase_scanner_t> srule;

const Reader::ReaderDescription<OBJReader> OBJReader::m_readerDescription("obj");

OBJReader::OBJReader( const string &name )
	: Reader(name, "Alias Wavefront OBJ 3D data reader", new ObjectParameter("result", "the loaded 3D object", new
	NullObject, MeshPrimitive::staticTypeId()))
{
	m_fileNameParameter->setTypedValue(name);
}

bool OBJReader::canRead( const string &fileName )
{
	// there really are no magic numbers, .obj is a simple ascii text file

	// so: enforce at least that the file has '.obj' extension
	if(fileName.rfind(".obj") != fileName.length() - 4)
		return false;

	// attempt to open the file
	ifstream in(fileName.c_str());
	return in.is_open();
}

ObjectPtr OBJReader::doOperation(ConstCompoundObjectPtr operands)
{
	// for now we are going to retrieve vertex, texture, normal coordinates, faces.
	// later (when we have the primitives), we will handle a larger subset of the
	// OBJ format

	IntVectorDataPtr vpf = new IntVectorData();
	m_vpf = &vpf->writable();

	IntVectorDataPtr vids = new IntVectorData();
	m_vids = &vids->writable();

	PrimitiveVariable::Interpolation i = PrimitiveVariable::Vertex;

	MeshPrimitivePtr mesh = new MeshPrimitive();

	V3fVectorDataPtr vertices = new V3fVectorData();
	m_vertices = &vertices->writable();
	mesh->variables.insert(PrimitiveVariableMap::value_type("P", PrimitiveVariable(i, vertices)));

 	// separate texture coordinates
	FloatVectorDataPtr sTextureCoordinates = new FloatVectorData();
	m_sTextureCoordinates = &sTextureCoordinates->writable();
	mesh->variables.insert(PrimitiveVariableMap::value_type("s", PrimitiveVariable(i, sTextureCoordinates)));

	FloatVectorDataPtr tTextureCoordinates = new FloatVectorData();
	m_tTextureCoordinates = &tTextureCoordinates->writable();
	mesh->variables.insert(PrimitiveVariableMap::value_type("t", PrimitiveVariable(i, tTextureCoordinates)));

	// build normals
	V3fVectorDataPtr normals = new V3fVectorData();
	m_normals = &normals->writable();
	mesh->variables.insert(PrimitiveVariableMap::value_type("N", PrimitiveVariable(i, normals)));

	// parse the file
	parseOBJ();

	// create our MeshPrimitive
	mesh->setTopology(vpf, vids, "linear");
	return mesh;
}

// parse a vertex
void OBJReader::parseVertex(const char * begin, const char * end)
{
	vector<float> vec;
	srule vertex = "v" >> real_p[append(vec)] >> real_p[append(vec)] >> real_p[append(vec)];
	parse_info<> result = parse(begin, vertex, space_p);

	// build v
	V3f v;
	v[0] = vec[0];
 	v[1] = vec[1];
 	v[2] = vec[2];

	// add this vertex
	m_vertices->push_back(v);
}

// parse a texture coordinate
void OBJReader::parseTextureCoordinate(const char * begin, const char * end)
{
	vector<float> vec;
	srule vertex = "vt" >> real_p[append(vec)] >> real_p[append(vec)] >> *(real_p[append(vec)]);
	parse_info<> result = parse(begin, vertex, space_p);

	// build v
	V3f vt;
	vt[0] = vec[0];
 	vt[1] = vec[1];
	vt[2] = vec.size() == 3 ? vec[2] : 0.0f;

	// add this texture coordinate
	m_introducedTextureCoordinates.push_back(vt);
}

// parse a normal
void OBJReader::parseNormal(const char * begin, const char * end)
{
	vector<float> vec;
	srule vertex = "vn" >> real_p[append(vec)] >> real_p[append(vec)] >> real_p[append(vec)];
	parse_info<> result = parse(begin, vertex, space_p);

	// build v
	V3f vn;
	vn[0] = vec[0];
	vn[1] = vec[1];
	vn[2] = vec[2];

	// add this normal
	m_introducedNormals.push_back(vn);
}

// parse face
void OBJReader::parseFace(const char * begin, const char * end)
{
	vector<int> vec;
	vector<int> tvec;
	vector<int> nvec;

	srule entry = int_p[append(vec)] >>
		(
			("/" >> (int_p[append(tvec)] | epsilon_p) >> "/" >> (int_p[append(nvec)] | epsilon_p))
			| epsilon_p
		);

	srule face = "f"  >> entry >> entry >> entry >> *(entry);
	parse_info<> result = parse(begin, face, space_p);

	// push back the degree of the face
	m_vpf->push_back(vec.size());

	// merge in the edges.  we index from 0, so shift them down.
	// also, vertices may be indexed negatively, in which case they are relative to
	// the current set of vertices
	for(vector<int>::const_iterator i = vec.begin(); i != vec.end(); ++i)
	{
		m_vids->push_back(*i > 0 ? *i - 1 : m_vertices->size() + *i);
	}

	// merge in texture coordinates and normals, if present
	// OBJ format requires an encoding for faces which uses one of the vertex/texture/normal specifications
	// consistently across the entire face.  eg. we can have all v/vt/vn, or all v//vn, or all v, but not
	// v//vn then v/vt/vn ...
	if(!nvec.empty())
	{
		if(nvec.size() != vec.size())
			throw Exception("invalid face specification");

		// copy in these references to normal vectors to the mesh's normal vector
		for(vector<int>::const_iterator i = nvec.begin(); i != nvec.end(); ++i)
		{
			m_normals->push_back(m_introducedNormals[*i > 0 ? *i - 1 : m_introducedNormals.size() + *i]);
		}
	}
	// otherwise, check if we have specified normals in some previous face
	// if so, and no normals were given here (examples, encoders that do this?), pump in
	// default normal.  the default normal defined here is the zero normal, which is by
	// definition orthogonal to every other vector.  this might result in odd lighting.
	else
	{
		V3f zero(0.0f, 0.0f, 0.0f);
		for(unsigned int i = 0; i < nvec.size(); ++i)
		{
			m_normals->push_back(zero);
		}
	}

	//
	// merge in texture coordinates, if present
	//
	if(!tvec.empty())
	{
		if(tvec.size() != vec.size())
			throw Exception("invalid face specification");

		for(unsigned int i = 0; i < tvec.size(); ++i)
		{
			int index = tvec[i] > 0 ? tvec[i] - 1 : m_introducedTextureCoordinates.size() + tvec[i];
			m_sTextureCoordinates->push_back(m_introducedTextureCoordinates[index][0]);
			m_tTextureCoordinates->push_back(m_introducedTextureCoordinates[index][1]);
		}
	}
	else
	{
		for(unsigned int i = 0; i < tvec.size(); ++i)
		{
			m_sTextureCoordinates->push_back(0.0f);
			m_tTextureCoordinates->push_back(0.0f);
		}
	}
}

void OBJReader::parseGroup(const char *begin, const char *end)
{
	// set current group
	vector<string> groupNames;
	srule grouping = "g" >> *(lexeme_d[alnum_p >> *(alnum_p)][append(groupNames)]);

	parse_info<> result = parse(begin, grouping, space_p);

	// from 'http://local.wasp.uwa.edu.au/~pbourke/dataformats/obj/':
	// The default group name is default.
	if(groupNames.empty())
	{
		groupNames.push_back("default");
	}

	// \todo associate mesh objects with group names
}

void OBJReader::parseOBJ() {

	srule comment = comment_p("#");

	// see
	// http://local.wasp.uwa.edu.au/~pbourke/dataformats/obj/

	// vertices
	srule vertex         = ("v"  >> real_p >> real_p >> real_p) [bind(&OBJReader::parseVertex,            ref(this), _1, _2)];
	srule vertex_texture = ("vt" >> real_p >> real_p)           [bind(&OBJReader::parseTextureCoordinate, ref(this), _1, _2)];
	srule vertex_normal  = ("vn" >> real_p >> real_p >> real_p) [bind(&OBJReader::parseNormal,            ref(this), _1, _2)];
	//srule vertex_parameter_space  = "vp" >> real_p >> real_p >> real_p;

	// srule cs_types = ("bmatrix" | "bezier" | "bspline" | "cardinal" | "taylor");
	// srule vertex_curve_or_surface = "cstype" >> "rat" >> cs_types;
	// srule vertex_degree  = "deg" >> real_p >> real_p;
	// srule vertex_basis_matrix  = "bmat";
	// srule vertex_step_size  = "step" >> int_p >> int_p;
	srule vertex_type = vertex | vertex_texture | vertex_normal;

	// elements
	srule point = "p" >> real_p >> *(real_p);
	srule  line = "l" >> int_p >> int_p >> *(int_p);
	srule  face = (ch_p('f') >> *(anychar_p))[bind(&OBJReader::parseFace, ref(this), _1, _2)];
	// srule curve = "curv";
	// srule curve_2d = "curv2";
	// srule surface = "surf";
	srule element = point | line | face;

 	// free-form curve / surface statements
	// srule parameter = "parm";
	// srule trim_loop = "trim";
	// srule hole_loop = "hole";
	// srule special_curve = "scrv";
	// srule special_point = "sp";
	// srule end_statement = "end";

	// connectivity
	//srule connect = "con";

	// grouping
	srule group_name = ("g" >> *(anychar_p))[bind(&OBJReader::parseGroup, ref(this), _1, _2)];
	//	srule smoothing_group = "s";
	//	srule merging_group = "mg";
	srule object_name = "o" >> int_p;
	srule grouping = group_name | object_name;

	// display and render attributes
	// srule bevel_interpretation = "bevel";
	// srule color_interpolation = "c_interp";
	// srule dissolve_interpolation = "d_interp";
	// srule level_of_detail = "lod";
	// srule material_name = "usemtl";
	// srule material_library = "mtllib";
	// srule shadow_casting = "shadow_obj";
	// srule ray_tracing = "trace_obj";
	// srule curve_approximation_technique = "ctech";
	// srule surface_approximation_technique = "stech";

	ifstream in(fileName().c_str());
	string str;
	while(getline(in, str))
		parse(str.c_str(), vertex_type | element | grouping | comment, space_p);
}
<commit_msg>Correcting interpolation of texture coordinates and normals to be FaceVarying, courtesy of Roberto Hradec. Also only adding these primvars if they actually contain data, to avoid adding invalid variables.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2009, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <iterator>
#include <fstream>

#include "boost/bind.hpp"
#include "boost/version.hpp"
#if BOOST_VERSION >= 103600
#define BOOST_SPIRIT_USE_OLD_NAMESPACE
#include "boost/spirit/include/classic.hpp"
#else
#include "boost/spirit.hpp"
#endif

#include "IECore/OBJReader.h"
#include "IECore/CompoundData.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/VectorTypedData.h"
#include "IECore/MessageHandler.h"
#include "IECore/NumericParameter.h"
#include "IECore/TypedParameter.h"
#include "IECore/MeshPrimitive.h"
#include "IECore/CompoundParameter.h"
#include "IECore/FileNameParameter.h"
#include "IECore/ObjectParameter.h"
#include "IECore/NullObject.h"

using namespace std;
using namespace IECore;
using namespace Imath;
using namespace boost;
using namespace boost::spirit;

IE_CORE_DEFINERUNTIMETYPED(OBJReader);

// syntactic sugar for specifying our grammar
typedef boost::spirit::rule<boost::spirit::phrase_scanner_t> srule;

const Reader::ReaderDescription<OBJReader> OBJReader::m_readerDescription("obj");

OBJReader::OBJReader( const string &name )
	: Reader(name, "Alias Wavefront OBJ 3D data reader", new ObjectParameter("result", "the loaded 3D object", new
	NullObject, MeshPrimitive::staticTypeId()))
{
	m_fileNameParameter->setTypedValue(name);
}

bool OBJReader::canRead( const string &fileName )
{
	// there really are no magic numbers, .obj is a simple ascii text file

	// so: enforce at least that the file has '.obj' extension
	if(fileName.rfind(".obj") != fileName.length() - 4)
		return false;

	// attempt to open the file
	ifstream in(fileName.c_str());
	return in.is_open();
}

ObjectPtr OBJReader::doOperation(ConstCompoundObjectPtr operands)
{
	// for now we are going to retrieve vertex, texture, normal coordinates, faces.
	// later (when we have the primitives), we will handle a larger subset of the
	// OBJ format

	IntVectorDataPtr vpf = new IntVectorData();
	m_vpf = &vpf->writable();

	IntVectorDataPtr vids = new IntVectorData();
	m_vids = &vids->writable();

	V3fVectorDataPtr vertices = new V3fVectorData();
	m_vertices = &vertices->writable();

 	// separate texture coordinates
	FloatVectorDataPtr sTextureCoordinates = new FloatVectorData();
	m_sTextureCoordinates = &sTextureCoordinates->writable();

	FloatVectorDataPtr tTextureCoordinates = new FloatVectorData();
	m_tTextureCoordinates = &tTextureCoordinates->writable();

	// build normals
	V3fVectorDataPtr normals = new V3fVectorData();
	m_normals = &normals->writable();

	// parse the file
	parseOBJ();

	// create our MeshPrimitive
	MeshPrimitivePtr mesh = new MeshPrimitive( vpf, vids, "linear", vertices );
	if( sTextureCoordinates->readable().size() )
	{
		mesh->variables.insert(PrimitiveVariableMap::value_type("s", PrimitiveVariable( PrimitiveVariable::FaceVarying, sTextureCoordinates)));

	}
	if( tTextureCoordinates->readable().size() )
	{
		mesh->variables.insert(PrimitiveVariableMap::value_type("t", PrimitiveVariable(  PrimitiveVariable::FaceVarying, tTextureCoordinates)));
	}
	if( normals->readable().size() )
	{
		mesh->variables.insert(PrimitiveVariableMap::value_type("N", PrimitiveVariable(  PrimitiveVariable::FaceVarying, normals)));
	}
	return mesh;
}

// parse a vertex
void OBJReader::parseVertex(const char * begin, const char * end)
{
	vector<float> vec;
	srule vertex = "v" >> real_p[append(vec)] >> real_p[append(vec)] >> real_p[append(vec)];
	parse_info<> result = parse(begin, vertex, space_p);

	// build v
	V3f v;
	v[0] = vec[0];
 	v[1] = vec[1];
 	v[2] = vec[2];

	// add this vertex
	m_vertices->push_back(v);
}

// parse a texture coordinate
void OBJReader::parseTextureCoordinate(const char * begin, const char * end)
{
	vector<float> vec;
	srule vertex = "vt" >> real_p[append(vec)] >> real_p[append(vec)] >> *(real_p[append(vec)]);
	parse_info<> result = parse(begin, vertex, space_p);

	// build v
	V3f vt;
	vt[0] = vec[0];
 	vt[1] = vec[1];
	vt[2] = vec.size() == 3 ? vec[2] : 0.0f;

	// add this texture coordinate
	m_introducedTextureCoordinates.push_back(vt);
}

// parse a normal
void OBJReader::parseNormal(const char * begin, const char * end)
{
	vector<float> vec;
	srule vertex = "vn" >> real_p[append(vec)] >> real_p[append(vec)] >> real_p[append(vec)];
	parse_info<> result = parse(begin, vertex, space_p);

	// build v
	V3f vn;
	vn[0] = vec[0];
	vn[1] = vec[1];
	vn[2] = vec[2];

	// add this normal
	m_introducedNormals.push_back(vn);
}

// parse face
void OBJReader::parseFace(const char * begin, const char * end)
{
	vector<int> vec;
	vector<int> tvec;
	vector<int> nvec;

	srule entry = int_p[append(vec)] >>
		(
			("/" >> (int_p[append(tvec)] | epsilon_p) >> "/" >> (int_p[append(nvec)] | epsilon_p))
			| epsilon_p
		);

	srule face = "f"  >> entry >> entry >> entry >> *(entry);
	parse_info<> result = parse(begin, face, space_p);

	// push back the degree of the face
	m_vpf->push_back(vec.size());

	// merge in the edges.  we index from 0, so shift them down.
	// also, vertices may be indexed negatively, in which case they are relative to
	// the current set of vertices
	for(vector<int>::const_iterator i = vec.begin(); i != vec.end(); ++i)
	{
		m_vids->push_back(*i > 0 ? *i - 1 : m_vertices->size() + *i);
	}

	// merge in texture coordinates and normals, if present
	// OBJ format requires an encoding for faces which uses one of the vertex/texture/normal specifications
	// consistently across the entire face.  eg. we can have all v/vt/vn, or all v//vn, or all v, but not
	// v//vn then v/vt/vn ...
	if(!nvec.empty())
	{
		if(nvec.size() != vec.size())
			throw Exception("invalid face specification");

		// copy in these references to normal vectors to the mesh's normal vector
		for(vector<int>::const_iterator i = nvec.begin(); i != nvec.end(); ++i)
		{
			m_normals->push_back(m_introducedNormals[*i > 0 ? *i - 1 : m_introducedNormals.size() + *i]);
		}
	}
	// otherwise, check if we have specified normals in some previous face
	// if so, and no normals were given here (examples, encoders that do this?), pump in
	// default normal.  the default normal defined here is the zero normal, which is by
	// definition orthogonal to every other vector.  this might result in odd lighting.
	else
	{
		V3f zero(0.0f, 0.0f, 0.0f);
		for(unsigned int i = 0; i < nvec.size(); ++i)
		{
			m_normals->push_back(zero);
		}
	}

	//
	// merge in texture coordinates, if present
	//
	if(!tvec.empty())
	{
		if(tvec.size() != vec.size())
			throw Exception("invalid face specification");

		for(unsigned int i = 0; i < tvec.size(); ++i)
		{
			int index = tvec[i] > 0 ? tvec[i] - 1 : m_introducedTextureCoordinates.size() + tvec[i];
			m_sTextureCoordinates->push_back(m_introducedTextureCoordinates[index][0]);
			m_tTextureCoordinates->push_back(m_introducedTextureCoordinates[index][1]);
		}
	}
	else
	{
		for(unsigned int i = 0; i < tvec.size(); ++i)
		{
			m_sTextureCoordinates->push_back(0.0f);
			m_tTextureCoordinates->push_back(0.0f);
		}
	}
}

void OBJReader::parseGroup(const char *begin, const char *end)
{
	// set current group
	vector<string> groupNames;
	srule grouping = "g" >> *(lexeme_d[alnum_p >> *(alnum_p)][append(groupNames)]);

	parse_info<> result = parse(begin, grouping, space_p);

	// from 'http://local.wasp.uwa.edu.au/~pbourke/dataformats/obj/':
	// The default group name is default.
	if(groupNames.empty())
	{
		groupNames.push_back("default");
	}

	// \todo associate mesh objects with group names
}

void OBJReader::parseOBJ() {

	srule comment = comment_p("#");

	// see
	// http://local.wasp.uwa.edu.au/~pbourke/dataformats/obj/

	// vertices
	srule vertex         = ("v"  >> real_p >> real_p >> real_p) [bind(&OBJReader::parseVertex,            ref(this), _1, _2)];
	srule vertex_texture = ("vt" >> real_p >> real_p)           [bind(&OBJReader::parseTextureCoordinate, ref(this), _1, _2)];
	srule vertex_normal  = ("vn" >> real_p >> real_p >> real_p) [bind(&OBJReader::parseNormal,            ref(this), _1, _2)];
	//srule vertex_parameter_space  = "vp" >> real_p >> real_p >> real_p;

	// srule cs_types = ("bmatrix" | "bezier" | "bspline" | "cardinal" | "taylor");
	// srule vertex_curve_or_surface = "cstype" >> "rat" >> cs_types;
	// srule vertex_degree  = "deg" >> real_p >> real_p;
	// srule vertex_basis_matrix  = "bmat";
	// srule vertex_step_size  = "step" >> int_p >> int_p;
	srule vertex_type = vertex | vertex_texture | vertex_normal;

	// elements
	srule point = "p" >> real_p >> *(real_p);
	srule  line = "l" >> int_p >> int_p >> *(int_p);
	srule  face = (ch_p('f') >> *(anychar_p))[bind(&OBJReader::parseFace, ref(this), _1, _2)];
	// srule curve = "curv";
	// srule curve_2d = "curv2";
	// srule surface = "surf";
	srule element = point | line | face;

 	// free-form curve / surface statements
	// srule parameter = "parm";
	// srule trim_loop = "trim";
	// srule hole_loop = "hole";
	// srule special_curve = "scrv";
	// srule special_point = "sp";
	// srule end_statement = "end";

	// connectivity
	//srule connect = "con";

	// grouping
	srule group_name = ("g" >> *(anychar_p))[bind(&OBJReader::parseGroup, ref(this), _1, _2)];
	//	srule smoothing_group = "s";
	//	srule merging_group = "mg";
	srule object_name = "o" >> int_p;
	srule grouping = group_name | object_name;

	// display and render attributes
	// srule bevel_interpretation = "bevel";
	// srule color_interpolation = "c_interp";
	// srule dissolve_interpolation = "d_interp";
	// srule level_of_detail = "lod";
	// srule material_name = "usemtl";
	// srule material_library = "mtllib";
	// srule shadow_casting = "shadow_obj";
	// srule ray_tracing = "trace_obj";
	// srule curve_approximation_technique = "ctech";
	// srule surface_approximation_technique = "stech";

	ifstream in(fileName().c_str());
	string str;
	while(getline(in, str))
		parse(str.c_str(), vertex_type | element | grouping | comment, space_p);
}
<|endoftext|>