/* -*- mode: c; c-basic-offset: 3 -*- */ /* * Mesa 3-D graphics library * Version: 3.5 * * Copyright (C) 1999-2001 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. * * Original authors: * Keith Whitwell * * Adapted to Mach64 by: * José Fonseca */ /* DO_XYZW: Emit xyz and maybe w coordinates. * DO_RGBA: Emit color. * DO_SPEC: Emit specular color. * DO_FOG: Emit fog coordinate in specular alpha. * DO_TEX0: Emit tex0 u,v coordinates. * DO_TEX1: Emit tex1 u,v coordinates. * DO_PTEX: Emit tex0,1 q coordinates where possible. * * Additionally, this template assumes it is emitting *transformed* * vertices; the modifications to emit untransformed vertices (ie. to * t&l hardware) are probably too great to cooexist with the code * already in this file. */ #define VIEWPORT_X(x) ((GLint) ((s[0] * (x) + s[12]) * 4.0)) #define VIEWPORT_Y(y) ((GLint) ((s[5] * (y) + s[13]) * 4.0)) #define VIEWPORT_Z(z) (((GLuint) (s[10] * (z) + s[14])) << 15) #ifndef LOCALVARS #define LOCALVARS #endif static void TAG(emit)( struct gl_context *ctx, GLuint start, GLuint end, void *dest, GLuint stride ) { LOCALVARS struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; #if DO_TEX1 GLfloat (*tc1)[4]; GLuint tc1_stride; #if DO_PTEX GLuint tc1_size; #endif #endif #if DO_TEX0 GLfloat (*tc0)[4]; GLuint tc0_stride; #if DO_PTEX GLuint tc0_size; #endif #endif #if DO_SPEC GLfloat (*spec)[4]; GLuint spec_stride; #endif #if DO_FOG GLfloat (*fog)[4]; GLuint fog_stride; #endif #if DO_RGBA GLfloat (*col)[4]; GLuint col_stride; #endif GLfloat (*coord)[4]; GLuint coord_stride; VERTEX *v = (VERTEX *)dest; const GLfloat *s = GET_VIEWPORT_MAT(); #if DO_TEX1 || DO_TEX0 || DO_XYZW const GLubyte *mask = VB->ClipMask; #endif int i; #if !DO_XYZW (void) s; /* Quiet compiler */ #endif /* fprintf(stderr, "%s(big) importable %d %d..%d\n", */ /* __FUNCTION__, VB->importable_data, start, end); */ #if DO_TEX1 { const GLuint t1 = GET_TEXSOURCE(1); tc1 = VB->AttribPtr[_TNL_ATTRIB_TEX0 + t1]->data; tc1_stride = VB->AttribPtr[_TNL_ATTRIB_TEX0 + t1]->stride; #if DO_PTEX tc1_size = VB->AttribPtr[_TNL_ATTRIB_TEX0 + t1]->size; #endif } #endif #if DO_TEX0 { const GLuint t0 = GET_TEXSOURCE(0); tc0 = VB->AttribPtr[_TNL_ATTRIB_TEX0 + t0]->data; tc0_stride = VB->AttribPtr[_TNL_ATTRIB_TEX0 + t0]->stride; #if DO_PTEX tc0_size = VB->AttribPtr[_TNL_ATTRIB_TEX0 + t0]->size; #endif } #endif #if DO_SPEC if (VB->AttribPtr[_TNL_ATTRIB_COLOR1]) { spec = VB->AttribPtr[_TNL_ATTRIB_COLOR1]->data; spec_stride = VB->AttribPtr[_TNL_ATTRIB_COLOR1]->stride; } else { spec = (GLfloat (*)[4])ctx->Current.Attrib[VERT_ATTRIB_COLOR1]; spec_stride = 0; } #endif #if DO_FOG if (VB->AttribPtr[_TNL_ATTRIB_FOG]) { fog = VB->AttribPtr[_TNL_ATTRIB_FOG]->data; fog_stride = VB->AttribPtr[_TNL_ATTRIB_FOG]->stride; } else { static GLfloat tmp[4] = {0, 0, 0, 0}; fog = &tmp; fog_stride = 0; } #endif #if DO_RGBA col = VB->AttribPtr[_TNL_ATTRIB_COLOR0]->data; col_stride = VB->AttribPtr[_TNL_ATTRIB_COLOR0]->stride; #endif coord = VB->NdcPtr->data; coord_stride = VB->NdcPtr->stride; if (start) { #if DO_TEX1 STRIDE_4F(tc1, start * tc1_stride); #endif #if DO_TEX0 STRIDE_4F(tc0, start * tc0_stride); #endif #if DO_SPEC STRIDE_4F(spec, start * spec_stride); #endif #if DO_FOG STRIDE_4F(fog, start * fog_stride); #endif #if DO_RGBA STRIDE_4F(col, start * col_stride); #endif STRIDE_4F(coord, start * coord_stride); } for (i=start; i < end; i++, v = (VERTEX *)((GLubyte *)v + stride)) { CARD32 *p = (CARD32 *)v; #if DO_TEX1 || DO_TEX0 GLfloat w; if (mask[i] == 0) { /* unclipped */ w = coord[0][3]; } else { /* clipped */ w = 1.0; } #endif #if DO_TEX1 #if DO_PTEX if (tc1_size == 4) { #ifdef MACH64_PREMULT_TEXCOORDS LE32_OUT_FLOAT( p++, w*tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ LE32_OUT_FLOAT( p++, w*tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ LE32_OUT_FLOAT( p++, w*tc1[0][3] ); /* VERTEX_?_SECONDARY_W */ #else /* !MACH64_PREMULT_TEXCOORDS */ float rhw = 1.0 / tc1[0][3]; LE32_OUT_FLOAT( p++, rhw*tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ LE32_OUT_FLOAT( p++, rhw*tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ LE32_OUT_FLOAT( p++, w*tc1[0][3] ); /* VERTEX_?_SECONDARY_W */ #endif /* !MACH64_PREMULT_TEXCOORDS */ } else { #endif /* DO_PTEX */ #ifdef MACH64_PREMULT_TEXCOORDS LE32_OUT_FLOAT( p++, w*tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ LE32_OUT_FLOAT( p++, w*tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_SECONDARY_W */ #else /* !MACH64_PREMULT_TEXCOORDS */ LE32_OUT_FLOAT( p++, tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ LE32_OUT_FLOAT( p++, tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_SECONDARY_W */ #endif /* !MACH64_PREMULT_TEXCOORDS */ #if DO_PTEX } #endif /* DO_PTEX */ STRIDE_4F(tc1, tc1_stride); #else /* !DO_TEX1 */ p += 3; #endif /* !DO_TEX1 */ #if DO_TEX0 #if DO_PTEX if (tc0_size == 4) { #ifdef MACH64_PREMULT_TEXCOORDS LE32_OUT_FLOAT( p++, w*tc0[0][0] ); /* VERTEX_?_S */ LE32_OUT_FLOAT( p++, w*tc0[0][1] ); /* VERTEX_?_T */ LE32_OUT_FLOAT( p++, w*tc0[0][3] ); /* VERTEX_?_W */ #else /* !MACH64_PREMULT_TEXCOORDS */ float rhw = 1.0 / tc0[0][3]; LE32_OUT_FLOAT( p++, rhw*tc0[0][0] ); /* VERTEX_?_S */ LE32_OUT_FLOAT( p++, rhw*tc0[0][1] ); /* VERTEX_?_T */ LE32_OUT_FLOAT( p++, w*tc0[0][3] ); /* VERTEX_?_W */ #endif /* !MACH64_PREMULT_TEXCOORDS */ } else { #endif /* DO_PTEX */ #ifdef MACH64_PREMULT_TEXCOORDS LE32_OUT_FLOAT( p++, w*tc0[0][0] ); /* VERTEX_?_S */ LE32_OUT_FLOAT( p++, w*tc0[0][1] ); /* VERTEX_?_T */ LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_W */ #else /* !MACH64_PREMULT_TEXCOORDS */ LE32_OUT_FLOAT( p++, tc0[0][0] ); /* VERTEX_?_S */ LE32_OUT_FLOAT( p++, tc0[0][1] ); /* VERTEX_?_T */ LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_W */ #endif /* !MACH64_PREMULT_TEXCOORDS */ #if DO_PTEX } #endif /* DO_PTEX */ STRIDE_4F(tc0, tc0_stride); #else /* !DO_TEX0 */ p += 3; #endif /* !DO_TEX0 */ #if DO_SPEC UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[0], spec[0][2]); /* VERTEX_?_SPEC_B */ UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[1], spec[0][1]); /* VERTEX_?_SPEC_G */ UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[2], spec[0][0]); /* VERTEX_?_SPEC_R */ STRIDE_4F(spec, spec_stride); #endif #if DO_FOG UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[3], fog[0][0]); /* VERTEX_?_SPEC_A */ /* ((GLubyte *)p)[3] = fog[0][0] * 255.0; */ STRIDE_4F(fog, fog_stride); #endif p++; #if DO_XYZW if (mask[i] == 0) { /* unclipped */ LE32_OUT( p++, VIEWPORT_Z( coord[0][2] ) ); /* VERTEX_?_Z */ } else { #endif p++; #if DO_XYZW } #endif #if DO_RGBA UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[0], col[0][2]); UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[1], col[0][1]); UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[2], col[0][0]); UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[3], col[0][3]); p++; STRIDE_4F(col, col_stride); #else p++; #endif #if DO_XYZW if (mask[i] == 0) { /* unclipped */ LE32_OUT( p, (VIEWPORT_X( coord[0][0] ) << 16) | /* VERTEX_?_X */ (VIEWPORT_Y( coord[0][1] ) & 0xffff) ); /* VERTEX_?_Y */ if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { fprintf( stderr, "%s: vert %d: %.2f %.2f %.2f %x\n", __FUNCTION__, i, (LE32_IN( p ) >> 16)/4.0, (LE32_IN( p ) & 0xffff)/4.0, LE32_IN( p - 2 )/65536.0, *(GLuint *)(p - 1) ); } } #endif #if DO_TEX1 || DO_TEX0 || DO_XYZW STRIDE_4F(coord, coord_stride); #endif assert( p + 1 - (CARD32 *)v == 10 ); } } #if DO_XYZW && DO_RGBA static GLboolean TAG(check_tex_sizes)( struct gl_context *ctx ) { LOCALVARS struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; /* Force 'missing' texcoords to something valid. */ if (DO_TEX1 && VB->AttribPtr[_TNL_ATTRIB_TEX0] == 0) VB->AttribPtr[_TNL_ATTRIB_TEX0] = VB->AttribPtr[_TNL_ATTRIB_TEX1]; if (DO_PTEX) return GL_TRUE; /* No hardware support for projective texture. Can fake it for * TEX0 only. */ if ((DO_TEX1 && VB->AttribPtr[_TNL_ATTRIB_TEX0 + GET_TEXSOURCE(1)]->size == 4)) { PTEX_FALLBACK(); return GL_FALSE; } if (DO_TEX0 && VB->AttribPtr[_TNL_ATTRIB_TEX0 + GET_TEXSOURCE(0)]->size == 4) { if (DO_TEX1) { PTEX_FALLBACK(); } return GL_FALSE; } return GL_TRUE; } static void TAG(interp)( struct gl_context *ctx, GLfloat t, GLuint edst, GLuint eout, GLuint ein, GLboolean force_boundary ) { LOCALVARS struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; GLubyte *ddverts = GET_VERTEX_STORE(); GLuint size = GET_VERTEX_SIZE(); const GLfloat *dstclip = VB->ClipPtr->data[edst]; GLfloat w; const GLfloat *s = GET_VIEWPORT_MAT(); CARD32 *dst = (CARD32 *)(ddverts + (edst * size)); CARD32 *in = (CARD32 *)(ddverts + (ein * size)); CARD32 *out = (CARD32 *)(ddverts + (eout * size)); (void)s; w = (dstclip[3] == 0.0F) ? 1.0 : (1.0 / dstclip[3]); #if DO_TEX1 { GLfloat temp; #if DO_PTEX GLfloat wout = VB->NdcPtr->data[eout][3]; GLfloat win = VB->NdcPtr->data[ein][3]; GLfloat qout = LE32_IN_FLOAT( out + 2 ) / wout; GLfloat qin = LE32_IN_FLOAT( in + 2 ) / win; GLfloat qdst, rqdst; INTERP_F( t, qdst, qout, qin ); rqdst = 1.0 / qdst; INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_SECONDARY_S */ dst++; out++; in++; INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_SECONDARY_T */ dst++; out++; in++; LE32_OUT_FLOAT( dst, w*rqdst ); /* VERTEX_?_SECONDARY_W */ dst++; out++; in++; #else /* !DO_PTEX */ #ifdef MACH64_PREMULT_TEXCOORDS GLfloat qout = w / LE32_IN_FLOAT( out + 2 ); GLfloat qin = w / LE32_IN_FLOAT( in + 2 ); INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_S */ dst++; out++; in++; INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_T */ dst++; out++; in++; #else /* !MACH64_PREMULT_TEXCOORDS */ INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_S */ dst++; out++; in++; INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_T */ dst++; out++; in++; #endif /* !MACH64_PREMULT_TEXCOORDS */ LE32_OUT_FLOAT( dst, w ); /* VERTEX_?_SECONDARY_W */ dst++; out++; in++; #endif /* !DO_PTEX */ } #else /* !DO_TEX1 */ dst += 3; out += 3; in += 3; #endif /* !DO_TEX1 */ #if DO_TEX0 { GLfloat temp; #if DO_PTEX GLfloat wout = VB->NdcPtr->data[eout][3]; GLfloat win = VB->NdcPtr->data[ein][3]; GLfloat qout = LE32_IN_FLOAT( out + 2 ) / wout; GLfloat qin = LE32_IN_FLOAT( in + 2 ) / win; GLfloat qdst, rqdst; INTERP_F( t, qdst, qout, qin ); rqdst = 1.0 / qdst; INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_S */ dst++; out++; in++; INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_T */ dst++; out++; in++; LE32_OUT_FLOAT( dst, w*rqdst ); /* VERTEX_?_W */ dst++; out++; in++; #else /* !DO_PTEX */ #ifdef MACH64_PREMULT_TEXCOORDS GLfloat qout = w / LE32_IN_FLOAT( out + 2 ); GLfloat qin = w / LE32_IN_FLOAT( in + 2 ); INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_S */ dst++; out++; in++; INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_T */ dst++; out++; in++; #else /* !MACH64_PREMULT_TEXCOORDS */ INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_S */ dst++; out++; in++; INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_T */ dst++; out++; in++; #endif /* !MACH64_PREMULT_TEXCOORDS */ LE32_OUT_FLOAT( dst, w ); /* VERTEX_?_W */ dst++; out++; in++; #endif /* !DO_PTEX */ } #else /* !DO_TEX0 */ dst += 3; out += 3; in += 3; #endif /* !DO_TEX0 */ #if DO_SPEC INTERP_UB( t, ((GLubyte *)dst)[0], ((GLubyte *)out)[0], ((GLubyte *)in)[0] ); /* VERTEX_?_SPEC_B */ INTERP_UB( t, ((GLubyte *)dst)[1], ((GLubyte *)out)[1], ((GLubyte *)in)[1] ); /* VERTEX_?_SPEC_G */ INTERP_UB( t, ((GLubyte *)dst)[2], ((GLubyte *)out)[2], ((GLubyte *)in)[2] ); /* VERTEX_?_SPEC_R */ #endif #if DO_FOG INTERP_UB( t, ((GLubyte *)dst)[3], ((GLubyte *)out)[3], ((GLubyte *)in)[3] ); /* VERTEX_?_SPEC_A */ #endif /* DO_FOG */ dst++; out++; in++; LE32_OUT( dst, VIEWPORT_Z( dstclip[2] * w ) ); /* VERTEX_?_Z */ dst++; out++; in++; INTERP_UB( t, ((GLubyte *)dst)[0], ((GLubyte *)out)[0], ((GLubyte *)in)[0] ); /* VERTEX_?_B */ INTERP_UB( t, ((GLubyte *)dst)[1], ((GLubyte *)out)[1], ((GLubyte *)in)[1] ); /* VERTEX_?_G */ INTERP_UB( t, ((GLubyte *)dst)[2], ((GLubyte *)out)[2], ((GLubyte *)in)[2] ); /* VERTEX_?_R */ INTERP_UB( t, ((GLubyte *)dst)[3], ((GLubyte *)out)[3], ((GLubyte *)in)[3] ); /* VERTEX_?_A */ dst++; /*out++; in++;*/ LE32_OUT( dst, (VIEWPORT_X( dstclip[0] * w ) << 16) | /* VERTEX_?_X */ (VIEWPORT_Y( dstclip[1] * w ) & 0xffff) ); /* VERTEX_?_Y */ assert( dst + 1 - (CARD32 *)(ddverts + (edst * size)) == 10 ); assert( in + 2 - (CARD32 *)(ddverts + (ein * size)) == 10 ); assert( out + 2 - (CARD32 *)(ddverts + (eout * size)) == 10 ); if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { fprintf( stderr, "%s: dst vert: %.2f %.2f %.2f %x\n", __FUNCTION__, (GLshort)(LE32_IN( dst ) >> 16)/4.0, (GLshort)(LE32_IN( dst ) & 0xffff)/4.0, LE32_IN( dst - 2 )/65536.0, *(GLuint *)(dst - 1) ); } } #endif /* DO_RGBA && DO_XYZW */ static void TAG(copy_pv)( struct gl_context *ctx, GLuint edst, GLuint esrc ) { #if DO_SPEC || DO_FOG || DO_RGBA LOCALVARS GLubyte *verts = GET_VERTEX_STORE(); GLuint size = GET_VERTEX_SIZE(); GLuint *dst = (GLuint *)(verts + (edst * size)); GLuint *src = (GLuint *)(verts + (esrc * size)); #endif #if DO_SPEC || DO_FOG dst[6] = src[6]; /* VERTEX_?_SPEC_ARGB */ #endif #if DO_RGBA dst[8] = src[8]; /* VERTEX_?_ARGB */ #endif } static void TAG(init)( void ) { setup_tab[IND].emit = TAG(emit); #if DO_XYZW && DO_RGBA setup_tab[IND].check_tex_sizes = TAG(check_tex_sizes); setup_tab[IND].interp = TAG(interp); #endif setup_tab[IND].copy_pv = TAG(copy_pv); #if DO_TEX1 setup_tab[IND].vertex_format = TEX1_VERTEX_FORMAT; setup_tab[IND].vertex_size = 10; #elif DO_TEX0 setup_tab[IND].vertex_format = TEX0_VERTEX_FORMAT; setup_tab[IND].vertex_size = 7; #elif DO_SPEC || DO_FOG setup_tab[IND].vertex_format = NOTEX_VERTEX_FORMAT; setup_tab[IND].vertex_size = 4; #else setup_tab[IND].vertex_format = TINY_VERTEX_FORMAT; setup_tab[IND].vertex_size = 3; #endif } #undef IND #undef TAG