Static objects using OpenGL VBOs and display lists

dev-ui
Piotr Dziwinski 2012-12-14 21:30:35 +01:00
parent 39ac36efda
commit 4811defca2
11 changed files with 491 additions and 99 deletions

View File

@ -142,6 +142,8 @@ CApplication::CApplication()
m_lowCPU = true;
m_useVbo = false;
for (int i = 0; i < DIR_MAX; ++i)
m_dataDirs[i] = nullptr;
@ -243,6 +245,10 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
{
SetDebugMode(true);
}
else if (arg == "-vbo")
{
m_useVbo = true;
}
else if (arg == "-loglevel")
{
waitLogLevel = true;
@ -262,6 +268,7 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
GetLogger()->Message("\n");
GetLogger()->Message("List of available options:\n");
GetLogger()->Message(" -help this help\n");
GetLogger()->Message(" -vbo enable OpenGL VBOs\n");
GetLogger()->Message(" -datadir path set custom data directory path\n");
GetLogger()->Message(" -debug enable debug mode (more info printed in logs)\n");
GetLogger()->Message(" -loglevel level set log level to level (one of: trace, debug, info, warn, error, none)\n");
@ -425,6 +432,8 @@ bool CApplication::Create()
return false;
}
static_cast<Gfx::CGLDevice*>(m_device)->SetUseVbo(m_useVbo);
// Create the 3D engine
m_engine = new Gfx::CEngine(m_iMan, this);

View File

@ -449,5 +449,7 @@ protected:
//! Low cpu mode
bool m_lowCPU;
int m_useVbo; // TODO: temporary
};

View File

@ -313,9 +313,24 @@ public:
//! Renders primitive composed of vertices with multitexturing (2 textures)
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0;
//! Renders primitive composed of vertices with color information
//! Renders primitive composed of vertices with solid color
virtual void DrawPrimitive(PrimitiveType type, const VertexCol *vertices , int vertexCount) = 0;
//! Creates a static buffer composed of given primitives with single texture vertices
virtual unsigned int CreateStaticObject(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) = 0;
//! Creates a static buffer composed of given primitives with multitexturing (2 textures)
virtual unsigned int CreateStaticObject(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) = 0;
//! Creates a static buffer composed of given primitives with solid color
virtual unsigned int CreateStaticObject(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) = 0;
//! Draws a static buffer
virtual void DrawStaticObject(unsigned int objectId) = 0;
//! Deletes a static buffer
virtual void DestroyStaticObject(unsigned int objectId) = 0;
//! Tests whether a sphere is (partially) within the frustum volume
//! Returns a mask of frustum planes for which the test is positive
virtual int ComputeSphereVisibility(const Math::Vector &center, float radius) = 0;

View File

@ -44,23 +44,18 @@ namespace Gfx {
* - vertex coordinates (x,y,z) as Math::Vector,
* - normal coordinates (nx,ny,nz) as Math::Vector
* - texture coordinates (u,v) as Math::Point.
*
* Additional padding is provided to align to even multiplies of 4 floats for faster access.
*/
struct Vertex
{
Math::Vector coord;
float pad1;
Math::Vector normal;
float pad2;
Math::Point texCoord;
float pad3, pad4;
explicit Vertex(Math::Vector aCoord = Math::Vector(),
Math::Vector aNormal = Math::Vector(),
Math::Point aTexCoord = Math::Point())
: coord(aCoord), pad1(0.0f), normal(aNormal),
pad2(0.0f),texCoord(aTexCoord), pad3(0.0f), pad4(0.0f) {}
: coord(aCoord), normal(aNormal),
texCoord(aTexCoord) {}
//! Returns a string "(c: [...], n: [...], tc: [...])"
@ -81,18 +76,15 @@ struct Vertex
* It contains:
* - vertex coordinates (x,y,z) as Math::Vector,
* - RGBA color as Color
*
* Additional padding is provided to align to even multiplies of 4 floats for faster access.
*/
struct VertexCol
{
Math::Vector coord;
float pad;
Color color;
explicit VertexCol(Math::Vector aCoord = Math::Vector(),
Color aColor = Color())
: coord(aCoord), pad(0.0f), color(aColor) {}
: coord(aCoord), color(aColor) {}
//! Returns a string "(c: [...], col: [...])"
inline std::string ToString() const
@ -111,15 +103,11 @@ struct VertexCol
*
* In addition to fields from Vector, it contains
* secondary texture coordinates (u2, v2) as Math::Point
*
* Additional padding is provided to align to even multiplies of 4 floats for faster access.
*/
struct VertexTex2
{
Math::Vector coord;
float pad1;
Math::Vector normal;
float pad2;
Math::Point texCoord;
Math::Point texCoord2;
@ -127,7 +115,7 @@ struct VertexTex2
Math::Vector aNormal = Math::Vector(),
Math::Point aTexCoord = Math::Point(),
Math::Point aTexCoord2 = Math::Point())
: coord(aCoord), pad1(0.0f), normal(aNormal), pad2(0.0f),
: coord(aCoord), normal(aNormal),
texCoord(aTexCoord), texCoord2(aTexCoord2) {}
//! Sets the fields from Vertex with texCoord2 = (0,0)

View File

@ -92,6 +92,7 @@ EngineObjLevel4::EngineObjLevel4(bool used, EngineTriangleType type, const Mater
this->type = type;
this->material = material;
this->state = state;
this->staticBufferId = 0;
vertices.reserve(LEVEL4_VERTEX_PREALLOCATE_COUNT);
}
@ -182,6 +183,7 @@ CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_alphaMode = 1;
m_updateGeometry = false;
m_updateStaticObjects = false;
m_interfaceMode = false;
@ -385,6 +387,7 @@ void CEngine::FrameUpdate()
ComputeDistance();
UpdateGeometry();
UpdateStaticObjects();
m_highlightTime = m_app->GetAbsTime();
@ -570,11 +573,27 @@ bool CEngine::DeleteObject(int objRank)
EngineObjLevel2& p2 = p1.next[l2];
if (! p2.used) continue;
if (p2.objRank == objRank)
if (p2.objRank != objRank) continue;
if (m_objects[objRank].staticBuffer)
{
p2.used = false;
p2.next.clear();
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
{
EngineObjLevel4& p4 = p3.next[l4];
m_device->DestroyStaticObject(p4.staticBufferId);
}
}
}
p2.used = false;
p2.next.clear();
}
}
@ -623,6 +642,22 @@ bool CEngine::GetObjectTransform(int objRank, Math::Matrix& transform)
return true;
}
void CEngine::SetObjectStatic(int objRank, bool staticBuffer)
{
if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
return;
m_objects[objRank].staticBuffer = staticBuffer;
}
bool CEngine::GetObjectStatic(int objRank)
{
if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
return false;
return m_objects[objRank].staticBuffer;
}
bool CEngine::SetObjectDrawWorld(int objRank, bool draw)
{
if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
@ -825,6 +860,17 @@ bool CEngine::AddTriangles(int objRank, const std::vector<VertexTex2>& vertices,
p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end());
if (m_objects[objRank].staticBuffer)
{
if (p4.staticBufferId != 0)
{
m_device->DestroyStaticObject(p4.staticBufferId);
p4.staticBufferId = 0;
}
m_updateStaticObjects = true;
}
if (globalUpdate)
{
m_updateGeometry = true;
@ -872,6 +918,17 @@ bool CEngine::AddSurface(int objRank, const std::vector<VertexTex2>& vertices,
p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end());
if (m_objects[objRank].staticBuffer)
{
if (p4.staticBufferId != 0)
{
m_device->DestroyStaticObject(p4.staticBufferId);
p4.staticBufferId = 0;
}
m_updateStaticObjects = true;
}
if (globalUpdate)
{
m_updateGeometry = true;
@ -898,8 +955,8 @@ bool CEngine::AddSurface(int objRank, const std::vector<VertexTex2>& vertices,
}
bool CEngine::AddQuick(int objRank, const EngineObjLevel4& buffer,
std::string tex1Name, std::string tex2Name,
float min, float max, bool globalUpdate)
std::string tex1Name, std::string tex2Name,
float min, float max, bool globalUpdate)
{
if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) )
{
@ -912,7 +969,26 @@ bool CEngine::AddQuick(int objRank, const EngineObjLevel4& buffer,
EngineObjLevel3& p3 = AddLevel3(p2, min, max);
p3.next.push_back(buffer);
p3.next.back().used = true; // ensure that it is used
EngineObjLevel4& p4 = p3.next.back();
p4.used = true; // ensure that it is used
if (m_objects[objRank].staticBuffer)
{
if (p4.staticBufferId != 0)
{
m_device->DestroyStaticObject(p4.staticBufferId);
p4.staticBufferId = 0;
}
PrimitiveType type;
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
type = PRIMITIVE_TRIANGLES;
else
type = PRIMITIVE_TRIANGLE_STRIP;
p4.staticBufferId = m_device->CreateStaticObject(type, &p4.vertices[0], p4.vertices.size());
}
if (globalUpdate)
{
@ -920,24 +996,24 @@ bool CEngine::AddQuick(int objRank, const EngineObjLevel4& buffer,
}
else
{
for (int i = 0; i < static_cast<int>( buffer.vertices.size() ); i++)
for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i++)
{
m_objects[objRank].bboxMin.x = Math::Min(buffer.vertices[i].coord.x, m_objects[objRank].bboxMin.x);
m_objects[objRank].bboxMin.y = Math::Min(buffer.vertices[i].coord.y, m_objects[objRank].bboxMin.y);
m_objects[objRank].bboxMin.z = Math::Min(buffer.vertices[i].coord.z, m_objects[objRank].bboxMin.z);
m_objects[objRank].bboxMax.x = Math::Max(buffer.vertices[i].coord.x, m_objects[objRank].bboxMax.x);
m_objects[objRank].bboxMax.y = Math::Max(buffer.vertices[i].coord.y, m_objects[objRank].bboxMax.y);
m_objects[objRank].bboxMax.z = Math::Max(buffer.vertices[i].coord.z, m_objects[objRank].bboxMax.z);
m_objects[objRank].bboxMin.x = Math::Min(p4.vertices[i].coord.x, m_objects[objRank].bboxMin.x);
m_objects[objRank].bboxMin.y = Math::Min(p4.vertices[i].coord.y, m_objects[objRank].bboxMin.y);
m_objects[objRank].bboxMin.z = Math::Min(p4.vertices[i].coord.z, m_objects[objRank].bboxMin.z);
m_objects[objRank].bboxMax.x = Math::Max(p4.vertices[i].coord.x, m_objects[objRank].bboxMax.x);
m_objects[objRank].bboxMax.y = Math::Max(p4.vertices[i].coord.y, m_objects[objRank].bboxMax.y);
m_objects[objRank].bboxMax.z = Math::Max(p4.vertices[i].coord.z, m_objects[objRank].bboxMax.z);
}
m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(),
m_objects[objRank].bboxMax.Length());
}
if (buffer.type == ENG_TRIANGLE_TYPE_TRIANGLES)
m_objects[objRank].totalTriangles += buffer.vertices.size() / 3;
else if (buffer.type == ENG_TRIANGLE_TYPE_SURFACE)
m_objects[objRank].totalTriangles += buffer.vertices.size() - 2;
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
m_objects[objRank].totalTriangles += p4.vertices.size() / 3;
else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
m_objects[objRank].totalTriangles += p4.vertices.size() - 2;
return true;
}
@ -1735,10 +1811,57 @@ void CEngine::UpdateGeometry()
m_updateGeometry = false;
}
void CEngine::UpdateStaticObjects()
{
if (!m_updateStaticObjects)
return;
for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
{
EngineObjLevel1& p1 = m_objectTree[l1];
if (! p1.used) continue;
for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++)
{
EngineObjLevel2& p2 = p1.next[l2];
if (! p2.used) continue;
int objRank = p2.objRank;
if (!m_objects[objRank].staticBuffer)
continue;
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
{
EngineObjLevel4& p4 = p3.next[l4];
if (! p4.used) continue;
if (p4.staticBufferId != 0)
continue;
PrimitiveType type;
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
type = PRIMITIVE_TRIANGLES;
else
type = PRIMITIVE_TRIANGLE_STRIP;
p4.staticBufferId = m_device->CreateStaticObject(type, &p4.vertices[0], p4.vertices.size());
}
}
}
}
}
void CEngine::Update()
{
ComputeDistance();
UpdateGeometry();
UpdateStaticObjects();
}
bool CEngine::DetectBBox(int objRank, Math::Point mouse)
@ -3106,20 +3229,7 @@ void CEngine::Draw3DScene()
SetMaterial(p4.material);
SetState(p4.state);
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
DrawObject(p4, m_objects[objRank].staticBuffer);
}
}
}
@ -3188,22 +3298,7 @@ void CEngine::Draw3DScene()
SetMaterial(p4.material);
SetState(p4.state);
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
DrawObject(p4, m_objects[objRank].staticBuffer);
}
}
}
@ -3264,21 +3359,7 @@ void CEngine::Draw3DScene()
SetMaterial(p4.material);
SetState(tState, tColor);
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
DrawObject(p4, m_objects[objRank].staticBuffer);
}
}
}
@ -3307,6 +3388,32 @@ void CEngine::Draw3DScene()
if (! m_overFront) DrawOverColor(); // draws the foreground color
}
void CEngine::DrawObject(const EngineObjLevel4& obj, bool staticBuffer)
{
if (staticBuffer)
{
m_device->DrawStaticObject(obj.staticBufferId);
if (obj.type == ENG_TRIANGLE_TYPE_TRIANGLES)
m_statisticTriangle += obj.vertices.size() / 3;
else
m_statisticTriangle += obj.vertices.size() - 2;
}
else
{
if (obj.type == ENG_TRIANGLE_TYPE_TRIANGLES)
{
m_device->DrawPrimitive(PRIMITIVE_TRIANGLES, &obj.vertices[0], obj.vertices.size());
m_statisticTriangle += obj.vertices.size() / 3;
}
else
{
m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, &obj.vertices[0], obj.vertices.size() );
m_statisticTriangle += obj.vertices.size() - 2;
}
}
}
void CEngine::DrawInterface()
{
m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false);
@ -3397,21 +3504,7 @@ void CEngine::DrawInterface()
SetMaterial(p4.material);
SetState(p4.state);
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLES,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() / 3;
}
else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
{
m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP,
&p4.vertices[0],
p4.vertices.size() );
m_statisticTriangle += p4.vertices.size() - 2;
}
DrawObject(p4, m_objects[objRank].staticBuffer);
}
}
}

View File

@ -195,7 +195,9 @@ struct EngineObject
//! Number of triangles
int totalTriangles;
//! Type of object
EngineObjectType type;
EngineObjectType type;
//! Whether the object is stored and rendered as static buffer
bool staticBuffer;
//! Transformation matrix
Math::Matrix transform;
//! Distance to object from eye point
@ -225,6 +227,7 @@ struct EngineObject
drawWorld = false;
drawFront = false;
totalTriangles = 0;
staticBuffer = false;
type = ENG_OBJTYPE_NULL;
transform.LoadIdentity();
bboxMax.LoadZero();
@ -252,6 +255,7 @@ struct EngineObjLevel4
Material material;
int state;
std::vector<VertexTex2> vertices;
unsigned int staticBufferId;
EngineObjLevel4(bool used = false,
EngineTriangleType type = ENG_TRIANGLE_TYPE_TRIANGLES,
@ -760,6 +764,12 @@ public:
bool GetObjectTransform(int objRank, Math::Matrix& transform);
//@}
//@{
//! Management of object static drawing flag
void SetObjectStatic(int objRank, bool staticBuffer);
bool GetObjectStatic(int objRank);
//@}
//! Sets drawWorld for given object
bool SetObjectDrawWorld(int objRank, bool draw);
//! Sets drawFront for given object
@ -1151,6 +1161,8 @@ public:
protected:
//! Prepares the interface for 3D scene
void Draw3DScene();
//! Draw 3D object
void DrawObject(const EngineObjLevel4& obj, bool staticBuffer);
//! Draws the user interface over the scene
void DrawInterface();
@ -1215,6 +1227,9 @@ protected:
//! Updates geometric parameters of objects (bounding box and radius)
void UpdateGeometry();
//! Updates static buffers of changed objects
void UpdateStaticObjects();
protected:
CInstanceManager* m_iMan;
CApplication* m_app;
@ -1293,6 +1308,7 @@ protected:
Color m_waterAddColor;
int m_statisticTriangle;
bool m_updateGeometry;
bool m_updateStaticObjects;
int m_alphaMode;
bool m_groundSpotVisible;
bool m_shadowVisible;

View File

@ -1157,18 +1157,24 @@ bool CModelFile::WriteBinaryModel(std::ostream& stream)
#ifndef MODELFILE_NO_ENGINE
/**
* TODO: move the function to CEngine or new class (CModelManager?)
* and make models shared static objects.
*/
bool CModelFile::CreateEngineObject(int objRank)
{
std::vector<VertexTex2> vs(3, VertexTex2());
m_engine->SetObjectStatic(objRank, true); // TODO: make optional in the future
float limit[2];
limit[0] = m_engine->GetLimitLOD(0); // frontier AB as config
limit[1] = m_engine->GetLimitLOD(1); // frontier BC as config
for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++)
{
// TODO move this to CEngine
float min = m_triangles[i].min;
float max = m_triangles[i].max;

View File

@ -363,6 +363,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force)
m_type == PT_EXPLOW )
{
CreateTriangle(obj, oType, 0);
m_engine->SetObjectStatic(m_object->GetObjectRank(0), false);
m_engine->DeleteShadow(m_object->GetObjectRank(0));
ExploStart();
}
@ -1397,6 +1398,8 @@ void CPyro::CreateTriangle(CObject* obj, ObjectType oType, int part)
int objRank = obj->GetObjectRank(part);
if (objRank == -1) return;
m_engine->SetObjectStatic(objRank, false);
float min = 0.0f;
float max = m_engine->GetLimitLOD(0);
int total = m_engine->GetObjectTotalTriangles(objRank);

View File

@ -478,6 +478,8 @@ VertexTex2 CTerrain::GetVertex(int x, int y, int step)
v.texCoord.x = (o.x-oo.x)*m_textureScale*m_textureSubdivCount;
v.texCoord.y = 1.0f - (o.z-oo.z)*m_textureScale*m_textureSubdivCount;
v.texCoord2 = v.texCoord;
return v;
}
@ -1166,6 +1168,10 @@ bool CTerrain::CreateSquare(int x, int y)
int objRank = m_engine->CreateObject();
m_engine->SetObjectType(objRank, ENG_OBJTYPE_TERRAIN);
// TODO: create a static object, but not split into squares, but a single object for all terrain
// Squares should be sub-objects accessing parts of triangle list
// m_engine->SetObjectStatic(objRank, true);
m_objRanks[x+y*m_mosaicCount] = objRank;
float min = 0.0f;

View File

@ -73,6 +73,8 @@ CGLDevice::CGLDevice(const GLDeviceConfig &config)
{
m_config = config;
m_lighting = false;
m_lastVboId = 0;
m_useVbo = false;
}
@ -109,6 +111,16 @@ bool CGLDevice::Create()
GetLogger()->Error("GLEW reports required extensions not supported\n");
return false;
}
if (GLEW_ARB_vertex_buffer_object)
{
GetLogger()->Info("Detected ARB_vertex_buffer_object extension - using VBOs\n");
m_useVbo = true;
}
else
{
GetLogger()->Info("No ARB_vertex_buffer_object extension present - using display lists\n");
}
}
#endif
@ -174,6 +186,16 @@ void CGLDevice::ConfigChanged(const GLDeviceConfig& newConfig)
Create();
}
void CGLDevice::SetUseVbo(bool useVbo)
{
m_useVbo = useVbo;
}
bool CGLDevice::GetUseVbo()
{
return m_useVbo;
}
void CGLDevice::BeginScene()
{
Clear();
@ -927,6 +949,206 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int
glDisableClientState(GL_COLOR_ARRAY);
}
unsigned int CGLDevice::CreateStaticObject(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount)
{
unsigned int id = 0;
if (m_useVbo)
{
id = ++m_lastVboId;
VboObjectInfo info;
info.primitiveType = primitiveType;
info.vertexType = VERTEX_TYPE_NORMAL;
info.vertexCount = vertexCount;
info.bufferId = 0;
glGenBuffers(1, &info.bufferId);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboObjects[id] = info;
}
else
{
id = glGenLists(1);
glNewList(id, GL_COMPILE);
DrawPrimitive(primitiveType, vertices, vertexCount);
glEndList();
}
return id;
}
unsigned int CGLDevice::CreateStaticObject(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount)
{
unsigned int id = 0;
if (m_useVbo)
{
id = ++m_lastVboId;
VboObjectInfo info;
info.primitiveType = primitiveType;
info.vertexType = VERTEX_TYPE_TEX2;
info.vertexCount = vertexCount;
info.bufferId = 0;
glGenBuffers(1, &info.bufferId);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboObjects[id] = info;
}
else
{
id = glGenLists(1);
glNewList(id, GL_COMPILE);
DrawPrimitive(primitiveType, vertices, vertexCount);
glEndList();
}
return id;
}
unsigned int CGLDevice::CreateStaticObject(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount)
{
unsigned int id = 0;
if (m_useVbo)
{
id = ++m_lastVboId;
VboObjectInfo info;
info.primitiveType = primitiveType;
info.vertexType = VERTEX_TYPE_COL;
info.vertexCount = vertexCount;
info.bufferId = 0;
glGenBuffers(1, &info.bufferId);
glBindBuffer(GL_ARRAY_BUFFER, info.bufferId);
glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_vboObjects[id] = info;
}
else
{
id = glGenLists(1);
glNewList(id, GL_COMPILE);
DrawPrimitive(primitiveType, vertices, vertexCount);
glEndList();
}
return id;
}
void CGLDevice::DrawStaticObject(unsigned int objectId)
{
if (m_useVbo)
{
auto it = m_vboObjects.find(objectId);
if (it == m_vboObjects.end())
return;
glEnable(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId);
if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, coord));
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, normal));
glActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, texCoord));
}
else if ((*it).second.vertexType == VERTEX_TYPE_TEX2)
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, coord));
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, normal));
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord));
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord2));
}
else if ((*it).second.vertexType == VERTEX_TYPE_COL)
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), static_cast<char*>(nullptr) + offsetof(VertexCol, coord));
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, sizeof(VertexCol), static_cast<char*>(nullptr) + offsetof(VertexCol, color));
}
GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType);
glDrawArrays(GL_TRIANGLES, 0, (*it).second.vertexCount);
if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
{
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0
}
else if ((*it).second.vertexType == VERTEX_TYPE_TEX2)
{
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
else if ((*it).second.vertexType == VERTEX_TYPE_COL)
{
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable(GL_VERTEX_ARRAY);
}
else
{
glCallList(objectId);
}
}
void CGLDevice::DestroyStaticObject(unsigned int objectId)
{
if (m_useVbo)
{
auto it = m_vboObjects.find(objectId);
if (it == m_vboObjects.end())
return;
glDeleteBuffers(1, &(*it).second.bufferId);
m_vboObjects.erase(it);
}
else
{
glDeleteLists(objectId, 1);
}
}
bool InPlane(Math::Vector normal, float originPlane, Math::Vector center, float radius)
{
float distance = originPlane + Math::DotProduct(normal, center);

View File

@ -27,6 +27,7 @@
#include <string>
#include <vector>
#include <set>
#include <map>
// Graphics module namespace
@ -84,6 +85,9 @@ public:
void ConfigChanged(const GLDeviceConfig &newConfig);
void SetUseVbo(bool useVbo);
bool GetUseVbo();
virtual void BeginScene();
virtual void EndScene();
@ -119,14 +123,18 @@ public:
virtual void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT);
//! Renders primitive composed of vertices with single texture
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f));
//! Renders primitive composed of vertices with multitexturing (2 textures)
virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f));
virtual void DrawPrimitive(PrimitiveType type, const VertexCol *vertices , int vertexCount);
virtual unsigned int CreateStaticObject(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount);
virtual unsigned int CreateStaticObject(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount);
virtual unsigned int CreateStaticObject(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount);
virtual void DrawStaticObject(unsigned int objectId);
virtual void DestroyStaticObject(unsigned int objectId);
virtual int ComputeSphereVisibility(const Math::Vector &center, float radius);
virtual void SetRenderState(RenderState state, bool enabled);
@ -200,6 +208,30 @@ private:
//! Set of all created textures
std::set<Texture> m_allTextures;
//! Type of vertex structure
enum VertexType
{
VERTEX_TYPE_NORMAL,
VERTEX_TYPE_TEX2,
VERTEX_TYPE_COL,
};
//! Info about static VBO buffers
struct VboObjectInfo
{
PrimitiveType primitiveType;
unsigned int bufferId;
VertexType vertexType;
int vertexCount;
};
//! Whether to use VBOs or display lists
bool m_useVbo;
//! Map of saved VBO objects
std::map<unsigned int, VboObjectInfo> m_vboObjects;
//! Last ID of VBO object
unsigned int m_lastVboId;
};