[英]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.