ARB
item_shader.h
Go to the documentation of this file.
1 // ============================================================ //
2 // //
3 // File : item_shader.h //
4 // Purpose : external interface of ITEM_SHADER //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in June 2016 //
7 // http://www.arb-home.de/ //
8 // //
9 // ============================================================ //
10 
11 #ifndef ITEM_SHADER_H
12 #define ITEM_SHADER_H
13 
14 #ifndef SMARTPTR_H
15 #include <smartptr.h>
16 #endif
17 #ifndef ARB_MSG_H
18 #include <arb_msg.h>
19 #endif
20 #ifndef AW_BASE_HXX
21 #include <aw_base.hxx>
22 #endif
23 #ifndef ITEMS_H
24 #include <items.h>
25 #endif
26 #ifndef AW_COLOR_GROUPS_HXX
27 #include <aw_color_groups.hxx>
28 #endif
29 #ifndef _GLIBCXX_STRING
30 #include <string>
31 #endif
32 
33 #define is_assert(cond) arb_assert(cond)
34 
35 class GBDATA;
36 class AW_gc_manager;
37 
38 // ----------------
39 // Phaser
40 
41 class Phaser {
42  float frequency; // 1.0 => [0.0 .. 1.0] gets mapped to whole color range;
43  // 2.0 => [0.0 .. 0.5] and [0.5 .. 1.0] each gets mapped to whole color range
44 
45  float preshift; // allowed values [0.0 .. 1.0]; applied BEFORE frequency mapping
46  float postshift; // allowed values [0.0 .. 1.0]; applied AFTER frequency mapping
47 
48  bool alternate; // if frequency>1.0 => use alternate mapping direction
49 
50  float result_lower_bound; // = result of rephase(0.0)
51  float result_upper_bound; // = result of rephase(1.0)
52 
53  static CONSTEXPR_INLINE bool is_normalized(const float& f) {
54  return f>=0.0 && f<=1.0;
55  }
56  static CONSTEXPR_INLINE float shift_and_wrap(const float& val, const float& shift, float wrapto) {
57  return shift>val ? val-shift+wrapto : val-shift;
58  }
59 
60  float rephase_inbound(float f) const {
61  is_assert(f>=0.0 && f<=1.0);
62 
63  const float preshifted(shift_and_wrap(f, preshift, 1.0));
64  const float blow(preshifted*frequency);
65 
66  int phase(blow);
67  float rest(blow-phase);
68  if (rest <= 0.0 && phase>0) {
69  rest = 1.0;
70  phase--;
71  }
72 
73  rest += postshift;
74  if (rest>1.0) {
75  rest -= 1.0;
76  phase++;
77  }
78  is_assert(is_normalized(rest));
79 
80  const bool do_alter(alternate && (phase&1));
81  const float altered(do_alter ? 1.0-rest : rest);
82 
83 #if defined(DEBUG) && 0
84  fprintf(stderr,
85  "f=%f preshifted=%f blow=%f postshifted=%f phase=%i rest=%f do_alter=%i altered=%f\n",
86  f, preshifted, blow, postshifted, phase, rest, do_alter, altered);
87 #endif
88 
89  is_assert(is_normalized(altered));
90  return altered;
91  }
92 
93  void calc_bound_results() {
94  result_lower_bound = rephase_inbound(0.0);
95  result_upper_bound = rephase_inbound(1.0);
96  }
97 
98 public:
99  Phaser() : // this Phaser does "nothing"
100  frequency(1.0),
101  preshift(0.0),
102  postshift(0.0),
103  alternate(false),
104  result_lower_bound(0.0),
105  result_upper_bound(1.0)
106  {}
107 
108  Phaser(float frequency_, bool alternate_, float preshift_, float postshift_) :
109  frequency(frequency_),
110  preshift(preshift_),
111  postshift(postshift_),
112  alternate(alternate_)
113  {
114  is_assert(is_normalized(preshift));
115  is_assert(is_normalized(postshift));
116 
117  calc_bound_results();
118  }
119 
120  float rephase(float f) const {
121  return
122  f<=0.0
123  ? result_lower_bound
124  : (f>=1.0
125  ? result_upper_bound
126  : rephase_inbound(f));
127  }
128 };
129 
130 // --------------------
131 // ValueTuple
132 
133 class ValueTuple {
143  ValueTuple *undefined_reverse_mix() const { arb_assert(0); return NULp; }
144 
145 public:
147 
148  virtual ~ValueTuple() {}
149 
150  virtual bool is_defined() const = 0;
151  virtual ShadedValue clone() const = 0;
152  virtual int range_offset(const Phaser&) const = 0; // returns int-offset into range [0 .. AW_RANGE_COLORS[
153 
154 #if defined(UNIT_TESTS)
155  virtual const char *inspect() const = 0;
156 #endif
157 
158  // ValueTuple factory:
159  static ShadedValue undefined();
160  static ShadedValue make(float f);
161  static ShadedValue make(float f1, float f2);
162  static ShadedValue make(float f1, float f2, float f3);
163 
164  // mix interface (main function + reverse visitors):
165  virtual ShadedValue mix(float my_ratio, const ValueTuple& other) const = 0;
166  virtual ShadedValue reverse_mix(float /*other_ratio*/, const class NoTuple& /*other*/) const { return undefined_reverse_mix(); }
167  virtual ShadedValue reverse_mix(float /*other_ratio*/, const class LinearTuple& /*other*/) const { return undefined_reverse_mix(); }
168  virtual ShadedValue reverse_mix(float /*other_ratio*/, const class PlanarTuple& /*other*/) const { return undefined_reverse_mix(); }
169  virtual ShadedValue reverse_mix(float /*other_ratio*/, const class SpatialTuple& /*other*/) const { return undefined_reverse_mix(); }
170 };
171 
173 
174 inline ShadedValue mix(const ShadedValue& val1, float val1_ratio, const ShadedValue& val2) {
175  return val1->mix(val1_ratio, *val2);
176 }
177 
178 // --------------------------
179 // ShaderPlugin
180 
181 class ItemShader;
182 
186 };
187 
189  RefPtr<ItemShader> plugged_into;
190 
191  std::string id;
192  std::string description;
193  std::string awar_prefix; // empty means "awars not initialized yet"
194 
195  virtual void init_specific_awars(AW_root *awr) = 0;
196 
197 protected:
198  const ItemShader *shader_plugged_into() const { return plugged_into; }
199 
200 public:
201  ShaderPlugin(const std::string& id_, const std::string& description_) :
202  plugged_into(NULp),
203  id(id_),
204  description(description_)
205  {
210  }
211  virtual ~ShaderPlugin() {}
212 
213  void announce_shader(ItemShader *shader) { plugged_into = shader; }
214 
215  const std::string& get_id() const { return id; }
216  const std::string& get_description() const { return description; }
217 
218  inline const char *get_shader_local_id() const;
219 
220  void init_awars(AW_root *awr, const char *awar_prefix_);
221  const char *plugin_awar(const char *name) const {
222  is_assert(!awar_prefix.empty()); // forgot to call init_awars?
223  return GBS_global_string("%s/%s", awar_prefix.c_str(), name);
224  }
225  const char *dimension_awar(int dim, const char *name) const {
226  is_assert(!awar_prefix.empty()); // forgot to call init_awars?
227  is_assert(dim>=0 && dim<3); // invalid dimension specified
228  return GBS_global_string("%s/%s_%i", awar_prefix.c_str(), name, dim);
229  }
230 
231  bool overlay_marked() const; // true if shader-plugin currently likes to display marked species in marked color
232  bool overlay_color_groups() const; // true if shader-plugin currently likes to display color groups
233 
234  virtual ShadedValue shade(GBDATA *gb_item) const = 0;
235 
236  virtual int get_dimension() const = 0; // returns (current) dimension of shader-plugin
237 
238  virtual bool customizable() const = 0;
239  virtual void customize(AW_root *awr) = 0;
240 
241  virtual char *store_config() const = 0;
242  virtual void load_or_reset_config(const char *cfgstr) = 0;
243 
244  virtual void activate(bool on) = 0; // called with true when plugin gets activated, with false when it gets deactivated
245 
247 };
248 
250 
251 // --------------------
252 // ItemShader
253 
254 #define NO_PLUGIN_SELECTED ""
255 
256 typedef void (*ReshadeCallback)();
257 
258 class ItemShader {
259  std::string id;
260  std::string description;
261  ReshadeCallback reshade_cb;
262 
263  int undefined_gc;
264 
265  mutable int reshade_delay_level;
266  mutable bool reshade_was_suppressed;
267 
268  void delay_reshade_callbacks(bool suppress) const {
269  reshade_delay_level += suppress ? 1 : -1;
270  is_assert(reshade_delay_level>=0);
271 
272  if (!reshade_delay_level) { // switched off delay
273  if (reshade_was_suppressed) {
274  reshade_cb();
275  reshade_was_suppressed = false;
276  }
277  }
278 
279 #if defined(ASSERTION_USED)
280  bool start_of_delay = reshade_delay_level == 1 && suppress;
281  is_assert(implicated(start_of_delay, !reshade_was_suppressed));
282 #endif
283  }
284  friend class DelayReshade;
285 
286 protected:
287  ShaderPluginPtr active_plugin; // null means: no plugin active
288  int first_range_gc; // has to be set by init()!
290 
291 public:
292  ItemShader(const std::string& id_, const std::string& description_, ReshadeCallback rcb, int undefined_gc_) :
293  id(id_),
294  description(description_),
295  reshade_cb(rcb),
296  undefined_gc(undefined_gc_),
297  reshade_delay_level(0),
298  reshade_was_suppressed(false),
299  first_range_gc(-1)
300  {}
301  virtual ~ItemShader() {}
302 
303  virtual void register_plugin(ShaderPluginPtr plugin) = 0;
304  virtual bool activate_plugin(const std::string& id) = 0; // returns 'true' on success
306  virtual std::string active_plugin_name() const = 0;
307 
308  bool is_active_plugin(const ShaderPlugin& plugin) const {
309  return active_plugin_name() == plugin.get_id();
310  }
311 
312  virtual void init() = 0; // call once after register_plugin was called (activates plugin stored in AWAR)
313  virtual void popup_config_window(AW_root *awr) = 0;
314 
315  virtual void check_dimension_change() = 0;
316 
317  const std::string& get_id() const { return id; }
318  const std::string& get_description() const { return description; }
319 
320  bool active() const { return active_plugin.isSet(); }
321  bool overlay_marked() const { return !active() || active_plugin->overlay_marked(); } // if true, caller should use marked-GC
322  bool overlay_color_groups() const { return active() ? active_plugin->overlay_color_groups() : AW_color_groups_active(); } // if true, caller should use color-groups-GCs
323 
324  ShadedValue shade(GBDATA *gb_item) const {
325  is_assert(active()); // don't call if no shader is active
326  return active() ? active_plugin->shade(gb_item) : ValueTuple::undefined();
327  }
328  int to_GC(const ShadedValue& val) const {
329  is_assert(first_range_gc>0);
330  if (val->is_defined()) {
331  return first_range_gc + val->range_offset(phaser);
332  }
333  return undefined_gc;
334  }
335 
338 
339  if (reshade_delay_level) reshade_was_suppressed = true;
340  else reshade_cb();
341  }
342 };
343 
344 class DelayReshade : virtual Noncopyable {
345  const ItemShader *shader;
346 public:
347  DelayReshade(const ItemShader *shader_) :
348  shader(shader_)
349  {
350  shader->delay_reshade_callbacks(true);
351  }
353  shader->delay_reshade_callbacks(false);
354  }
355 };
356 
357 inline const char *ShaderPlugin::get_shader_local_id() const {
358  is_assert(plugged_into);
359  return GBS_global_string("%s_%s", plugged_into->get_id().c_str(), get_id().c_str());
360 }
362  if (plugged_into && plugged_into->is_active_plugin(*this)) {
363  plugged_into->trigger_reshade_callback(mode);
364  }
365 }
366 
367 // -----------------------------
368 // ItemShader registry
369 
370 ItemShader *registerItemShader(AW_root *awr, AW_gc_manager *gcman, BoundItemSel& itemtype, const char *unique_id, const char *description, const char *help_id, ReshadeCallback reshade, int undef_gc);
371 
372 #else
373 #error item_shader.h included twice
374 #endif // ITEM_SHADER_H
virtual bool is_defined() const =0
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * id
Definition: AliAdmin.cxx:17
#define implicated(hypothesis, conclusion)
Definition: arb_assert.h:289
return string(buffer, length)
bool active() const
Definition: item_shader.h:320
static ShadedValue make(float f)
Definition: ValueTuple.cxx:508
bool overlay_marked() const
Definition: item_shader.h:321
ShadedValue shade(GBDATA *gb_item) const
Definition: item_shader.h:324
virtual char * store_config() const =0
SmartPtr< ShaderPlugin > ShaderPluginPtr
Definition: item_shader.h:249
ValueTuple::ShadedValue ShadedValue
Definition: item_shader.h:172
void announce_shader(ItemShader *shader)
Definition: item_shader.h:213
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
virtual ShadedValue reverse_mix(float, const class NoTuple &) const
Definition: item_shader.h:166
void init_awars(AW_root *awr, const char *awar_prefix_)
virtual ~ItemShader()
Definition: item_shader.h:301
const char * get_shader_local_id() const
Definition: item_shader.h:357
ItemShader * registerItemShader(AW_root *awr, AW_gc_manager *gcman, BoundItemSel &itemtype, const char *unique_id, const char *description, const char *help_id, ReshadeCallback reshade, int undef_gc)
bool overlay_marked() const
Phaser(float frequency_, bool alternate_, float preshift_, float postshift_)
Definition: item_shader.h:108
virtual ShadedValue shade(GBDATA *gb_item) const =0
ShaderPlugin(const std::string &id_, const std::string &description_)
Definition: item_shader.h:201
const ItemShader * shader_plugged_into() const
Definition: item_shader.h:198
virtual bool activate_plugin(const std::string &id)=0
bool overlay_color_groups() const
virtual ShadedValue reverse_mix(float, const class LinearTuple &) const
Definition: item_shader.h:167
bool isSet() const
test if SmartPtr is not NULp
Definition: smartptr.h:245
virtual ShadedValue reverse_mix(float, const class SpatialTuple &) const
Definition: item_shader.h:169
virtual bool customizable() const =0
Generic smart pointer.
Definition: smartptr.h:149
bool deactivate_plugin()
Definition: item_shader.h:305
#define false
Definition: ureadseq.h:13
virtual ShadedValue reverse_mix(float, const class PlanarTuple &) const
Definition: item_shader.h:168
virtual int get_dimension() const =0
virtual ShadedValue mix(float my_ratio, const ValueTuple &other) const =0
virtual void check_dimension_change()=0
#define CONSTEXPR_INLINE
Definition: cxxforward.h:111
bool is_active_plugin(const ShaderPlugin &plugin) const
Definition: item_shader.h:308
virtual int range_offset(const Phaser &) const =0
#define NO_PLUGIN_SELECTED
Definition: item_shader.h:254
virtual void register_plugin(ShaderPluginPtr plugin)=0
Phaser()
Definition: item_shader.h:99
const std::string & get_description() const
Definition: item_shader.h:216
virtual ~ShaderPlugin()
Definition: item_shader.h:211
SmartPtr< ValueTuple > ShadedValue
Definition: item_shader.h:146
const char * dimension_awar(int dim, const char *name) const
Definition: item_shader.h:225
virtual void init()=0
const char * plugin_awar(const char *name) const
Definition: item_shader.h:221
virtual void load_or_reset_config(const char *cfgstr)=0
bool AW_color_groups_active()
Definition: AW_preset.cxx:1163
virtual std::string active_plugin_name() const =0
void(* ReshadeCallback)()
Definition: item_shader.h:256
static ShadedValue undefined()
Definition: ValueTuple.cxx:505
void trigger_reshade_callback(ReshadeMode mode)
Definition: item_shader.h:336
ShadedValue mix(const ShadedValue &val1, float val1_ratio, const ShadedValue &val2)
Definition: item_shader.h:174
int first_range_gc
Definition: item_shader.h:288
void trigger_reshade_if_active_cb(ReshadeMode mode)
Definition: item_shader.h:361
DelayReshade(const ItemShader *shader_)
Definition: item_shader.h:347
virtual void customize(AW_root *awr)=0
virtual ShadedValue clone() const =0
#define NULp
Definition: cxxforward.h:116
ReshadeMode
Definition: item_shader.h:183
virtual void activate(bool on)=0
virtual ~ValueTuple()
Definition: item_shader.h:148
Phaser phaser
Definition: item_shader.h:289
const std::string & get_id() const
Definition: item_shader.h:215
ItemShader(const std::string &id_, const std::string &description_, ReshadeCallback rcb, int undefined_gc_)
Definition: item_shader.h:292
const std::string & get_description() const
Definition: item_shader.h:318
bool overlay_color_groups() const
Definition: item_shader.h:322
virtual void popup_config_window(AW_root *awr)=0
#define is_assert(cond)
Definition: item_shader.h:33
const std::string & get_id() const
Definition: item_shader.h:317
int to_GC(const ShadedValue &val) const
Definition: item_shader.h:328
ShaderPluginPtr active_plugin
Definition: item_shader.h:287
float rephase(float f) const
Definition: item_shader.h:120