MythTV  master
bumpscope.cpp
Go to the documentation of this file.
1 #include "mainvisual.h"
2 #include "bumpscope.h"
3 
4 #include <compat.h>
5 #include <mythlogging.h>
6 
7 // This was:
8 // Bump Scope - Visualization Plugin for XMMS
9 // Copyright (C) 1999-2001 Zinx Verituse
10 
11 #include <cmath>
12 #include <cstdlib>
13 
14 #include <iostream>
15 using namespace std;
16 
17 #include <QCoreApplication>
18 #include <QPainter>
19 
21 {
22  m_fps = 15;
23 
24  for (unsigned int i = 255; i > 0; i--)
25  {
26  m_intense1[i] = cos(((double)(255 - i) * M_PI) / 512.0);
27  m_intense2[i] = pow(m_intense1[i], 250) * 150;
28  }
29  m_intense1[0] = m_intense1[1];
30  m_intense2[0] = m_intense2[1];
31 }
32 
34 {
35  delete [] m_rgb_buf;
36  delete m_image;
37  for (size_t i = 0; i < m_phongdat.size(); i++)
38  m_phongdat[i].resize(0);
39  m_phongdat.resize(0);
40 }
41 
42 void BumpScope::resize(const QSize &newsize)
43 {
44  m_size = newsize;
45 
46  m_size.setHeight((m_size.height() / 2) * 2);
47  m_size.setWidth((m_size.width() / 4) * 4);
48 
49  delete [] m_rgb_buf;
50 
51  int bufsize = (m_size.height() + 2) * (m_size.width() + 2);
52 
53  m_rgb_buf = new unsigned char[bufsize];
54 
55  m_bpl = m_size.width() + 2;
56 
57  delete m_image;
58  m_image = new QImage(m_size.width(), m_size.height(), QImage::Format_Indexed8);
59 
60  m_width = m_size.width();
61  m_height = m_size.height();
62  m_phongrad = m_width;
63 
64  m_x = m_width / 2;
65  m_y = m_height;
66 
67  m_phongdat.resize(m_phongrad * 2);
68  for (size_t i = 0; i < m_phongdat.size(); i++)
69  m_phongdat[i].resize(m_phongrad * 2);
70 
71  generate_phongdat();
72  generate_cmap(m_color);
73 }
74 
75 void BumpScope::blur_8(unsigned char *ptr, int w, int h, int bpl)
76 {
77  (void)w;
78 
79  uchar *iptr = ptr + bpl + 1;
80  uint i = bpl * h;
81 
82  while (i--)
83  {
84  uint sum = (iptr[-bpl] + iptr[-1] + iptr[1] + iptr[bpl]) >> 2;
85  if (sum > 2)
86  sum -= 2;
87  *(iptr++) = sum;
88  }
89 }
90 
91 void BumpScope::generate_cmap(unsigned int color)
92 {
93  if (m_image)
94  {
95  uint red = color / 0x10000;
96  uint green = (color % 0x10000) / 0x100;
97  uint blue = color % 0x100;
98 
99  for (uint i = 255; i > 0; i--)
100  {
101  uint r, g, b;
102  r = (unsigned int)((100 * static_cast<double>(red) / 255)
103  * m_intense1[i] + m_intense2[i]);
104  if (r > 255)
105  r = 255;
106  g = (unsigned int)((100 * static_cast<double>(green) / 255)
107  * m_intense1[i] + m_intense2[i]);
108  if (g > 255)
109  g = 255;
110  b = (unsigned int)((100 * static_cast<double>(blue) / 255)
111  * m_intense1[i] + m_intense2[i]);
112  if (b > 255)
113  b = 255;
114 
115  m_image->setColor(i, qRgba(r, g, b, 255));
116  }
117 
118  m_image->setColor(0, m_image->color(1));
119  }
120 }
121 
123 {
124  unsigned int y, x;
125  double i, i2;
126 
127  unsigned int PHONGRES = m_phongrad * 2;
128 
129  for (y = 0; y < m_phongrad; y++)
130  {
131  for (x = 0; x < m_phongrad; x++)
132  {
133  i = (double)x / ((double)m_phongrad) - 1;
134  i2 = (double)y / ((double)m_phongrad) - 1;
135 
136  //if (m_diamond)
137  i = 1 - pow(i*i2,.75) - i*i - i2*i2;
138  //else
139  // i = 1 - i*i - i2*i2;
140 
141  if (i >= 0)
142  {
143  //if (m_diamond)
144  i = i*i*i * 255.0;
145  //else
146  // i = i*i*i * 255.0;
147 
148  if (i > 255)
149  i = 255;
150  unsigned char uci = (unsigned char)i;
151 
152  m_phongdat[y][x] = uci;
153  m_phongdat[(PHONGRES-1)-y][x] = uci;
154  m_phongdat[y][(PHONGRES-1)-x] = uci;
155  m_phongdat[(PHONGRES-1)-y][(PHONGRES-1)-x] = uci;
156  }
157  else
158  {
159  m_phongdat[y][x] = 0;
160  m_phongdat[(PHONGRES-1)-y][x] = 0;
161  m_phongdat[y][(PHONGRES-1)-x] = 0;
162  m_phongdat[(PHONGRES-1)-y][(PHONGRES-1)-x] = 0;
163  }
164  }
165  }
166 }
167 
168 #define M_PI_F static_cast<float>(M_PI)
169 void BumpScope::translate(int x, int y, int *xo, int *yo, int *xd, int *yd,
170  int *angle)
171 {
172  unsigned int HEIGHT = m_height;
173  unsigned int WIDTH = m_width;
174 
175  int wd2 = (int)(WIDTH / 2);
176  int hd2 = (int)(HEIGHT / 2);
177 
178  /* try setting y to both maxes */
179  *yo = HEIGHT/2;
180  *angle = (int)(asinf((float)(y-(HEIGHT/2.0F))/(float)*yo)/(M_PI_F/180.0F));
181  *xo = (int)((x-(WIDTH/2.0F))/cosf(*angle*(M_PI/180.0)));
182 
183  if (*xo >= -wd2 && *xo <= wd2) {
184  *xd = (*xo>0)?-1:1;
185  *yd = 0;
186  return;
187  }
188 
189  *yo = -*yo;
190  *angle = (int)(asin((float)(y-(HEIGHT/2.0F))/(float)*yo)/(M_PI_F/180.0F));
191  *xo = (int)((x-(WIDTH/2.0F))/cosf(*angle*(M_PI/180.0)));
192 
193  if (*xo >= -wd2 && *xo <= wd2) {
194  *xd = (*xo>0)?-1:1;
195  *yd = 0;
196  return;
197  }
198 
199  /* try setting x to both maxes */
200  *xo = WIDTH/2;
201  *angle = (int)(acosf((float)(x-(WIDTH/2.0F))/(float)*xo)/(M_PI_F/180.0F));
202  *yo = (int)((y-(HEIGHT/2.0F))/sinf(*angle*(M_PI/180.0)));
203 
204  if (*yo >= -hd2 && *yo <= hd2) {
205  *yd = (*yo>0)?-1:1;
206  *xd = 0;
207  return;
208  }
209 
210  *xo = -*xo;
211  *angle = (int)(acosf((float)(x-(WIDTH/2.0F))/(float)*xo)/(M_PI_F/180.0F));
212  *yo = (int)((y-(HEIGHT/2.0F))/sinf(*angle*(M_PI/180.0)));
213 
214  /* if this isn't right, it's out of our range and we don't care */
215  *yd = (*yo>0)?-1:1;
216  *xd = 0;
217 }
218 
219 inline void BumpScope::draw_vert_line(unsigned char *buffer, int x, int y1,
220  int y2)
221 {
222  int y;
223  unsigned char *p;
224 
225  if (y1 < y2)
226  {
227  p = buffer + ((y1 + 1) * m_bpl) + x + 1;
228  for (y = y1; y <= y2; y++)
229  {
230  *p = 0xff;
231  p += m_bpl;
232  }
233  }
234  else if (y2 < y1)
235  {
236  p = buffer + ((y2 + 1) * m_bpl) + x + 1;
237  for (y = y2; y <= y1; y++)
238  {
239  *p = 0xff;
240  p += m_bpl;
241  }
242  }
243  else
244  buffer[((y1 + 1) * m_bpl) + x + 1] = 0xff;
245 }
246 
247 void BumpScope::render_light(int lx, int ly)
248 {
249  int prev_y, out_y, dy, dx, xp, yp;
250  unsigned int PHONGRES = m_phongrad * 2;
251  unsigned int i, j;
252 
253  prev_y = m_bpl + 1;
254  out_y = 0;
255  unsigned char *outputbuf = m_image->bits();
256 
257  for (dy = (-ly) + (PHONGRES / 2), j = 0; j < m_height; j++, dy++,
258  prev_y += m_bpl - m_width)
259  {
260  for (dx = (-lx) + (PHONGRES / 2), i = 0; i < m_width; i++, dx++,
261  prev_y++, out_y++)
262  {
263  xp = (m_rgb_buf[prev_y - 1] - m_rgb_buf[prev_y + 1]) + dx;
264  yp = (m_rgb_buf[prev_y - m_bpl] - m_rgb_buf[prev_y + m_bpl]) + dy;
265 
266  if (yp < 0 || yp >= (int)PHONGRES ||
267  xp < 0 || xp >= (int)PHONGRES)
268  {
269  outputbuf[out_y] = 0;
270  continue;
271  }
272 
273  outputbuf[out_y] = m_phongdat[yp][xp];
274  }
275  }
276 }
277 
278 void BumpScope::rgb_to_hsv(unsigned int color, double *h, double *s, double *v)
279 {
280  double r = (double)(color>>16) / 255.0;
281  double g = (double)((color>>8)&0xff) / 255.0;
282  double b = (double)(color&0xff) / 255.0;
283 
284  double max = r;
285  if (g > max) max = g;
286  if (b > max) max = b;
287 
288  double min = r;
289  if (g < min) min = g;
290  if (b < min) min = b;
291 
292  *v = max;
293 
294  if (max != 0.0) *s = (max - min) / max;
295  else *s = 0.0;
296 
297  if (*s == 0.0) *h = 0.0;
298  else
299  {
300  double delta = max - min;
301 
302  if (r == max) *h = (g - b) / delta;
303  else if (g == max) *h = 2.0 + (b - r) / delta;
304  else if (b == max) *h = 4.0 + (r - g) / delta;
305 
306  *h = *h * 60.0;
307 
308  if (*h < 0.0) *h = *h + 360;
309  }
310 }
311 
312 void BumpScope::hsv_to_rgb(double h, double s, double v, unsigned int *color)
313 {
314  double r, g, b;
315 
316  if (s == 0.0)
317  s = 0.000001;
318 
319  if (h == -1.0)
320  {
321  r = v; g = v; b = v;
322  }
323  else
324  {
325  if (h == 360.0) h = 0.0;
326  h = h / 60.0;
327  int i = (int) h;
328  double f = h - i;
329  double w = v * (1.0 - s);
330  double q = v * (1.0 - (s * f));
331  double t = v * (1.0 - (s * (1.0 - f)));
332 
333  switch (i)
334  {
335  case 0: r = v; g = t; b = w; break;
336  case 1: r = q; g = v; b = w; break;
337  case 2: r = w; g = v; b = t; break;
338  case 3: r = w; g = q; b = v; break;
339  case 4: r = t; g = w; b = v; break;
340  /*case 5: use default to keep gcc from complaining */
341  default: r = v; g = w; b = q; break;
342  }
343  }
344 
345  *color = ((unsigned int)(r*255)<<16) | ((unsigned int)(g*255)<<8) | ((unsigned int)(b*255));
346 }
347 
349 {
350  if (!node || node->m_length == 0 || !m_image)
351  return false;
352 
353  int numSamps = 512;
354  if (node->m_length < 512)
355  numSamps = node->m_length;
356 
357  int prev_y = (int)m_height / 2 +
358  ((int)node->m_left[0] * (int)m_height) / 0x10000;
359 
360  if (prev_y < 0)
361  prev_y = 0;
362  if (prev_y >= (int)m_height) prev_y = m_height - 1;
363 
364  for (uint i = 0; i < m_width; i++)
365  {
366  int y = (i * numSamps) / (m_width - 1);
367  y = (int)m_height / 2 +
368  ((int)node->m_left[y] * (int)m_height) / 0x10000;
369 
370  if (y < 0)
371  y = 0;
372  if (y >= (int)m_height)
373  y = m_height - 1;
374 
375  draw_vert_line(m_rgb_buf, i, prev_y, y);
376  prev_y = y;
377  }
378 
379  blur_8(m_rgb_buf, m_width, m_height, m_bpl);
380 
381  return false;
382 }
383 
384 bool BumpScope::draw(QPainter *p, const QColor &back)
385 {
386  if (!m_image || m_image->isNull())
387  {
388  LOG(VB_GENERAL, LOG_ERR, "BumpScope::draw: Bad image");
389  return false;
390  }
391 
392  (void)back;
393 
394  m_ilx = m_x;
395  m_ily = m_y;
396 
397  if (m_moving_light)
398  {
399  if (!m_was_moving)
400  {
401  translate(m_ilx, m_ily, &m_ixo, &m_iyo, &m_ixd, &m_iyd, &m_iangle);
402  m_was_moving = 1;
403  }
404 
405  m_ilx = (int)(m_width / 2.0F + cosf(m_iangle * (M_PI / 180.0)) * m_ixo);
406  m_ily = (int)(m_height / 2.0F + sinf(m_iangle * (M_PI / 180.0)) * m_iyo);
407 
408  m_iangle += 2;
409  if (m_iangle >= 360)
410  m_iangle = 0;
411 
412  m_ixo += m_ixd;
413  if (m_ixo > ((int)m_width / 2) || m_ixo < -((int)m_width / 2))
414  {
415  m_ixo = (m_ixo > 0) ? (m_width / 2) : -(m_width / 2);
416  if (random() & 1)
417  {
418  m_ixd = (m_ixd > 0) ? -1 : 1;
419  m_iyd = 0;
420  }
421  else
422  {
423  m_iyd = (m_iyd > 0) ? -1 : 1;
424  m_ixd = 0;
425  }
426  }
427 
428  m_iyo += m_iyd;
429  if (m_iyo > ((int)m_height / 2) || m_iyo < -((int)m_height / 2))
430  {
431  m_iyo = (m_iyo > 0) ? (m_height / 2) : -(m_height / 2);
432  if (random() & 1)
433  {
434  m_ixd = (m_ixd > 0) ? -1 : 1;
435  m_iyd = 0;
436  }
437  else
438  {
439  m_iyd = (m_iyd > 0) ? -1 : 1;
440  m_ixd = 0;
441  }
442  }
443  }
444 
445  if (m_color_cycle)
446  {
447  if (!m_was_color)
448  {
449  rgb_to_hsv(m_color, &m_ih, &m_is, &m_iv);
450  m_was_color = 1;
451 
452  if (random() & 1)
453  {
454  m_ihd = (random() & 1) * 2 - 1;
455  m_isd = 0;
456  }
457  else
458  {
459  m_isd = 0.01 * ((random() & 1) * 2 - 1);
460  m_ihd = 0;
461  }
462  }
463 
464  hsv_to_rgb(m_ih, m_is, m_iv, &m_icolor);
465 
466  generate_cmap(m_icolor);
467 
468  if (m_ihd)
469  {
470  m_ih += m_ihd;
471  if (m_ih >= 360)
472  m_ih = 0;
473  if (m_ih < 0)
474  m_ih = 359;
475  if ((random() % 150) == 0)
476  {
477  if (random() & 1)
478  {
479  m_ihd = (random() & 1) * 2 - 1;
480  m_isd = 0;
481  }
482  else
483  {
484  m_isd = 0.01 * ((random() & 1) * 2 - 1);
485  m_ihd = 0;
486  }
487  }
488  }
489  else
490  {
491  m_is += m_isd;
492 
493  if (m_is <= 0 || m_is >= 0.5)
494  {
495  if (m_is < 0)
496  m_is = 0;
497  if (m_is > 0.52)
498  m_isd = -0.01;
499  else if (m_is == 0)
500  {
501  m_ihd = random() % 360;
502  m_isd = 0.01;
503  }
504  else
505  {
506  if (random() & 1)
507  {
508  m_ihd = (random() & 1) * 2 - 1;
509  m_isd = 0;
510  }
511  else
512  {
513  m_isd = 0.01 * ((random() & 1) * 2 - 1);
514  m_ihd = 0;
515  }
516  }
517  }
518  }
519  }
520 
521  render_light(m_ilx, m_ily);
522 
523  p->drawImage(0, 0, *m_image);
524 
525  return true;
526 }
527 
528 static class BumpScopeFactory : public VisFactory
529 {
530  public:
531  const QString &name(void) const override // VisFactory
532  {
533  static QString name = QCoreApplication::translate("Visualizers",
534  "BumpScope");
535  return name;
536  }
537 
538  uint plugins(QStringList *list) const override // VisFactory
539  {
540  *list << name();
541  return 1;
542  }
543 
544  VisualBase *create(MainVisual *parent, const QString &pluginName) const override // VisFactory
545  {
546  (void)parent;
547  (void)pluginName;
548  return new BumpScope();
549  }
bool process(VisualNode *node) override
Definition: bumpscope.cpp:348
void blur_8(unsigned char *ptr, int w, int h, int bpl)
Definition: bumpscope.cpp:75
static void rgb_to_hsv(unsigned int color, double *h, double *s, double *v)
Definition: bumpscope.cpp:278
unsigned int uint
Definition: compat.h:140
const QString & name(void) const override
Definition: bumpscope.cpp:531
static void hsv_to_rgb(double h, double s, double v, unsigned int *color)
Definition: bumpscope.cpp:312
unsigned char r
Definition: ParseText.cpp:329
unsigned char b
Definition: ParseText.cpp:329
void draw_vert_line(unsigned char *buffer, int x, int y1, int y2)
Definition: bumpscope.cpp:219
void generate_cmap(unsigned int color)
Definition: bumpscope.cpp:91
uint plugins(QStringList *list) const override
Definition: bumpscope.cpp:538
unsigned char t
Definition: ParseText.cpp:329
const char * name
Definition: ParseText.cpp:328
unsigned int HEIGHT
Definition: graphic.c:13
void generate_phongdat(void)
Definition: bumpscope.cpp:122
virtual ~BumpScope()
Definition: bumpscope.cpp:33
#define M_PI
Definition: goom_tools.h:5
#define M_PI_F
Definition: bumpscope.cpp:168
unsigned int WIDTH
Definition: graphic.c:14
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
long m_length
Definition: videovisual.h:35
void resize(const QSize &size) override
Definition: bumpscope.cpp:42
void render_light(int lx, int ly)
Definition: bumpscope.cpp:247
void translate(int x, int y, int *xo, int *yo, int *xd, int *yd, int *angle)
Definition: bumpscope.cpp:169
static long int random(void)
Definition: compat.h:149
static guint32 * back
Definition: goom_core.c:34
bool draw(QPainter *p, const QColor &back) override
Definition: bumpscope.cpp:384
BumpScopeFactory BumpScopeFactory
short * m_left
Definition: videovisual.h:33
VisualBase * create(MainVisual *parent, const QString &pluginName) const override
Definition: bumpscope.cpp:544
unsigned char g
Definition: ParseText.cpp:329