If there is only one normal, don't transform it multiple times.
[mesa.git] / src / mesa / tnl / t_vb_normals.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
4 *
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 */
27
28
29 #include "glheader.h"
30 #include "colormac.h"
31 #include "context.h"
32 #include "macros.h"
33 #include "imports.h"
34 #include "mtypes.h"
35
36 #include "math/m_xform.h"
37
38 #include "t_context.h"
39 #include "t_pipeline.h"
40
41
42
43 struct normal_stage_data {
44 normal_func NormalTransform;
45 GLvector4f normal;
46 };
47
48 #define NORMAL_STAGE_DATA(stage) ((struct normal_stage_data *)stage->privatePtr)
49
50
51
52
53 static GLboolean run_normal_stage( GLcontext *ctx,
54 struct tnl_pipeline_stage *stage )
55 {
56 struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
57 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
58
59 ASSERT(store->NormalTransform);
60
61 if (stage->changed_inputs) {
62 /* We can only use the display list's saved normal lengths if we've
63 * got a transformation matrix with uniform scaling.
64 */
65 const GLfloat *lengths;
66 if (ctx->ModelviewMatrixStack.Top->flags & MAT_FLAG_GENERAL_SCALE)
67 lengths = NULL;
68 else
69 lengths = VB->NormalLengthPtr;
70
71 /* If there is only one normal, don't transform it multiple times:
72 */
73 if (VB->NormalPtr->stride == 0)
74 VB->NormalPtr->count = 1;
75
76 store->NormalTransform( ctx->ModelviewMatrixStack.Top,
77 ctx->_ModelViewInvScale,
78 VB->NormalPtr, /* input normals */
79 lengths,
80 &store->normal ); /* resulting normals */
81
82 if (VB->NormalPtr->stride == 0) {
83 VB->NormalPtr->count = VB->Count;
84 store->normal.stride = 0;
85 }
86 else
87 store->normal.stride = 16;
88 }
89
90 VB->NormalPtr = &store->normal;
91 VB->AttribPtr[_TNL_ATTRIB_NORMAL] = VB->NormalPtr;
92
93 VB->NormalLengthPtr = 0; /* no longer valid */
94 return GL_TRUE;
95 }
96
97
98 static GLboolean run_validate_normal_stage( GLcontext *ctx,
99 struct tnl_pipeline_stage *stage )
100 {
101 struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
102
103
104 if (ctx->_NeedEyeCoords) {
105 GLuint transform = NORM_TRANSFORM_NO_ROT;
106
107 if (ctx->ModelviewMatrixStack.Top->flags & (MAT_FLAG_GENERAL |
108 MAT_FLAG_ROTATION |
109 MAT_FLAG_GENERAL_3D |
110 MAT_FLAG_PERSPECTIVE))
111 transform = NORM_TRANSFORM;
112
113
114 if (ctx->Transform.Normalize) {
115 store->NormalTransform = _mesa_normal_tab[transform | NORM_NORMALIZE];
116 }
117 else if (ctx->Transform.RescaleNormals &&
118 ctx->_ModelViewInvScale != 1.0) {
119 store->NormalTransform = _mesa_normal_tab[transform | NORM_RESCALE];
120 }
121 else {
122 store->NormalTransform = _mesa_normal_tab[transform];
123 }
124 }
125 else {
126 if (ctx->Transform.Normalize) {
127 store->NormalTransform = _mesa_normal_tab[NORM_NORMALIZE];
128 }
129 else if (!ctx->Transform.RescaleNormals &&
130 ctx->_ModelViewInvScale != 1.0) {
131 store->NormalTransform = _mesa_normal_tab[NORM_RESCALE];
132 }
133 else {
134 store->NormalTransform = 0;
135 }
136 }
137
138 if (store->NormalTransform) {
139 stage->run = run_normal_stage;
140 return stage->run( ctx, stage );
141 } else {
142 stage->active = GL_FALSE; /* !!! */
143 return GL_TRUE;
144 }
145 }
146
147
148 static void check_normal_transform( GLcontext *ctx,
149 struct tnl_pipeline_stage *stage )
150 {
151 stage->active = !ctx->VertexProgram._Enabled &&
152 (ctx->Light.Enabled || (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS));
153
154 /* Don't clobber the initialize function:
155 */
156 if (stage->privatePtr)
157 stage->run = run_validate_normal_stage;
158 }
159
160
161 static GLboolean alloc_normal_data( GLcontext *ctx,
162 struct tnl_pipeline_stage *stage )
163 {
164 TNLcontext *tnl = TNL_CONTEXT(ctx);
165 struct normal_stage_data *store;
166 stage->privatePtr = MALLOC(sizeof(*store));
167 store = NORMAL_STAGE_DATA(stage);
168 if (!store)
169 return GL_FALSE;
170
171 _mesa_vector4f_alloc( &store->normal, 0, tnl->vb.Size, 32 );
172
173 /* Now run the stage.
174 */
175 stage->run = run_validate_normal_stage;
176 return stage->run( ctx, stage );
177 }
178
179
180
181 static void free_normal_data( struct tnl_pipeline_stage *stage )
182 {
183 struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
184 if (store) {
185 _mesa_vector4f_free( &store->normal );
186 FREE( store );
187 stage->privatePtr = NULL;
188 }
189 }
190
191 #define _TNL_NEW_NORMAL_TRANSFORM (_NEW_MODELVIEW| \
192 _NEW_TRANSFORM| \
193 _NEW_PROGRAM| \
194 _MESA_NEW_NEED_NORMALS| \
195 _MESA_NEW_NEED_EYE_COORDS)
196
197
198
199 const struct tnl_pipeline_stage _tnl_normal_transform_stage =
200 {
201 "normal transform", /* name */
202 _TNL_NEW_NORMAL_TRANSFORM, /* re-check */
203 _TNL_NEW_NORMAL_TRANSFORM, /* re-run */
204 GL_FALSE, /* active? */
205 _TNL_BIT_NORMAL, /* inputs */
206 _TNL_BIT_NORMAL, /* outputs */
207 0, /* changed_inputs */
208 NULL, /* private data */
209 free_normal_data, /* destructor */
210 check_normal_transform, /* check */
211 alloc_normal_data /* run -- initially set to alloc */
212 };