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" :
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
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(); }
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
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); }
Ouf ! Voilà tout !
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); }
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 ?
Partager