Program Listing for File DiscreteColor.h

Return to documentation for file (include/flamegpu/visualiser/color/DiscreteColor.h)

#ifndef INCLUDE_FLAMEGPU_VISUALISER_COLOR_DISCRETECOLOR_H_
#define INCLUDE_FLAMEGPU_VISUALISER_COLOR_DISCRETECOLOR_H_

#include <map>
#include <string>

#include <sstream>

#include "flamegpu/exception/FLAMEGPUException.h"
#include "flamegpu/visualiser/color/ColorFunction.h"
#include "flamegpu/visualiser/color/Color.h"

namespace flamegpu {
namespace visualiser {

struct Palette;

template<typename T = int32_t>
class DiscreteColor : public ColorFunction, public std::map<T, Color> {
 public:
    DiscreteColor(const std::string& variable_name, const Color &fallback);
    DiscreteColor(const std::string& variable_name, const Palette& palette, const Color& fallback, T offset = 0, T stride = 1);
    DiscreteColor(const std::string& variable_name, const Palette& palette, T offset = 0, T stride = 1);

    std::string getSrc(unsigned int array_len) const override;
    std::string getSamplerName() const override;
    std::string getAgentVariableName() const override;
    std::type_index getAgentVariableRequiredType() const override;

    bool validate() const;

 private:
    Color fallback;
    const std::string variable_name;
};
typedef DiscreteColor<uint32_t> uDiscreteColor;
typedef DiscreteColor<int32_t> iDiscreteColor;
// Define this here, so the static assert can give a better compile error for unwanted template instantiations
template<typename T>
std::string DiscreteColor<T>::getSrc(const unsigned int array_len) const {
    static_assert(std::is_same<T, int32_t>::value || std::is_same<T, uint32_t>::value, "T must be of type int32_t or uint32_t");
    // Validate colors
    if (!validate()) {
        THROW exception::InvalidOperation("DiscreteColor contains invalid color!");
    }
    std::stringstream ss;
    ss << "uniform samplerBuffer color_arg;" << "\n";
    ss << "vec4 calculateColor() {" << "\n";
    // Fetch discrete value
    if (std::is_same<T, int32_t>::value) {
        ss << "    const int category = floatBitsToInt(texelFetch(color_arg, gl_InstanceID * " << array_len << " + " << element << ").x);" << "\n";
    } else if (std::is_same<T, uint32_t>::value) {
        ss << "    const unsigned int category = floatBitsToUint(texelFetch(color_arg, gl_InstanceID * " << array_len << " + " << element << ").x);" << "\n";
    }
    // Select the desired color
    ss << "    switch (category) {" << "\n";
    for (const auto& m : *this)
        ss << "      case " << m.first << ": return vec4(" << m.second[0] << ", " << m.second[1] << ", " << m.second[2] << ", 1);" << "\n";
    // Fallback value
    ss << "      default: return vec4(" << fallback[0] << ", " << fallback[1] << ", " << fallback[2] << ", 1);" << "\n";
    ss << "    }" << "\n";
    ss << "}" << "\n";
    return ss.str();
}
}  // namespace visualiser
}  // namespace flamegpu

#endif  // INCLUDE_FLAMEGPU_VISUALISER_COLOR_DISCRETECOLOR_H_