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