#include "main/bufferobj.h"
#include "main/context.h"
#include "main/macros.h"
+#include "main/mfeatures.h"
#include "main/vtxfmt.h"
#include "main/dlist.h"
#include "main/eval.h"
*/
static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
{
- GLcontext *ctx = exec->ctx;
+ struct gl_context *ctx = exec->ctx;
struct vbo_context *vbo = vbo_context(ctx);
GLuint i;
exec->vtx.attrsz[i],
exec->vtx.attrptr[i]);
- if (memcmp(current, tmp, sizeof(tmp)) != 0)
- {
+ if (memcmp(current, tmp, sizeof(tmp)) != 0) {
memcpy(current, tmp, sizeof(tmp));
/* Given that we explicitly state size here, there is no need
}
-static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
+/**
+ * Copy current vertex attribute values into the current vertex.
+ */
+static void
+vbo_exec_copy_from_current(struct vbo_exec_context *exec)
{
- GLcontext *ctx = exec->ctx;
+ struct gl_context *ctx = exec->ctx;
struct vbo_context *vbo = vbo_context(ctx);
GLint i;
- for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
- const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+ for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
+ const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
switch (exec->vtx.attrsz[i]) {
case 4: exec->vtx.attrptr[i][3] = current[3];
case 3: exec->vtx.attrptr[i][2] = current[2];
/**
* Flush existing data, set new attrib size, replay copied vertices.
+ * This is called when we transition from a small vertex attribute size
+ * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
+ * We need to go back over the previous 2-component texcoords and insert
+ * zero and one values.
*/
-static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
- GLuint attr,
- GLuint newsz )
+static void
+vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
+ GLuint attr, GLuint newSize )
{
- GLcontext *ctx = exec->ctx;
+ struct gl_context *ctx = exec->ctx;
struct vbo_context *vbo = vbo_context(ctx);
- GLint lastcount = exec->vtx.vert_count;
- GLfloat *tmp;
- GLuint oldsz;
+ const GLint lastcount = exec->vtx.vert_count;
+ GLfloat *old_attrptr[VBO_ATTRIB_MAX];
+ const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
+ const GLuint oldSize = exec->vtx.attrsz[attr];
GLuint i;
/* Run pipeline on current vertices, copy wrapped vertices
*/
vbo_exec_wrap_buffers( exec );
+ if (unlikely(exec->vtx.copied.nr)) {
+ /* We're in the middle of a primitive, keep the old vertex
+ * format around to be able to translate the copied vertices to
+ * the new format.
+ */
+ memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
+ }
- /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
- * when the attribute already exists in the vertex and is having
- * its size increased.
- */
- vbo_exec_copy_to_current( exec );
-
+ if (unlikely(oldSize)) {
+ /* Do a COPY_TO_CURRENT to ensure back-copying works for the
+ * case when the attribute already exists in the vertex and is
+ * having its size increased.
+ */
+ vbo_exec_copy_to_current( exec );
+ }
/* Heuristic: Attempt to isolate attributes received outside
* begin/end so that they don't bloat the vertices.
*/
if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
- exec->vtx.attrsz[attr] == 0 &&
- lastcount > 8 &&
- exec->vtx.vertex_size) {
+ !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current( exec );
reset_attrfv( exec );
}
/* Fix up sizes:
*/
- oldsz = exec->vtx.attrsz[attr];
- exec->vtx.attrsz[attr] = newsz;
-
- exec->vtx.vertex_size += newsz - oldsz;
+ exec->vtx.attrsz[attr] = newSize;
+ exec->vtx.vertex_size += newSize - oldSize;
exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
(exec->vtx.vertex_size * sizeof(GLfloat)));
exec->vtx.vert_count = 0;
exec->vtx.buffer_ptr = exec->vtx.buffer_map;
-
- /* Recalculate all the attrptr[] values
- */
- for (i = 0, tmp = exec->vtx.vertex ; i < VBO_ATTRIB_MAX ; i++) {
- if (exec->vtx.attrsz[i]) {
- exec->vtx.attrptr[i] = tmp;
- tmp += exec->vtx.attrsz[i];
+ if (unlikely(oldSize)) {
+ /* Size changed, recalculate all the attrptr[] values
+ */
+ GLfloat *tmp = exec->vtx.vertex;
+
+ for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+ if (exec->vtx.attrsz[i]) {
+ exec->vtx.attrptr[i] = tmp;
+ tmp += exec->vtx.attrsz[i];
+ }
+ else
+ exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
}
- else
- exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
- }
- /* Copy from current to repopulate the vertex with correct values.
- */
- vbo_exec_copy_from_current( exec );
+ /* Copy from current to repopulate the vertex with correct
+ * values.
+ */
+ vbo_exec_copy_from_current( exec );
+ }
+ else {
+ /* Just have to append the new attribute at the end */
+ exec->vtx.attrptr[attr] = exec->vtx.vertex +
+ exec->vtx.vertex_size - newSize;
+ }
/* Replay stored vertices to translate them
* to new format here.
*
* -- No need to replay - just copy piecewise
*/
- if (exec->vtx.copied.nr)
- {
+ if (unlikely(exec->vtx.copied.nr)) {
GLfloat *data = exec->vtx.copied.buffer;
GLfloat *dest = exec->vtx.buffer_ptr;
GLuint j;
assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
-
+
for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
- if (exec->vtx.attrsz[j]) {
+ GLuint sz = exec->vtx.attrsz[j];
+
+ if (sz) {
+ GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
+ GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
+
if (j == attr) {
- if (oldsz) {
- COPY_CLEAN_4V( dest, oldsz, data );
- data += oldsz;
- dest += newsz;
+ if (oldSize) {
+ GLfloat tmp[4];
+ COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
+ COPY_SZ_4V(dest + new_offset, newSize, tmp);
} else {
- const GLfloat *current = (const GLfloat *)vbo->currval[j].Ptr;
- COPY_SZ_4V( dest, newsz, current );
- dest += newsz;
+ GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
+ COPY_SZ_4V(dest + new_offset, sz, current);
}
}
else {
- GLuint sz = exec->vtx.attrsz[j];
- COPY_SZ_4V( dest, sz, data );
- dest += sz;
- data += sz;
+ COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
}
}
}
+
+ data += old_vtx_size;
+ dest += exec->vtx.vertex_size;
}
exec->vtx.buffer_ptr = dest;
}
-static void vbo_exec_fixup_vertex( GLcontext *ctx,
- GLuint attr, GLuint sz )
+/**
+ * This is when a vertex attribute transitions to a different size.
+ * For example, we saw a bunch of glTexCoord2f() calls and now we got a
+ * glTexCoord4f() call. We promote the array from size=2 to size=4.
+ */
+static void
+vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- int i;
- if (sz > exec->vtx.attrsz[attr]) {
+ if (newSize > exec->vtx.attrsz[attr]) {
/* New size is larger. Need to flush existing vertices and get
* an enlarged vertex format.
*/
- vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
+ vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
}
- else if (sz < exec->vtx.active_sz[attr]) {
+ else if (newSize < exec->vtx.active_sz[attr]) {
static const GLfloat id[4] = { 0, 0, 0, 1 };
+ GLuint i;
/* New size is smaller - just need to fill in some
* zeros. Don't need to flush or wrap.
*/
- for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
+ for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
exec->vtx.attrptr[attr][i-1] = id[i-1];
}
- exec->vtx.active_sz[attr] = sz;
+ exec->vtx.active_sz[attr] = newSize;
/* Does setting NeedFlush belong here? Necessitates resetting
* vtxfmt on each flush (otherwise flags won't get reset
* afterwards).
*/
if (attr == 0)
- exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
}
-#if FEATURE_beginend
-
-/*
+/**
+ * This macro is used to implement all the glVertex, glColor, glTexCoord,
+ * glVertexAttrib, etc functions.
*/
-#define ATTR( A, N, V0, V1, V2, V3 ) \
-do { \
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
- \
- if (exec->vtx.active_sz[A] != N) \
- vbo_exec_fixup_vertex(ctx, A, N); \
- \
- { \
- GLfloat *dest = exec->vtx.attrptr[A]; \
- if (N>0) dest[0] = V0; \
- if (N>1) dest[1] = V1; \
- if (N>2) dest[2] = V2; \
- if (N>3) dest[3] = V3; \
- } \
- \
- if ((A) == 0) { \
- GLuint i; \
- \
- for (i = 0; i < exec->vtx.vertex_size; i++) \
- exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
- \
+#define ATTR( A, N, V0, V1, V2, V3 ) \
+do { \
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
+ \
+ if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
+ ctx->Driver.BeginVertices( ctx ); \
+ \
+ if (unlikely(exec->vtx.active_sz[A] != N)) \
+ vbo_exec_fixup_vertex(ctx, A, N); \
+ \
+ { \
+ GLfloat *dest = exec->vtx.attrptr[A]; \
+ if (N>0) dest[0] = V0; \
+ if (N>1) dest[1] = V1; \
+ if (N>2) dest[2] = V2; \
+ if (N>3) dest[3] = V3; \
+ } \
+ \
+ if ((A) == 0) { \
+ /* This is a glVertex call */ \
+ GLuint i; \
+ \
+ for (i = 0; i < exec->vtx.vertex_size; i++) \
+ exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
+ \
exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
- exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
- \
- if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
- vbo_exec_vtx_wrap( exec ); \
- } \
+ \
+ /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
+ /* something to draw (not just updating a color or texcoord).*/ \
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
+ \
+ if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
+ vbo_exec_vtx_wrap( exec ); \
+ } \
} while (0)
#include "vbo_attrib_tmp.h"
-
+#if FEATURE_beginend
#if FEATURE_evaluators
#endif /* FEATURE_evaluators */
+/**
+ * Flush (draw) vertices.
+ * \param unmap - leave VBO unmapped after flushing?
+ */
+static void
+vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
+{
+ if (exec->vtx.vert_count || unmap) {
+ vbo_exec_vtx_flush( exec, unmap );
+ }
+
+ if (exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current( exec );
+ reset_attrfv( exec );
+ }
+}
+
+
/**
* Called via glBegin.
*/
* begin/end pairs.
*/
if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
- vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
+ vbo_exec_FlushVertices_internal(exec, GL_FALSE);
i = exec->vtx.prim_count++;
exec->vtx.prim[i].mode = mode;
}
+/**
+ * Called via glPrimitiveRestartNV()
+ */
+static void GLAPIENTRY
+vbo_exec_PrimitiveRestartNV(void)
+{
+ GLenum curPrim;
+ GET_CURRENT_CONTEXT( ctx );
+
+ curPrim = ctx->Driver.CurrentExecPrimitive;
+
+ if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
+ }
+ else {
+ vbo_exec_End();
+ vbo_exec_Begin(curPrim);
+ }
+}
+
+
+
static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
{
GLvertexformat *vfmt = &exec->vtxfmt;
vfmt->Begin = vbo_exec_Begin;
vfmt->End = vbo_exec_End;
+ vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
_MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
_MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
+ /* integer-valued */
+ vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
+ vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
+ vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
+ vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
+ vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
+ vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
+ vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
+
+ /* unsigned integer-valued */
+ vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
+ vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
+ vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
+ vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
+ vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
+ vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
+ vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
+
vfmt->Materialfv = vbo_Materialfv;
vfmt->EdgeFlag = vbo_EdgeFlag;
#else /* FEATURE_beginend */
-#define ATTR( A, N, V0, V1, V2, V3 ) \
-do { \
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
- \
- /* FLUSH_UPDATE_CURRENT needs to be set manually */ \
- exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
- \
- if (exec->vtx.active_sz[A] != N) \
- vbo_exec_fixup_vertex(ctx, A, N); \
- \
- { \
- GLfloat *dest = exec->vtx.attrptr[A]; \
- if (N>0) dest[0] = V0; \
- if (N>1) dest[1] = V1; \
- if (N>2) dest[2] = V2; \
- if (N>3) dest[3] = V3; \
- } \
-} while (0)
-
-#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
-#define TAG(x) vbo_##x
-
-#include "vbo_attrib_tmp.h"
-
static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
{
/* silence warnings */
* This replaces the malloced buffer which was created in
* vb_exec_vtx_init() below.
*/
-void vbo_use_buffer_objects(GLcontext *ctx)
+void vbo_use_buffer_objects(struct gl_context *ctx)
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
/* Any buffer name but 0 can be used here since this bufferobj won't
void vbo_exec_vtx_init( struct vbo_exec_context *exec )
{
- GLcontext *ctx = exec->ctx;
+ struct gl_context *ctx = exec->ctx;
struct vbo_context *vbo = vbo_context(ctx);
GLuint i;
/* Hook our functions into the dispatch table.
*/
- _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
+ _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
ASSERT(i < Elements(exec->vtx.attrsz));
void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
{
/* using a real VBO for vertex data */
- GLcontext *ctx = exec->ctx;
+ struct gl_context *ctx = exec->ctx;
unsigned i;
/* True VBOs should already be unmapped
_mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
}
-void vbo_exec_BeginVertices( GLcontext *ctx )
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- if (0) printf("%s\n", __FUNCTION__);
- vbo_exec_vtx_map( exec );
-
- assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
- exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
-}
-void vbo_exec_FlushVertices_internal( GLcontext *ctx, GLboolean unmap )
+/**
+ * Called upon first glVertex, glColor, glTexCoord, etc.
+ */
+void vbo_exec_BeginVertices( struct gl_context *ctx )
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- if (exec->vtx.vert_count || unmap) {
- vbo_exec_vtx_flush( exec, unmap );
- }
+ vbo_exec_vtx_map( exec );
- if (exec->vtx.vertex_size) {
- vbo_exec_copy_to_current( exec );
- reset_attrfv( exec );
- }
+ assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
}
/**
+ * Called via ctx->Driver.FlushVertices()
* \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
*/
-void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
+void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
assert(exec->flush_call_depth == 1);
#endif
- if (0) printf("%s\n", __FUNCTION__);
-
- if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- if (0) printf("%s - inside begin/end\n", __FUNCTION__);
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ /* We've had glBegin but not glEnd! */
#ifdef DEBUG
exec->flush_call_depth--;
assert(exec->flush_call_depth == 0);
return;
}
- vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
+ /* Flush (draw), and make sure VBO is left unmapped when done */
+ vbo_exec_FlushVertices_internal(exec, GL_TRUE);
/* Need to do this to ensure BeginVertices gets called again:
*/
- if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) {
- _mesa_restore_exec_vtxfmt( ctx );
- exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
- }
-
- exec->ctx->Driver.NeedFlush &= ~flags;
+ ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
#ifdef DEBUG
exec->flush_call_depth--;
void GLAPIENTRY
-_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
vbo_Color4f(r, g, b, a);
}
void GLAPIENTRY
-_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
+_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
{
vbo_Normal3f(x, y, z);
}
void GLAPIENTRY
-_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
{
vbo_MultiTexCoord4f(target, s, t, r, q);
}
+
void GLAPIENTRY
-_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
{
vbo_Materialfv(face, pname, params);
}
void GLAPIENTRY
-_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+_es_Materialf(GLenum face, GLenum pname, GLfloat param)
+{
+ GLfloat p[4];
+ p[0] = param;
+ p[1] = p[2] = p[3] = 0.0F;
+ vbo_Materialfv(face, pname, p);
+}
+
+
+/**
+ * A special version of glVertexAttrib4f that does not treat index 0 as
+ * VBO_ATTRIB_POS.
+ */
+static void
+VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
+ else
+ ERROR();
+}
+
+void GLAPIENTRY
+_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ VertexAttrib4f_nopos(index, x, y, z, w);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib1f(GLuint indx, GLfloat x)
+{
+ VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+{
+ VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+ VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
{
- vbo_VertexAttrib4fARB(index, x, y, z, w);
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
}