MythTV  0.26-pre
bumpscope.cpp
Go to the documentation of this file.
00001 #include "mainvisual.h"
00002 #include "bumpscope.h"
00003 
00004 #include <compat.h>
00005 #include <mythlogging.h>
00006 
00007 // This was:
00008 // Bump Scope - Visualization Plugin for XMMS
00009 // Copyright (C) 1999-2001 Zinx Verituse
00010 
00011 #include <cmath>
00012 #include <cstdlib>
00013 
00014 #include <iostream>
00015 using namespace std;
00016 
00017 #include <QCoreApplication>
00018 #include <QPainter>
00019 
00020 BumpScope::BumpScope() :
00021     m_image(NULL),
00022 
00023     m_size(0,0),
00024 
00025     m_color(0x2050FF),
00026     m_x(0), m_y(0), m_width(800), m_height(600),
00027     m_phongrad(800),
00028 
00029     m_color_cycle(true),
00030     m_moving_light(true),
00031     //m_diamond(true),
00032 
00033     m_bpl(0),
00034 
00035     m_rgb_buf(NULL),
00036 
00037     m_iangle(0), m_ixo(0), m_iyo(0), m_ixd(0), m_iyd(0), m_ilx(0), m_ily(0),
00038     m_was_moving(0), m_was_color(0),
00039     m_ih(0.0), m_is(0.0), m_iv(0.0), m_isd(0.0), m_ihd(0),
00040     m_icolor(0)
00041 {
00042     m_fps = 15;
00043 
00044     for (unsigned int i = 255; i > 0; i--)
00045     {
00046         m_intense1[i] = cos(((double)(255 - i) * M_PI) / 512.0);
00047         m_intense2[i] = pow(m_intense1[i], 250) * 150;
00048     }
00049     m_intense1[0] = m_intense1[1];
00050     m_intense2[0] = m_intense2[1];
00051 }
00052 
00053 BumpScope::~BumpScope()
00054 {
00055     if (m_rgb_buf)
00056         delete [] m_rgb_buf;
00057 
00058     if (m_image)
00059         delete m_image;
00060 
00061     for (unsigned int i = 0; i < m_phongdat.size(); i++)
00062         m_phongdat[i].resize(0);
00063     m_phongdat.resize(0);
00064 }
00065 
00066 void BumpScope::resize(const QSize &newsize)
00067 {
00068     m_size = newsize;
00069 
00070     m_size.setHeight((m_size.height() / 2) * 2);
00071     m_size.setWidth((m_size.width() / 4) * 4);
00072 
00073     if (m_rgb_buf)
00074         delete [] m_rgb_buf;
00075 
00076     int bufsize = (m_size.height() + 2) * (m_size.width() + 2);
00077 
00078     m_rgb_buf = new unsigned char[bufsize];
00079 
00080     m_bpl = m_size.width() + 2;
00081 
00082     if (m_image)
00083         delete m_image;
00084 
00085     m_image = new QImage(m_size.width(), m_size.height(), QImage::Format_Indexed8);
00086 
00087     m_width = m_size.width();
00088     m_height = m_size.height();
00089     m_phongrad = m_width;
00090 
00091     m_x = m_width / 2;
00092     m_y = m_height;
00093 
00094     m_phongdat.resize(m_phongrad * 2);
00095     for (unsigned int i = 0; i < m_phongdat.size(); i++)
00096         m_phongdat[i].resize(m_phongrad * 2);
00097 
00098     generate_phongdat();
00099     generate_cmap(m_color);
00100 }
00101 
00102 void BumpScope::blur_8(unsigned char *ptr, int w, int h, int bpl)
00103 {
00104     (void)w;
00105 
00106     register unsigned int i, sum;
00107     register unsigned char *iptr;
00108 
00109     iptr = ptr + bpl + 1;
00110     i = bpl * h;
00111 
00112     while (i--)
00113     {
00114         sum = (iptr[-bpl] + iptr[-1] + iptr[1] + iptr[bpl]) >> 2;
00115         if (sum > 2)
00116             sum -= 2;
00117         *(iptr++) = sum;
00118     }
00119 }
00120 
00121 void BumpScope::generate_cmap(unsigned int color)
00122 {
00123     unsigned int i, red, blue, green, r, g, b;
00124 
00125     if (m_image)
00126     {
00127         red = (unsigned int)(color / 0x10000);
00128         green = (unsigned int)((color % 0x10000) / 0x100);
00129         blue = (unsigned int)(color % 0x100);
00130 
00131         for (i = 255; i > 0; i--)
00132         {
00133              r = (unsigned int)(((double)(100 * red / 255) * m_intense1[i] + m_intense2[i]));
00134              if (r > 255)
00135                  r = 255;
00136              g = (unsigned int)(((double)(100 * green / 255) * m_intense1[i] + m_intense2[i]));
00137              if (g > 255)
00138                  g = 255;
00139              b = (unsigned int)(((double)(100 * blue / 255) * m_intense1[i] + m_intense2[i]));
00140              if (b > 255)
00141                  b = 255;
00142 
00143              m_image->setColor(i, qRgba(r, g, b, 255));
00144          }
00145 
00146          m_image->setColor(0, m_image->color(1));
00147     }
00148 }
00149 
00150 void BumpScope::generate_phongdat(void)
00151 {
00152     unsigned int y, x;
00153     double i, i2;
00154 
00155     unsigned int PHONGRES = m_phongrad * 2;
00156 
00157     for (y = 0; y < m_phongrad; y++)
00158     {
00159         for (x = 0; x < m_phongrad; x++)
00160         {
00161             i = (double)x / ((double)m_phongrad) - 1;
00162             i2 = (double)y / ((double)m_phongrad) - 1;
00163 
00164             //if (m_diamond)
00165                i = 1 - pow(i*i2,.75) - i*i - i2*i2;
00166             //else
00167             //   i = 1 - i*i - i2*i2;
00168 
00169             if (i >= 0)
00170             {
00171                 //if (m_diamond)
00172                     i = i*i*i * 255.0;
00173                 //else
00174                 //    i = i*i*i * 255.0;
00175 
00176                 if (i > 255)
00177                     i = 255;
00178                 unsigned char uci = (unsigned char)i;
00179 
00180                 m_phongdat[y][x] = uci;
00181                 m_phongdat[(PHONGRES-1)-y][x] = uci;
00182                 m_phongdat[y][(PHONGRES-1)-x] = uci;
00183                 m_phongdat[(PHONGRES-1)-y][(PHONGRES-1)-x] = uci;
00184             }
00185             else
00186             {
00187                 m_phongdat[y][x] = 0;
00188                 m_phongdat[(PHONGRES-1)-y][x] = 0;
00189                 m_phongdat[y][(PHONGRES-1)-x] = 0;
00190                 m_phongdat[(PHONGRES-1)-y][(PHONGRES-1)-x] = 0;
00191             }
00192         }
00193     }
00194 }
00195 
00196 void BumpScope::translate(int x, int y, int *xo, int *yo, int *xd, int *yd,
00197                           int *angle)
00198 {
00199     unsigned int HEIGHT = m_height;
00200     unsigned int WIDTH = m_width;
00201 
00202     int wd2 = (int)(WIDTH / 2);
00203     int hd2 = (int)(HEIGHT / 2);
00204 
00205     /* try setting y to both maxes */
00206     *yo = HEIGHT/2;
00207     *angle = (int)(asin((float)(y-(HEIGHT/2))/(float)*yo)/(M_PI/180.0));
00208     *xo = (int)((x-(WIDTH/2))/cos(*angle*(M_PI/180.0)));
00209 
00210     if (*xo >= -wd2 && *xo <= wd2) {
00211         *xd = (*xo>0)?-1:1;
00212         *yd = 0;
00213         return;
00214     }
00215 
00216     *yo = -*yo;
00217     *angle = (int)(asin((float)(y-(HEIGHT/2))/(float)*yo)/(M_PI/180.0));
00218     *xo = (int)((x-(WIDTH/2))/cos(*angle*(M_PI/180.0)));
00219 
00220     if (*xo >= -wd2 && *xo <= wd2) {
00221         *xd = (*xo>0)?-1:1;
00222         *yd = 0;
00223         return;
00224     }
00225 
00226     /* try setting x to both maxes */
00227     *xo = WIDTH/2;
00228     *angle = (int)(acos((float)(x-(WIDTH/2))/(float)*xo)/(M_PI/180.0));
00229     *yo = (int)((y-(HEIGHT/2))/sin(*angle*(M_PI/180.0)));
00230 
00231     if (*yo >= -hd2 && *yo <= hd2) {
00232         *yd = (*yo>0)?-1:1;
00233         *xd = 0;
00234         return;
00235     }
00236 
00237     *xo = -*xo;
00238     *angle = (int)(acos((float)(x-(WIDTH/2))/(float)*xo)/(M_PI/180.0));
00239     *yo = (int)((y-(HEIGHT/2))/sin(*angle*(M_PI/180.0)));
00240 
00241     /* if this isn't right, it's out of our range and we don't care */
00242     *yd = (*yo>0)?-1:1;
00243     *xd = 0;
00244 }
00245 
00246 inline void BumpScope::draw_vert_line(unsigned char *buffer, int x, int y1,
00247                                       int y2)
00248 {
00249     int y;
00250     unsigned char *p;
00251 
00252     if (y1 < y2)
00253     {
00254         p = buffer + ((y1 + 1) * m_bpl) + x + 1;
00255         for (y = y1; y <= y2; y++)
00256         {
00257             *p = 0xff;
00258             p += m_bpl;
00259         }
00260     }
00261     else if (y2 < y1)
00262     {
00263         p = buffer + ((y2 + 1) * m_bpl) + x + 1;
00264         for (y = y2; y <= y1; y++)
00265         {
00266             *p = 0xff;
00267             p += m_bpl;
00268         }
00269     }
00270     else
00271         buffer[((y1 + 1) * m_bpl) + x + 1] = 0xff;
00272 }
00273 
00274 void BumpScope::render_light(int lx, int ly)
00275 {
00276     int prev_y, out_y, dy, dx, xp, yp;
00277     unsigned int PHONGRES = m_phongrad * 2;
00278     unsigned int i, j;
00279 
00280     prev_y = m_bpl + 1;
00281     out_y = 0;
00282     unsigned char *outputbuf = (unsigned char *)(m_image->bits());
00283 
00284     for (dy = (-ly) + (PHONGRES / 2), j = 0; j < m_height; j++, dy++,
00285          prev_y += m_bpl - m_width)
00286     {
00287         for (dx = (-lx) + (PHONGRES / 2), i = 0; i < m_width; i++, dx++,
00288              prev_y++, out_y++)
00289         {
00290             xp = (m_rgb_buf[prev_y - 1] - m_rgb_buf[prev_y + 1]) + dx;
00291             yp = (m_rgb_buf[prev_y - m_bpl] - m_rgb_buf[prev_y + m_bpl]) + dy;
00292 
00293             if (yp < 0 || yp >= (int)PHONGRES ||
00294                 xp < 0 || xp >= (int)PHONGRES)
00295             {
00296                 outputbuf[out_y] = 0;
00297                 continue;
00298             }
00299 
00300             outputbuf[out_y] = m_phongdat[yp][xp];
00301         }
00302     }
00303 }
00304 
00305 void BumpScope::rgb_to_hsv(unsigned int color, double *h, double *s, double *v)
00306 {
00307   double max, min, delta, r, g, b;
00308 
00309   r = (double)(color>>16) / 255.0;
00310   g = (double)((color>>8)&0xff) / 255.0;
00311   b = (double)(color&0xff) / 255.0;
00312 
00313   max = r;
00314   if (g > max) max = g;
00315   if (b > max) max = b;
00316 
00317   min = r;
00318   if (g < min) min = g;
00319   if (b < min) min = b;
00320 
00321   *v = max;
00322 
00323   if (max != 0.0) *s = (max - min) / max;
00324   else *s = 0.0;
00325 
00326   if (*s == 0.0) *h = 0.0;
00327   else
00328     {
00329       delta = max - min;
00330 
00331       if (r == max) *h = (g - b) / delta;
00332       else if (g == max) *h = 2.0 + (b - r) / delta;
00333       else if (b == max) *h = 4.0 + (r - g) / delta;
00334 
00335       *h = *h * 60.0;
00336 
00337       if (*h < 0.0) *h = *h + 360;
00338     }
00339 }
00340 
00341 void BumpScope::hsv_to_rgb(double h, double s, double v, unsigned int *color)
00342 {
00343   int i;
00344   double f, w, q, t, r, g, b;
00345 
00346   if (s == 0.0)
00347     s = 0.000001;
00348 
00349   if (h == -1.0)
00350     {
00351       r = v; g = v; b = v;
00352     }
00353   else
00354     {
00355       if (h == 360.0) h = 0.0;
00356       h = h / 60.0;
00357       i = (int) h;
00358       f = h - i;
00359       w = v * (1.0 - s);
00360       q = v * (1.0 - (s * f));
00361       t = v * (1.0 - (s * (1.0 - f)));
00362 
00363       switch (i)
00364         {
00365         case 0: r = v; g = t; b = w; break;
00366         case 1: r = q; g = v; b = w; break;
00367         case 2: r = w; g = v; b = t; break;
00368         case 3: r = w; g = q; b = v; break;
00369         case 4: r = t; g = w; b = v; break;
00370         /*case 5: use default to keep gcc from complaining */
00371         default: r = v; g = w; b = q; break;
00372         }
00373     }
00374 
00375   *color = ((unsigned int)((double)r*255)<<16) | ((unsigned int)((double)g*255)<<8) | ((unsigned int)((double)b*255));
00376 }
00377 
00378 bool BumpScope::process(VisualNode *node)
00379 {
00380     if (!node || node->length == 0 || !m_image)
00381         return false;
00382 
00383     int numSamps = 512;
00384     if (node->length < 512)
00385         numSamps = node->length;
00386 
00387     unsigned int i;
00388     int y, prev_y;
00389 
00390     prev_y = (int)m_height / 2 + ((int)node->left[0] * (int)m_height) /
00391              (int)0x10000;
00392 
00393     if (prev_y < 0)
00394         prev_y = 0;
00395     if (prev_y >= (int)m_height) prev_y = m_height - 1;
00396 
00397     for (i = 0; i < m_width; i++)
00398     {
00399         y = (i * numSamps) / (m_width - 1);
00400         y = (int)m_height / 2 + ((int)node->left[y] * (int)m_height) /
00401             (int)0x10000;
00402 
00403         if (y < 0)
00404             y = 0;
00405         if (y >= (int)m_height)
00406             y = m_height - 1;
00407 
00408         draw_vert_line(m_rgb_buf, i, prev_y, y);
00409         prev_y = y;
00410     }
00411 
00412     blur_8(m_rgb_buf, m_width, m_height, m_bpl);
00413 
00414     return false;
00415 }
00416 
00417 bool BumpScope::draw(QPainter *p, const QColor &back)
00418 {
00419     if (!m_image || m_image->isNull())
00420     {
00421         LOG(VB_GENERAL, LOG_ERR, "BumpScope::draw: Bad image");
00422         return false;
00423     }
00424 
00425     (void)back;
00426 
00427     m_ilx = m_x;
00428     m_ily = m_y;
00429 
00430     if (m_moving_light)
00431     {
00432         if (!m_was_moving)
00433         {
00434             translate(m_ilx, m_ily, &m_ixo, &m_iyo, &m_ixd, &m_iyd, &m_iangle);
00435             m_was_moving = 1;
00436         }
00437 
00438         m_ilx = (int)(m_width / 2 + cos(m_iangle * (M_PI / 180.0)) * m_ixo);
00439         m_ily = (int)(m_height / 2 + sin(m_iangle * (M_PI / 180.0)) * m_iyo);
00440 
00441         m_iangle += 2;
00442         if (m_iangle >= 360)
00443             m_iangle = 0;
00444 
00445         m_ixo += m_ixd;
00446         if ((int)m_ixo > ((int)m_width / 2) || (int)m_ixo < -((int)m_width / 2))
00447         {
00448             m_ixo = (m_ixo > 0) ? (m_width / 2) : -(m_width / 2);
00449             if (random() & 1)
00450             {
00451                 m_ixd = (m_ixd > 0) ? -1 : 1;
00452                 m_iyd = 0;
00453             }
00454             else
00455             {
00456                 m_iyd = (m_iyd > 0) ? -1 : 1;
00457                 m_ixd = 0;
00458             }
00459         }
00460 
00461         m_iyo += m_iyd;
00462         if ((int)m_iyo > ((int)m_height / 2) || (int)m_iyo < -((int)m_height / 2))
00463         {
00464             m_iyo = (m_iyo > 0) ? (m_height / 2) : -(m_height / 2);
00465             if (random() & 1)
00466             {
00467                 m_ixd = (m_ixd > 0) ? -1 : 1;
00468                 m_iyd = 0;
00469             }
00470             else
00471             {
00472                 m_iyd = (m_iyd > 0) ? -1 : 1;
00473                 m_ixd = 0;
00474             }
00475         }
00476     }
00477 
00478     if (m_color_cycle)
00479     {
00480         if (!m_was_color)
00481         {
00482             rgb_to_hsv(m_color, &m_ih, &m_is, &m_iv);
00483             m_was_color = 1;
00484 
00485             if (random() & 1)
00486             {
00487                 m_ihd = (random() & 1) * 2 - 1;
00488                 m_isd = 0;
00489             }
00490             else
00491             {
00492                 m_isd = 0.01 * ((random() & 1) * 2 - 1);
00493                 m_ihd = 0;
00494             }
00495         }
00496 
00497         hsv_to_rgb(m_ih, m_is, m_iv, &m_icolor);
00498 
00499         generate_cmap(m_icolor);
00500 
00501         if (m_ihd)
00502         {
00503             m_ih += m_ihd;
00504             if (m_ih >= 360)
00505                 m_ih = 0;
00506             if (m_ih < 0)
00507                 m_ih = 359;
00508             if ((random() % 150) == 0)
00509             {
00510                 if (random() & 1)
00511                 {
00512                     m_ihd = (random() & 1) * 2 - 1;
00513                     m_isd = 0;
00514                 }
00515                 else
00516                 {
00517                     m_isd = 0.01 * ((random() & 1) * 2 - 1);
00518                     m_ihd = 0;
00519                 }
00520             }
00521         }
00522         else
00523         {
00524             m_is += m_isd;
00525 
00526             if (m_is <= 0 || m_is >= 0.5)
00527             {
00528                 if (m_is < 0)
00529                     m_is = 0;
00530                 if (m_is > 0.52)
00531                     m_isd = -0.01;
00532                 else if (m_is == 0)
00533                 {
00534                     m_ihd = random() % 360;
00535                     m_isd = 0.01;
00536                 }
00537                 else
00538                 {
00539                     if (random() & 1)
00540                     {
00541                         m_ihd = (random() & 1) * 2 - 1;
00542                         m_isd = 0;
00543                     }
00544                     else
00545                     {
00546                         m_isd = 0.01 * ((random() & 1) * 2 - 1);
00547                         m_ihd = 0;
00548                     }
00549                 }
00550             }
00551         }
00552     }
00553 
00554     render_light(m_ilx, m_ily);
00555 
00556     p->drawImage(0, 0, *m_image);
00557 
00558     return true;
00559 }
00560 
00561 static class BumpScopeFactory : public VisFactory
00562 {
00563   public:
00564     const QString &name(void) const
00565     {
00566         static QString name = QCoreApplication::translate("Visualizers",
00567                                                           "BumpScope");
00568         return name;
00569     }
00570 
00571     uint plugins(QStringList *list) const
00572     {
00573         *list << name();
00574         return 1;
00575     }
00576 
00577     VisualBase *create(MainVisual *parent, const QString &pluginName) const
00578     {
00579         (void)parent;
00580         (void)pluginName;
00581         return new BumpScope();
00582     }
00583 }BumpScopeFactory;
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends