00001 #include "mainvisual.h"
00002 #include "bumpscope.h"
00003
00004 #include <compat.h>
00005 #include <mythlogging.h>
00006
00007
00008
00009
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
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
00165 i = 1 - pow(i*i2,.75) - i*i - i2*i2;
00166
00167
00168
00169 if (i >= 0)
00170 {
00171
00172 i = i*i*i * 255.0;
00173
00174
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
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
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
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
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;