neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
gradient.hpp
Go to the documentation of this file.
1// gradient.hpp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2020 Leigh Johnston. All Rights Reserved.
5
6 This program is free software: you can redistribute it and / or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#pragma once
21
22#include <neogfx/neogfx.hpp>
26
27namespace neogfx
28{
29 template <gradient_sharing Sharing>
30 class basic_gradient : public reference_counted<i_gradient>
31 {
32 // types
33 public:
35 typedef i_gradient abstract_type;
42 // construction
43 public:
46 basic_gradient(const i_gradient& aOther);
48 explicit basic_gradient(const i_string& aCssDeclaration);
49 explicit basic_gradient(const sRGB_color& aColor);
50 basic_gradient(const sRGB_color& aColor, gradient_direction aDirection);
54 basic_gradient(const basic_gradient& aOther, const abstract_color_stop_list& aColorStops);
55 basic_gradient(const basic_gradient& aOther, const abstract_color_stop_list& aColorStops, const abstract_alpha_stop_list& aAlphaStops);
57 basic_gradient(const std::initializer_list<sRGB_color>& aColors, gradient_direction aDirection = gradient_direction::Vertical);
58 public:
59 basic_gradient& operator=(const i_gradient& aOther) override;
60 public:
61 void clone(neolib::i_ref_ptr<i_gradient> & aResult) const override;
62 // meta
63 public:
64 gradient_id id() const override;
65 bool is_singular() const override;
66 // operations
67 public:
68 abstract_color_stop_list const& color_stops() const override;
70 abstract_alpha_stop_list const& alpha_stops() const override;
72 abstract_color_stop_list::const_iterator find_color_stop(scalar aPos, bool aToInsert = false) const override;
73 abstract_color_stop_list::const_iterator find_color_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert = false) const override;
74 abstract_alpha_stop_list::const_iterator find_alpha_stop(scalar aPos, bool aToInsert = false) const override;
75 abstract_alpha_stop_list::const_iterator find_alpha_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert = false) const override;
76 abstract_color_stop_list::iterator find_color_stop(scalar aPos, bool aToInsert = false) override;
77 abstract_color_stop_list::iterator find_color_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert = false) override;
78 abstract_alpha_stop_list::iterator find_alpha_stop(scalar aPos, bool aToInsert = false) override;
79 abstract_alpha_stop_list::iterator find_alpha_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert = false) override;
84 sRGB_color at(scalar aPos) const override;
85 sRGB_color at(scalar aPos, scalar aStart, scalar aEnd) const override;
86 sRGB_color color_at(scalar aPos) const override;
87 sRGB_color color_at(scalar aPos, scalar aStart, scalar aEnd) const override;
89 sRGB_color::view_component alpha_at(scalar aPos, scalar aStart, scalar aEnd) const override;
90 self_type& reverse() override;
93 gradient_direction direction() const override;
97 gradient_shape shape() const override;
99 gradient_size size() const override;
101 const optional_vec2& exponents() const override;
102 self_type& set_exponents(const optional_vec2 & aExponents) override;
103 const optional_point& center() const override;
104 self_type& set_center(const optional_point & aCenter) override;
105 const std::optional<gradient_tile>& tile() const override;
106 self_type& set_tile(const std::optional<gradient_tile>& aTile) override;
107 scalar smoothness() const override;
108 self_type& set_smoothness(scalar aSmoothness) override;
109 const optional_rect& bounding_box() const override;
110 self_type& set_bounding_box(const optional_rect& aBoundingBox) override;
111 self_type& set_bounding_box_if_none(const optional_rect& aBoundingBox) override;
112 // helpers
113 public:
114 self_type with_bounding_box(const optional_rect& aBoundingBox) const
115 {
116 auto result = *this;
117 result.set_bounding_box(aBoundingBox);
118 return result;
119 }
121 {
122 auto result = *this;
123 if (result.bounding_box() == std::nullopt)
124 result.set_bounding_box(aBoundingBox);
125 return result;
126 }
127 // shader
128 public:
129 const i_gradient_sampler& colors() const override;
130 const i_gradient_filter& filter() const override;
131 // object
132 private:
133 void share_object(i_ref_ptr<i_gradient>& aRef) const override;
134 // implementation
135 private:
136 i_gradient const& object() const;
137 i_gradient& object();
138 // attributes
139 private:
140 mutable neolib::ref_ptr<i_gradient> iObject;
141 optional_rect iBoundingBox;
142 };
143
147
151
152 inline void apply_bounding_box(color_or_gradient& aColorOrGradient, rect const& aBoundingBox)
153 {
154 if (std::holds_alternative<gradient>(aColorOrGradient))
155 static_variant_cast<gradient>(aColorOrGradient).set_bounding_box(aBoundingBox);
156 }
157
158 inline void apply_bounding_box(optional_color_or_gradient& aColorOrGradient, rect const& aBoundingBox)
159 {
160 if (aColorOrGradient != std::nullopt)
161 apply_bounding_box(*aColorOrGradient, aBoundingBox);
162 }
163
164 inline color_or_gradient with_bounding_box(color_or_gradient const& aColorOrGradient, rect const& aBoundingBox, bool aOnlyIfTiled = false)
165 {
166 if (std::holds_alternative<gradient>(aColorOrGradient))
167 {
168 auto const& g = static_variant_cast<gradient const&>(aColorOrGradient);
169 if (!aOnlyIfTiled || (g.tile() != std::nullopt && !g.tile()->aligned))
170 return g.with_bounding_box(aBoundingBox);
171 }
172 return aColorOrGradient;
173 }
174
175
176 inline bool operator==(const gradient& aLhs, const gradient& aRhs)
177 {
178 if (aLhs.is_singular() != aRhs.is_singular())
179 return false;
180 else if (aLhs.is_singular())
181 return false;
182 else if (aLhs.id() == aRhs.id())
183 return true;
184 else
185 return std::forward_as_tuple(aLhs.color_stops(), aLhs.alpha_stops(), aLhs.direction(), aLhs.orientation(), aLhs.shape(), aLhs.size(), aLhs.exponents(), aLhs.center(), aLhs.tile(), aLhs.smoothness()) ==
186 std::forward_as_tuple(aRhs.color_stops(), aRhs.alpha_stops(), aRhs.direction(), aRhs.orientation(), aRhs.shape(), aRhs.size(), aRhs.exponents(), aRhs.center(), aRhs.tile(), aRhs.smoothness());
187 }
188
189 inline std::partial_ordering operator<=>(const gradient& aLhs, const gradient& aRhs)
190 {
191 if (aLhs.is_singular() || aRhs.is_singular())
192 {
193 if (aLhs.is_singular() == aRhs.is_singular())
194 return std::partial_ordering::unordered;
195 if (aLhs.is_singular() < aRhs.is_singular())
196 return std::partial_ordering::less;
197 else
198 return std::partial_ordering::greater;
199 }
200 else if (aLhs.id() == aRhs.id())
201 return std::partial_ordering::equivalent;
202 else
203 return std::forward_as_tuple(aLhs.color_stops(), aLhs.alpha_stops(), aLhs.direction(), aLhs.orientation(), aLhs.shape(), aLhs.size(), aLhs.exponents(), aLhs.center(), aLhs.tile(), aLhs.smoothness()) <=>
204 std::forward_as_tuple(aRhs.color_stops(), aRhs.alpha_stops(), aRhs.direction(), aRhs.orientation(), aRhs.shape(), aRhs.size(), aRhs.exponents(), aRhs.center(), aRhs.tile(), aRhs.smoothness());
205 }
206
207 inline optional_color_or_gradient with_bounding_box(optional_color_or_gradient const& aColorOrGradient, rect const& aBoundingBox)
208 {
209 if (aColorOrGradient != std::nullopt)
210 return with_bounding_box(*aColorOrGradient, aBoundingBox);
211 return aColorOrGradient;
212 }
213
214 template <typename Elem, typename Traits>
215 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const i_gradient& aGradient)
216 {
217 aStream << std::setprecision(4) << "[";
218 aStream << "(";
219 for (auto const& stop : aGradient.color_stops())
220 aStream << (&stop != &aGradient.color_stops()[0] ? ", " : "") << stop.first() << ", " << sRGB_color{ stop.second() };
221 aStream << ")";
222 aStream << ", (";
223 for (auto const& stop : aGradient.alpha_stops())
224 aStream << (&stop != &aGradient.alpha_stops()[0] ? ", " : "") << stop.first() << ", " << stop.second() * 1.0 / std::numeric_limits<sRGB_color::view_component>::max();
225 aStream << ")";
226 aStream << ", " << enum_to_string(aGradient.direction());
227 if (std::holds_alternative<scalar>(aGradient.orientation()))
228 aStream << ", " << std::get<scalar>(aGradient.orientation());
229 else
230 aStream << ", " << enum_to_string(std::get<corner>(aGradient.orientation()));
231 aStream << ", " << enum_to_string(aGradient.shape());
232 aStream << ", " << enum_to_string(aGradient.size());
233 aStream << ", (";
234 if (aGradient.exponents())
235 aStream << aGradient.exponents()->x << ", " << aGradient.exponents()->y;
236 aStream << ")";
237 aStream << ", (";
238 if (aGradient.center())
239 aStream << aGradient.center()->x << ", " << aGradient.center()->y;
240 aStream << ")";
241 aStream << ", (";
242 if (aGradient.tile())
243 aStream << aGradient.tile()->extents.cx << ", " << aGradient.tile()->extents.cy << ", " << aGradient.tile()->aligned;
244 aStream << ")";
245 aStream << ", " << aGradient.smoothness();
246 aStream << "]";
247 return aStream;
248 }
249
250 template <typename Elem, typename Traits>
251 inline std::basic_istream<Elem, Traits>& operator>>(std::basic_istream<Elem, Traits>& aStream, i_gradient& aGradient)
252 {
253 auto previousImbued = aStream.getloc();
254 if (typeid(std::use_facet<std::ctype<char>>(previousImbued)) != typeid(neolib::comma_as_whitespace))
255 aStream.imbue(std::locale{ previousImbued, new neolib::comma_as_whitespace{} });
256 char ignore;
257 std::string tempString;
258 scalar tempScalar;
259 aStream >> ignore >> ignore;
260 gradient::color_stop_list colorStops;
261 while (aStream)
262 {
263 gradient::color_stop colorStop;
264 aStream >> colorStop.first() >> colorStop.second();
265 if (aStream)
266 colorStops.push_back(colorStop);
267 }
268 aStream.clear();
269 aStream >> ignore >> ignore;
270 gradient::alpha_stop_list alphaStops;
271 while (aStream)
272 {
273 gradient::alpha_stop alphaStop;
274 aStream >> alphaStop.first() >> tempScalar;
275 alphaStop.second() = static_cast<sRGB_color::view_component>(tempScalar * std::numeric_limits<sRGB_color::view_component>::max());
276 if (aStream)
277 alphaStops.push_back(alphaStop);
278 }
279 aStream.clear();
280 aStream >> ignore;
282 aStream >> tempString;
284 gradient_orientation orientation;
285 if (aStream >> tempScalar)
286 {
287 orientation = tempScalar;
288 }
289 else
290 {
291 aStream.clear();
292 aStream >> tempString;
293 orientation = neolib::string_to_enum<corner>(tempString);
294 }
295 gradient_shape shape;
296 aStream >> tempString;
297 shape = neolib::string_to_enum<gradient_shape>(tempString);
299 aStream >> tempString;
301 aStream >> ignore;
302 optional_vec2 exponents;
303 if (aStream >> tempScalar)
304 {
305 scalar y;
306 aStream >> y;
307 exponents.emplace(tempScalar, y);
308 }
309 else
310 aStream.clear();
311 aStream >> ignore;
312 aStream >> ignore;
313 optional_point center;
314 if (aStream >> tempScalar)
315 {
316 scalar y;
317 aStream >> y;
318 center.emplace(tempScalar, y);
319 }
320 else
321 aStream.clear();
322 aStream >> ignore;
323 aStream >> ignore;
324 std::optional<gradient_tile> tile;
325 if (aStream >> tempScalar)
326 {
327 scalar cy;
328 bool aligned;
329 aStream >> cy;
330 aStream >> aligned;
331 tile = gradient_tile{ neogfx::size{ tempScalar, cy }, aligned };
332 }
333 else
334 aStream.clear();
335 aStream >> ignore;
336 scalar smoothness;
337 aStream >> smoothness;
338 aStream >> ignore;
339 aGradient = gradient{ colorStops, alphaStops, direction };
340 aGradient.set_orientation(orientation);
341 aGradient.set_shape(shape);
342 aGradient.set_size(size);
343 aGradient.set_exponents(exponents);
344 aGradient.set_center(center);
345 aGradient.set_tile(tile);
346 aGradient.set_smoothness(smoothness);
347 aStream.imbue(previousImbued);
348 return aStream;
349 }
350
351 template <typename Elem, typename Traits>
352 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, const color_or_gradient& aColorOrGradient)
353 {
354 aStream << '[';
355 aStream << aColorOrGradient.index();
356 if (aColorOrGradient.index() != 0)
357 {
358 aStream << ',';
359 if (std::holds_alternative<color>(aColorOrGradient))
360 aStream << static_variant_cast<color const&>(aColorOrGradient);
361 else if (std::holds_alternative<gradient>(aColorOrGradient))
362 aStream << static_variant_cast<gradient const&>(aColorOrGradient);
363 }
364 aStream << ']';
365 return aStream;
366 }
367
368 template <typename Elem, typename Traits>
369 inline std::basic_istream<Elem, Traits>& operator>>(std::basic_istream<Elem, Traits>& aStream, color_or_gradient& aColorOrGradient)
370 {
371 auto previousImbued = aStream.getloc();
372 if (typeid(std::use_facet<std::ctype<char>>(previousImbued)) != typeid(neolib::comma_and_brackets_as_whitespace))
373 aStream.imbue(std::locale{ previousImbued, new neolib::comma_as_whitespace{} });
374 std::size_t index;
375 aStream >> index;
376 switch (index)
377 {
378 case 0:
379 break;
380 case 1:
381 {
382 color temp;
383 aStream >> temp;
384 aColorOrGradient = temp;
385 }
386 break;
387 case 2:
388 {
389 gradient temp;
390 aStream >> temp;
391 aColorOrGradient = temp;
392 }
393 break;
394 }
395 aStream.imbue(previousImbued);
396 return aStream;
397 }
398}
399
401
402template <>
404{
406};
ViewComponent view_component
Definition color.hpp:83
const optional_rect & bounding_box() const override
self_type & set_combined_alpha(sRGB_color::view_component aAlpha) override
alpha_stop_list::abstract_type abstract_alpha_stop_list
Definition gradient.hpp:41
basic_gradient(const i_string &aCssDeclaration)
const i_gradient_sampler & colors() const override
void clone(neolib::i_ref_ptr< i_gradient > &aResult) const override
basic_gradient< Sharing > self_type
Definition gradient.hpp:34
sRGB_color color_at(scalar aPos, scalar aStart, scalar aEnd) const override
basic_gradient(const i_gradient &aOther)
self_type & set_size(gradient_size aSize) override
basic_gradient(const abstract_color_stop_list &aColorStops, const abstract_alpha_stop_list &aAlphaStops, gradient_direction aDirection=gradient_direction::Vertical)
self_type with_bounding_box_if_none(const optional_rect &aBoundingBox) const
Definition gradient.hpp:120
gradient_id id() const override
abstract_alpha_stop_list::const_iterator find_alpha_stop(scalar aPos, bool aToInsert=false) const override
self_type & set_bounding_box(const optional_rect &aBoundingBox) override
gradient_orientation orientation() const override
abstract_color_stop_list::iterator insert_color_stop(scalar aPos) override
i_gradient abstract_type
Definition gradient.hpp:35
basic_gradient(const sRGB_color &aColor)
self_type & set_shape(gradient_shape aShape) override
self_type & set_center(const optional_point &aCenter) override
abstract_alpha_stop_list::iterator insert_alpha_stop(scalar aPos) override
basic_gradient(const basic_gradient &aOther, const abstract_color_stop_list &aColorStops)
abstract_alpha_stop_list const & alpha_stops() const override
basic_gradient(const neolib::i_vector< sRGB_color::abstract_type > &aColors, gradient_direction aDirection=gradient_direction::Vertical)
basic_gradient(const i_ref_ptr< i_gradient > &aObject)
self_type & set_smoothness(scalar aSmoothness) override
abstract_alpha_stop_list::iterator find_alpha_stop(scalar aPos, bool aToInsert=false) override
color_stop_list::abstract_type abstract_color_stop_list
Definition gradient.hpp:40
sRGB_color color_at(scalar aPos) const override
self_type & set_direction(gradient_direction aDirection) override
abstract_color_stop_list::const_iterator find_color_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert=false) const override
self_type with_bounding_box(const optional_rect &aBoundingBox) const
Definition gradient.hpp:114
basic_gradient(const sRGB_color &aColor1, const sRGB_color &aColor2, gradient_direction aDirection=gradient_direction::Vertical)
abstract_alpha_stop_list & alpha_stops() override
gradient_size size() const override
sRGB_color::view_component alpha_at(scalar aPos, scalar aStart, scalar aEnd) const override
basic_gradient(const abstract_color_stop_list &aColorStops, gradient_direction aDirection=gradient_direction::Vertical)
neolib::pair< scalar, sRGB_color > color_stop
Definition gradient.hpp:36
const i_gradient_filter & filter() const override
abstract_color_stop_list const & color_stops() const override
self_type & reverse() override
bool is_singular() const override
basic_gradient(const basic_gradient &aOther)
self_type & set_tile(const std::optional< gradient_tile > &aTile) override
gradient_shape shape() const override
gradient_direction direction() const override
sRGB_color::view_component alpha_at(scalar aPos) const override
abstract_color_stop_list & color_stops() override
basic_gradient & operator=(const i_gradient &aOther) override
self_type & set_exponents(const optional_vec2 &aExponents) override
basic_gradient(const std::initializer_list< sRGB_color > &aColors, gradient_direction aDirection=gradient_direction::Vertical)
self_type & set_alpha(sRGB_color::view_component aAlpha) override
const std::optional< gradient_tile > & tile() const override
sRGB_color at(scalar aPos) const override
basic_gradient(const basic_gradient &aOther, const abstract_color_stop_list &aColorStops, const abstract_alpha_stop_list &aAlphaStops)
abstract_color_stop_list::iterator find_color_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert=false) override
abstract_color_stop_list::iterator find_color_stop(scalar aPos, bool aToInsert=false) override
sRGB_color at(scalar aPos, scalar aStart, scalar aEnd) const override
abstract_color_stop_list::const_iterator find_color_stop(scalar aPos, bool aToInsert=false) const override
neolib::pair< scalar, sRGB_color::view_component > alpha_stop
Definition gradient.hpp:37
neolib::vector< color_stop > color_stop_list
Definition gradient.hpp:38
basic_gradient(const sRGB_color &aColor, gradient_direction aDirection)
self_type & set_orientation(gradient_orientation aOrientation) override
abstract_alpha_stop_list::iterator find_alpha_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert=false) override
neolib::vector< alpha_stop > alpha_stop_list
Definition gradient.hpp:39
const optional_point & center() const override
self_type & set_bounding_box_if_none(const optional_rect &aBoundingBox) override
scalar smoothness() const override
abstract_color_stop_list::iterator insert_color_stop(scalar aPos, scalar aStart, scalar aEnd) override
const optional_vec2 & exponents() const override
abstract_alpha_stop_list::iterator insert_alpha_stop(scalar aPos, scalar aStart, scalar aEnd) override
abstract_alpha_stop_list::const_iterator find_alpha_stop(scalar aPos, scalar aStart, scalar aEnd, bool aToInsert=false) const override
reference & emplace(Args &&... args)
Definition optional.hpp:166
const second_type & second() const final
Definition pair.hpp:69
const first_type & first() const final
Definition pair.hpp:67
void push_back(abstract_value_type const &aValue) final
Definition vector.hpp:201
#define define_setting_type_as(T, Name)
game::id_t gradient_id
color_or_gradient with_bounding_box(color_or_gradient const &aColorOrGradient, rect const &aBoundingBox, bool aOnlyIfTiled=false)
Definition gradient.hpp:164
text_direction direction(glyph_char const &g)
std::basic_istream< Elem, Traits > & operator>>(std::basic_istream< Elem, Traits > &aStream, basic_point< T > &aPoint)
neolib::optional< gradient > optional_gradient
Definition gradient.hpp:148
neolib::variant< color, gradient > color_or_gradient
Definition gradient.hpp:149
shared_gradient gradient
Definition gradient.hpp:146
basic_gradient< gradient_sharing::Shared > shared_gradient
Definition gradient.hpp:144
bool operator==(const basic_rect< CoordinateType, CoordinateSystem > &left, const basic_rect< CoordinateType, CoordinateSystem > &right)
neolib::optional< color_or_gradient > optional_color_or_gradient
Definition gradient.hpp:150
void apply_bounding_box(color_or_gradient &aColorOrGradient, rect const &aBoundingBox)
Definition gradient.hpp:152
gradient_direction
std::partial_ordering operator<=>(const gradient &aLhs, const gradient &aRhs)
Definition gradient.hpp:189
basic_size< coordinate > size
double scalar
Definition numerical.hpp:63
ref_ptr< ConcreteType > make_ref(Args &&... args)
Definition plf_hive.h:79