File indexing completed on 2024-05-26 04:33:10

0001 /*
0002 *  SPDX-FileCopyrightText: 2010-2012 José Luis Vergara <pentalis@gmail.com>
0003 *
0004 *  SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "phong_pixel_processor.h"
0008 #include <cmath>
0009 #include <iostream>
0010 #include <KoChannelInfo.h>
0011 
0012 PhongPixelProcessor::PhongPixelProcessor(quint32 pixelArea, const KisPropertiesConfigurationSP config)
0013 {
0014     m_pixelArea = pixelArea;
0015     initialize(config);
0016 }
0017 
0018 void PhongPixelProcessor::initialize(const KisPropertiesConfigurationSP config)
0019 {
0020     // Basic, fundamental
0021     normal_vector = QVector3D(0, 0, 1);
0022     vision_vector = QVector3D(0, 0, 1);
0023     x_vector = QVector3D(1, 0, 0);
0024     y_vector = QVector3D(0, 1, 0);
0025 
0026     // Mutable
0027     light_vector = QVector3D(0, 0, 0);
0028     reflection_vector = QVector3D(0, 0, 0);
0029 
0030     //setLightVector(QVector3D(-8, 8, 2));
0031 
0032     Illuminant light[PHONG_TOTAL_ILLUMINANTS];
0033     QVariant guiLight[PHONG_TOTAL_ILLUMINANTS];
0034 
0035     qint32 azimuth;
0036     qint32 inclination;
0037 
0038     for (int i = 0; i < PHONG_TOTAL_ILLUMINANTS; i++) {
0039         if (config->getBool(PHONG_ILLUMINANT_IS_ENABLED[i])) {
0040             if (config->getProperty(PHONG_ILLUMINANT_COLOR[i], guiLight[i])) {
0041                 light[i].RGBvalue << guiLight[i].value<QColor>().redF();
0042                 light[i].RGBvalue << guiLight[i].value<QColor>().greenF();
0043                 light[i].RGBvalue << guiLight[i].value<QColor>().blueF();
0044 
0045                 azimuth = config->getInt(PHONG_ILLUMINANT_AZIMUTH[i]) - 90;
0046                 inclination = config->getInt(PHONG_ILLUMINANT_INCLINATION[i]);
0047 
0048                 qreal m; //2D vector magnitude
0049                 light[i].lightVector.setZ( sin( inclination * M_PI / 180 ) );
0050                 m = cos( inclination * M_PI / 180);
0051 
0052                 light[i].lightVector.setX( cos( azimuth * M_PI / 180 ) * m  );
0053                 light[i].lightVector.setY( sin( azimuth * M_PI / 180 ) * m  );
0054                 //Pay close attention to this, indexes will move in this line
0055                 lightSources.append(light[i]);
0056             }
0057         }
0058     }
0059 
0060     size = lightSources.size();
0061 
0062     //Code that exists only to swiftly switch to the other algorithm (reallyFastIlluminatePixel) to test
0063     if (size > 0) {
0064         fastLight = light[0];
0065         fastLight2 = light[0];
0066     }
0067 
0068     //Ka, Kd and Ks must be between 0 and 1 or grave errors will happen
0069     Ka = config->getDouble(PHONG_AMBIENT_REFLECTIVITY);
0070     Kd = config->getDouble(PHONG_DIFFUSE_REFLECTIVITY);
0071     Ks = config->getDouble(PHONG_SPECULAR_REFLECTIVITY);
0072     shiny_exp = config->getInt(PHONG_SHINYNESS_EXPONENT);
0073 
0074     Ia = Id = Is = 0;
0075 
0076     diffuseLightIsEnabled = config->getBool(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED);
0077     specularLightIsEnabled = config->getBool(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED);
0078 
0079     realheightmap = QVector<double>(m_pixelArea, 0);
0080 }
0081 
0082 
0083 PhongPixelProcessor::~PhongPixelProcessor()
0084 {
0085 
0086 }
0087 
0088 
0089 void PhongPixelProcessor::setLightVector(QVector3D lightVector)
0090 {
0091     lightVector.normalize();
0092     light_vector = lightVector;
0093 }
0094 
0095 QVector<quint16> PhongPixelProcessor::IlluminatePixelFromHeightmap(quint32 posup, quint32 posdown, quint32 posleft, quint32 posright)
0096 {
0097     QVector<quint16> finalPixel(4, 0xFFFF);
0098 
0099     if (lightSources.size() == 0)
0100         return finalPixel;
0101 
0102     // Algorithm begins, Phong Illumination Model
0103     normal_vector.setX(- realheightmap[posright] + realheightmap[posleft]);
0104     normal_vector.setY(- realheightmap[posup] + realheightmap[posdown]);
0105     normal_vector.setZ(8);
0106     normal_vector.normalize();
0107 
0108     // PREPARE ALGORITHM HERE
0109 
0110     finalPixel = IlluminatePixel();
0111 
0112     return finalPixel;
0113 }
0114 
0115 QVector<quint16> PhongPixelProcessor::IlluminatePixel()
0116 {
0117     qreal temp;
0118     quint8 channel = 0;
0119     const quint8 totalChannels = 3; // The 4th is alpha and we'll fill it with a nice 0xFFFF
0120     qreal computation[] = {0, 0, 0};
0121     QVector<quint16> finalPixel(4, 0xFFFF);
0122 
0123     if (lightSources.size() == 0)
0124         return finalPixel;
0125 
0126     // PREPARE ALGORITHM HERE
0127 
0128     for (int i = 0; i < size; i++) {
0129         light_vector = lightSources.at(i).lightVector;
0130 
0131         for (channel = 0; channel < totalChannels; channel++) {
0132             Ia = lightSources.at(i).RGBvalue.at(channel) * Ka;
0133             computation[channel] += Ia;
0134         }
0135         if (diffuseLightIsEnabled) {
0136             temp = Kd * QVector3D::dotProduct(normal_vector, light_vector);
0137             for (channel = 0; channel < totalChannels; channel++) {
0138                 Id = lightSources.at(i).RGBvalue.at(channel) * temp;
0139                 if (Id < 0)     Id = 0;
0140                 if (Id > 1)     Id = 1;
0141                 computation[channel] += Id;
0142             }
0143         }
0144 
0145         if (specularLightIsEnabled) {
0146             reflection_vector = (2 * pow(QVector3D::dotProduct(normal_vector, light_vector), shiny_exp)) * normal_vector - light_vector;
0147             temp = Ks * QVector3D::dotProduct(vision_vector, reflection_vector);
0148             for (channel = 0; channel < totalChannels; channel++) {
0149                 Is = lightSources.at(i).RGBvalue.at(channel) * temp;
0150                 if (Is < 0)     Is = 0;
0151                 if (Is > 1)     Is = 1;
0152                 computation[channel] += Is;
0153             }
0154         }
0155     }
0156 
0157     for (channel = 0; channel < totalChannels; channel++) {
0158         if (computation[channel] > 1)
0159             computation[channel] = 1;
0160         if (computation[channel] < 0)
0161             computation[channel] = 0;
0162     }
0163 
0164     //RGBA actually uses the BGRA order of channels, hence the disorder
0165     finalPixel[2] = quint16(computation[0] * 0xFFFF);
0166     finalPixel[1] = quint16(computation[1] * 0xFFFF);
0167     finalPixel[0] = quint16(computation[2] * 0xFFFF);
0168 
0169     return finalPixel;
0170 }
0171 
0172 QVector<quint16> PhongPixelProcessor::IlluminatePixelFromNormalmap(qreal r, qreal g, qreal b)
0173 {
0174     QVector<quint16> finalPixel(4, 0xFFFF);
0175 
0176     if (lightSources.size() == 0)
0177         return finalPixel;
0178 
0179     //  if ()
0180     // Algorithm begins, Phong Illumination Model
0181     normal_vector.setX(r*2-1.0);
0182     normal_vector.setY(-(g*2-1.0));
0183     normal_vector.setZ(b*2-1.0);
0184     //normal_vector.normalize();
0185 
0186     // PREPARE ALGORITHM HERE
0187 
0188     finalPixel = IlluminatePixel();
0189 
0190     return finalPixel;
0191 }