1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4
5 #ifdef _WIN32
6 #include <direct.h>
7 #define getcwd _getcwd
8 #else
9 #include <unistd.h>
10 #endif
11
12 #include "ShaderEditor.h"
13 #include "Renderer.h"
14 #include "FFT.h"
15 #include "MIDI.h"
16 #include "Timer.h"
17 #include "Misc.h"
18 #include "UniConversion.h"
19 #include "jsonxx.h"
20 #include "Capture.h"
21 #include "SetupDialog.h"
22
ParseColor(const std::string & color)23 unsigned int ParseColor(const std::string& color) {
24 if (color.size() < 6 || color.size() > 8) return 0xFFFFFFFF;
25 if (color.size() == 6)
26 {
27 std::string text = "0x" + color;
28 unsigned int v = std::stoul(text, 0, 16);
29 return (0xFF000000 | ((v & 0xFF0000) >> 16) | (v & 0x00FF00) | ((v & 0x0000FF) << 16));
30 }
31 else
32 {
33 std::string text = "0x" + color;
34 unsigned int v = std::stoul(text, 0, 16);
35 return ((v & 0xFF000000) | ((v & 0x00FF0000) >> 16) | (v & 0x0000FF00) | ((v & 0x000000FF) << 16));
36 }
37 }
38
ReplaceTokens(std::string & sDefShader,const char * sTokenBegin,const char * sTokenName,const char * sTokenEnd,std::vector<std::string> & tokens)39 void ReplaceTokens( std::string &sDefShader, const char * sTokenBegin, const char * sTokenName, const char * sTokenEnd, std::vector<std::string> &tokens )
40 {
41 if (sDefShader.find(sTokenBegin) != std::string::npos
42 && sDefShader.find(sTokenName) != std::string::npos
43 && sDefShader.find(sTokenEnd) != std::string::npos
44 && sDefShader.find(sTokenBegin) < sDefShader.find(sTokenName)
45 && sDefShader.find(sTokenName) < sDefShader.find(sTokenEnd))
46 {
47 int nTokenStart = (int)(sDefShader.find(sTokenBegin) + strlen(sTokenBegin));
48 std::string sTextureToken = sDefShader.substr( nTokenStart, sDefShader.find(sTokenEnd) - nTokenStart );
49
50 std::string sFinalShader;
51 sFinalShader = sDefShader.substr( 0, sDefShader.find(sTokenBegin) );
52
53 //for (std::map<std::string, Renderer::Texture*>::iterator it = tokens.begin(); it != tokens.end(); it++)
54 for (int i=0; i < tokens.size(); i++)
55 {
56 std::string s = sTextureToken;
57 while (s.find(sTokenName) != std::string::npos)
58 {
59 s.replace( s.find(sTokenName), strlen(sTokenName), tokens[i], 0, std::string::npos );
60 }
61 sFinalShader += s;
62 }
63 sFinalShader += sDefShader.substr( sDefShader.find(sTokenEnd) + strlen(sTokenEnd), std::string::npos );
64 sDefShader = sFinalShader;
65 }
66 }
67
main(int argc,const char * argv[])68 int main( int argc, const char *argv[] )
69 {
70 Misc::PlatformStartup();
71
72 const char * configFile = "config.json";
73 if ( argc > 1 )
74 {
75 configFile = argv[ 1 ];
76 printf( "Loading config file '%s'...\n", configFile );
77 }
78 else
79 {
80 char configPath[ 256 ] = { 0 };
81 if ( getcwd( configPath, 255 ) )
82 {
83 printf( "Looking for config.json in '%s'...\n", configPath );
84 }
85 }
86
87 jsonxx::Object options;
88 FILE * fConf = fopen( configFile, "rb" );
89 if ( fConf )
90 {
91 printf( "Config file found, parsing...\n" );
92
93 char szConfig[ 65535 ];
94 memset( szConfig, 0, 65535 );
95 fread( szConfig, 1, 65535, fConf );
96 fclose( fConf );
97
98 options.parse( szConfig );
99 }
100
101 FFT::Create();
102
103 bool skipSetupDialog = false;
104 if ( options.has<jsonxx::Boolean>( "skipSetupDialog" ) )
105 skipSetupDialog = options.get<jsonxx::Boolean>( "skipSetupDialog" );
106
107 SetupDialog::SETTINGS settings;
108 settings.sFFT.bUseRecordingDevice = true;
109 settings.sFFT.pDeviceID = NULL;
110 if ( options.has<jsonxx::Object>( "audio" ) )
111 {
112 if ( options.get<jsonxx::Object>( "audio" ).has<jsonxx::Boolean>( "useInput" ) )
113 settings.sFFT.bUseRecordingDevice = options.get<jsonxx::Object>( "audio" ).get<jsonxx::Boolean>( "useInput" );
114 }
115
116 settings.sRenderer.bVsync = false;
117 #ifdef _DEBUG
118 settings.sRenderer.nWidth = 1280;
119 settings.sRenderer.nHeight = 720;
120 settings.sRenderer.windowMode = RENDERER_WINDOWMODE_WINDOWED;
121 #else
122 settings.sRenderer.nWidth = 1920;
123 settings.sRenderer.nHeight = 1080;
124 settings.sRenderer.windowMode = RENDERER_WINDOWMODE_FULLSCREEN;
125
126 if ( options.has<jsonxx::Object>( "window" ) )
127 {
128 if ( options.get<jsonxx::Object>( "window" ).has<jsonxx::Number>( "width" ) )
129 settings.sRenderer.nWidth = options.get<jsonxx::Object>( "window" ).get<jsonxx::Number>( "width" );
130 if ( options.get<jsonxx::Object>( "window" ).has<jsonxx::Number>( "height" ) )
131 settings.sRenderer.nHeight = options.get<jsonxx::Object>( "window" ).get<jsonxx::Number>( "height" );
132 if ( options.get<jsonxx::Object>( "window" ).has<jsonxx::Boolean>( "fullscreen" ) )
133 settings.sRenderer.windowMode = options.get<jsonxx::Object>( "window" ).get<jsonxx::Boolean>( "fullscreen" ) ? RENDERER_WINDOWMODE_FULLSCREEN : RENDERER_WINDOWMODE_WINDOWED;
134 }
135 if ( !skipSetupDialog )
136 {
137 if ( !SetupDialog::Open( &settings ) )
138 {
139 return -1;
140 }
141 }
142 #endif
143
144 if (!Renderer::Open( &settings.sRenderer ))
145 {
146 printf("Renderer::Open failed\n");
147 return -1;
148 }
149
150 if (!FFT::Open( &settings.sFFT ))
151 {
152 printf("FFT::Open() failed, continuing anyway...\n");
153 //return -1;
154 }
155
156 if (!MIDI::Open())
157 {
158 printf("MIDI::Open() failed, continuing anyway...\n");
159 //return -1;
160 }
161
162 std::map<std::string,Renderer::Texture*> textures;
163 std::map<int,std::string> midiRoutes;
164
165 const char * szDefaultFontPath = Misc::GetDefaultFontPath();
166
167 SHADEREDITOR_OPTIONS editorOptions;
168 editorOptions.nFontSize = 16;
169 if ( !szDefaultFontPath )
170 {
171 printf( "Misc::GetDefaultFontPath couldn't find ANY default fonts!\n" );
172 }
173 else
174 {
175 editorOptions.sFontPath = szDefaultFontPath;
176 }
177 editorOptions.nOpacity = 0xC0;
178 editorOptions.bUseSpacesForTabs = true;
179 editorOptions.nTabSize = 2;
180 editorOptions.bVisibleWhitespace = false;
181 editorOptions.eAutoIndent = aitSmart;
182
183 int nDebugOutputHeight = 200;
184 int nTexPreviewWidth = 64;
185 float fFFTSmoothingFactor = 0.9f; // higher value, smoother FFT
186 float fFFTSlightSmoothingFactor = 0.6f; // higher value, smoother FFT
187 float fScrollXFactor = 1.0f;
188 float fScrollYFactor = 1.0f;
189
190 std::string sPostExitCmd;
191
192 if (!options.empty())
193 {
194 if (options.has<jsonxx::Object>("rendering"))
195 {
196 if (options.get<jsonxx::Object>("rendering").has<jsonxx::Number>("fftSmoothFactor"))
197 fFFTSmoothingFactor = options.get<jsonxx::Object>("rendering").get<jsonxx::Number>("fftSmoothFactor");
198 if (options.get<jsonxx::Object>("rendering").has<jsonxx::Number>("fftAmplification"))
199 FFT::fAmplification = options.get<jsonxx::Object>("rendering").get<jsonxx::Number>("fftAmplification");
200 }
201
202 if (options.has<jsonxx::Object>("textures"))
203 {
204 printf("Loading textures...\n");
205 std::map<std::string, jsonxx::Value*> tex = options.get<jsonxx::Object>("textures").kv_map();
206 for (std::map<std::string, jsonxx::Value*>::iterator it = tex.begin(); it != tex.end(); it++)
207 {
208 const char * fn = it->second->string_value_->c_str();
209 printf("* %s...\n",fn);
210 Renderer::Texture * tex = Renderer::CreateRGBA8TextureFromFile( fn );
211 if (!tex)
212 {
213 printf("Renderer::CreateRGBA8TextureFromFile(%s) failed\n",fn);
214 return -1;
215 }
216 textures[it->first] = tex;
217 }
218 }
219 if (options.has<jsonxx::Object>("font"))
220 {
221 if (options.get<jsonxx::Object>("font").has<jsonxx::Number>("size"))
222 editorOptions.nFontSize = options.get<jsonxx::Object>("font").get<jsonxx::Number>("size");
223 if (options.get<jsonxx::Object>("font").has<jsonxx::String>("file"))
224 {
225 std::string fontpath = options.get<jsonxx::Object>("font").get<jsonxx::String>("file");
226 if (!Misc::FileExists(fontpath.c_str()))
227 {
228 printf("Font path (%s) is invalid!\n", fontpath.c_str());
229 return -1;
230 }
231 editorOptions.sFontPath = fontpath;
232 }
233 }
234 if (options.has<jsonxx::Object>("gui"))
235 {
236 if (options.get<jsonxx::Object>("gui").has<jsonxx::Number>("outputHeight"))
237 nDebugOutputHeight = options.get<jsonxx::Object>("gui").get<jsonxx::Number>("outputHeight");
238 if (options.get<jsonxx::Object>("gui").has<jsonxx::Number>("texturePreviewWidth"))
239 nTexPreviewWidth = options.get<jsonxx::Object>("gui").get<jsonxx::Number>("texturePreviewWidth");
240 if (options.get<jsonxx::Object>("gui").has<jsonxx::Number>("opacity"))
241 editorOptions.nOpacity = options.get<jsonxx::Object>("gui").get<jsonxx::Number>("opacity");
242 if (options.get<jsonxx::Object>("gui").has<jsonxx::Boolean>("spacesForTabs"))
243 editorOptions.bUseSpacesForTabs = options.get<jsonxx::Object>("gui").get<jsonxx::Boolean>("spacesForTabs");
244 if (options.get<jsonxx::Object>("gui").has<jsonxx::Number>("tabSize"))
245 editorOptions.nTabSize = options.get<jsonxx::Object>("gui").get<jsonxx::Number>("tabSize");
246 if (options.get<jsonxx::Object>("gui").has<jsonxx::Boolean>("visibleWhitespace"))
247 editorOptions.bVisibleWhitespace = options.get<jsonxx::Object>("gui").get<jsonxx::Boolean>("visibleWhitespace");
248 if (options.get<jsonxx::Object>("gui").has<jsonxx::String>("autoIndent"))
249 {
250 std::string autoIndent = options.get<jsonxx::Object>("gui").get<jsonxx::String>("autoIndent");
251 if (autoIndent == "smart") {
252 editorOptions.eAutoIndent = aitSmart;
253 } else if (autoIndent == "preserve") {
254 editorOptions.eAutoIndent = aitPreserve;
255 } else {
256 editorOptions.eAutoIndent = aitNone;
257 }
258 }
259 if (options.get<jsonxx::Object>("gui").has<jsonxx::Number>("scrollXFactor"))
260 fScrollXFactor = options.get<jsonxx::Object>("gui").get<jsonxx::Number>("scrollXFactor");
261 if (options.get<jsonxx::Object>("gui").has<jsonxx::Number>("scrollYFactor"))
262 fScrollYFactor = options.get<jsonxx::Object>("gui").get<jsonxx::Number>("scrollYFactor");
263 }
264 if (options.has<jsonxx::Object>("theme"))
265 {
266 const auto& theme = options.get<jsonxx::Object>("theme");
267 if (theme.has<jsonxx::String>("text"))
268 editorOptions.theme.text = ParseColor(theme.get<jsonxx::String>("text"));
269 if (theme.has<jsonxx::String>("comment"))
270 editorOptions.theme.comment = ParseColor(theme.get<jsonxx::String>("comment"));
271 if (theme.has<jsonxx::String>("number"))
272 editorOptions.theme.number = ParseColor(theme.get<jsonxx::String>("number"));
273 if (theme.has<jsonxx::String>("op"))
274 editorOptions.theme.op = ParseColor(theme.get<jsonxx::String>("op"));
275 if (theme.has<jsonxx::String>("keyword"))
276 editorOptions.theme.keyword = ParseColor(theme.get<jsonxx::String>("keyword"));
277 if (theme.has<jsonxx::String>("type"))
278 editorOptions.theme.type = ParseColor(theme.get<jsonxx::String>("type"));
279 if (theme.has<jsonxx::String>("builtin"))
280 editorOptions.theme.builtin = ParseColor(theme.get<jsonxx::String>("builtin"));
281 if (theme.has<jsonxx::String>("preprocessor"))
282 editorOptions.theme.preprocessor = ParseColor(theme.get<jsonxx::String>("preprocessor"));
283 if (theme.has<jsonxx::String>("selection"))
284 editorOptions.theme.selection = ParseColor(theme.get<jsonxx::String>("selection"));
285 if (theme.has<jsonxx::String>("charBackground")) {
286 editorOptions.theme.bUseCharBackground = true;
287 editorOptions.theme.charBackground = ParseColor(theme.get<jsonxx::String>("charBackground"));
288 }
289 }
290 if (options.has<jsonxx::Object>("midi"))
291 {
292 std::map<std::string, jsonxx::Value*> tex = options.get<jsonxx::Object>("midi").kv_map();
293 for (std::map<std::string, jsonxx::Value*>::iterator it = tex.begin(); it != tex.end(); it++)
294 {
295 midiRoutes[it->second->number_value_] = it->first;
296 }
297 }
298 if (options.has<jsonxx::String>("postExitCmd"))
299 {
300 sPostExitCmd = options.get<jsonxx::String>("postExitCmd");
301 }
302 Capture::LoadSettings( options );
303 }
304 if (!editorOptions.sFontPath.size())
305 {
306 printf("Couldn't find any of the default fonts. Please specify one in config.json\n");
307 return -1;
308 }
309 if (!Capture::Open(settings.sRenderer))
310 {
311 printf("Initializing capture system failed!\n");
312 return 0;
313 }
314
315 Renderer::Texture * texPreviousFrame = Renderer::CreateRGBA8Texture();
316 Renderer::Texture * texFFT = Renderer::Create1DR32Texture( FFT_SIZE );
317 Renderer::Texture * texFFTSmoothed = Renderer::Create1DR32Texture( FFT_SIZE );
318 Renderer::Texture * texFFTIntegrated = Renderer::Create1DR32Texture( FFT_SIZE );
319
320 bool shaderInitSuccessful = false;
321 char szShader[65535];
322 char szError[4096];
323 FILE * f = fopen(Renderer::defaultShaderFilename,"rb");
324 if (f)
325 {
326 printf("Loading last shader...\n");
327
328 memset( szShader, 0, 65535 );
329 fread( szShader, 1, 65535, f );
330 fclose(f);
331 if (Renderer::ReloadShader( szShader, (int)strlen(szShader), szError, 4096 ))
332 {
333 printf("Last shader works fine.\n");
334 shaderInitSuccessful = true;
335 }
336 else {
337 printf("Shader error:\n%s\n", szError);
338 }
339 }
340 if (!shaderInitSuccessful)
341 {
342 printf("No valid last shader found, falling back to default...\n");
343
344 std::string sDefShader = Renderer::defaultShader;
345
346 std::vector<std::string> tokens;
347 for (std::map<std::string, Renderer::Texture*>::iterator it = textures.begin(); it != textures.end(); it++)
348 tokens.push_back(it->first);
349 ReplaceTokens(sDefShader, "{%textures:begin%}", "{%textures:name%}", "{%textures:end%}", tokens);
350
351 tokens.clear();
352 for (std::map<int,std::string>::iterator it = midiRoutes.begin(); it != midiRoutes.end(); it++)
353 tokens.push_back(it->second);
354 ReplaceTokens(sDefShader, "{%midi:begin%}", "{%midi:name%}", "{%midi:end%}", tokens);
355
356 strncpy( szShader, sDefShader.c_str(), 65535 );
357 if (!Renderer::ReloadShader( szShader, (int)strlen(szShader), szError, 4096 ))
358 {
359 printf("Default shader compile failed:\n");
360 puts(szError);
361 assert(0);
362 }
363 }
364
365 Misc::InitKeymaps();
366
367 #ifdef SCI_LEXER
368 Scintilla_LinkLexers();
369 #endif
370 Scintilla::Surface * surface = Scintilla::Surface::Allocate( SC_TECHNOLOGY_DEFAULT );
371 surface->Init( NULL );
372
373 int nMargin = 20;
374
375 bool bTexPreviewVisible = true;
376
377 editorOptions.rect = Scintilla::PRectangle( nMargin, nMargin, settings.sRenderer.nWidth - nMargin - nTexPreviewWidth - nMargin, settings.sRenderer.nHeight - nMargin * 2 - nDebugOutputHeight );
378 ShaderEditor mShaderEditor( surface );
379 mShaderEditor.Initialise( editorOptions );
380 mShaderEditor.SetText( szShader );
381
382 editorOptions.rect = Scintilla::PRectangle( nMargin, settings.sRenderer.nHeight - nMargin - nDebugOutputHeight, settings.sRenderer.nWidth - nMargin - nTexPreviewWidth - nMargin, settings.sRenderer.nHeight - nMargin );
383 ShaderEditor mDebugOutput( surface );
384 mDebugOutput.Initialise( editorOptions );
385 mDebugOutput.SetText( "" );
386 mDebugOutput.SetReadOnly(true);
387
388 static float fftData[FFT_SIZE];
389 memset(fftData, 0, sizeof(float) * FFT_SIZE);
390 static float fftDataSmoothed[FFT_SIZE];
391 memset(fftDataSmoothed, 0, sizeof(float) * FFT_SIZE);
392
393
394 static float fftDataSlightlySmoothed[FFT_SIZE];
395 memset(fftDataSlightlySmoothed, 0, sizeof(float) * FFT_SIZE);
396 static float fftDataIntegrated[FFT_SIZE];
397 memset(fftDataIntegrated, 0, sizeof(float) * FFT_SIZE);
398
399 bool bShowGui = true;
400 Timer::Start();
401 float fNextTick = 0.1f;
402 float fLastTimeMS = Timer::GetTime();
403 while (!Renderer::WantsToQuit())
404 {
405 bool newShader = false;
406 float time = Timer::GetTime() / 1000.0; // seconds
407 Renderer::StartFrame();
408
409 for(int i=0; i<Renderer::mouseEventBufferCount; i++)
410 {
411 if (bShowGui)
412 {
413 switch (Renderer::mouseEventBuffer[i].eventType)
414 {
415 case Renderer::MOUSEEVENTTYPE_MOVE:
416 mShaderEditor.ButtonMovePublic( Scintilla::Point( Renderer::mouseEventBuffer[i].x, Renderer::mouseEventBuffer[i].y ) );
417 break;
418 case Renderer::MOUSEEVENTTYPE_DOWN:
419 mShaderEditor.ButtonDown( Scintilla::Point( Renderer::mouseEventBuffer[i].x, Renderer::mouseEventBuffer[i].y ), time * 1000, false, false, false );
420 break;
421 case Renderer::MOUSEEVENTTYPE_UP:
422 mShaderEditor.ButtonUp( Scintilla::Point( Renderer::mouseEventBuffer[i].x, Renderer::mouseEventBuffer[i].y ), time * 1000, false );
423 break;
424 case Renderer::MOUSEEVENTTYPE_SCROLL:
425 mShaderEditor.WndProc( SCI_LINESCROLL, (int)(-Renderer::mouseEventBuffer[i].x * fScrollXFactor), (int)(-Renderer::mouseEventBuffer[i].y * fScrollYFactor));
426 break;
427 }
428 }
429 }
430 Renderer::mouseEventBufferCount = 0;
431
432 for(int i=0; i<Renderer::keyEventBufferCount; i++)
433 {
434 if (Renderer::keyEventBuffer[i].scanCode == 283) // F2
435 {
436 if (bTexPreviewVisible)
437 {
438 mShaderEditor.SetPosition( Scintilla::PRectangle( nMargin, nMargin, settings.sRenderer.nWidth - nMargin, settings.sRenderer.nHeight - nMargin * 2 - nDebugOutputHeight ) );
439 mDebugOutput .SetPosition( Scintilla::PRectangle( nMargin, settings.sRenderer.nHeight - nMargin - nDebugOutputHeight, settings.sRenderer.nWidth - nMargin, settings.sRenderer.nHeight - nMargin ) );
440 bTexPreviewVisible = false;
441 }
442 else
443 {
444 mShaderEditor.SetPosition( Scintilla::PRectangle( nMargin, nMargin, settings.sRenderer.nWidth - nMargin - nTexPreviewWidth - nMargin, settings.sRenderer.nHeight - nMargin * 2 - nDebugOutputHeight ) );
445 mDebugOutput .SetPosition( Scintilla::PRectangle( nMargin, settings.sRenderer.nHeight - nMargin - nDebugOutputHeight, settings.sRenderer.nWidth - nMargin - nTexPreviewWidth - nMargin, settings.sRenderer.nHeight - nMargin ) );
446 bTexPreviewVisible = true;
447 }
448 }
449 else if (Renderer::keyEventBuffer[i].scanCode == 286 || (Renderer::keyEventBuffer[i].ctrl && Renderer::keyEventBuffer[i].scanCode == 'r')) // F5
450 {
451 mShaderEditor.GetText(szShader,65535);
452 if (Renderer::ReloadShader( szShader, (int)strlen(szShader), szError, 4096 ))
453 {
454 // Shader compilation successful; we set a flag to save if the frame render was successful
455 // (If there is a driver crash, don't save.)
456 newShader = true;
457 }
458 else
459 {
460 mDebugOutput.SetText( szError );
461 }
462 }
463 else if (Renderer::keyEventBuffer[i].scanCode == 292 || (Renderer::keyEventBuffer[i].ctrl && Renderer::keyEventBuffer[i].scanCode == 'f')) // F11 or Ctrl/Cmd-f
464 {
465 bShowGui = !bShowGui;
466 }
467 else if (bShowGui)
468 {
469 bool consumed = false;
470 if (Renderer::keyEventBuffer[i].scanCode)
471 {
472 mShaderEditor.KeyDown(
473 iswalpha(Renderer::keyEventBuffer[i].scanCode) ? towupper(Renderer::keyEventBuffer[i].scanCode) : Renderer::keyEventBuffer[i].scanCode,
474 Renderer::keyEventBuffer[i].shift,
475 Renderer::keyEventBuffer[i].ctrl,
476 Renderer::keyEventBuffer[i].alt,
477 &consumed);
478 }
479 if (!consumed && Renderer::keyEventBuffer[i].character)
480 {
481 char utf8[5] = {0,0,0,0,0};
482 wchar_t utf16[2] = {Renderer::keyEventBuffer[i].character, 0};
483 Scintilla::UTF8FromUTF16(utf16, 1, utf8, 4 * sizeof(char));
484 mShaderEditor.AddCharUTF(utf8, (unsigned int)strlen(utf8));
485 }
486
487 }
488 }
489 Renderer::keyEventBufferCount = 0;
490
491 Renderer::SetShaderConstant( "fGlobalTime", time );
492 Renderer::SetShaderConstant( "v2Resolution", settings.sRenderer.nWidth, settings.sRenderer.nHeight );
493
494 float fTime = Timer::GetTime();
495 Renderer::SetShaderConstant( "fFrameTime", ( fTime - fLastTimeMS ) / 1000.0f );
496 fLastTimeMS = fTime;
497
498 for (std::map<int,std::string>::iterator it = midiRoutes.begin(); it != midiRoutes.end(); it++)
499 {
500 Renderer::SetShaderConstant( it->second.c_str(), MIDI::GetCCValue( it->first ) );
501 }
502
503
504 if (FFT::GetFFT(fftData))
505 {
506 Renderer::UpdateR32Texture( texFFT, fftData );
507
508 const static float maxIntegralValue = 1024.0f;
509 for ( int i = 0; i < FFT_SIZE; i++ )
510 {
511 fftDataSmoothed[i] = fftDataSmoothed[i] * fFFTSmoothingFactor + (1 - fFFTSmoothingFactor) * fftData[i];
512
513 fftDataSlightlySmoothed[i] = fftDataSlightlySmoothed[i] * fFFTSlightSmoothingFactor + (1 - fFFTSlightSmoothingFactor) * fftData[i];
514 fftDataIntegrated[i] = fftDataIntegrated[i] + fftDataSlightlySmoothed[i];
515 if (fftDataIntegrated[i] > maxIntegralValue) {
516 fftDataIntegrated[i] -= maxIntegralValue;
517 }
518 }
519
520 Renderer::UpdateR32Texture( texFFTSmoothed, fftDataSmoothed );
521 Renderer::UpdateR32Texture( texFFTIntegrated, fftDataIntegrated );
522 }
523
524 Renderer::SetShaderTexture( "texFFT", texFFT );
525 Renderer::SetShaderTexture( "texFFTSmoothed", texFFTSmoothed );
526 Renderer::SetShaderTexture( "texFFTIntegrated", texFFTIntegrated );
527 Renderer::SetShaderTexture( "texPreviousFrame", texPreviousFrame );
528
529 for (std::map<std::string, Renderer::Texture*>::iterator it = textures.begin(); it != textures.end(); it++)
530 {
531 Renderer::SetShaderTexture( it->first.c_str(), it->second );
532 }
533
534 Renderer::RenderFullscreenQuad();
535
536 Renderer::CopyBackbufferToTexture( texPreviousFrame );
537
538 Renderer::StartTextRendering();
539
540 if (bShowGui)
541 {
542 if (time > fNextTick)
543 {
544 mShaderEditor.Tick();
545 mDebugOutput.Tick();
546 fNextTick = time + 0.1;
547 }
548
549 mShaderEditor.Paint();
550 mDebugOutput.Paint();
551
552 Renderer::SetTextRenderingViewport( Scintilla::PRectangle(0,0,Renderer::nWidth,Renderer::nHeight) );
553
554 if (bTexPreviewVisible)
555 {
556 int y1 = nMargin;
557 int x1 = settings.sRenderer.nWidth - nMargin - nTexPreviewWidth;
558 int x2 = settings.sRenderer.nWidth - nMargin;
559 for (std::map<std::string, Renderer::Texture*>::iterator it = textures.begin(); it != textures.end(); it++)
560 {
561 int y2 = y1 + nTexPreviewWidth * (it->second->height / (float)it->second->width);
562 Renderer::BindTexture( it->second );
563 Renderer::RenderQuad(
564 Renderer::Vertex( x1, y1, 0xccFFFFFF, 0.0, 0.0 ),
565 Renderer::Vertex( x2, y1, 0xccFFFFFF, 1.0, 0.0 ),
566 Renderer::Vertex( x2, y2, 0xccFFFFFF, 1.0, 1.0 ),
567 Renderer::Vertex( x1, y2, 0xccFFFFFF, 0.0, 1.0 )
568 );
569 surface->DrawTextNoClip( Scintilla::PRectangle(x1,y1,x2,y2), *mShaderEditor.GetTextFont(), y2 - 5.0, it->first.c_str(), (int)it->first.length(), 0xffFFFFFF, 0x00000000);
570 y1 = y2 + nMargin;
571 }
572 }
573
574 char szLayout[255];
575 Misc::GetKeymapName(szLayout);
576 std::string sHelp = "F2 - toggle texture preview F5 or Ctrl-R - recompile shader F11 - hide GUI Current keymap: ";
577 sHelp += szLayout;
578 surface->DrawTextNoClip( Scintilla::PRectangle(20,Renderer::nHeight - 20,100,Renderer::nHeight), *mShaderEditor.GetTextFont(), Renderer::nHeight - 5.0, sHelp.c_str(), (int)sHelp.length(), 0x80FFFFFF, 0x00000000);
579 }
580
581
582 Renderer::EndTextRendering();
583
584 Renderer::EndFrame();
585
586 Capture::CaptureFrame();
587
588 if (newShader)
589 {
590 // Frame render successful, save shader
591 FILE * f = fopen(Renderer::defaultShaderFilename,"wb");
592 if (f)
593 {
594 fwrite( szShader, strlen(szShader), 1, f );
595 fclose(f);
596 mDebugOutput.SetText( "" );
597 }
598 else
599 {
600 mDebugOutput.SetText( "Unable to save shader! Your work will be lost when you quit!" );
601 }
602 }
603 }
604
605
606 delete surface;
607
608 MIDI::Close();
609 FFT::Close();
610
611 Renderer::ReleaseTexture( texPreviousFrame );
612 Renderer::ReleaseTexture( texFFT );
613 Renderer::ReleaseTexture( texFFTSmoothed );
614 for (std::map<std::string, Renderer::Texture*>::iterator it = textures.begin(); it != textures.end(); it++)
615 {
616 Renderer::ReleaseTexture( it->second );
617 }
618
619 Renderer::Close();
620
621 if ( !sPostExitCmd.empty() )
622 {
623 Misc::ExecuteCommand( sPostExitCmd.c_str(), Renderer::defaultShaderFilename );
624 }
625
626 FFT::Destroy();
627
628 Misc::PlatformShutdown();
629
630 return 0;
631 }
632