When I try to limit fps using _ftime the framerate delay (aka. sleeping time) increases.
After a minute the frames drop to almost zero.
Is there a solution for this problem?
I'm trying to make a delay in this style:
void init(int unused){
Initilize();
glutDisplayFunc (render);
glutReshapeFunc (reshape);
glutKeyboardFunc (keyboard);
glutMouseFunc (mouse);
glutIdleFunc (timer);
glutMainLoop();
timer(); //Get into the loop
}
void timer(void)
{
_ftime(&lasttime); //get the time
glutPostRedisplay(); //Redraw all the elements and check for input
long timetowait;
_ftime(&curtime); //get the after time
timetowait = ( (int) 1000/60 - ((1000 * (curtime.time - lasttime.time)) + curtime.millitm - lasttime.millitm)); //caculate the time to wait
timetowait = max(timetowait, 0); //Don't want to have a negative sleep ;)
glutTimerFunc(timetowait , timer, 0); //And now sleep
}
If this is a compatibility issue here are the specs:
Windows 7 x86 on a x64 bit laptop (don't blame me about this)
and using Dev C++ with glut extension (or in other words .DevPak file)
The whole source code:
#include <GL/glut.h>
#include <GL/glu.h>
#include <stdio.h>
#include <string.h>
#ifdef __unix__
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#define OS_Windows 0
#elif defined(_WIN32) || defined(WIN32)
#include <io.h>
#include <windows.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <time.h>
#define OS_Windows 1
#endif
//Default variables
char defaultcontrolconfig[5] = { 0x18, 0x19, 0x1A, 0x1B, 0x20 }; //UP,DOWN,LEFT,RIGHT,SPACE(JUMP)
unsigned short defaultx = 500,defaulty = 500,defaultmode = 0; //X RES,Y RES, FULLSCREENMODE (0 NO ,1 YES)
/**
By default it should be
UP - move on negative z axis
DOWN - move on positive z axis
LEFT - move left relative to the camera (mostly negative x axis)
RIGHT - move right relative to the camera (mostly positive x axis)
SPACE - jump (fxp. decreasing the Z value)
**/
unsigned char controls[5],plsaply;
unsigned short gamescreen;
FILE *configuration;
unsigned short displayx,displayy,displaymode,loop,clicked;
int winIDMain,frames;
double mainboxx = -1 ,mainboxy;
int timetowait;
#ifdef __unix__
struct timespec curtime,lasttime;
#endif
#ifdef OS_Windows
struct _timeb curtime, lasttime;
#endif
void keyboard(unsigned char c, int x, int y) {
if (gamescreen == 0){
if (c == 27) {
exit(0);
}
}else if(gamescreen == 1){
if(c == 27) {
gamescreen = 0;
}
}else if(gamescreen == 2){
switch(c){
case 27:
gamescreen = 1;
break;
}
}
}
void mouse(int button, int state, int x, int y) {
int perpartpixels;
if(clicked == 1){
loop = 1;
clicked = 0;
}
if(loop > 0){ //To pervent gliched clicking
loop--;
}else{
if(gamescreen == 0) {
perpartpixels = glutGet(GLUT_WINDOW_HEIGHT) / 40; //Aproxx 5% of the resolution
if (button == GLUT_LEFT_BUTTON){
printf("X:%d Y:%d\n",x,y);
if((y <= perpartpixels * 4 && y >= perpartpixels * 4 - 15) && (x >= 0 && x <= 81)){
printf("Play\n");
clicked = 1;
}else if((y <= perpartpixels * 5 && y >= perpartpixels * 5 - 15) && (x >= 0 && x <= 72)){
gamescreen = 1;
printf("Game Screen changed\n");
clicked = 1;
}else if((y <= perpartpixels * 6 && y >= perpartpixels * 6 - 15) && (x >= 0 && x <= 36)){
exit(0);
}
}
}else if(gamescreen == 1){
perpartpixels = glutGet(GLUT_WINDOW_HEIGHT) / 40; //Aproxx 5% of the resolution
if (button == GLUT_LEFT_BUTTON){
printf("X:%d Y:%d\n",x,y);
if((y >= perpartpixels * 4 - 15 && y <= perpartpixels * 4) && (x >= 0 && x <= 72)){
gamescreen = 2;
printf("Game screen changed\n");
clicked = 1;
}else if((y >= perpartpixels * 5 - 15 && y <= perpartpixels * 5) && (x >= 0 && x <= 162)){
configuration = fopen("configuration/controls.conf", "wb");
fwrite(defaultcontrolconfig,1,5,configuration);
fclose(configuration);
configuration = fopen("configuration/display.conf", "wb");
fprintf(configuration,"%hd\n%hd\n%hd",defaultx,defaulty,defaultmode);
fclose(configuration);
printf("Settings restored to default\n");
plsaply = 1;
clicked = 1;
}else if((y >= perpartpixels * 6 - 15 && y <= perpartpixels * 6) && (x >= 0 && x <= 36)){
gamescreen = 0;
printf("Game screen changed\n");
clicked = 1;
}
}
}else if(gamescreen == 2){
perpartpixels = glutGet(GLUT_WINDOW_HEIGHT) / 40; //Aproxx 5% of the resolution
if(button == GLUT_LEFT_BUTTON){
if((y >= perpartpixels * 38 && y <= perpartpixels * 40) && (x >= 0 && x <= 36)){
gamescreen = 1;
printf("Game screen changed\n");
clicked = 1;
}
}
}
}
}
void render(void) {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
frames++;
char str[50];
if(gamescreen == 0) {
if(mainboxx >= 2.0){
mainboxx = -1;
}else{
mainboxx+= 0.01;
}
if(mainboxx >= -0.4 && mainboxx <= -0.3){
mainboxy += 0.03;
}else if(mainboxx >= -0.3 && mainboxx <= -0.2){
mainboxy += 0.01;
}else if(mainboxx >= -0.2 && mainboxx <= 0.2){
mainboxy -= 0.01;
}else if(mainboxx >= 0.2){
mainboxy = 0;
}
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity;
glColor3f(0.1,0.1,0.1);
glTranslatef(-mainboxx, 0 , -1);
glBegin(GL_QUADS);
glVertex3f((mainboxx - 0.05),(mainboxy - 0.05),0);
glVertex3f((mainboxx - 0.05),(mainboxy + 0.05),0);
glVertex3f((mainboxx + 0.05),(mainboxy + 0.05),0);
glVertex3f((mainboxx + 0.05),(mainboxy - 0.05),0);
glVertex3f( -2, -0.05, 0);
glVertex3f( -0.2, -0.05, 0);
glVertex3f( -0.2, -1, 0);
glVertex3f( -2, -1, 0);
glVertex3f( 0.2, -0.05, 0);
glVertex3f( 2.91, -0.05, 0);
glVertex3f( 2.91, -1, 0);
glVertex3f( 0.2, -1, 0);
glEnd();
glPopMatrix();
sprintf(str, "%d", frames);
char mainmenustring[9] = "Main Menu";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.9);
int mainmenulen, mainmenui;
mainmenulen = 9;
for (mainmenui = 0; mainmenui < mainmenulen; mainmenui++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, mainmenustring[mainmenui]);
}
char startstring[5] = "Start";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.8);
int startlen, starti;
startlen = 5;
for (starti = 0; starti < startlen; starti++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, startstring[starti]);
}
char settingsstring[8] = "Settings";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.75);
int settingslen, settingsi;
settingslen = 8;
for (settingsi = 0; settingsi < settingslen; settingsi++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, settingsstring[settingsi]);
}
char exitstring[4] = "Exit";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.7);
int exitlen, exiti;
exitlen = 4;
for (exiti = 0; exiti < exitlen; exiti++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, exitstring[exiti]);
}
glColor3f(1, 1, 1);
glRasterPos2f(-1, -1);
int flen, fi;
flen = (int)strlen(str);
for (fi = 0; fi < flen; fi++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, str[fi]);
}
}else if (gamescreen == 1) {
if(plsaply){
sprintf(str, "%d Please restart to apply changes", frames);
}else{
sprintf(str, "%d", frames);
}
char settingstring[8] = "Settings";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.9);
int settinglen, settingi;
settinglen = 8;
for (settingi = 0; settingi < settinglen; settingi++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, settingstring[settingi]);
}
char constring[8] = "Controls";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.8);
int conlen, coni;
conlen = 8;
for (coni = 0; coni < conlen; coni++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, constring[coni]);
}
char rtoodstring[18] = "Restore to Default";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.75);
int rtoodlen, rtoodi;
rtoodlen = 18;
for (rtoodi = 0; rtoodi < rtoodlen; rtoodi++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, rtoodstring[rtoodi]);
}
char bckstring[4] = "Back";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.7);
int bcklen, bcki;
bcklen = 4;
for (bcki = 0; bcki < bcklen; bcki++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, bckstring[bcki]);
}
glColor3f(1, 1, 1);
glRasterPos2f(-1, -1);
int flen, fi;
flen = (int)strlen(str);
for (fi = 0; fi < flen; fi++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, str[fi]);
}
}else if (gamescreen == 2){
char bckbtnstring[4] = "Back";
glColor3f(1, 1, 1);
glRasterPos2f(-1, -0.9);
int bckbtnlen, bckbtni;
bckbtnlen = 4;
for (bckbtni = 0; bckbtni < bckbtnlen; bckbtni++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, bckbtnstring[bckbtni]);
}
}
glutSwapBuffers();
}
void reshape (int w, int h)
{
if(displaymode == 1){
glutFullScreen();
displayx = w;
displayy = h;
}
glViewport (0, 0, w, h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
}
void timer(void);
void init(int unused);
void Initilize();
void init(int unused){
Initilize();
glutDisplayFunc (render);
glutReshapeFunc (reshape);
glutKeyboardFunc (keyboard);
glutMouseFunc (mouse);
glutIdleFunc (timer);
glutMainLoop();
timer();
}
void timer(void)
{
_ftime(&lasttime);
glutPostRedisplay();
long timetowait;
_ftime(&curtime);
timetowait = ( (int) 1000/60 - ((1000 * (curtime.time - lasttime.time)) + curtime.millitm - lasttime.millitm));
timetowait = max(timetowait, 0);
glutTimerFunc(timetowait , timer, 0);
}
// Load config functions
void loadconfiguration(void) {
//Check if config folder is present otherwise create it
#ifdef __unix__
int result = mkdir("configuration", 0777);
#endif
#ifdef OS_Windows
int result = _mkdir("configuration");
#endif
if(result == -1){
printf("Ignore creating folder:\nError -1 Directory already exists\n");
}else if(result != 0){
printf("Error: %d while creating configuration folder\n", result);
}
//Check if control configuration is present otherwise create it
#ifdef __unix__
if (access("configuration/controls.conf",F_OK)!= -1)
{
printf ("Found controls configuration file\n");
configuration = fopen("configuration/controls.conf", "rb");
}
else
{
configuration = fopen("configuration/controls.conf", "wb");
fwrite(defaultcontrolconfig,1,5,configuration);
}
#endif
#ifdef OS_Windows
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes("configuration/controls.conf") && GetLastError()==ERROR_FILE_NOT_FOUND)
{
configuration = fopen("configuration/controls.conf", "wb");
fwrite(defaultcontrolconfig,1,5,configuration);
}
else
{
printf ("Found controls configuration file\n");
configuration = fopen("configuration/controls.conf", "rb");
}
#endif
fread(controls,1,5,configuration);
printf("Finished loading controls configuration\n");
fclose(configuration);
//Check if display configuration is present otherwise create it
#ifdef __unix__
if (access("configuration/display.conf",F_OK)!= -1)
{
printf ("Found display configuration file\n");
configuration = fopen("configuration/display.conf", "rb");
}
else
{
configuration = fopen("configuration/display.conf", "wb");
fprintf(configuration,"%hd\n%hd\n%hd",defaultx,defaulty,defaultmode);
}
#endif
#ifdef OS_Windows
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes("configuration/display.conf") && GetLastError()==ERROR_FILE_NOT_FOUND)
{
configuration = fopen("configuration/display.conf", "wb");
fprintf(configuration,"%hd\n%hd\n%hd",defaultx,defaulty,defaultmode);
}
else
{
printf ("Found display configuration file\n");
configuration = fopen("configuration/display.conf", "rb");
}
#endif
rewind(configuration);
fscanf(configuration,"%hd\n%hd\n%hd",&displayx,&displayy,&displaymode);
printf("Finished loading display configuration\n");
fclose(configuration);
printf("Finished loading configurations\n");
}
void Initilize() {
glClearColor(0, 0, 0, 0.1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
int main() {
loadconfiguration();
char *myargv [1];
int myargc=1;
myargv [0]=strdup ("./file");
glutInit(&myargc, myargv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(displayx, displayy);
printf("Making a window\n");
winIDMain = glutCreateWindow("GL Game");
init(0);
}
Also I'am trying to get it as much as possible to be cross platform. Is it because of my code or the glut engine itself.
From glut documentation :
So this method does not performs the display but tells glut to do it. This means that this method should be quite fast. So
timetowait
is about the length of a frame.Then, from glut documentation :
and
So I think you end up registering a lot of
timer()
calls that actually prevent GLUT from doing any display. Each time glut calls the idle Func, it creates a new chain of recursivetimer()
calls.To solve your problem :
Call
timer()
only once when initializing. And change your function toThis should ask for a refresh every 60th of a seccond.