简体   繁体   English

限制fps的过剩

[英]Limiting fps in glut

When I try to limit fps using _ftime the framerate delay (aka. sleeping time) increases. 当我尝试使用_ftime限制fps时,帧速率延迟(也称为睡眠时间)会增加。

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) x64位笔记本电脑上的Windows 7 x86(不要怪我)

and using Dev C++ with glut extension (or in other words .DevPak file) 并使用具有glut扩展名的Dev C ++(或换句话说就是.DevPak文件)

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. 是因为我的代码还是glut引擎本身。

From glut documentation : 过剩文档

glutPostRedisplay marks the current window as needing to be redisplayed. glutPostRedisplay将当前窗口标记为需要重新显示。

So this method does not performs the display but tells glut to do it. 因此,此方法不会执行显示,但会告诉glut进行显示。 This means that this method should be quite fast. 这意味着该方法应该相当快。 So timetowait is about the length of a frame. 因此, timetowait时间大约是一帧的长度。

Then, from glut documentation : 然后,从glut文档

glutTimerFunc registers a timer callback to be triggered in a specified number of milliseconds. glutTimerFunc注册要在指定的毫秒数内触发的计时器回调。

and

Multiple timer callbacks at same or differing times may be registered simultaneously. 可以同时注册在相同或不同时间的多个计时器回调。

So I think you end up registering a lot of timer() calls that actually prevent GLUT from doing any display. 因此,我认为您最终注册了许多timer()调用,这些调用实际上阻止了GLUT进行任何显示。 Each time glut calls the idle Func, it creates a new chain of recursive timer() calls. 每次glut调用空闲的Func时,都会创建一个新的递归timer()调用链。


To solve your problem : 解决您的问题:

Call timer() only once when initializing. 初始化时仅调用一次timer() And change your function to 并将您的功能更改为

void timer(int) {
    glutPostRedisplay();
    glutTimerFunc(1000/60, timer, 0);
}

This should ask for a refresh every 60th of a seccond. 这应该要求每60秒刷新一次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM