blob: f6fc5f4a071aece7780a9fe6ccf261082bbd3cdc [file] [log] [blame]
/*
Copyright (c) 2011-2012 NVIDIA Corporation
Copyright (c) 2011-2012 Cass Everitt
Copyright (c) 2012 Scott Nations
Copyright (c) 2012 Mathias Schott
Copyright (c) 2012 Nigel Stewart
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __REGAL_CLIENT_STATE_H__
#define __REGAL_CLIENT_STATE_H__
#include "RegalUtil.h"
REGAL_GLOBAL_BEGIN
#include <cstring> // For memset, memcpy
#include <string>
#include <algorithm> // For std::swap
#include <boost/print/print_string.hpp>
#include <boost/print/string_list.hpp>
#include "RegalEmu.h"
#include "RegalIff.h"
#include "RegalToken.h"
#include "RegalDispatch.h"
REGAL_GLOBAL_END
REGAL_NAMESPACE_BEGIN
//
// OpenGL Client State Tracking
//
// Motivating requirements:
//
// - Emulation of glPushClientAttrib and glPopClientAttrib for OpenGL ES and
// core OpenGL that lack the functionality.
//
// - OpenGL client state capture, browsing, diff and serialization.
//
// - Emulation of BaseVertex commands
//
// See also:
//
// - Gallium3D
// http://wiki.freedesktop.org/wiki/Software/gallium
// http://dri.freedesktop.org/doxygen/gallium/p__state_8h-source.html
//
// - Tracking Graphics State For Networked Rendering
// Ian Buck, Greg Humphreys and Pat Hanrahan.
// Stanford University
// Proceedings of the 2000 Eurographics/SIGGRAPH Workshop on Graphics Hardware
// http://graphics.stanford.edu/papers/state_tracking/
//
// - Chromium: A Stream Processing Framework for Interactive Rendering on Clusters
// Greg Humphreys, Mike Houston, Ren Ng
// Stanford University
// SIGGRAPH 2002
// http://graphics.stanford.edu/papers/cr/
//
namespace ClientState
{
using ::boost::print::hex;
using ::boost::print::print_string;
typedef ::boost::print::string_list<std::string> string_list;
inline static void enable(DispatchTable &dt, const GLenum cap, const GLboolean enable)
{
if (enable)
dt.call(&dt.glEnableClientState)(cap);
else
dt.call(&dt.glDisableClientState)(cap);
}
inline static void enablei(DispatchTable &dt, const GLenum cap, const GLuint index, const GLboolean enable)
{
if (enable)
dt.call(&dt.glEnableClientStateiEXT)(cap,index);
else
dt.call(&dt.glDisableClientStateiEXT)(cap,index);
}
inline static void enableToString(string_list& tmp, const GLboolean b, const char* bEnum, const char *delim = "\n")
{
tmp << print_string(b ? "glEnableClientState(" : "glDisableClientState(",bEnum,");",delim);
}
inline static void enableiToString(string_list& tmp, const GLboolean b, const char* bEnum, const GLuint index, const char *delim = "\n")
{
tmp << print_string(b ? "glEnableClientStateiEXT(" : "glDisableClientStateiEXT(",bEnum,",",index,");",delim);
}
//
// glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
//
const GLuint nNamedArrays = 7 + REGAL_EMU_MAX_TEXTURE_COORDS;
typedef enum _vaName
{
VERTEX = 0,
NORMAL = 1,
FOG_COORD = 2,
COLOR = 3,
SECONDARY_COLOR = 4,
INDEX = 5,
EDGE_FLAG = 6,
TEX_COORD = 7
} vaName;
GLenum vaEnum[][6] =
{
{ GL_VERTEX_ARRAY, GL_VERTEX_ARRAY_POINTER, GL_VERTEX_ARRAY_BUFFER_BINDING, GL_VERTEX_ARRAY_SIZE, GL_VERTEX_ARRAY_TYPE, GL_VERTEX_ARRAY_STRIDE },
{ GL_NORMAL_ARRAY, GL_NORMAL_ARRAY_POINTER, GL_NORMAL_ARRAY_BUFFER_BINDING, GL_ZERO, GL_NORMAL_ARRAY_TYPE, GL_NORMAL_ARRAY_STRIDE },
{ GL_FOG_COORD_ARRAY, GL_FOG_COORD_ARRAY_POINTER, GL_FOG_COORD_ARRAY_BUFFER_BINDING, GL_ZERO, GL_FOG_COORD_ARRAY_TYPE, GL_FOG_COORD_ARRAY_STRIDE },
{ GL_COLOR_ARRAY, GL_COLOR_ARRAY_POINTER, GL_COLOR_ARRAY_BUFFER_BINDING, GL_COLOR_ARRAY_SIZE, GL_COLOR_ARRAY_TYPE, GL_COLOR_ARRAY_STRIDE },
{ GL_SECONDARY_COLOR_ARRAY, GL_SECONDARY_COLOR_ARRAY_POINTER, GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING, GL_SECONDARY_COLOR_ARRAY_SIZE, GL_SECONDARY_COLOR_ARRAY_TYPE, GL_SECONDARY_COLOR_ARRAY_STRIDE },
{ GL_INDEX_ARRAY, GL_INDEX_ARRAY_POINTER, GL_INDEX_ARRAY_BUFFER_BINDING, GL_ZERO, GL_INDEX_ARRAY_TYPE, GL_INDEX_ARRAY_STRIDE },
{ GL_EDGE_FLAG_ARRAY, GL_EDGE_FLAG_ARRAY_POINTER, GL_EDGE_FLAG_ARRAY_BUFFER_BINDING, GL_ZERO, GL_ZERO, GL_EDGE_FLAG_ARRAY_STRIDE },
{ GL_TEXTURE_COORD_ARRAY, GL_TEXTURE_COORD_ARRAY_POINTER, GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, GL_TEXTURE_COORD_ARRAY_SIZE, GL_TEXTURE_COORD_ARRAY_TYPE, GL_TEXTURE_COORD_ARRAY_STRIDE },
};
struct NamedVertexArray
{
GLboolean enabled; // GL_x_ARRAY
const GLvoid* pointer; // GL_x_ARRAY_POINTER
GLuint buffer; // GL_x_ARRAY_BUFFER_BINDING
GLint size; // GL_x_ARRAY_SIZE
GLenum type; // GL_x_ARRAY_TYPE
GLint stride; // GL_x_ARRAY_STRIDE
inline NamedVertexArray()
: enabled(GL_FALSE)
, pointer(NULL)
, buffer(0)
, size(4)
, type(GL_FLOAT)
, stride(0)
{
}
inline NamedVertexArray &swap(NamedVertexArray &other)
{
std::swap(enabled,other.enabled);
std::swap(pointer,other.pointer);
std::swap(buffer,other.buffer);
std::swap(size,other.size);
std::swap(type,other.type);
std::swap(stride,other.stride);
return *this;
}
NamedVertexArray &get(DispatchTable &dt, vaName va)
{
GLint vaInt = static_cast<GLint>(va);
RegalAssert(vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays));
if (vaInt >= 0)
{
if (vaInt < 7)
{
enabled = dt.call(&dt.glIsEnabled)(vaEnum[vaInt][0]);
dt.call(&dt.glGetPointerv)(vaEnum[vaInt][1],const_cast<GLvoid**>(&pointer));
dt.call(&dt.glGetIntegerv)(vaEnum[vaInt][2],reinterpret_cast<GLint*>(&buffer));
if (vaEnum[vaInt][3] != GL_ZERO)
dt.call(&dt.glGetIntegerv)(vaEnum[vaInt][3],&size);
if (vaEnum[vaInt][4] != GL_ZERO)
dt.call(&dt.glGetIntegerv)(vaEnum[vaInt][4],reinterpret_cast<GLint*>(&type));
dt.call(&dt.glGetIntegerv)(vaEnum[vaInt][5],&stride);
}
else
{
GLuint index = static_cast<GLuint>(vaInt - 7);
enabled = dt.call(&dt.glIsEnabledi)(vaEnum[7][0],index);
dt.call(&dt.glGetPointeri_vEXT)(vaEnum[7][1],index,const_cast<GLvoid**>(&pointer));
dt.call(&dt.glGetIntegeri_v)(vaEnum[7][2],index,reinterpret_cast<GLint*>(&buffer));
dt.call(&dt.glGetIntegeri_v)(vaEnum[7][3],index,&size);
dt.call(&dt.glGetIntegeri_v)(vaEnum[7][4],index,reinterpret_cast<GLint*>(&type));
dt.call(&dt.glGetIntegeri_v)(vaEnum[7][5],index,&stride);
}
}
return *this;
}
const NamedVertexArray &set(DispatchTable &dt, vaName va) const
{
GLint vaInt = static_cast<GLint>(va);
RegalAssert(vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays));
if (vaInt >= 0)
{
if (vaInt < 7)
{
enable(dt,vaEnum[vaInt][0],enabled);
dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
switch (vaInt)
{
case VERTEX:
dt.call(&dt.glVertexPointer)(size,type,stride,pointer);
break;
case NORMAL:
dt.call(&dt.glNormalPointer)(type,stride,pointer);
break;
case FOG_COORD:
dt.call(&dt.glFogCoordPointer)(type,stride,pointer);
break;
case COLOR:
dt.call(&dt.glColorPointer)(size,type,stride,pointer);
break;
case SECONDARY_COLOR:
dt.call(&dt.glSecondaryColorPointer)(size,type,stride,pointer);
break;
case INDEX:
dt.call(&dt.glIndexPointer)(type,stride,pointer);
break;
case EDGE_FLAG:
dt.call(&dt.glEdgeFlagPointer)(stride,pointer);
break;
default:
break;
}
}
else
{
GLuint index = static_cast<GLuint>(vaInt - 7);
enablei(dt,vaEnum[7][0],index,enabled);
dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,buffer);
dt.call(&dt.glMultiTexCoordPointerEXT)(GL_TEXTURE0+index,size,type,stride,pointer);
}
}
return *this;
}
std::string toString(vaName va, const char *delim = "\n") const
{
string_list tmp;
GLint vaInt = static_cast<GLint>(va);
RegalAssert(vaInt >= 0 && vaInt < static_cast<GLint>(nNamedArrays));
if (vaInt >= 0)
{
if (vaInt < 7)
{
enableToString(tmp, enabled, Token::toString(vaEnum[vaInt][0]), delim);
tmp << print_string("glBindBuffer(GL_ARRAY_BUFFER,",buffer,");",delim);
switch (vaInt)
{
case VERTEX:
tmp << print_string("glVertexPointer(",size,",",type,",",stride,",0x",pointer,");",delim);
break;
case NORMAL:
tmp << print_string("glNormalPointer(",type,",",stride,",0x",pointer,");",delim);
break;
case FOG_COORD:
tmp << print_string("glFogCoordPointer(",type,",",stride,",0x",pointer,");",delim);
break;
case COLOR:
tmp << print_string("glColorPointer(",size,",",type,",",stride,",0x",pointer,");",delim);
break;
case SECONDARY_COLOR:
tmp << print_string("glSecondaryColorPointer(",size,",",type,",",stride,",0x",pointer,");",delim);
break;
case INDEX:
tmp << print_string("glIndexPointer(",type,",",stride,",0x",pointer,");",delim);
break;
case EDGE_FLAG:
tmp << print_string("glEdgeFlagPointer(",stride,",0x",pointer,");",delim);
break;
default:
break;
}
}
else
{
GLuint index = static_cast<GLuint>(vaInt - 7);
enableiToString(tmp, enabled, Token::toString(vaEnum[vaInt][0]), index, delim);
tmp << print_string("glBindBuffer(GL_ARRAY_BUFFER,",buffer,");",delim);
tmp << print_string("glMultiTexCoordPointerEXT(",Token::toString(GL_TEXTURE0+index),",",size,",",type,",",stride,",0x",pointer,");",delim);
}
}
return tmp;
}
};
struct VertexBufferBindPoint
{
GLuint buffer; // GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
GLintptr offset; // GL_VERTEX_ATTRIB_RELATIVE_OFFSET
GLsizei stride; // GL_VERTEX_ATTRIB_ARRAY_STRIDE
GLuint divisor; // GL_VERTEX_ATTRIB_ARRAY_DIVISOR
inline VertexBufferBindPoint()
: buffer(0)
, offset(0)
, stride(0)
, divisor(0)
{
}
inline VertexBufferBindPoint &swap(VertexBufferBindPoint &other)
{
std::swap(buffer,other.buffer);
std::swap(offset,other.offset);
std::swap(stride,other.stride);
std::swap(divisor,other.divisor);
return *this;
}
VertexBufferBindPoint &get(DispatchTable &dt, GLuint index)
{
RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS);
if (index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
{
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,reinterpret_cast<GLint*>(&buffer));
dt.call(&dt.glGetVertexAttribPointerv)(index,GL_VERTEX_ATTRIB_ARRAY_POINTER,reinterpret_cast<GLvoid **>(&offset));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_STRIDE,reinterpret_cast<GLint*>(&stride));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_DIVISOR,reinterpret_cast<GLint*>(&divisor));
}
return *this;
}
const VertexBufferBindPoint &set(DispatchTable &dt, GLuint index) const
{
RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS);
if (index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
{
dt.call(&dt.glBindVertexBuffer)(index,buffer,offset,stride);
dt.call(&dt.glVertexBindingDivisor)(index,divisor);
}
return *this;
}
std::string toString(GLuint index, const char *delim = "\n") const
{
string_list tmp;
RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS);
if (index < REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS)
{
tmp << print_string("glBindVertexBuffer(",index,",",buffer,",",offset,",",stride,");",delim);
tmp << print_string("glVertexBindingDivisor(",index,",",divisor,");",delim);
}
return tmp;
}
};
struct GenericVertexArray
{
GLboolean enabled; // GL_VERTEX_ATTRIB_ARRAY_ENABLED
GLint size; // GL_VERTEX_ATTRIB_ARRAY_SIZE
GLenum type; // GL_VERTEX_ATTRIB_ARRAY_TYPE
GLuint relativeOffset; // GL_VERTEX_ATTRIB_RELATIVE_OFFSET
GLboolean normalized; // GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
GLboolean isInteger; // GL_VERTEX_ATTRIB_ARRAY_INTEGER
GLboolean isLong; // GL_VERTEX_ATTRIB_ARRAY_LONG
GLuint bindingIndex; // GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
inline GenericVertexArray()
: enabled(GL_FALSE)
, size(4)
, type(GL_FLOAT)
, relativeOffset(0)
, normalized(GL_FALSE)
, isInteger(GL_FALSE)
, isLong(GL_FALSE)
, bindingIndex(0)
{
}
inline GenericVertexArray &swap(GenericVertexArray &other)
{
std::swap(enabled,other.enabled);
std::swap(size,other.size);
std::swap(type,other.type);
std::swap(relativeOffset,other.relativeOffset);
std::swap(normalized,other.normalized);
std::swap(isInteger,other.isInteger);
std::swap(isLong,other.isLong);
std::swap(bindingIndex,other.bindingIndex);
return *this;
}
GenericVertexArray &get(DispatchTable &dt, GLuint index)
{
RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIBS);
if (index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
{
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_ENABLED,reinterpret_cast<GLint*>(&enabled));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_SIZE,&size);
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_TYPE,reinterpret_cast<GLint*>(&type));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_RELATIVE_OFFSET,reinterpret_cast<GLint*>(&relativeOffset));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,reinterpret_cast<GLint*>(&normalized));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_INTEGER,reinterpret_cast<GLint*>(&isInteger));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_LONG,reinterpret_cast<GLint*>(&isLong));
dt.call(&dt.glGetVertexAttribiv)(index,GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,reinterpret_cast<GLint*>(&bindingIndex));
}
return *this;
}
const GenericVertexArray &set(DispatchTable &dt, GLuint index) const
{
RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIBS);
if (index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
{
if (enabled)
dt.call(&dt.glEnableVertexAttribArray)(index);
else
dt.call(&dt.glDisableVertexAttribArray)(index);
if (isInteger)
dt.call(&dt.glVertexAttribIFormat)(index,size,type,relativeOffset);
else if (isLong)
dt.call(&dt.glVertexAttribLFormat)(index,size,type,relativeOffset);
else
dt.call(&dt.glVertexAttribFormat)(index,size,type,normalized,relativeOffset);
dt.call(&dt.glVertexAttribBinding)(index,bindingIndex);
}
return *this;
}
std::string toString(GLuint index, const char *delim = "\n") const
{
string_list tmp;
RegalAssert(index < REGAL_EMU_MAX_VERTEX_ATTRIBS);
if (index < REGAL_EMU_MAX_VERTEX_ATTRIBS)
{
if (enabled)
tmp << print_string("glEnableVertexAttribArray(",index,");",delim);
else
tmp << print_string("glDisableVertexAttribArray(",index,");",delim);
if (isInteger)
tmp << print_string("glVertexAttribIFormat(",index,",",size,",",type,",",relativeOffset,");",delim);
else if (isLong)
tmp << print_string("glVertexAttribLFormat(",index,",",size,",",type,",",relativeOffset,");",delim);
else
tmp << print_string("glVertexAttribFormat(",index,",",size,",",type,",",normalized,",",relativeOffset,");",delim);
tmp << print_string("glVertexAttribBinding(",index,",",bindingIndex,");",delim);
}
return tmp;
}
};
struct VertexArray
{
NamedVertexArray named[nNamedArrays];
VertexBufferBindPoint bindings[REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS];
GenericVertexArray generic[REGAL_EMU_MAX_VERTEX_ATTRIBS];
GLuint elementArrayBufferBinding; // GL_ELEMENT_ARRAY_BUFFER_BINDING
// Table 23.8. Vertex Array Data (not in Vertex Array objects)
//
// dsn: primitiveRestartFixedIndex is not in this table but should be (khronos bug 10250)
GLenum clientActiveTexture; // GL_CLIENT_ACTIVE_TEXTURE
GLboolean primitiveRestartFixedIndex; // GL_PRIMITIVE_RESTART_FIXED_INDEX
GLboolean primitiveRestart; // GL_PRIMITIVE_RESTART
GLuint primitiveRestartIndex; // GL_PRIMITIVE_RESTART_INDEX
GLuint arrayBufferBinding; // GL_ARRAY_BUFFER_BINDING
GLuint vertexArrayBinding; // GL_VERTEX_ARRAY_BINDING
inline VertexArray()
: elementArrayBufferBinding(0)
, clientActiveTexture(GL_TEXTURE0)
, primitiveRestartFixedIndex(GL_FALSE)
, primitiveRestart(GL_FALSE)
, primitiveRestartIndex(0)
, arrayBufferBinding(0)
, vertexArrayBinding(0)
{
for (GLuint ii=0; ii<nNamedArrays; ii++)
named[ii]= NamedVertexArray();
named[NORMAL].size = 3;
named[FOG_COORD].size = 1;
named[SECONDARY_COLOR].size = 3;
named[INDEX].size = 1;
named[EDGE_FLAG].size = 1;
named[EDGE_FLAG].type = GL_BOOL;
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
bindings[ii] = VertexBufferBindPoint();
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
generic[ii] = GenericVertexArray();
}
inline VertexArray &swap(VertexArray &other)
{
for (GLuint ii=0; ii<nNamedArrays; ii++)
named[ii].swap(other.named[ii]);
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
bindings[ii].swap(other.bindings[ii]);
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
generic[ii].swap(other.generic[ii]);
std::swap(elementArrayBufferBinding,other.elementArrayBufferBinding);
std::swap(clientActiveTexture,other.clientActiveTexture);
std::swap(primitiveRestartFixedIndex,other.primitiveRestartFixedIndex);
std::swap(primitiveRestart,other.primitiveRestart);
std::swap(primitiveRestartIndex,other.primitiveRestartIndex);
std::swap(arrayBufferBinding,other.arrayBufferBinding);
std::swap(vertexArrayBinding,other.vertexArrayBinding);
return *this;
}
inline VertexArray &get(DispatchTable &dt)
{
dt.call(&dt.glGetIntegerv)(GL_VERTEX_ARRAY_BINDING,reinterpret_cast<GLint*>(&vertexArrayBinding));
if (vertexArrayBinding)
dt.call(&dt.glBindVertexArray)(0);
for (GLuint ii=0; ii<nNamedArrays; ii++)
named[ii].get(dt,static_cast<vaName>(ii));
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
bindings[ii].get(dt,ii);
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
generic[ii].get(dt,ii);
dt.call(&dt.glGetIntegerv)(GL_ELEMENT_ARRAY_BUFFER_BINDING,reinterpret_cast<GLint*>(&elementArrayBufferBinding));
dt.call(&dt.glGetIntegerv)(GL_CLIENT_ACTIVE_TEXTURE,reinterpret_cast<GLint*>(&clientActiveTexture));
primitiveRestartFixedIndex = dt.call(&dt.glIsEnabled)(GL_PRIMITIVE_RESTART_FIXED_INDEX);
primitiveRestart = dt.call(&dt.glIsEnabled)(GL_PRIMITIVE_RESTART);
dt.call(&dt.glGetIntegerv)(GL_PRIMITIVE_RESTART_INDEX,reinterpret_cast<GLint*>(&primitiveRestartIndex));
dt.call(&dt.glGetIntegerv)(GL_ARRAY_BUFFER_BINDING,reinterpret_cast<GLint*>(&arrayBufferBinding));
if (vertexArrayBinding)
dt.call(&dt.glBindVertexArray)(vertexArrayBinding);
return *this;
}
inline const VertexArray &set(DispatchTable &dt) const
{
dt.call(&dt.glBindVertexArray)(0);
for (GLuint ii=0; ii<nNamedArrays; ii++)
named[ii].set(dt,static_cast<vaName>(ii));
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
bindings[ii].set(dt,ii);
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
generic[ii].set(dt,ii);
dt.call(&dt.glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER,elementArrayBufferBinding);
dt.call(&dt.glClientActiveTexture)(clientActiveTexture);
enable(dt,GL_PRIMITIVE_RESTART_FIXED_INDEX,primitiveRestartFixedIndex);
enable(dt,GL_PRIMITIVE_RESTART,primitiveRestart);
dt.call(&dt.glPrimitiveRestartIndex)(primitiveRestartIndex);
dt.call(&dt.glBindBuffer)(GL_ARRAY_BUFFER,arrayBufferBinding);
dt.call(&dt.glBindVertexArray)(vertexArrayBinding);
return *this;
}
inline std::string toString(const char *delim = "\n") const
{
string_list tmp;
for (GLuint ii=0; ii<nNamedArrays; ii++)
named[ii].toString(static_cast<vaName>(ii),delim);
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIB_BINDINGS; ii++)
bindings[ii].toString(ii,delim);
for (GLuint ii=0; ii<REGAL_EMU_MAX_VERTEX_ATTRIBS; ii++)
generic[ii].toString(ii,delim);
tmp << print_string("glBindBuffer(GL_ELEMENT_ARRAY_BUFFER",elementArrayBufferBinding,");",delim);
tmp << print_string("glClientActiveTexture(",clientActiveTexture,");",delim);
enableToString(tmp,primitiveRestartFixedIndex,"GL_PRIMITIVE_RESTART_FIXED_INDEX",delim);
enableToString(tmp,primitiveRestart,"GL_PRIMITIVE_RESTART",delim);
tmp << print_string("glPrimitiveRestartIndex(",primitiveRestartIndex,");",delim);
tmp << print_string("glBindBuffer(GL_ARRAY_BUFFER,",arrayBufferBinding,");",delim);
tmp << print_string("glBindVertexArray(",vertexArrayBinding,");",delim);
return tmp;
}
void SetEnablei(GLenum cap, GLuint index, GLboolean enabled)
{
// these two are not in Vertex Array objects, so always handle them
switch (cap)
{
case GL_PRIMITIVE_RESTART_FIXED_INDEX:
primitiveRestartFixedIndex = enabled;
break;
case GL_PRIMITIVE_RESTART:
primitiveRestart = enabled;
break;
default:
break;
}
// only handle the rest if no VAO is bound
if (vertexArrayBinding)
return;
switch (cap)
{
case GL_VERTEX_ARRAY:
named[VERTEX].enabled = enabled;
break;
case GL_NORMAL_ARRAY:
named[NORMAL].enabled = enabled;
break;
case GL_FOG_COORD_ARRAY:
named[FOG_COORD].enabled = enabled;
break;
case GL_COLOR_ARRAY:
named[COLOR].enabled = enabled;
break;
case GL_SECONDARY_COLOR_ARRAY:
named[SECONDARY_COLOR].enabled = enabled;
break;
case GL_INDEX_ARRAY:
named[INDEX].enabled = enabled;
break;
case GL_EDGE_FLAG_ARRAY:
named[EDGE_FLAG].enabled = enabled;
break;
case GL_TEXTURE_COORD_ARRAY:
named[index+7].enabled = enabled;
break;
default:
break;
}
}
inline void glEnable(GLenum cap)
{
SetEnablei(cap, 0, GL_TRUE);
}
inline void glDisable(GLenum cap)
{
SetEnablei(cap, 0, GL_FALSE);
}
inline void glEnablei(GLenum cap, GLuint index)
{
SetEnablei(cap, index, GL_TRUE);
}
inline void glDisablei(GLenum cap, GLuint index)
{
SetEnablei(cap, index, GL_FALSE);
}
inline void glEnableVertexAttribArray(GLuint index)
{
if (!vertexArrayBinding)
generic[index].enabled = GL_TRUE;
}
inline void glDisableVertexAttribArray(GLenum cap, GLuint index)
{
UNUSED_PARAMETER(cap);
if (!vertexArrayBinding)
generic[index].enabled = GL_FALSE;
}
void BindBuffer( GLenum target, GLuint buffer )
{
switch (target)
{
case GL_ARRAY_BUFFER:
arrayBufferBinding = buffer;
break;
case GL_ELEMENT_ARRAY_BUFFER:
if (!vertexArrayBinding)
elementArrayBufferBinding = buffer;
break;
default:
break;
}
}
void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )
{
if (!vertexArrayBinding)
{
named[VERTEX].buffer = arrayBufferBinding;
named[VERTEX].size = size;
named[VERTEX].type = type;
named[VERTEX].stride = stride;
named[VERTEX].pointer = pointer;
}
}
void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer )
{
if (!vertexArrayBinding)
{
named[NORMAL].buffer = arrayBufferBinding;
named[NORMAL].type = type;
named[NORMAL].stride = stride;
named[NORMAL].pointer = pointer;
}
}
void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )
{
if (!vertexArrayBinding)
{
named[COLOR].buffer = arrayBufferBinding;
named[COLOR].size = size;
named[COLOR].type = type;
named[COLOR].stride = stride;
named[COLOR].pointer = pointer;
}
}
void glSecondaryColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer )
{
if (!vertexArrayBinding)
{
named[SECONDARY_COLOR].buffer = arrayBufferBinding;
named[SECONDARY_COLOR].size = size;
named[SECONDARY_COLOR].type = type;
named[SECONDARY_COLOR].stride = stride;
named[SECONDARY_COLOR].pointer = pointer;
}
}
void glIndexPointer(GLenum type, GLsizei stride, const GLvoid *pointer )
{
if (!vertexArrayBinding)
{
named[INDEX].buffer = arrayBufferBinding;
named[INDEX].type = type;
named[INDEX].stride = stride;
named[INDEX].pointer = pointer;
}
}
void glEdgeFlagPointer(GLsizei stride, const GLvoid *pointer )
{
if (!vertexArrayBinding)
{
named[EDGE_FLAG].buffer = arrayBufferBinding;
named[EDGE_FLAG].stride = stride;
named[EDGE_FLAG].pointer = pointer;
}
}
void glFogCoordPointer(GLenum type, GLsizei stride, const GLvoid *pointer )
{
if (!vertexArrayBinding)
{
named[FOG_COORD].buffer = arrayBufferBinding;
named[FOG_COORD].type = type;
named[FOG_COORD].stride = stride;
named[FOG_COORD].pointer = pointer;
}
}
//<> void glTexCoordPointer(GLint size,GLenum type,GLsizei stride, const GLvoid *pointer )
//<> named[index+7].enabled = enabled;
void glBindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride)
{
if (!vertexArrayBinding)
{
bindings[bindingindex].buffer = buffer;
bindings[bindingindex].offset = offset;
bindings[bindingindex].stride = stride;
}
}
inline void glVertexBindingDivisor(GLuint bindingindex, GLuint divisor)
{
if (!vertexArrayBinding)
bindings[bindingindex].divisor = divisor;
}
//<> glVertexAttribIFormat(index,size,type,relativeOffset);
//<> glVertexAttribLFormat(index,size,type,relativeOffset);
//<> glVertexAttribFormat(index,size,type,normalized,relativeOffset);
inline void glVertexAttribBinding(GLuint attribindex, GLuint bindingindex)
{
if (!vertexArrayBinding)
generic[attribindex].bindingIndex = bindingindex;
}
inline void glClientActiveTexture(GLenum texture)
{
clientActiveTexture = texture;
}
inline void glPrimitiveRestartIndex(GLuint index)
{
primitiveRestartIndex = index;
}
inline void glBindVertexArray(GLuint array)
{
vertexArrayBinding = array;
}
//<> also need to handle appropriate DSA entrypoints
//<> glMultiTexCoordPointerEXT(GL_TEXTURE0+index,size,type,stride,pointer);
};
}
REGAL_NAMESPACE_END
#endif