Bonjour,

Je cherche à développer un space shooter 2D en combinant à la fois SDL et OpenGL.

Mon code fonctionne sous Windows et Linux mais là où j'arrive à un pic de consommation de 20% du CPU chez Microsoft, je suis systématiquement à 50% sur mon Ubuntu (le moniteur système ne distinguant pas les deux coeurs), 100% d'un processeur, sur l'Ubuntu d'un ami, chez qui le jeu fonctionne très mal (j'ai vérifié que ses drivers Nvidia étaient bien installés).

Comment donc puis-je optimiser ce code pour qu'il fonctionne aussi bien sous Linux que sous Windows?

Je me suis inspiré de ce tutoriel pour la structure de mon moteur.

Les fonctions principales employant OpenGL dans mon code, sont les suivantes :

- pour la classe principale "Engine" :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
void CEngine::Init()
{
	// Register SDL_Quit to be called at exit; makes sure things are cleaned up when we quit.
	atexit( SDL_Quit );
 
	// Initialize SDL's subsystems - in this case, only video.
	if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
	{
		fprintf( stderr, "Unable to init SDL: %s\n", SDL_GetError() );
		exit( 1 );
	}
 
	// Attempt to create a window with the specified height and width.
	SetSize( m_iWidth, m_iHeight );
 
	//Double tampon
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
 
	//Couleur de nettoyage
	glClearColor(1.0,1.0,1.0,0.0);
 
	//Remettre a zero la matrice de projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
 
    // Mettre les matrices en place pour une vue orthogonale
    gluOrtho2D(0, m_iWidth, m_iHeight,0);
 
	// If we fail, return error.
	if ( m_pScreen == NULL )
	{
		fprintf( stderr, "Unable to set up video: %s\n", SDL_GetError() );
		exit( 1 );
	}
 
	AdditionalInit();
}
 
/** The main loop. **/
void CEngine::Start()
{
	m_lLastTick = SDL_GetTicks();
	m_bQuit = false;
 
	// Main loop: loop forever.
	while ( !m_bQuit )
	{
		// Handle mouse and keyboard input
		HandleInput();
 
		if ( m_bMinimized ) {
			// Release some system resources if the app. is minimized.
			#if _WIN32
            WaitMessage(); // pause the application until focus in regained
            #endif
 
		} else {
			// Do some thinking
			DoThink();
 
			// Render stuff
			DoRender();
		}
	}
 
	End();
}
 
/** Handles the rendering and FPS calculations. **/
void CEngine::DoRender()
{
	++m_iFPSCounter;
	m_iFPSLimit += m_iFPSTickCounter;
 
	if ( m_iFPSTickCounter >= 1000 )
	{
		m_iCurrentFPS = m_iFPSCounter;
		m_iFPSCounter = 0;
		m_iFPSTickCounter = 0;
	}
 
    if (m_iFPSLimit < 1000/30)
        return;
 
    m_iFPSLimit = 0;
 
	// Lock surface if needed
	if ( SDL_MUSTLOCK( m_pScreen ) )
		if ( SDL_LockSurface( m_pScreen ) < 0 )
			return;
 
	// Effacer le tampon des couleurs
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glClearDepth(0.0f);
 
	glLoadIdentity();
 
	Render( GetSurface() );
 
	// Unlock if needed
	if ( SDL_MUSTLOCK( m_pScreen ) )
		SDL_UnlockSurface( m_pScreen );
 
	// Tell SDL to update the whole gScreen
	//SDL_Flip( m_pScreen );
	glFlush();
    SDL_GL_SwapBuffers();
}
Et pour sa sous-classe "CMyEngine":

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void CMyEngine::Render( SDL_Surface* pDestSurface )
{
	// Display slick graphics on screen
 
	//Modifie la projection
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
 
	//Retrouve la vision orthogonale
	gluOrtho2D(vis.x,vis.x + vis.w,vis.y + vis.h,vis.y);
 
	//Modifie les textures
	glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
 
	//On applique le monde sur l'écran
	world.affiche();
 
	//On met en place le test alpha
	glEnable(GL_ALPHA_TEST);
	//On dessine en fonction de la valeur alpha
	glAlphaFunc(GL_GREATER,0.5f);
 
	//Affiche les obstacles
	int i;
	for (i = 0;i<(int)obstacles.size();i++)
	{
		obstacles[i]->affiche();
	}
 
	//On applique les persos sur l'ecran
	for (i = 0;i<(int)tabperso.size();i++)
	{
		tabperso[i]->affiche();
	}
 
	//On applique les tirs
	for (i = 0;i<(int)tabtirs.size();i++)
	{
		tabtirs[i]->affiche();
	}
 
	//On desactive le test sur la valeur alpha
	glDisable(GL_ALPHA_TEST);
}
J'ajoute le code d'affichage de la classe "Sprite":

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Sprite::affiche()
{
	GLfloat xt0 = (GLfloat)((float)_clip.x/(float)_rect.w);
	GLfloat xt1 = (GLfloat)(((float)_clip.x+(float)_clip.w)/(float)_rect.w);
	GLfloat yt0 = (GLfloat)((float)_clip.y/(float)_rect.h);
	GLfloat yt1 = (GLfloat)(((float)_clip.y+(float)_clip.h)/(float)_rect.h);
 
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, _texture->textu);
 
	//glColor4f(0.0,0.0,0.0,0.5);
	glBegin(GL_QUADS);
		glTexCoord2f(xt0,yt0);
		glVertex3f((GLfloat)_rect.x,(GLfloat)_rect.y,0);					// En haut a gauche
		glTexCoord2f(xt1,yt0);
		glVertex3f((GLfloat)_rect.x+_clip.w,(GLfloat)_rect.y,0);			// En haut a droite
		glTexCoord2f(xt1,yt1);
		glVertex3f((GLfloat)_rect.x+_clip.w,(GLfloat)_rect.y+_clip.h,0);	// En bas a droite
		glTexCoord2f(xt0,yt1);
		glVertex3f((GLfloat)_rect.x,(GLfloat)_rect.y+_clip.h,0);			// En bas a gauche
	glEnd();
	glDisable(GL_TEXTURE_2D);
}
Ouf ! Voilà tout !

Je pressens que la réponse doit être une évidence pour les spécialistes mais qu'elle reste invisible pour un débutant comme moi.

Edit : Serait-il plus efficace de calculer à chaque cycle, pixel par pixel l'image que je veux afficher et de créer ou modifier une seule et même texture pour tout l'écran plutôt que d'afficher une texture par objet comme je le fais actuellement ?