избегая глобальных переменных при использовании GLUT - PullRequest
4 голосов
/ 29 января 2012

GLUT - отличный API, и его очень легко использовать, но у меня возникли некоторые трудности с обработкой области видимости.При определении обратных вызовов нет возможности передавать параметры, поэтому мне кажется, что программист вынужден полагаться на глобальные переменные, которые мне трудно принять.Прямо сейчас у меня есть весь код GLUT в его собственном модуле, работающий в его собственном потоке, и я определяю статический указатель, который я назначаю в точке входа в модуль, например:

Основной модуль

int main( int argc, char** argv ) {
    int foo;
    boost::thread graphicsThread(glutMain, argc, argv, &foo);

    //...

    graphicsThread.join();
    return 0;
}

Модуль GLUT

static int* FOO_REF;

int glutMain( int argc, char** argv, int* foo ) {
    FOO_REF = foo;
    glutInit(&argc, argv);
    //etc...

Есть ли лучшее решение, чем это?

Ответы [ 2 ]

1 голос
/ 29 января 2012

Если вы используете freeglut или производное и хотите ограничиться только производными freeglut, у него есть нестандартное расширение, чтобы точно решить проблему. Вы можете связать void* с каждым окном. Если вы сделаете эту структуру, которая содержит все данные для каждого окна, вы можете полностью избежать глобальных.

Справка:

#include <GL/glut.h>
#include <GL/freeglut_ext.h>


void * glutGetWindowData();
glutSetWindowData(void *data);
0 голосов
/ 27 июля 2016

Я объявил global.h для всех моих глобальных переменных. И инициализировать их в основном. Для моих «основных / общих» переменных (например, camera, position, iterationNumber, ...) все они были объявлены отдельно. В основном:

include "global.h"
Vector position_g = ...
Vector angles_g   = ...
int time_g        = 0;

int main () {
    ...
}

Но для переменных, которые были «специфичны для каждого раздела», то есть только в одном игровом режиме / уровне, я сделал объединение и перечисление.

enum mainGame{skipLevel, ...};
enum mainMenu {viewingSettings, ...};

typedef union generic_union {
    int i;
    char c;
    bool b;
    char s[100]; // or char * s;
    float f;
} generic;

И объявлена ​​переменная globalData.

extern generic * globalData; // in global.h
generic * globalData = NULL; // in main

Что теперь можно использовать:

int main () {
    ...
    globalData = malloc (sizeof (generic)*numGlobals);
    globalData[skipLevel].b = false;
    ...
}

Теперь, когда в вашей функции обработки нажатия клавиш вы можете назначить клавишу для переключения globalData [skipLevel]. И в любом другом файле все, что вам нужно сделать, это включить global.h.

include "global.h"
void onKeyPress (... ) {
     If (inMainGame) {
         If (key == SPACE) {
             globalData [skipLevel] = true;
          }
    }

И, наконец, использование:

include "global.h" 
void levelManager () {
     ...
    if (globalData[skipLevel]) level++;
     ...
}

Плюсы Нужно только тащить переменную 1 и одну включать.

Вы можете освободить переменные, которые вам больше не нужны или которые вы используете в этом случае. ( очень полезно для уменьшения "загрязнения"). Если одному игровому режиму нужна только 1 переменная, это все, что вам нужно сохранить, если ему нужно 48, просто!

Может легко обрабатывать любой тип переменной, добавляя его в объединение.

Абсолютно портативный

Против Нужно помнить тип переменной, чтобы разыменовать универсальный союз (не так сложно)

И следите за используемыми перечислениями (вы можете использовать стиль для перечислений, например mainMenu_e, чтобы решить эту проблему)

Добавляет сложность, но по мере роста числа переменных такая система, потому что она того стоит.

Лично я нахожу это очень опрятным, несмотря на несколько лишних движущихся частей. Если это неясно, дайте мне знать, и я постараюсь это исправить:)

...