304 lines
8.1 KiB
C
304 lines
8.1 KiB
C
|
|
/*
|
|
* Mesa 3-D graphics library
|
|
* Version: 5.1
|
|
*
|
|
* Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
/* Author:
|
|
* Keith Whitwell <keith@tungstengraphics.com>
|
|
*/
|
|
|
|
#include "glheader.h"
|
|
#include "context.h"
|
|
#include "enums.h"
|
|
#include "glapi.h"
|
|
#include "imports.h"
|
|
#include "macros.h"
|
|
#include "mtypes.h"
|
|
#include "t_context.h"
|
|
#include "t_save_api.h"
|
|
|
|
/* If someone compiles a display list like:
|
|
* glBegin(Triangles)
|
|
* glVertex()
|
|
* ... lots of vertices ...
|
|
* glEnd()
|
|
*
|
|
* or:
|
|
* glDrawArrays(...)
|
|
*
|
|
* and then tries to execute it like this:
|
|
*
|
|
* glBegin(Lines)
|
|
* glCallList()
|
|
* glEnd()
|
|
*
|
|
* it will wind up in here, as the vertex copying used when wrapping
|
|
* buffers in list compilation (Triangles) won't be right for how the
|
|
* list is being executed (as Lines).
|
|
*
|
|
* This could be avoided by not compiling as vertex_lists until after
|
|
* the first glEnd() has been seen. However, that would miss an
|
|
* important category of display lists, for the sake of a degenerate
|
|
* usage.
|
|
*
|
|
* Further, replaying degenerately-called lists in this fashion is
|
|
* probably still faster than the replay using opcodes.
|
|
*/
|
|
|
|
typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
|
|
|
|
|
|
/* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
|
|
static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
|
|
{
|
|
ctx->Exec->VertexAttrib1fvNV(target, v);
|
|
}
|
|
|
|
static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
|
|
{
|
|
ctx->Exec->VertexAttrib2fvNV(target, v);
|
|
}
|
|
|
|
static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
|
|
{
|
|
ctx->Exec->VertexAttrib3fvNV(target, v);
|
|
}
|
|
|
|
static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
|
|
{
|
|
ctx->Exec->VertexAttrib4fvNV(target, v);
|
|
}
|
|
|
|
static attr_func vert_attrfunc[4] = {
|
|
VertexAttrib1fvNV,
|
|
VertexAttrib2fvNV,
|
|
VertexAttrib3fvNV,
|
|
VertexAttrib4fvNV
|
|
};
|
|
|
|
|
|
static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
|
|
{
|
|
switch (target) {
|
|
case _TNL_ATTRIB_MAT_FRONT_SHININESS:
|
|
ctx->Exec->Materialfv( GL_FRONT, GL_SHININESS, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_BACK_SHININESS:
|
|
ctx->Exec->Materialfv( GL_BACK, GL_SHININESS, v );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
|
|
{
|
|
switch (target) {
|
|
case _TNL_ATTRIB_MAT_FRONT_INDEXES:
|
|
ctx->Exec->Materialfv( GL_FRONT, GL_COLOR_INDEXES, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_BACK_INDEXES:
|
|
ctx->Exec->Materialfv( GL_BACK, GL_COLOR_INDEXES, v );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
|
|
{
|
|
switch (target) {
|
|
case _TNL_ATTRIB_MAT_FRONT_EMISSION:
|
|
ctx->Exec->Materialfv( GL_FRONT, GL_EMISSION, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_BACK_EMISSION:
|
|
ctx->Exec->Materialfv( GL_BACK, GL_EMISSION, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_FRONT_AMBIENT:
|
|
ctx->Exec->Materialfv( GL_FRONT, GL_AMBIENT, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_BACK_AMBIENT:
|
|
ctx->Exec->Materialfv( GL_BACK, GL_AMBIENT, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_FRONT_DIFFUSE:
|
|
ctx->Exec->Materialfv( GL_FRONT, GL_DIFFUSE, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_BACK_DIFFUSE:
|
|
ctx->Exec->Materialfv( GL_BACK, GL_DIFFUSE, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_FRONT_SPECULAR:
|
|
ctx->Exec->Materialfv( GL_FRONT, GL_SPECULAR, v );
|
|
break;
|
|
case _TNL_ATTRIB_MAT_BACK_SPECULAR:
|
|
ctx->Exec->Materialfv( GL_BACK, GL_SPECULAR, v );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static attr_func mat_attrfunc[4] = {
|
|
mat_attr1fv,
|
|
0,
|
|
mat_attr3fv,
|
|
mat_attr4fv
|
|
};
|
|
|
|
|
|
static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
|
|
{
|
|
ctx->Exec->Indexf(v[0]);
|
|
}
|
|
|
|
static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
|
|
{
|
|
ctx->Exec->EdgeFlag((v[0] == 1.0));
|
|
}
|
|
|
|
struct loopback_attr {
|
|
GLint target;
|
|
GLint sz;
|
|
attr_func func;
|
|
};
|
|
|
|
/* Don't emit ends and begins on wrapped primitives. Don't replay
|
|
* wrapped vertices. If we get here, it's probably because the the
|
|
* precalculated wrapping is wrong.
|
|
*/
|
|
static void loopback_prim( GLcontext *ctx,
|
|
struct tnl_vertex_list *list, GLuint i,
|
|
struct loopback_attr *la, GLuint nr )
|
|
{
|
|
struct tnl_prim *prim = &list->prim[i];
|
|
GLint begin = prim->start;
|
|
GLint end = begin + prim->count;
|
|
GLfloat *data;
|
|
GLint j;
|
|
GLuint k;
|
|
|
|
if (prim->mode & PRIM_BEGIN) {
|
|
glBegin( prim->mode & PRIM_MODE_MASK );
|
|
} else {
|
|
assert(i == 0);
|
|
assert(begin == 0);
|
|
begin += list->wrap_count;
|
|
}
|
|
|
|
data = list->buffer + begin * list->vertex_size;
|
|
|
|
for (j = begin ; j < end ; j++) {
|
|
GLfloat *tmp = data + la[0].sz;
|
|
|
|
for (k = 1 ; k < nr ; k++) {
|
|
la[k].func( ctx, la[k].target, tmp );
|
|
tmp += la[k].sz;
|
|
}
|
|
|
|
/* Fire the vertex
|
|
*/
|
|
la[0].func( ctx, VERT_ATTRIB_POS, data );
|
|
data = tmp;
|
|
}
|
|
|
|
if (prim->mode & PRIM_END) {
|
|
glEnd();
|
|
}
|
|
else {
|
|
assert (i == list->prim_count-1);
|
|
}
|
|
}
|
|
|
|
/* Primitives generated by DrawArrays/DrawElements/Rectf may be
|
|
* caught here. If there is no primitive in progress, execute them
|
|
* normally, otherwise need to track and discard the generated
|
|
* primitives.
|
|
*/
|
|
static void loopback_weak_prim( GLcontext *ctx,
|
|
struct tnl_vertex_list *list, GLuint i,
|
|
struct loopback_attr *la, GLuint nr )
|
|
{
|
|
if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END)
|
|
loopback_prim( ctx, list, i, la, nr );
|
|
else {
|
|
struct tnl_prim *prim = &list->prim[i];
|
|
|
|
/* Use the prim_weak flag to ensure that if this primitive
|
|
* wraps, we don't mistake future vertex_lists for part of the
|
|
* surrounding primitive.
|
|
*
|
|
* While this flag is set, we are simply disposing of data
|
|
* generated by an operation now known to be a noop.
|
|
*/
|
|
if (prim->mode & PRIM_BEGIN)
|
|
ctx->Driver.CurrentExecPrimitive |= PRIM_WEAK;
|
|
if (prim->mode & PRIM_END)
|
|
ctx->Driver.CurrentExecPrimitive &= ~PRIM_WEAK;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void _tnl_loopback_vertex_list( GLcontext *ctx, struct tnl_vertex_list *list )
|
|
{
|
|
struct loopback_attr la[_TNL_ATTRIB_MAX];
|
|
GLuint i, nr = 0;
|
|
|
|
for (i = 0 ; i <= _TNL_ATTRIB_TEX7 ; i++) {
|
|
if (list->attrsz[i]) {
|
|
la[nr].target = i;
|
|
la[nr].sz = list->attrsz[i];
|
|
la[nr].func = vert_attrfunc[list->attrsz[i]-1];
|
|
nr++;
|
|
}
|
|
}
|
|
|
|
for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ;
|
|
i <= _TNL_ATTRIB_MAT_BACK_INDEXES ;
|
|
i++) {
|
|
if (list->attrsz[i]) {
|
|
la[nr].target = i;
|
|
la[nr].sz = list->attrsz[i];
|
|
la[nr].func = mat_attrfunc[list->attrsz[i]-1];
|
|
nr++;
|
|
}
|
|
}
|
|
|
|
if (list->attrsz[_TNL_ATTRIB_EDGEFLAG]) {
|
|
la[nr].target = _TNL_ATTRIB_EDGEFLAG;
|
|
la[nr].sz = list->attrsz[_TNL_ATTRIB_EDGEFLAG];
|
|
la[nr].func = edgeflag_attr1fv;
|
|
nr++;
|
|
}
|
|
|
|
if (list->attrsz[_TNL_ATTRIB_INDEX]) {
|
|
la[nr].target = _TNL_ATTRIB_INDEX;
|
|
la[nr].sz = list->attrsz[_TNL_ATTRIB_INDEX];
|
|
la[nr].func = index_attr1fv;
|
|
nr++;
|
|
}
|
|
|
|
for (i = 0 ; i < list->prim_count ; i++) {
|
|
if (list->prim[i].mode & PRIM_WEAK)
|
|
loopback_weak_prim( ctx, list, i, la, nr );
|
|
else
|
|
loopback_prim( ctx, list, i, la, nr );
|
|
}
|
|
}
|