2013-05-31 3 views
0

В игре, которую я пишу, я хотел бы, чтобы выделенный сервер подключался к клиенту с рендерингом OpenGL. Все выглядит великолепно, за исключением того, что сервер имеет несчастливую зависимость от mesa/OpenGL. В идеале, я бы хотел иметь выделенный сервер без необходимости устанавливать что-либо поверх десятикратного.Отделив зависимость OpenGL от кода клиента и кода сервера

В принципе, это сводится к этому. У каждого из моих игровых объектов есть спрайт. Чтобы сделать этот спрайт, данные изображения должны быть отправлены на графическую карту через glTexImage2D, а GLuint связан с данными текстуры. Чтобы сделать текстуру, вам нужен идентификатор текстуры.

Я отделяю клиента от сервера, используя два разных основных файла, которые содержат одни и те же файлы основной игры. Только графические файлы клиента #include. Моя общая структура класса выглядит следующим образом:

//Core game stuff 
class Image 
{ 
    int width, height; 
    //Image data 
} 

class Sprite 
{ 
    const Image image; 
} 

//Graphics namespace 
void renderObject() 
{ 
    //Some rendering code... 

    GLuint texId = loadTexture(someSprite.image); 

    renderTexture(texId); 

    unloadTexture(texId); 
} 

Теперь это выглядит великолепно, пока мы не осознаем, что передача данных изображения на видеокарте каждый кадр является медленно и нуждается в кэше. Было бы целесообразно хранить GLuint на изображении и даже дать ему функцию getTexture(). Если не задано, функция загрузит текстуру и вернет идентификатор. Таким образом, данные изображения будут отправляться только на графическую карту один раз.

//Core game stuff 
class Image 
{ 
    int width, height; 
    //Image data 

    GLuint textureId; 

    public: 

    ~Image() 
    { 
     //... 

     unloadTexture(textureId); 
    } 

    GLuint getTexture() 
    { 
     if(!textureId) 
      return textureId = loadTexture(); 
     else 
      return textureId; 
    } 
} 

class Sprite 
{ 
    const Image image; 
} 

//Graphics namespace 
void renderObject() 
{ 
    //Some rendering code... 

    renderTexture(someSprite.image.getTexture()); //loadTexture() is only called once 
} 

Однако, в связи с использованием gl* функций и #include <GL/gl.h> это делает Image зависит от OpenGL, что делает все мои игры объектов зависит от OpenGL. На этом этапе версия сервера моего кода (без контекста OpenGL или рендеринга) зависит от OpenGL.

Как вы предлагаете мне решить это? A #ifdef CLIENT будет одним из решений, хотя я бы хотел его избежать.

ответ

1

Я прочитал ваше сообщение как запрашивающее (1) минимальные изменения в вашем коде выше и (2) не используя какие-либо конструкции препроцессора.

Поскольку вы запрещаете дифференциацию времени компиляции (например, с использованием #ifdef), решение, скорее всего, сводится к тому, что клиент установит некоторые данные во время выполнения, чтобы изменить путь выполнения.Самый непосредственное проявление этой идеи было бы глобальные указатели на функцию:

unsigned int (*loadTexturePtr)(int width, int height, void *pixels) = NULL; 
void (*unloadTexturePtr)(unsigned int texId) = NULL; 

клиента коды инициализации устанавливают их, чтобы указать на зависимые реализации GL. Ваш код изображения практически не изменился:

class Image 
{ 
unsigned int textureId; 
public: 
~Image() 
{ 
    if (textureId && unloadTexturePtr) unloadTexturePtr(textureId); 
} 
unsigned int getTexture() 
{ 
    if(!textureId && loadTexturePtr) textureId = loadTexturePtr(...); 
    return textureId; 
} 
... 
} 
+0

Я не думал об этом, не плохая идея. – lowq

5

Вы бы решили решить эту проблему , оставив всю вашу архитектуру клиент/сервер и делая это правильно.

У серверов нет необходимости знать ничего совсем не о OpenGL. Этого не нужно знать о «спрайтах» или «изображениях». Ему даже не нужно знать, что должен делать конкретный клиент ничья. Все, что нужно сделать серверу, - это поддерживать состояние мира, ферму, которая заявляет об этом различным клиентам, и обновлять это состояние на основе данных, которые предоставляют эти клиенты.

Если ваш сервер даже загружает «изображения» и «спрайты», вы делаете клиент/сервер неправильно. Все, что нужно загрузить, - это любые физические и коллизионные свойства, которые имеют эти объекты. Каждый отдельный клиент загружает «изображения» и т. Д.

Ваш сервер не должен использовать OpenGL вообще.

+0

OpenGL не имеет возможностей для загрузки изображений. – lowq

+0

В очень динамичном мире, и в моей игре, в частности, клиент не знает обо всех возможных текстурах и спрайтах, которые могут быть в игре. Сервер _sends_ клиент эту информацию. – lowq

+0

@roadkillguy: Во-первых, если это правда, вы должны были указать, что это необходимо для функциональности вашего сервера в вашем вопросе. Большинство архитектур клиент/сервер не нуждаются в этом, независимо от того, насколько «очень динамичны» их миры, так что это то, о чем вы должны были заявить заранее. Во-вторых, как вы указали, отправка изображений клиенту по-прежнему не включает * OpenGL *, о чем вы просили. Таким образом, ваша проблема по-прежнему выглядит плохой архитектурой кода: объект «Image» вашего сервера не имеет бизнес, хранящий объект текстуры OpenGL. –

Смежные вопросы