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