Simple GUI Library
shadow.cpp
Go to the documentation of this file.
1/**
2 * @author Nikita Mochalov (github.com/tralf-strues)
3 * @file shadow.cpp
4 * @date 2021-11-22
5 *
6 * @copyright Copyright (c) 2021
7 */
8
9#include "paint/shadow.h"
10
11namespace Sgl
12{
13 ShadowSpecification::ShadowSpecification(const Sml::Vec2i& offset, const Sml::Vec2f& scale,
14 int32_t blurRadius, Sml::Color color)
15 : m_Offset(offset), m_Scale(scale), m_Color(color)
16 {
17 m_BlurKernel = Sml::createGaussianBlurKernel(blurRadius);
18 assert(m_BlurKernel);
19 }
20
21 ShadowSpecification::~ShadowSpecification()
22 {
23 if (m_BlurKernel != nullptr)
24 {
25 delete m_BlurKernel;
26 }
27 }
28
29 const Sml::Vec2i& ShadowSpecification::getOffset() const { return m_Offset; }
30 const Sml::Vec2f& ShadowSpecification::getScale() const { return m_Scale; }
31 int32_t ShadowSpecification::getBlurRadius() const { return m_BlurKernel->getRadius(); }
32 Sml::Color ShadowSpecification::getColor() const { return m_Color; }
33
34 Shadow::~Shadow()
35 {
36 if (m_Texture != nullptr)
37 {
38 delete m_Texture;
39 }
40 }
41
42 Sml::Texture* Shadow::getTexture() const { return m_Texture; }
43
44 const ShadowSpecification* Shadow::getSpecification() const { return m_Specification; }
45 void Shadow::setSpecification(const ShadowSpecification* specification) { m_Specification = specification; }
46
47 Shadow::Shadow(const ShadowSpecification* specification) : m_Specification(specification) {}
48
49 void Shadow::update(const Sml::Texture* srcTexture, const Sml::Rectangle<int32_t>& objectRegion)
50 {
51 assert(srcTexture);
52
53 if (m_Specification == nullptr) { return; }
54
55 if (m_Texture != nullptr)
56 {
57 delete m_Texture;
58 }
59
60 int32_t blurRadius = m_Specification->getBlurRadius();
61
62 int32_t shadowWidth = objectRegion.width + 2 * blurRadius;
63 int32_t shadowHeight = objectRegion.height + 2 * blurRadius;
64
65 Sml::Color* srcPixels = srcTexture->readPixels(&objectRegion);
66 Sml::Color* dstPixels = new Sml::Color[shadowWidth * shadowHeight];
67 memset(dstPixels, 0, shadowWidth * shadowHeight * sizeof(Sml::Color));
68
69 float shadowColorAlpha = static_cast<float>(Sml::colorGetA(m_Specification->getColor())) / (255.f * 255.f);
70
71 for (int32_t y = 0; y < objectRegion.height; ++y)
72 {
73 for (int32_t x = 0; x < objectRegion.width; ++x)
74 {
75 Sml::Color srcColor = srcPixels[x + y * objectRegion.width];
76
77 float curColorAlphaFloat = shadowColorAlpha * static_cast<float>(Sml::colorGetA(srcColor));
78 uint8_t curColorAlpha = 255 * curColorAlphaFloat;
79
80 Sml::Color curColor = Sml::colorSetA(m_Specification->getColor(), curColorAlpha);
81 dstPixels[(x + blurRadius) + (y + blurRadius) * shadowWidth] = curColor;
82 }
83 }
84
85 Sml::Color* blurredPixels = new Sml::Color[shadowWidth * shadowHeight];
86
87 Sml::applyKernel(m_Specification->m_BlurKernel,
88 dstPixels,
89 blurredPixels,
90 shadowWidth,
91 shadowHeight);
92
93 m_Texture = new Sml::Texture(shadowWidth, shadowHeight);
94 m_Texture->updatePixels(blurredPixels);
95
96 delete[] srcPixels;
97 delete[] dstPixels;
98 delete[] blurredPixels;
99 }
100
101 void Shadow::render(const Sml::Rectangle<int32_t>& object, const Sml::Rectangle<int32_t>& targetRegion)
102 {
103 if (m_Texture == nullptr)
104 {
105 return;
106 }
107
108 Sml::Rectangle<int32_t> shadowRegion{0,
109 0,
110 static_cast<int32_t>(m_Texture->getWidth()),
111 static_cast<int32_t>(m_Texture->getHeight())};
112
113 shadowRegion = Sml::centerRegion(object, shadowRegion);
114 shadowRegion.pos += m_Specification->getOffset() + targetRegion.pos;
115
116 int32_t scaledWidth = static_cast<int32_t>(m_Texture->getWidth());
117 int32_t scaledHeight = static_cast<int32_t>(m_Texture->getHeight());
118
119 shadowRegion.pos.x -= (scaledWidth - shadowRegion.width) / 2;
120 shadowRegion.pos.y -= (scaledHeight - shadowRegion.height) / 2;
121 shadowRegion.width = scaledWidth;
122 shadowRegion.height = scaledHeight;
123
124 Sml::renderTexture(*m_Texture, &shadowRegion, nullptr);
125 }
126
127 // void Shadow::renderRectangular(const Shadow* shadow, const Sml::Rectangle<int32_t>& object,
128 // const Sml::Rectangle<int32_t>& targetRegion)
129 // {
130 // assert(shadow);
131
132 // Sml::Rectangle<int32_t> rectangle{targetRegion.pos + object.pos + shadow->m_Offset,
133 // object.width, object.height};
134
135 // rectangle.width *= shadow->getScale().x;
136 // rectangle.height *= shadow->getScale().y;
137 // rectangle.pos.x -= (rectangle.width - object.width) / 2;
138 // rectangle.pos.y -= (rectangle.height - object.height) / 2;
139
140 // Sml::Renderer::getInstance().setColor(shadow->m_Color);
141 // Sml::renderFilledRect(rectangle);
142
143 // rectangle.pos.x -= shadow->getBlurRadius();
144 // rectangle.pos.y -= shadow->getBlurRadius();
145 // rectangle.width += 2 * shadow->getBlurRadius();
146 // rectangle.height += 2 * shadow->getBlurRadius();
147
148 // if (rectangle.pos.x >= targetRegion.width || rectangle.pos.y >= targetRegion.height)
149 // {
150 // return;
151 // }
152
153 // if (rectangle.pos.x < 0)
154 // {
155 // rectangle.width += rectangle.pos.x;
156 // rectangle.pos.x = 0;
157 // }
158
159 // if (rectangle.pos.y < 0)
160 // {
161 // rectangle.height += rectangle.pos.y;
162 // rectangle.pos.y = 0;
163 // }
164
165 // Sml::applyKernel(shadow->m_BlurKernel, rectangle);
166 // }
167}