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