File indexing completed on 2024-04-28 05:46:50
0001 /***************************************************************************** 0002 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU Lesser General Public License as * 0006 * published by the Free Software Foundation; either version 2.1 of the * 0007 * License, or (at your option) version 3, or any later version accepted * 0008 * by the membership of KDE e.V. (or its successor approved by the * 0009 * membership of KDE e.V.), which shall act as a proxy defined in * 0010 * Section 6 of version 3 of the license. * 0011 * * 0012 * This program is distributed in the hope that it will be useful, * 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0015 * Lesser General Public License for more details. * 0016 * * 0017 * You should have received a copy of the GNU Lesser General Public * 0018 * License along with this library. If not, * 0019 * see <http://www.gnu.org/licenses/>. * 0020 *****************************************************************************/ 0021 0022 #include "shadow_p.h" 0023 #include "log.h" 0024 0025 #include <cstdlib> 0026 0027 static void 0028 qtcCreateShadowGradient(float *buff, size_t size) 0029 { 0030 const float r = size / 6.5; 0031 for (size_t i = 0;i < size;i++) { 0032 buff[i] = qtcMax(0, expf(-(i / r)) - 0.0015); 0033 } 0034 } 0035 0036 static void 0037 qtcFillShadowPixel(uint8_t *pixel, const QtcColor *c1, 0038 const QtcColor *c2, double bias, QtcPixelByteOrder order) 0039 { 0040 uint8_t alpha = qtcBound(0, 0xff * bias, 0xff); 0041 if (alpha == 0) { 0042 memset(pixel, 0, 4); 0043 return; 0044 } 0045 QtcColor color; 0046 // c1 is the start color, c2 the end color 0047 _qtcColorMix(c2, c1, bias, &color); 0048 uint8_t red = qtcBound(0, 0xff * color.red, 0xff) * alpha / 0xff; 0049 uint8_t green = qtcBound(0, 0xff * color.green, 0xff) * alpha / 0xff; 0050 uint8_t blue = qtcBound(0, 0xff * color.blue, 0xff) * alpha / 0xff; 0051 switch (order) { 0052 case QTC_PIXEL_ARGB: 0053 pixel[0] = alpha; 0054 pixel[1] = red; 0055 pixel[2] = green; 0056 pixel[3] = blue; 0057 break; 0058 case QTC_PIXEL_BGRA: 0059 pixel[0] = blue; 0060 pixel[1] = green; 0061 pixel[2] = red; 0062 pixel[3] = alpha; 0063 break; 0064 default: 0065 case QTC_PIXEL_RGBA: 0066 pixel[0] = red; 0067 pixel[1] = green; 0068 pixel[2] = blue; 0069 pixel[3] = alpha; 0070 break; 0071 } 0072 } 0073 0074 static inline float 0075 _qtcDistance(int x, int y, int x0, int y0, bool square) 0076 { 0077 int dx = x - x0; 0078 int dy = y - y0; 0079 if (dx == 0) { 0080 return std::abs(dy); 0081 } 0082 if (dy == 0) { 0083 return std::abs(dx); 0084 } 0085 return (square ? qtcMax(std::abs(dx), std::abs(dy)) : 0086 sqrtf(dx * dx + dy * dy)); 0087 } 0088 0089 static inline float 0090 _qtcGradientGetValue(float *gradient, size_t size, float distance) 0091 { 0092 if (distance < 0 || distance > size - 1) { 0093 return 0; 0094 } 0095 int index = floorf(distance); 0096 if (qtcEqual(index, distance)) { 0097 return gradient[index]; 0098 } 0099 return (gradient[index] * (index + 1 - distance) + 0100 gradient[index + 1] * (distance - index)); 0101 } 0102 0103 static QtCurve::Image* 0104 qtcShadowSubImage(size_t size, float *gradient, int vertical_align, 0105 int horizontal_align, const QtcColor *c1, const QtcColor *c2, 0106 bool square, QtcPixelByteOrder order) 0107 { 0108 int height = vertical_align ? size : 1; 0109 int y0 = vertical_align == -1 ? height - 1 : 0; 0110 int width = horizontal_align ? size : 1; 0111 int x0 = horizontal_align == -1 ? width - 1 : 0; 0112 auto *res = new QtCurve::Image(width, height, 4); 0113 for (int x = 0;x < width;x++) { 0114 for (int y = 0;y < height;y++) { 0115 qtcFillShadowPixel( 0116 &res->data[(x + y * width) * 4], c1, c2, 0117 _qtcGradientGetValue( 0118 gradient, size, _qtcDistance(x, y, x0, y0, square)), order); 0119 } 0120 } 0121 return res; 0122 } 0123 0124 void 0125 qtcShadowCreate(size_t size, const QtcColor *c1, const QtcColor *c2, 0126 size_t radius, bool square, QtcPixelByteOrder order, 0127 QtCurve::Image **images) 0128 { 0129 size_t full_size = size + radius; 0130 QtCurve::LocalBuff<float, 128> gradient(full_size); 0131 for (size_t i = 0;i < radius;i++) { 0132 gradient[i] = 0; 0133 } 0134 qtcCreateShadowGradient(gradient.get() + radius, size); 0135 int aligns[8][2] = { 0136 {0, -1}, 0137 {1, -1}, 0138 {1, 0}, 0139 {1, 1}, 0140 {0, 1}, 0141 {-1, 1}, 0142 {-1, 0}, 0143 {-1, -1}, 0144 }; 0145 for (int i = 0;i < 8;i++) { 0146 images[i] = qtcShadowSubImage(full_size, gradient.get(), aligns[i][1], 0147 aligns[i][0], c1, c2, square, order); 0148 } 0149 }