在我正在编写的游戏中,我希望有一个专用服务器连接到具有OpenGL渲染的客户端。除了服务器对mesa / OpenGL的不幸依赖之外,一切看起来都很棒。理想情况下,我希望能够拥有一个专用服务器,而无需在十分之一上安装任何东西。
基本上,归结为此。我的每个游戏对象都有一个精灵。为了渲染此精灵,必须通过glTexImage2D
将图像数据发送到图形卡,并将GLuint
与纹理数据相关联。要渲染纹理,您需要纹理ID。
我通过使用两个不同的主文件将客户端与服务器分开,这两个主文件共享相同的核心游戏文件。只有客户端#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()
函数。如果未设置,该函数将加载纹理并返回id。因此,图像数据只会被发送到图形卡一次。
//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。
你怎么建议我去解决这个问题? #ifdef CLIENT
是一种解决方案,但我想避免它。
答案 0 :(得分:5)
您可以通过放弃您的整个客户端/服务器架构并正确地解决这个问题。
服务器无需知道任何的OpenGL。它不需要知道“精灵”或“图像”。它甚至不需要知道特定客户端应该绘制。所有服务器需要做的是维护世界状态,向各个客户端说明状态,并根据客户端提供的输入更新该状态。
如果您的服务器甚至加载“images”和“sprite”,那么您的客户端/服务器就会出错。它应该加载的是这些对象具有的物理和碰撞属性。每个客户都可以加载“图像”等等。
您的服务器根本不应该使用OpenGL。
答案 1 :(得分: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;
}
...
}