Results 1 to 12 of 12

Thread: Problems with QPainter

  1. #1
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    691
    Thanks
    59
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Problems with QPainter

    Hi to all, I'm writing an audio editor. I have to draw the waveform.
    The paint event of my wavewidget is so done:

    Qt Code:
    1. /***************************************************************/
    2. /* Paint event */
    3. /***************************************************************/
    4. void WaveWidget::paintEvent( QPaintEvent* pe )
    5. {
    6. // I call updateWave only if necessary if not I draw what is in cache
    7. if( m_waveCachePixmap.isNull() )
    8. {
    9. updateWave();
    10. }
    11.  
    12. QPainter p( this );
    13. p.setRenderHint( QPainter::Antialiasing );
    14. p.drawPixmap( 0, 0, m_waveCachePixmap );
    15. }
    To copy to clipboard, switch view to plain text mode 

    where the updateWave() is so done:

    Qt Code:
    1. /************************************************************************/
    2. /* updateWave */
    3. /* call this only when the wave is changed, */
    4. /************************************************************************/
    5. void WaveWidget::updateWave()
    6. {
    7. int h = height();
    8. int w = width();
    9.  
    10. // I want another width and height here.
    11. // Also, you might to clear the cache at resize events
    12. QPixmap temp = QPixmap( w, h );
    13.  
    14. QPainter p( &temp );
    15. p.fillRect( temp.rect(), Qt::white );
    16. p.setRenderHint( QPainter::Antialiasing );
    17.  
    18.  
    19. QPen pen( Qt::blue, 1 ); // blue solid line, 1 pixels wide
    20. p.setPen( pen );
    21.  
    22. // Draw the waveform or no data thingie
    23. if( m_wave )
    24. {
    25. unsigned int numSamples = m_wave->getNumSamples();
    26. int channels = m_wave->getNumChannels();
    27. FMOD_SOUND_TYPE soundType = m_wave->getSoundType();
    28. FMOD_SOUND_FORMAT soundFormat = m_wave->getSoundFormat();
    29.  
    30. int sampleSize = channels * ( soundFormat == PCM8 ) ? 1 : 2;
    31.  
    32. //char* stream = sound->stream;
    33. void* soundStream = m_wave->getSoundStream();
    34. int maxHeight = (h / 2) / channels;
    35. int increment = (h / 2);
    36.  
    37. switch( soundFormat )
    38. {
    39. case PCM8: //8 bits mono
    40. {
    41. qDebug("PCM8 sound file");
    42. char* audio = reinterpret_cast<char*>(soundStream);
    43. for( unsigned int i = 0; i < numSamples ; i++ )
    44. {
    45. char* current = (audio) + (i * sampleSize);
    46. char audio = *current;
    47. float reproc = audio / (float)(1 << 8);
    48. //DrawLine( i, 0, i, height * reproc );
    49. //QLine line( x, startY, x, startY + Y);
    50. //p.drawLine(line);
    51. //startY += increment;
    52. }
    53. break;
    54. }
    55. case PCM16: //16 bits stereo (LRLRLRLR...LRLR)
    56. {
    57. qDebug("PCM16 sound file");
    58. short* audio = reinterpret_cast<short*>(soundStream);
    59. for( unsigned int i = 0; i < numSamples; i++ )
    60. {
    61. int startY = maxHeight;
    62. for( int k = 0; k < channels; k++ )
    63. {
    64. //short* value1 = reinterpret_cast<short*>(stream + k * 2);
    65. //short* value1 = audio + k * 2;
    66. short* value1 = audio + k;
    67. int x = i / ( numSamples / w);//?
    68. int y = *value1 * maxHeight / 0x0000FFFF * 2;
    69. QLine line( x, startY, x, startY + y );
    70. //std::cout << "Drawing at x: " << x << "startY: " << startY << "y: " << y << "\n";
    71. p.drawLine(line);
    72. startY += increment;
    73. }
    74. //std::cout << audio[i] << "\n";
    75. audio += sampleSize;
    76. }
    77. break;
    78. }
    79.  
    80. default:
    81. {
    82. qDebug("Undefined sound type");
    83. break;
    84. }
    85. }
    86. }
    87. else
    88. {
    89. // Inform the user that no file has been loaded - perhaps using a
    90. // no-data icon or something
    91. qDebug("No data");
    92. }
    93.  
    94. m_waveCachePixmap = temp;
    95. }
    To copy to clipboard, switch view to plain text mode 

    I have some problems:
    1) It doesn't draw nothing
    2) I get the follow strange errors that with my poor experience in Qt I can not solve:
    QPainter::begin: Paint device returned engine == 0, type: 2
    QPainter::setRenderHint: painter must be active to set rendering hints
    QPainter::setPen: Painter not active
    3) The step of drawing ( that doesn't work ) blok the application.

    I hope to get help.
    Best Regards
    Franco Amato

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problems with QPainter

    Please provide a minimal compilable example reproducing the problem.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    691
    Thanks
    59
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problems with QPainter

    How can I give you a compilable project?
    I send to your private mail? Give me your mail please.

    Franco
    Franco Amato

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problems with QPainter

    Attach it to your post. Make sure it is a minimal and compilable example. I don't want your whole project.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    691
    Thanks
    59
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problems with QPainter

    Hi,at the moment my project is at a minimal level :-)
    I'll try to attach the minimal of the minimal

    Qt Code:
    1. // the main
    2. int main(int argc, char* argv[])
    3. {
    4. QApplication app( argc, argv );
    5. MainWindow mainWin;
    6. mainWin.showMaximized();
    7. // init audio system
    8. QTimer::singleShot( 1, AudioDevice::getInstance(), SLOT(init() ) );
    9. return app.exec();
    10. }
    To copy to clipboard, switch view to plain text mode 

    I create a QMainWindow containing a centralWidget

    Qt Code:
    1. #ifndef __MAINWINDOW_H__
    2. #define __MAINWINDOW_H__
    3.  
    4. /* system include */
    5. #include <iostream>
    6. #include <vector>
    7. /* qt include */
    8. #include <QMainWindow>
    9. /* interfaces include */
    10. #include "CentralWidget.h"
    11. #include "WaveWidget.h"
    12.  
    13. QT_BEGIN_NAMESPACE
    14. class QAction;
    15. class QMenu;
    16. QT_END_NAMESPACE
    17.  
    18. class MainWindow : public QMainWindow
    19. {
    20. Q_OBJECT
    21.  
    22. public:
    23. MainWindow( QWidget *parent = 0, Qt::WindowFlags flags = 0 );
    24.  
    25. protected:
    26. virtual void closeEvent(QCloseEvent *event);
    27. virtual void paintEvent(QPaintEvent *event);
    28.  
    29. private slots:
    30. void openAudioFile();
    31. void about();
    32.  
    33. private:
    34. void createActions();
    35. void createMenus();
    36. void createStatusBar();
    37.  
    38. /* Menus */
    39. QMenu* fileMenu;
    40. QMenu* helpMenu;
    41. /* Actions */
    42. QAction* openAct;
    43. QAction* exitAct;
    44. QAction* aboutAct;
    45. QAction* aboutQtAct;
    46.  
    47. CentralWidget* mp_cW;
    48. };
    49.  
    50. #endif //__MAINWINDOW_H__
    To copy to clipboard, switch view to plain text mode 

    I post only some relevant methods of MainWindow and of the rest of the classes:
    Qt Code:
    1. MainWindow::MainWindow( QWidget *parent, Qt::WindowFlags flags )
    2. : QMainWindow(parent, flags)
    3. {
    4. setObjectName("MainWindow");
    5. setWindowTitle("ECP Studio");
    6.  
    7. createActions();
    8. createMenus();
    9. createStatusBar();
    10.  
    11. mp_cW = new CentralWidget( this );
    12. setCentralWidget( mp_cW );
    13. }
    14.  
    15. // I pass the audio file to the centralWidget
    16. void MainWindow::openAudioFile()
    17. {
    18. QString fileName = QFileDialog::getOpenFileName( this );
    19. if( !fileName.isEmpty() )
    20. {
    21. mp_cW->setSoundFile( fileName );
    22. }
    23. }
    To copy to clipboard, switch view to plain text mode 

    The centralwidget:
    Qt Code:
    1. #include "WaveWidget.h"
    2.  
    3. class CentralWidget : public QWidget
    4. {
    5. public:
    6. // ctor
    7. CentralWidget( QWidget* parent = 0 );
    8. // set the path of the sound file
    9. void setSoundFile( QString soundName_ );
    10.  
    11. protected:
    12. // override paintEvent
    13. virtual void paintEvent( QPaintEvent * );
    14.  
    15. private:
    16. QVBoxLayout* mp_vBox;
    17. WaveWidget* mp_wave;
    18. QString m_soundName;
    19. };
    20.  
    21. #endif //__CENTRALWIDGET_H__
    To copy to clipboard, switch view to plain text mode 

    Again only some methods:

    Qt Code:
    1. CentralWidget::CentralWidget( QWidget* parent /* = 0 */ )
    2. : QWidget(parent),
    3. mp_vBox( 0 ),
    4. mp_wave( 0 )
    5. {
    6. /*vertical layout */
    7. QVBoxLayout *layout = new QVBoxLayout;
    8. /* waveform visualizer */
    9. mp_wave = new WaveWidget( this );
    10. layout->addWidget(mp_wave);
    11. setLayout(layout);
    12. }
    13.  
    14. void CentralWidget::setSoundFile( QString soundName_ )
    15. {
    16. m_soundName = soundName_;
    17. mp_wave->setSoundFile( m_soundName );
    18. }
    To copy to clipboard, switch view to plain text mode 

    Now the waveWidget, where I would display the waveform. Its a child of the centralwidget

    Qt Code:
    1. #include <QWidget>
    2. #include <QMouseEvent>
    3.  
    4. #include "SoundData.h"
    5.  
    6. class WaveWidget : public QWidget
    7. {
    8. Q_OBJECT
    9.  
    10. public:
    11. WaveWidget( QWidget* parent = 0 );
    12. void setSoundFile( QString soundName_ );
    13. void setWave( SoundData* );
    14.  
    15. protected:
    16. virtual void paintEvent( QPaintEvent* event );
    17. virtual void resizeEvent ( QResizeEvent* event );
    18. virtual void mousePressEvent( QMouseEvent *event );
    19. virtual void mouseMoveEvent( QMouseEvent *event );
    20. virtual void mouseReleaseEvent( QMouseEvent *event );
    21.  
    22. private:
    23. void updateWave();
    24.  
    25. QPixmap m_waveCachePixmap;
    26. SoundData* m_wave;
    27. };
    28.  
    29. #endif //__WAVEWIDGET_H__
    To copy to clipboard, switch view to plain text mode 

    It contain SoundData that's a wrapper around the sound data.
    Again only some relevant methods:

    Qt Code:
    1. /************************************************************************/
    2. /* Constructor */
    3. /************************************************************************/
    4. WaveWidget::WaveWidget( QWidget* parent /* = 0 */ )
    5. : QWidget( parent ),
    6. m_wave( 0 )
    7. {
    8. }
    9.  
    10. /************************************************************************/
    11. /* setSoundFile */
    12. /************************************************************************/
    13. void WaveWidget::setSoundFile( QString soundName_ )
    14. {
    15. m_wave = new SoundData();
    16. m_wave->loadSoundData( soundName_ );
    17. setWave( m_wave );
    18. }
    19.  
    20. /************************************************************************/
    21. /* setWave */
    22. /************************************************************************/
    23. void WaveWidget::setWave( SoundData* w )
    24. {
    25. m_wave = w;
    26. m_waveCachePixmap = QPixmap(); // Empty the cache as the wave data has changed
    27.  
    28. int samples = m_wave->getNumSamples();
    29. resize( samples, 500 ); // NEW NEW NEW
    30.  
    31. update(); // This triggers a paint event later on, lets Qt decide
    32. // how and when (if your widget is hidden, etc)
    33. }
    34.  
    35. /************************************************************************/
    36. /* updateWave */
    37. /************************************************************************/
    38. void WaveWidget::updateWave()
    39. {
    40. int h = height();
    41. int w = width();
    42.  
    43. // I want another width and height here.
    44. // Also, you might to clear the cache at resize events
    45. QPixmap temp = QPixmap( w, h );
    46.  
    47. QPainter p( &temp );
    48. p.fillRect( temp.rect(), Qt::white );
    49. p.setRenderHint( QPainter::Antialiasing );
    50.  
    51.  
    52. QPen pen( Qt::blue, 1 ); // blue solid line, 1 pixels wide
    53. p.setPen( pen );
    54.  
    55. // Draw the waveform or no data thingie
    56. if( m_wave )
    57. {
    58. unsigned int numSamples = m_wave->getNumSamples();
    59. int channels = m_wave->getNumChannels();
    60. FMOD_SOUND_TYPE soundType = m_wave->getSoundType();
    61. FMOD_SOUND_FORMAT soundFormat = m_wave->getSoundFormat();
    62.  
    63. int sampleSize = channels * ( soundFormat == PCM8 ) ? 1 : 2;
    64.  
    65. //char* stream = sound->stream;
    66. void* soundStream = m_wave->getSoundStream();
    67. int maxHeight = (h / 2) / channels;
    68. int increment = (h / 2);
    69.  
    70. switch( soundFormat )
    71. {
    72. case PCM8: //8 bits mono
    73. {
    74. qDebug("PCM8 sound file");
    75. char* audio = reinterpret_cast<char*>(soundStream);
    76. for( unsigned int i = 0; i < numSamples ; i++ )
    77. {
    78. char* current = (audio) + (i * sampleSize);
    79. char audio = *current;
    80. float reproc = audio / (float)(1 << 8);
    81. //DrawLine( i, 0, i, height * reproc );
    82. //QLine line( x, startY, x, startY + Y);
    83. //p.drawLine(line);
    84. //startY += increment;
    85. }
    86. break;
    87. }
    88. case PCM16: //16 bits stereo (LRLRLRLR...LRLR)
    89. {
    90. qDebug("PCM16 sound file");
    91. short* audio = reinterpret_cast<short*>(soundStream);
    92. for( unsigned int i = 0; i < numSamples; i++ )
    93. {
    94. int startY = maxHeight;
    95. for( int k = 0; k < channels; k++ )
    96. {
    97. //short* value1 = reinterpret_cast<short*>(stream + k * 2);
    98. short* value1 = audio + k * 2;
    99. //short* value1 = audio + k;
    100. int x = i / ( numSamples / w);//?
    101. int y = *value1 * maxHeight / 0x0000FFFF * 2;
    102. QLine line( x, startY, x, startY + y );
    103.  
    104. p.drawLine(line);
    105. startY += increment;
    106. }
    107. //std::cout << audio[i] << "\n";
    108. audio += sampleSize;
    109. }
    110. break;
    111. }
    112.  
    113. default:
    114. {
    115. qDebug("Undefined sound type");
    116. break;
    117. }
    118. }
    119. }
    120. else
    121. {
    122. // Inform the user that no file has been loaded - perhaps using a
    123. // no-data icon or something
    124. qDebug("No data");
    125. }
    126.  
    127. m_waveCachePixmap = temp;
    128. }
    129.  
    130. /************************************************************************/
    131. /* Paint event */
    132. /************************************************************************/
    133. void WaveWidget::paintEvent( QPaintEvent* pe )
    134. {
    135. // chiamo la updateWave solo se e' necessario se no disegno quella in cache
    136. if( m_waveCachePixmap.isNull() )
    137. {
    138. updateWave();
    139. }
    140.  
    141. QPainter p( this );
    142. p.setRenderHint( QPainter::Antialiasing );
    143. p.drawPixmap( 0, 0, m_waveCachePixmap );
    144. }
    145.  
    146. /************************************************************************/
    147. /* Resize event */
    148. /************************************************************************/
    149. void WaveWidget::resizeEvent ( QResizeEvent * event )
    150. {
    151. m_waveCachePixmap = QPixmap(); // I invalidate the cache
    152. update();
    153. event->accept();
    154. }
    To copy to clipboard, switch view to plain text mode 

    I hope is not too much code. But with less code I don't think how you can help me.
    Let me know if you would also have the soundData class, is not a problem.

    I really hope you can help me.
    Best Regards,
    Franco
    Franco Amato

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problems with QPainter

    I'm sorry but in my view, "minimal" can't be longer than 30 lines. If you send me your code, you won't find the problem, because the point of asking for a minimal compilable example is for you to sit down, take a look at your code, cut out the parts which you think are relevant to the problem and build a separate application out of this. In many cases it occurs that the new app is working correctly which suggests the error is in some other part of your app. Get rid of all the actions and events, leave only the crucial part related to the paint event.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  7. #7
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    691
    Thanks
    59
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problems with QPainter

    Quote Originally Posted by wysota View Post
    I'm sorry but in my view, "minimal" can't be longer than 30 lines. If you send me your code, you won't find the problem, because the point of asking for a minimal compilable example is for you to sit down, take a look at your code, cut out the parts which you think are relevant to the problem and build a separate application out of this. In many cases it occurs that the new app is working correctly which suggests the error is in some other part of your app. Get rid of all the actions and events, leave only the crucial part related to the paint event.
    Dear wysota thank you for your help but I still don't understand.
    I only have 2 actions more ( Close the app, and show about ) that I don't sent.
    Did you try to load an audio file? And it work? So I definitively don't understand. What can I do to solve my problem? I really hope you can give to me some suggestions.

    Best Regards,
    Franco
    Franco Amato

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problems with QPainter

    I didn't build your app. It's too tedious for me to copy & paste so many different files. It would really be better if you got rid of everything apart the relevant code. I.e. I don't see a point of the SoundData class being part of this example.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #9
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    691
    Thanks
    59
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problems with QPainter

    Quote Originally Posted by wysota View Post
    I didn't build your app. It's too tedious for me to copy & paste so many different files. It would really be better if you got rid of everything apart the relevant code. I.e. I don't see a point of the SoundData class being part of this example.
    Hi wysota,
    I'll create only the wavewidhet ( without centralWidget nor QMainWindow ) and I'll try to draw some random values instead of sound pcm samples and past the code here.

    Best Regards,
    Franco
    Franco Amato

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problems with QPainter

    Great. Try to fit it into those 30 lines. You don't even have to paint anything as you are getting errors before any painting is done - just initialize the painter.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  11. #11
    Join Date
    Nov 2007
    Location
    Italy
    Posts
    691
    Thanks
    59
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problems with QPainter

    Quote Originally Posted by wysota View Post
    Great. Try to fit it into those 30 lines. You don't even have to paint anything as you are getting errors before any painting is done - just initialize the painter.
    Dear wysota. I solved the problem that gave the error. Is the line:
    Qt Code:
    1. resize(wave->getSamples(), 200);
    To copy to clipboard, switch view to plain text mode 
    This did that the waveWidget was expanded ( in the x direction ) more that the mainWindow because the number of audio samples I have is ~10E6.
    So I tried to attach the waveWidget to a QScrollArea without success so:

    Qt Code:
    1. CentralWidget::CentralWidget( QWidget* parent /* = 0 */ )
    2. : QWidget(parent),
    3. mp_vBox( 0 ),
    4. mp_wave( 0 )
    5. {
    6. /* vertical layout */
    7. mp_vBox = new QVBoxLayout( this );
    8. /* scroll area */
    9. scrollArea = new QScrollArea();
    10. /* waveform visualizer */
    11. mp_wave = new WaveWidget( this );
    12. scrollArea->setWidget( mp_wave );
    13. mp_vBox->addWidget( scrollArea );
    14. setLayout( mp_vBox );
    15. }
    To copy to clipboard, switch view to plain text mode 
    This did that now I can't see the waveWidget.
    Where my code is wrong?

    Best Regards
    Franco Amato

  12. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problems with QPainter

    Call QScrollArea::setWidgetResizable() with true as the parameter and see if it helps. In general you should reimplement sizeHint() for your wave widget.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. how to get QPainter object for QLabel
    By bpatel in forum Newbie
    Replies: 7
    Last Post: 28th May 2010, 10:30
  2. QPrinter problems
    By Teuniz in forum Qt Programming
    Replies: 1
    Last Post: 3rd November 2007, 08:51
  3. Weird color problems related to QTextEdit and QPainter
    By Erlendhg in forum Qt Programming
    Replies: 5
    Last Post: 18th June 2007, 21:57
  4. QPainter and QImage
    By beerkg in forum Newbie
    Replies: 3
    Last Post: 7th September 2006, 14:48
  5. Replies: 7
    Last Post: 20th March 2006, 20:03

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.