]> git.sesse.net Git - vlc/blob - modules/video_filter/atmo/AtmoTools.cpp
atmo: add support for Fnordlicht devices
[vlc] / modules / video_filter / atmo / AtmoTools.cpp
1 /*
2  * AtmoTools.cpp: Collection of tool and helperfunction
3  *
4  * See the README.txt file for copyright information and how to reach the author(s).
5  *
6  * $Id$
7  */
8
9 #include "AtmoTools.h"
10 #include "AtmoDynData.h"
11 #include "AtmoLiveView.h"
12 #include "AtmoClassicConnection.h"
13 #include "AtmoDmxSerialConnection.h"
14 #include "AtmoMultiConnection.h"
15 #include "MoMoConnection.h"
16 #include "FnordlichtConnection.h"
17 #include "AtmoExternalCaptureInput.h"
18 #include <math.h>
19
20 #if !defined(_ATMO_VLC_PLUGIN_)
21 #   include "AtmoColorChanger.h"
22 #   include "AtmoLeftRightColorChanger.h"
23
24 #   include "AtmoDummyConnection.h"
25 #   include "AtmoNulConnection.h"
26 #   include "MondolightConnection.h"
27
28 #   include "AtmoGdiDisplayCaptureInput.h"
29 #endif
30
31 CAtmoTools::CAtmoTools(void)
32 {
33 }
34
35 CAtmoTools::~CAtmoTools(void)
36 {
37 }
38
39 void CAtmoTools::ShowShutdownColor(CAtmoDynData *pDynData)
40 {
41     pDynData->LockCriticalSection();
42
43     CAtmoConnection *atmoConnection = pDynData->getAtmoConnection();
44     CAtmoConfig *atmoConfig = pDynData->getAtmoConfig();
45     if((atmoConnection != NULL) && (atmoConfig!=NULL) && atmoConfig->isSetShutdownColor()) {
46        int i;
47        pColorPacket packet;
48        AllocColorPacket(packet, atmoConfig->getZoneCount());
49
50        // set a special color? on shutdown of the software? mostly may use black or so ...
51        // if this function ist disabled ... atmo will continuing to show the last color...
52        for(i = 0; i < packet->numColors; i++) {
53            packet->zone[i].r = atmoConfig->getShutdownColor_Red();
54            packet->zone[i].g = atmoConfig->getShutdownColor_Green();
55            packet->zone[i].b = atmoConfig->getShutdownColor_Blue();
56        }
57
58        packet = CAtmoTools::ApplyGamma(atmoConfig, packet);
59
60        if(atmoConfig->isUseSoftwareWhiteAdj())
61           packet = CAtmoTools::WhiteCalibration(atmoConfig, packet);
62
63        atmoConnection->SendData(packet);
64
65        delete (char *)packet;
66
67         }
68
69     pDynData->UnLockCriticalSection();
70 }
71
72 EffectMode CAtmoTools::SwitchEffect(CAtmoDynData *pDynData, EffectMode newEffectMode)
73 {
74     // may need a critical section??
75     if(pDynData == NULL) {
76        return emUndefined;
77     }
78     pDynData->LockCriticalSection();
79
80     CAtmoConfig *atmoConfig = pDynData->getAtmoConfig();
81     if(atmoConfig == NULL) {
82        pDynData->UnLockCriticalSection();
83        return emUndefined;
84     }
85     CAtmoConnection *atmoConnection = pDynData->getAtmoConnection();
86
87     EffectMode oldEffectMode = atmoConfig->getEffectMode();
88     CThread *currentEffect = pDynData->getEffectThread();
89     CAtmoInput *currentInput = pDynData->getLiveInput();
90     CAtmoPacketQueue *currentPacketQueue = pDynData->getLivePacketQueue();
91
92
93     if(oldEffectMode == emLivePicture) {
94         /* in case of disabling the live mode
95            first we have to stop the input
96            then the effect thread!
97         */
98         if(currentInput != NULL) {
99            pDynData->setLiveInput( NULL );
100            currentInput->Close();
101            delete currentInput;
102            currentInput = NULL;
103         }
104     }
105
106     // stop and delete/cleanup current Effect Thread...
107     pDynData->setEffectThread( NULL );
108     if(currentEffect != NULL) {
109        currentEffect->Terminate();
110        delete currentEffect;
111        currentEffect = NULL;
112     }
113
114     if(oldEffectMode == emLivePicture) {
115        /*
116          and last we kill the PacketQueue used for communication between the threads
117        */
118        pDynData->setLivePacketQueue( NULL );
119        delete currentPacketQueue;
120        currentPacketQueue = NULL;
121     }
122
123     if((atmoConnection!=NULL) && (atmoConnection->isOpen()==ATMO_TRUE)) {
124         // neuen EffectThread nur mit aktiver Connection starten...
125
126         switch(newEffectMode) {
127             case emDisabled:
128                 break;
129
130             case emStaticColor: {
131                  // get values from config - and put them to all channels?
132                  pColorPacket packet;
133                  AllocColorPacket(packet, atmoConfig->getZoneCount());
134                  for(int i=0; i < packet->numColors; i++){
135                      packet->zone[i].r = atmoConfig->getStaticColor_Red();
136                      packet->zone[i].g = atmoConfig->getStaticColor_Green();
137                      packet->zone[i].b = atmoConfig->getStaticColor_Blue();
138                  }
139
140                  packet = CAtmoTools::ApplyGamma( atmoConfig, packet );
141
142                  if(atmoConfig->isUseSoftwareWhiteAdj())
143                     packet = CAtmoTools::WhiteCalibration(atmoConfig, packet);
144
145                  atmoConnection->SendData( packet );
146
147                  delete (char *)packet;
148
149                  break;
150              }
151
152             case emLivePicture: {
153                 currentEffect = new CAtmoLiveView(pDynData);
154
155 #if !defined(_ATMO_VLC_PLUGIN_)
156                 CAtmoPacketQueueStatus *packetMon = NULL;
157                 if(atmoConfig->getShow_statistics()) {
158                    packetMon = new CAtmoPacketQueueStatus(pDynData->getHinstance(), (HWND)NULL);
159                    packetMon->createWindow();
160                    packetMon->showWindow(SW_SHOW);
161                 }
162                 currentPacketQueue = new CAtmoPacketQueue(packetMon);
163                 pDynData->setLivePictureSource(lpsScreenCapture);
164                 currentInput = new CAtmoGdiDisplayCaptureInput( pDynData );
165 #else
166                 currentPacketQueue = new CAtmoPacketQueue();
167                 pDynData->setLivePictureSource(lpsExtern);
168                 currentInput = new CAtmoExternalCaptureInput( pDynData );
169 #endif
170                 break;
171             }
172
173 #if !defined(_ATMO_VLC_PLUGIN_)
174             case emColorChange:
175                 currentEffect = new CAtmoColorChanger(atmoConnection, atmoConfig);
176                 break;
177
178             case emLrColorChange:
179                 currentEffect = new CAtmoLeftRightColorChanger(atmoConnection, atmoConfig);
180                 break;
181 #endif
182         }
183
184     }
185
186     atmoConfig->setEffectMode( newEffectMode );
187
188     pDynData->setLivePacketQueue( currentPacketQueue );
189     pDynData->setEffectThread( currentEffect );
190     pDynData->setLiveInput( currentInput );
191
192     if(currentEffect != NULL)
193        currentEffect->Run();
194     if(currentInput != NULL)
195        currentInput->Open();
196
197     pDynData->UnLockCriticalSection();
198     return oldEffectMode;
199 }
200
201 LivePictureSource CAtmoTools::SwitchLiveSource(CAtmoDynData *pDynData, LivePictureSource newLiveSource)
202 {
203     LivePictureSource oldSource;
204     pDynData->LockCriticalSection();
205
206     oldSource = pDynData->getLivePictureSource();
207     pDynData->setLivePictureSource( newLiveSource );
208
209     if ((pDynData->getAtmoConfig()->getEffectMode() == emLivePicture) &&
210         (pDynData->getEffectThread() != NULL) &&
211         (pDynData->getLivePacketQueue() != NULL))
212     {
213         CAtmoInput *input = pDynData->getLiveInput();
214         pDynData->setLiveInput( NULL );
215         if(input != NULL) {
216             input->Close();
217             delete input;
218             input = NULL;
219         }
220
221         switch(pDynData->getLivePictureSource()) {
222 #if !defined(_ATMO_VLC_PLUGIN_)
223                case lpsScreenCapture:
224                     input = new CAtmoGdiDisplayCaptureInput( pDynData );
225                break;
226 #endif
227                case lpsExtern:
228                     input = new CAtmoExternalCaptureInput( pDynData );
229                break;
230         }
231
232         pDynData->setLiveInput( input );
233         if(input != NULL)
234            input->Open();
235     }
236
237     pDynData->UnLockCriticalSection();
238     return oldSource;
239 }
240
241 ATMO_BOOL CAtmoTools::RecreateConnection(CAtmoDynData *pDynData)
242 {
243     pDynData->LockCriticalSection();
244
245     CAtmoConnection *current = pDynData->getAtmoConnection();
246     CAtmoConfig *atmoConfig = pDynData->getAtmoConfig();
247     AtmoConnectionType act = atmoConfig->getConnectionType();
248     pDynData->setAtmoConnection(NULL);
249     if(current != NULL) {
250        current->CloseConnection();
251        delete current;
252     }
253
254     switch(act) {
255            case actClassicAtmo: {
256                CAtmoClassicConnection *tempConnection = new CAtmoClassicConnection( atmoConfig );
257                if(tempConnection->OpenConnection() == ATMO_FALSE) {
258 #if !defined(_ATMO_VLC_PLUGIN_)
259                   if(atmoConfig->getIgnoreConnectionErrorOnStartup() == ATMO_FALSE)
260                   {
261                         char errorMsgBuf[200];
262                         sprintf(errorMsgBuf,"Failed to open serial port com%d with errorcode: %d (0x%x)",
263                                     pDynData->getAtmoConfig()->getComport(),
264                                     tempConnection->getLastError(),
265                                     tempConnection->getLastError()
266                                 );
267                         MessageBox(0,errorMsgBuf,"Error",MB_ICONERROR | MB_OK);
268                   }
269 #endif
270                   pDynData->setAtmoConnection(tempConnection);
271
272                   pDynData->UnLockCriticalSection();
273                   return ATMO_FALSE;
274                }
275                pDynData->setAtmoConnection(tempConnection);
276                pDynData->ReloadZoneDefinitionBitmaps();
277
278                tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
279
280                CAtmoTools::SetChannelAssignment(pDynData,
281                                                 atmoConfig->getCurrentChannelAssignment());
282
283                pDynData->UnLockCriticalSection();
284                return ATMO_TRUE;
285            }
286
287 #if !defined(_ATMO_VLC_PLUGIN_)
288            case actDummy:
289            {
290                // actDummy8,actDummy12,actDummy16
291                CAtmoDummyConnection *tempConnection = new CAtmoDummyConnection(pDynData->getHinstance(),
292                                                                                atmoConfig);
293                if(tempConnection->OpenConnection() == ATMO_FALSE) {
294                   pDynData->setAtmoConnection(tempConnection);
295                   pDynData->UnLockCriticalSection();
296                   return ATMO_FALSE;
297                }
298                pDynData->setAtmoConnection(tempConnection);
299                pDynData->ReloadZoneDefinitionBitmaps();
300
301                tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
302
303                CAtmoTools::SetChannelAssignment(pDynData, pDynData->getAtmoConfig()->getCurrentChannelAssignment());
304
305                pDynData->UnLockCriticalSection();
306                return ATMO_TRUE;
307            }
308 #endif
309
310            case actDMX: {
311                // create here your DMX connections... instead of the dummy....
312                CAtmoDmxSerialConnection *tempConnection = new CAtmoDmxSerialConnection( atmoConfig );
313                if(tempConnection->OpenConnection() == ATMO_FALSE) {
314                   pDynData->setAtmoConnection(tempConnection);
315
316                   pDynData->UnLockCriticalSection();
317                   return ATMO_FALSE;
318                }
319                pDynData->setAtmoConnection(tempConnection);
320                pDynData->ReloadZoneDefinitionBitmaps();
321
322                tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
323
324                CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
325
326                pDynData->UnLockCriticalSection();
327                return ATMO_TRUE;
328            }
329
330 #if !defined(_ATMO_VLC_PLUGIN_)
331            case actNUL: {
332                CAtmoNulConnection *tempConnection = new CAtmoNulConnection( atmoConfig );
333                if(tempConnection->OpenConnection() == ATMO_FALSE) {
334                   pDynData->setAtmoConnection(tempConnection);
335                   pDynData->UnLockCriticalSection();
336                   return ATMO_FALSE;
337                }
338                pDynData->setAtmoConnection(tempConnection);
339                pDynData->ReloadZoneDefinitionBitmaps();
340
341                tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
342
343                CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
344
345                pDynData->UnLockCriticalSection();
346                return ATMO_TRUE;
347            }
348 #endif
349
350            case actMultiAtmo: {
351                CAtmoMultiConnection *tempConnection = new CAtmoMultiConnection( atmoConfig );
352                if(tempConnection->OpenConnection() == ATMO_FALSE) {
353                   pDynData->setAtmoConnection(tempConnection);
354                   pDynData->UnLockCriticalSection();
355                   return ATMO_FALSE;
356                }
357                pDynData->setAtmoConnection(tempConnection);
358                pDynData->ReloadZoneDefinitionBitmaps();
359
360                tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
361
362                CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
363
364                pDynData->UnLockCriticalSection();
365                return ATMO_TRUE;
366            }
367
368 #if !defined(_ATMO_VLC_PLUGIN_)
369            case actMondolight: {
370                CMondolightConnection *tempConnection = new CMondolightConnection( atmoConfig );
371                if(tempConnection->OpenConnection() == ATMO_FALSE) {
372                   pDynData->setAtmoConnection(tempConnection);
373                   pDynData->UnLockCriticalSection();
374                   return ATMO_FALSE;
375                }
376                pDynData->setAtmoConnection(tempConnection);
377                pDynData->ReloadZoneDefinitionBitmaps();
378
379                tempConnection->CreateDefaultMapping(atmoConfig->getChannelAssignment(0));
380
381                CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment());
382
383                pDynData->UnLockCriticalSection();
384                return ATMO_TRUE;
385            }
386 #endif
387            case actMoMoLight: {
388                CMoMoConnection *tempConnection = new CMoMoConnection( atmoConfig );
389                if(tempConnection->OpenConnection() == ATMO_FALSE) {
390                   pDynData->setAtmoConnection(tempConnection);
391                   pDynData->UnLockCriticalSection();
392                   return ATMO_FALSE;
393                }
394                pDynData->setAtmoConnection(tempConnection);
395                pDynData->ReloadZoneDefinitionBitmaps();
396
397                tempConnection->CreateDefaultMapping( atmoConfig->getChannelAssignment(0) );
398
399                CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment() );
400
401                pDynData->UnLockCriticalSection();
402                return ATMO_TRUE;
403            }
404
405            case actFnordlicht: {
406                CFnordlichtConnection *tempConnection = new CFnordlichtConnection( atmoConfig );
407                if(tempConnection->OpenConnection() == ATMO_FALSE) {
408                   pDynData->setAtmoConnection(tempConnection);
409                   pDynData->UnLockCriticalSection();
410                   return ATMO_FALSE;
411                }
412                pDynData->setAtmoConnection(tempConnection);
413                pDynData->ReloadZoneDefinitionBitmaps();
414
415                tempConnection->CreateDefaultMapping( atmoConfig->getChannelAssignment(0) );
416
417                CAtmoTools::SetChannelAssignment(pDynData, atmoConfig->getCurrentChannelAssignment() );
418
419                pDynData->UnLockCriticalSection();
420                return ATMO_TRUE;
421            }
422
423            default: {
424                pDynData->UnLockCriticalSection();
425                return ATMO_FALSE;
426            }
427     }
428 }
429
430 pColorPacket CAtmoTools::WhiteCalibration(CAtmoConfig *pAtmoConfig, pColorPacket ColorPacket)
431 {
432     int w_adj_red   = pAtmoConfig->getWhiteAdjustment_Red();
433     int w_adj_green = pAtmoConfig->getWhiteAdjustment_Green();
434     int w_adj_blue  = pAtmoConfig->getWhiteAdjustment_Blue();
435
436     for (int i = 0; i < ColorPacket->numColors; i++)  {
437         ColorPacket->zone[i].r = (unsigned char)(((int)w_adj_red   * (int)ColorPacket->zone[i].r) / 255);
438         ColorPacket->zone[i].g = (unsigned char)(((int)w_adj_green * (int)ColorPacket->zone[i].g) / 255);
439         ColorPacket->zone[i].b = (unsigned char)(((int)w_adj_blue  * (int)ColorPacket->zone[i].b) / 255);
440     }
441     return ColorPacket;
442 }
443
444 pColorPacket CAtmoTools::ApplyGamma(CAtmoConfig *pAtmoConfig, pColorPacket ColorPacket)
445 {
446   double v;
447   switch(pAtmoConfig->getSoftware_gamma_mode()) {
448     case agcNone: break;
449     case agcPerColor: {
450         double GammaRed   = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_red());
451         double GammaGreen = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_green());
452         double GammaBlue  = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_blue());
453         for (int i = 0; i < ColorPacket->numColors; i++)
454         {
455           v = ColorPacket->zone[i].r;
456           v = (pow( v / 255.0f, GammaRed ) * 255.0f);
457           ColorPacket->zone[i].r = ATMO_MIN((int)v, 255);
458
459           v = ColorPacket->zone[i].g;
460           v = (pow( v / 255.0f, GammaGreen ) * 255.0f);
461           ColorPacket->zone[i].g = ATMO_MIN((int)v, 255);
462
463           v = ColorPacket->zone[i].b;
464           v = (pow( v / 255.0f, GammaBlue ) * 255.0f);
465           ColorPacket->zone[i].b = ATMO_MIN((int)v, 255);
466         }
467         break;
468     }
469     case agcGlobal:   {
470         double Gamma   = 10.0 / ((double)pAtmoConfig->getSoftware_gamma_global());
471         for (int i = 0; i < ColorPacket->numColors; i++)
472         {
473           v = ColorPacket->zone[i].r;
474           v = (pow( v / 255.0f, Gamma ) * 255.0f);
475           ColorPacket->zone[i].r = ATMO_MIN((int)v, 255);
476
477           v = ColorPacket->zone[i].g;
478           v = (pow( v / 255.0f, Gamma ) * 255.0f);
479           ColorPacket->zone[i].g = ATMO_MIN((int)v, 255);
480
481           v = ColorPacket->zone[i].b;
482           v = (pow( v / 255.0f, Gamma ) * 255.0f);
483           ColorPacket->zone[i].b = ATMO_MIN((int)v, 255);
484         }
485         break;
486     }
487   }
488   return ColorPacket;
489 }
490
491 int CAtmoTools::SetChannelAssignment(CAtmoDynData *pDynData, int index)
492 {
493     CAtmoConfig *pAtmoConfig = pDynData->getAtmoConfig();
494     CAtmoConnection *pAtmoConnection = pDynData->getAtmoConnection();
495     int oldIndex = pAtmoConfig->getCurrentChannelAssignment();
496
497     CAtmoChannelAssignment *ca = pAtmoConfig->getChannelAssignment(index);
498     if((ca!=NULL) && (pAtmoConnection!=NULL)) {
499         pAtmoConnection->SetChannelAssignment(ca);
500         pAtmoConfig->setCurrentChannelAssignment(index);
501     }
502     return oldIndex;
503 }
504
505
506 #if !defined(_ATMO_VLC_PLUGIN_)
507
508 void CAtmoTools::SaveBitmap(HDC hdc,HBITMAP hBmp,char *fileName) {
509      BITMAPINFO bmpInfo;
510      BITMAPFILEHEADER  bmpFileHeader;
511      ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
512      bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
513
514      GetDIBits(hdc,hBmp,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
515      if(bmpInfo.bmiHeader.biSizeImage<=0)
516         bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth * abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
517      void *pBuf = malloc(bmpInfo.bmiHeader.biSizeImage);
518      bmpInfo.bmiHeader.biCompression=BI_RGB;
519
520      GetDIBits(hdc,hBmp,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS);
521
522
523      bmpFileHeader.bfReserved1=0;
524      bmpFileHeader.bfReserved2=0;
525      bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
526      bmpFileHeader.bfType = MakeIntelWord('M','B');
527      bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
528
529
530      FILE *fp = NULL;
531      fp = fopen(fileName,"wb");
532      fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
533      fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
534      fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
535      fclose(fp);
536 }
537
538
539
540 #endif
541