Very Slow Display function?

Hi,

I’m trying to work on a basic powder game like project but just with OpenGL and I created this basic code:


#include <GL/glut.h>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <cstdio>

#define screen_x 1024 
#define screen_y 768

#define M_PI 3.14
struct Particle {
	float x;
	float y;
	float r;
	float vx;
	float vy;
	float m;
	int type;
	float color[3];
};

struct Line {
	float x1;
	float y1;
	float x2;
	float y2;
} line;

void timer(int = 0);
void display();
void mouse(int, int, int, int);
void mouseMotion(int, int);
void add_particle(float, float = 0, float = 0);
void remove_particles();
void keyboard(unsigned char, int, int);

int NEXT = 0;
int	mouse_x, mouse_y, WIN,
mode = 2,
crit_mass = 1,
MAX_MASS = 50000000;
float cnst_elastic = 0.75;
double z = 0.0;
bool PRESSED_LEFT = false, PRESSED_RIGHT = false,
PRESSED_MIDDLE = false, SPEED_PARTICLES = false;

std::vector<Particle> particles;

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(screen_x, screen_y);
	glutInitWindowPosition(50, 50);
	WIN = glutCreateWindow("Rohan Toy");

	glClearColor(0, 0, 0, 1);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-screen_x / 2, screen_x / 2, screen_y / 2, -screen_y / 2, 0, 1);

	glutDisplayFunc(display);
	glutMouseFunc(mouse);
	glutMotionFunc(mouseMotion);
	glutKeyboardFunc(keyboard);
	timer();

	glutMainLoop();
	return 0;
}

void timer(int){
	display();
	if (PRESSED_LEFT && !SPEED_PARTICLES)
	{
		add_particle(1);
		PRESSED_LEFT = false;
	}

	if (PRESSED_RIGHT)
	{
		int x = mouse_x;
		int y = mouse_y;
		for (int i = 0; i<250; i++){
			mouse_x = rand() % 250 - 125 + x;
			mouse_y = rand() % 250 - 125 + y;
			add_particle(rand() % 500 + 250);
		}
		PRESSED_RIGHT = false;
	}

	if (PRESSED_MIDDLE)
		remove_particles();


	for (int i; i < particles.size(); i++)
	{
		Particle &p = particles[i];
		if (p.type == 2)
			p.y += 0.45;
		else
			p.y += 0.50;
		particles[i] = p;
	}

	for (int i; i < particles.size(); i++)
	{
		Particle &p = particles[i];
		for (int c; c < particles.size(); c++)
		{
			Particle &z = particles[i];
			if (z.y == p.y)
			{
				p.y -= 0.50;
				particles[i] = p;
			}
		}
	}

	glutTimerFunc(0.1, timer, 0);
}

void display(){
	glClear(GL_COLOR_BUFFER_BIT);


	for (int i = 0; i < particles.size(); i++){
		Particle &p = particles[i];
		glColor3f(p.color[0], p.color[1], p.color[2]);
		glBegin(GL_POLYGON);
		for (float a = 0; a < 2 * M_PI; a += 0.25)
			glVertex2f(p.r*cos(a) + p.x, p.r*sin(a) + p.y);
		glEnd();
	}

	glFlush();
	glutSwapBuffers();
	
}

void mouse(int button, int state, int x, int y){
	mouse_x = x - screen_x / 2;
	mouse_y = y - screen_y / 2;

	if (SPEED_PARTICLES){
		if (line.x2 != 0 && line.y2 != 0 && state == GLUT_UP && PRESSED_LEFT)
			add_particle(100, line.x1 - line.x2, line.y1 - line.y2);
		else{
			line.x1 = line.x2 = mouse_x;
			line.y1 = line.y2 = mouse_y;
		}
	}

	if (button == GLUT_LEFT_BUTTON)
		PRESSED_LEFT = state == GLUT_DOWN;
	else if (button == GLUT_RIGHT_BUTTON)
		PRESSED_RIGHT = state == GLUT_DOWN;
	else if (button == GLUT_MIDDLE_BUTTON)
		PRESSED_MIDDLE = state == GLUT_DOWN;
}

void mouseMotion(int x, int y){
	mouse_x = x - screen_x / 2;
	mouse_y = y - screen_y / 2;

	if (SPEED_PARTICLES && PRESSED_LEFT){
		line.x2 = mouse_x;
		line.y2 = mouse_y;
	}
}

void add_particle(float m, float vx, float vy){
	Particle p;
	p.x = mouse_x;
	p.y = mouse_y;
	p.vx = vx / 30;
	p.vy = vy / 30;
	p.m = m;
	p.r = pow((p.m / M_PI), 0.175);
	if (NEXT == 0)
		p.type = 1;
	else
		p.type = 2;
	p.color[0] = 1.0;
	p.color[1] = 1.0 - p.m * 1 / MAX_MASS;
	p.color[2] = 0.0;

	particles.push_back(p);

	if (line.x1 != 0)
		line.x1 = line.x2 = line.y1 = line.y2 = 0;
}

void remove_particles(){
	for (int j = 0; j<5; j++){
		for (int i = 0; i < particles.size(); i++)
			particles.pop_back();
	}
}

void keyboard(unsigned char key, int x, int y)

Press\Hold “R” on keyboard and it becomes extremely slow while other games like Powder toy are barely even lagging, is there a different way of doing this maybe using some Video function than this?

  1. Store the data as a 2D array and render it as a texture, not as individual points.

  2. If you’re rendering many primitives, use vertex arrays (glDrawArrays etc) rather than glBegin/glEnd. Modern versions of OpenGL (OpenGL 3, OpenGL ES, WebGL) have either deprecated or removed those operations because they’re too inefficient.

This is going to be slow:

	for (int i = 0; i < particles.size(); i++){
		Particle &p = particles[i];
		glColor3f(p.color[0], p.color[1], p.color[2]);
		glBegin(GL_POLYGON);
		for (float a = 0; a < 2 * M_PI; a += 0.25)
			glVertex2f(p.r*cos(a) + p.x, p.r*sin(a) + p.y);
		glEnd();
	}

…and this is going to be fast:

	glBegin(GL_POLYGON);

	for (int i = 0; i < particles.size(); i++){
		Particle &p = particles[i];
		glColor3f(p.color[0], p.color[1], p.color[2]);
		for (float a = 0; a < 2 * M_PI; a += 0.25)
			glVertex2f(p.r*cos(a) + p.x, p.r*sin(a) + p.y);
	}

	glEnd();

You really don’t need a VBO or glDrawArrays for this; glBegin/glEnd (even though they are deprecated and you shouldn’t etc) are plenty capable of running fast if you’re a bit smart about how you use them. Putting them outside a loop rather than inside it is one way of being smart.

glBegin/glEnd are more than capable of being plenty fast enough if you can put them outside a loop rather than inside it. Unfortunately because you’re using GL_POLYGON you can’t do that. If you can find a way to switch to GL_QUADS or GL_TRIANGLES and move that glBegin/glEnd outside your “for (int i” loop, this will go like a rocket and you won’t need a VBO or glDrawArrays/glDrawElements.

Thanks Guys, it helped.