[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / visualizations / OpenGLSpectrum / opengl_spectrum.cpp
1 /*  XMMS - Cross-platform multimedia player
2  *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 /*
20  *  Wed May 24 10:49:37 CDT 2000
21  *  Fixes to threading/context creation for the nVidia X4 drivers by
22  *  Christian Zander <phoenix@minion.de>
23  */
24
25 /*
26  *  Ported to XBMC by d4rk
27  *  Also added 'hSpeed' to animate transition between bar heights
28  *
29  *  Ported to GLES 2.0 by Gimli
30  */
31
32 #define __STDC_LIMIT_MACROS
33
34 #include "addons/include/xbmc_vis_dll.h"
35 #include <string.h>
36 #include <math.h>
37 #include <stdint.h>
38
39 #if defined(HAS_GLES)
40 #include "VisGUIShader.h"
41
42 #ifndef M_PI
43 #define M_PI       3.141592654f
44 #endif
45 #define DEG2RAD(d) ( (d) * M_PI/180.0f )
46
47 //OpenGL wrapper - allows us to use same code of functions draw_bars and render
48 #define GL_PROJECTION             MM_PROJECTION
49 #define GL_MODELVIEW              MM_MODELVIEW
50
51 #define glPushMatrix()            vis_shader->PushMatrix()
52 #define glPopMatrix()             vis_shader->PopMatrix()
53 #define glTranslatef(x,y,z)       vis_shader->Translatef(x,y,z)
54 #define glRotatef(a,x,y,z)        vis_shader->Rotatef(DEG2RAD(a),x,y,z)
55 #define glPolygonMode(a,b)        ;
56 #define glBegin(a)                vis_shader->Enable()
57 #define glEnd()                   vis_shader->Disable()
58 #define glMatrixMode(a)           vis_shader->MatrixMode(a)
59 #define glLoadIdentity()          vis_shader->LoadIdentity()
60 #define glFrustum(a,b,c,d,e,f)    vis_shader->Frustum(a,b,c,d,e,f)
61
62 GLenum  g_mode = GL_TRIANGLES;
63 float g_fWaveform[2][512];
64 const char *frag = "precision mediump float; \n"
65                    "varying lowp vec4 m_colour; \n"
66                    "void main () \n"
67                    "{ \n"
68                    "  gl_FragColor = m_colour; \n"
69                    "}\n";
70
71 const char *vert = "attribute vec4 m_attrpos;\n"
72                    "attribute vec4 m_attrcol;\n"
73                    "attribute vec4 m_attrcord0;\n"
74                    "attribute vec4 m_attrcord1;\n"
75                    "varying vec4   m_cord0;\n"
76                    "varying vec4   m_cord1;\n"
77                    "varying lowp   vec4 m_colour;\n"
78                    "uniform mat4   m_proj;\n"
79                    "uniform mat4   m_model;\n"
80                    "void main ()\n"
81                    "{\n"
82                    "  mat4 mvp    = m_proj * m_model;\n"
83                    "  gl_Position = mvp * m_attrpos;\n"
84                    "  m_colour    = m_attrcol;\n"
85                    "  m_cord0     = m_attrcord0;\n"
86                    "  m_cord1     = m_attrcord1;\n"
87                    "}\n";
88
89 CVisGUIShader *vis_shader = NULL;
90
91 #elif defined(HAS_SDL_OPENGL)
92 #include <GL/glew.h>
93 GLenum  g_mode = GL_FILL;
94
95 #endif
96
97 #define NUM_BANDS 16
98
99 GLfloat x_angle = 20.0, x_speed = 0.0;
100 GLfloat y_angle = 45.0, y_speed = 0.5;
101 GLfloat z_angle = 0.0, z_speed = 0.0;
102 GLfloat heights[16][16], cHeights[16][16], scale;
103 GLfloat hSpeed = 0.05;
104
105 #if defined(HAS_SDL_OPENGL)
106 void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2)
107 {
108   if(y1 == y2)
109   {
110     glVertex3f(x1, y1, z1);
111     glVertex3f(x2, y1, z1);
112     glVertex3f(x2, y2, z2);
113
114     glVertex3f(x2, y2, z2);
115     glVertex3f(x1, y2, z2);
116     glVertex3f(x1, y1, z1);
117   }
118   else
119   {
120     glVertex3f(x1, y1, z1);
121     glVertex3f(x2, y1, z2);
122     glVertex3f(x2, y2, z2);
123
124     glVertex3f(x2, y2, z2);
125     glVertex3f(x1, y2, z1);
126     glVertex3f(x1, y1, z1);
127   }
128 }
129
130 void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue )
131 {
132   GLfloat width = 0.1;
133
134   if (g_mode == GL_POINT)
135     glColor3f(0.2, 1.0, 0.2);
136
137   if (g_mode != GL_POINT)
138   {
139     glColor3f(red,green,blue);
140     draw_rectangle(x_offset, height, z_offset, x_offset + width, height, z_offset + 0.1);
141   }
142   draw_rectangle(x_offset, 0, z_offset, x_offset + width, 0, z_offset + 0.1);
143
144   if (g_mode != GL_POINT)
145   {
146     glColor3f(0.5 * red, 0.5 * green, 0.5 * blue);
147     draw_rectangle(x_offset, 0.0, z_offset + 0.1, x_offset + width, height, z_offset + 0.1);
148   }
149   draw_rectangle(x_offset, 0.0, z_offset, x_offset + width, height, z_offset );
150
151   if (g_mode != GL_POINT)
152   {
153     glColor3f(0.25 * red, 0.25 * green, 0.25 * blue);
154     draw_rectangle(x_offset, 0.0, z_offset , x_offset, height, z_offset + 0.1);
155   }
156   draw_rectangle(x_offset + width, 0.0, z_offset , x_offset + width, height, z_offset + 0.1);
157 }
158
159 #elif defined(HAS_GLES)
160
161 void draw_bar(GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue )
162 {
163   // avoid zero sized bars, which results in overlapping triangles of same depth and display artefacts
164   height = std::max(height, 1e-3f);
165   GLfloat col[] =  {
166                       red * 0.1f, green * 0.1f, blue * 0.1f,
167                       red * 0.2f, green * 0.2f, blue * 0.2f,
168                       red * 0.3f, green * 0.3f, blue * 0.3f,
169                       red * 0.4f, green * 0.4f, blue * 0.4f,
170                       red * 0.5f, green * 0.5f, blue * 0.5f,
171                       red * 0.6f, green * 0.6f, blue * 0.6f,
172                       red * 0.7f, green * 0.7f, blue * 0.7f,
173                       red * 0.8f, green * 0.8f, blue *0.8f
174                    };
175   GLfloat ver[] =  {
176                       x_offset + 0.0f, 0.0f,    z_offset + 0.0f,
177                       x_offset + 0.1f, 0.0f,    z_offset + 0.0f,
178                       x_offset + 0.1f, 0.0f,    z_offset + 0.1f,
179                       x_offset + 0.0f, 0.0f,    z_offset + 0.1f,
180                       x_offset + 0.0f, height,  z_offset + 0.0f,
181                       x_offset + 0.1f, height,  z_offset + 0.0f,
182                       x_offset + 0.1f, height,  z_offset + 0.1f,
183                       x_offset + 0.0f, height,  z_offset + 0.1f
184                    };
185
186   GLubyte idx[] =  {
187                       // Bottom
188                       0, 1, 2,
189                       0, 2, 3,
190                       // Left
191                       0, 4, 7,
192                       0, 7, 3,
193                       // Back
194                       3, 7, 6,
195                       3, 6, 2,
196                       // Right
197                       1, 5, 6,
198                       1, 6, 2,
199                       // Front
200                       0, 4, 5,
201                       0, 5, 1,
202                       // Top
203                       4, 5, 6,
204                       4, 6, 7
205                    };
206
207   GLint   posLoc = vis_shader->GetPosLoc();
208   GLint   colLoc = vis_shader->GetColLoc();
209
210   glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
211   glVertexAttribPointer(posLoc, 3, GL_FLOAT, 0, 0, ver);
212
213   glEnableVertexAttribArray(posLoc);
214   glEnableVertexAttribArray(colLoc);
215
216   glDrawElements(g_mode, 36, GL_UNSIGNED_BYTE, idx);
217
218   glDisableVertexAttribArray(posLoc);
219   glDisableVertexAttribArray(colLoc);
220 }
221 #endif
222
223 void draw_bars(void)
224 {
225   int x,y;
226   GLfloat x_offset, z_offset, r_base, b_base;
227
228   glClear(GL_DEPTH_BUFFER_BIT);
229   glPushMatrix();
230   glTranslatef(0.0,-0.5,-5.0);
231   glRotatef(x_angle,1.0,0.0,0.0);
232   glRotatef(y_angle,0.0,1.0,0.0);
233   glRotatef(z_angle,0.0,0.0,1.0);
234   
235   glPolygonMode(GL_FRONT_AND_BACK, g_mode);
236   glBegin(GL_TRIANGLES);
237   
238   for(y = 0; y < 16; y++)
239   {
240     z_offset = -1.6 + ((15 - y) * 0.2);
241
242     b_base = y * (1.0 / 15);
243     r_base = 1.0 - b_base;
244
245     for(x = 0; x < 16; x++)
246     {
247       x_offset = -1.6 + ((float)x * 0.2);
248       if (::fabs(cHeights[y][x]-heights[y][x])>hSpeed)
249       {
250         if (cHeights[y][x]<heights[y][x])
251           cHeights[y][x] += hSpeed;
252         else
253           cHeights[y][x] -= hSpeed;
254       }
255       draw_bar(x_offset, z_offset,
256         cHeights[y][x], r_base - (float(x) * (r_base / 15.0)),
257         (float)x * (1.0 / 15), b_base);
258     }
259   }
260   glEnd();
261   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
262   glPopMatrix();
263 }
264
265 //-- Create -------------------------------------------------------------------
266 // Called on load. Addon should fully initalize or return error status
267 //-----------------------------------------------------------------------------
268 ADDON_STATUS ADDON_Create(void* hdl, void* props)
269 {
270   if (!props)
271     return ADDON_STATUS_UNKNOWN;
272
273   scale = 1.0 / log(256.0);
274
275 #if defined(HAS_GLES)
276   vis_shader = new CVisGUIShader(vert, frag);
277
278   if(!vis_shader)
279     return ADDON_STATUS_UNKNOWN;
280
281   if(!vis_shader->CompileAndLink())
282   {
283     delete vis_shader;
284     return ADDON_STATUS_UNKNOWN;
285   }  
286 #endif
287
288   scale = 1.0 / log(256.0);
289
290   return ADDON_STATUS_NEED_SETTINGS;
291 }
292
293 //-- Render -------------------------------------------------------------------
294 // Called once per frame. Do all rendering here.
295 //-----------------------------------------------------------------------------
296 extern "C" void Render()
297 {
298   glDisable(GL_BLEND);
299   glMatrixMode(GL_PROJECTION);
300   glPushMatrix();
301   glLoadIdentity();
302   glFrustum(-1, 1, -1, 1, 1.5, 10);
303   glMatrixMode(GL_MODELVIEW);
304   glPushMatrix();
305   glLoadIdentity();
306   glEnable(GL_DEPTH_TEST);
307   glDepthFunc(GL_LESS);
308   glPolygonMode(GL_FRONT, GL_FILL);
309   //glPolygonMode(GL_BACK, GL_FILL);
310   x_angle += x_speed;
311   if(x_angle >= 360.0)
312     x_angle -= 360.0;
313
314   y_angle += y_speed;
315   if(y_angle >= 360.0)
316     y_angle -= 360.0;
317
318   z_angle += z_speed;
319   if(z_angle >= 360.0)
320     z_angle -= 360.0;
321
322   draw_bars();
323   glPopMatrix();
324   glMatrixMode(GL_PROJECTION);
325   glPopMatrix();
326   glDisable(GL_DEPTH_TEST);
327   glEnable(GL_BLEND);
328 }
329
330 extern "C" void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName)
331 {
332   int x, y;
333
334   for(x = 0; x < 16; x++)
335   {
336     for(y = 0; y < 16; y++)
337     {
338       cHeights[y][x] = 0.0;
339     }
340   }
341
342   x_speed = 0.0;
343   y_speed = 0.5;
344   z_speed = 0.0;
345   x_angle = 20.0;
346   y_angle = 45.0;
347   z_angle = 0.0;
348 }
349
350 extern "C" void AudioData(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
351 {
352   int i,c;
353   int y=0;
354   GLfloat val;
355
356   int xscale[] = {0, 1, 2, 3, 5, 7, 10, 14, 20, 28, 40, 54, 74, 101, 137, 187, 255};
357
358   for(y = 15; y > 0; y--)
359   {
360     for(i = 0; i < 16; i++)
361     {
362       heights[y][i] = heights[y - 1][i];
363     }
364   }
365
366   for(i = 0; i < NUM_BANDS; i++)
367   {
368     for(c = xscale[i], y = 0; c < xscale[i + 1]; c++)
369     {
370       if (c<iAudioDataLength)
371       {
372         if((int)(pAudioData[c] * (INT16_MAX)) > y)
373           y = (int)(pAudioData[c] * (INT16_MAX));
374       }
375       else
376         continue;
377     }
378     y >>= 7;
379     if(y > 0)
380       val = (logf(y) * scale);
381     else
382       val = 0;
383     heights[0][i] = val;
384   }
385 }
386
387
388 //-- GetInfo ------------------------------------------------------------------
389 // Tell XBMC our requirements
390 //-----------------------------------------------------------------------------
391 extern "C" void GetInfo(VIS_INFO* pInfo)
392 {
393   pInfo->bWantsFreq = false;
394   pInfo->iSyncDelay = 0;
395 }
396
397
398 //-- GetSubModules ------------------------------------------------------------
399 // Return any sub modules supported by this vis
400 //-----------------------------------------------------------------------------
401 extern "C" unsigned int GetSubModules(char ***names)
402 {
403   return 0; // this vis supports 0 sub modules
404 }
405
406 //-- OnAction -----------------------------------------------------------------
407 // Handle XBMC actions such as next preset, lock preset, album art changed etc
408 //-----------------------------------------------------------------------------
409 extern "C" bool OnAction(long flags, const void *param)
410 {
411   bool ret = false;
412   return ret;
413 }
414
415 //-- GetPresets ---------------------------------------------------------------
416 // Return a list of presets to XBMC for display
417 //-----------------------------------------------------------------------------
418 extern "C" unsigned int GetPresets(char ***presets)
419 {
420   return 0;
421 }
422
423 //-- GetPreset ----------------------------------------------------------------
424 // Return the index of the current playing preset
425 //-----------------------------------------------------------------------------
426 extern "C" unsigned GetPreset()
427 {
428   return 0;
429 }
430
431 //-- IsLocked -----------------------------------------------------------------
432 // Returns true if this add-on use settings
433 //-----------------------------------------------------------------------------
434 extern "C" bool IsLocked()
435 {
436   return false;
437 }
438
439 //-- Stop ---------------------------------------------------------------------
440 // This dll must cease all runtime activities
441 // !!! Add-on master function !!!
442 //-----------------------------------------------------------------------------
443 extern "C" void ADDON_Stop()
444 {
445 }
446
447 //-- Destroy ------------------------------------------------------------------
448 // Do everything before unload of this add-on
449 // !!! Add-on master function !!!
450 //-----------------------------------------------------------------------------
451 extern "C" void ADDON_Destroy()
452 {
453 #if defined(HAS_GLES)
454   if(vis_shader) 
455   {
456     vis_shader->Free();
457     delete vis_shader;
458   }
459 #endif
460 }
461
462 //-- HasSettings --------------------------------------------------------------
463 // Returns true if this add-on use settings
464 // !!! Add-on master function !!!
465 //-----------------------------------------------------------------------------
466 extern "C" bool ADDON_HasSettings()
467 {
468   return true;
469 }
470
471 //-- GetStatus ---------------------------------------------------------------
472 // Returns the current Status of this visualisation
473 // !!! Add-on master function !!!
474 //-----------------------------------------------------------------------------
475 extern "C" ADDON_STATUS ADDON_GetStatus()
476 {
477   return ADDON_STATUS_OK;
478 }
479
480 //-- GetSettings --------------------------------------------------------------
481 // Return the settings for XBMC to display
482 // !!! Add-on master function !!!
483 //-----------------------------------------------------------------------------
484 extern "C" unsigned int ADDON_GetSettings(ADDON_StructSetting ***sSet)
485 {
486   return 0;
487 }
488
489 //-- FreeSettings --------------------------------------------------------------
490 // Free the settings struct passed from XBMC
491 // !!! Add-on master function !!!
492 //-----------------------------------------------------------------------------
493
494 extern "C" void ADDON_FreeSettings()
495 {
496 }
497
498 //-- SetSetting ---------------------------------------------------------------
499 // Set a specific Setting value (called from XBMC)
500 // !!! Add-on master function !!!
501 //-----------------------------------------------------------------------------
502 extern "C" ADDON_STATUS ADDON_SetSetting(const char *strSetting, const void* value)
503 {
504   if (!strSetting || !value)
505     return ADDON_STATUS_UNKNOWN;
506
507   if (strcmp(strSetting, "bar_height")==0)
508   {
509     switch (*(int*) value)
510     {
511     case 1://standard
512       scale = 1.f / log(256.f);
513       break;
514
515     case 2://big
516       scale = 2.f / log(256.f);
517       break;
518
519     case 3://real big
520       scale = 3.f / log(256.f);
521       break;
522
523     case 4://unused
524       scale = 0.33f / log(256.f);
525       break;
526
527     case 0://small
528     default:
529       scale = 0.5f / log(256.f);
530       break;
531     }
532     return ADDON_STATUS_OK;
533   }
534   else if (strcmp(strSetting, "speed")==0)
535   {
536     switch (*(int*) value)
537     {
538     case 1:
539       hSpeed = 0.025f;
540       break;
541
542     case 2:
543       hSpeed = 0.0125f;
544       break;
545
546     case 3:
547       hSpeed = 0.1f;
548       break;
549
550     case 4:
551       hSpeed = 0.2f;
552       break;
553
554     case 0:
555     default:
556       hSpeed = 0.05f;
557       break;
558     }
559     return ADDON_STATUS_OK;
560   }
561   else if (strcmp(strSetting, "mode")==0)
562   {
563 #if defined(HAS_SDL_OPENGL)
564     switch (*(int*) value)
565     {
566       case 1:
567         g_mode = GL_LINE;
568         break;
569
570       case 2:
571         g_mode = GL_POINT;
572         break;
573
574       case 0:
575       default:
576         g_mode = GL_FILL;
577         break;
578     }
579 #else
580     switch (*(int*) value)
581     {
582       case 1:
583         g_mode = GL_LINE_LOOP;
584         break;
585
586       case 2:
587         g_mode = GL_LINES; //no points on gles!
588         break;
589
590       case 0:
591       default:
592         g_mode = GL_TRIANGLES;
593         break;
594     }
595
596 #endif
597
598     return ADDON_STATUS_OK;
599   }
600
601   return ADDON_STATUS_UNKNOWN;
602 }
603
604 //-- Announce -----------------------------------------------------------------
605 // Receive announcements from XBMC
606 // !!! Add-on master function !!!
607 //-----------------------------------------------------------------------------
608 extern "C" void ADDON_Announce(const char *flag, const char *sender, const char *message, const void *data)
609 {
610 }