[MESA]
[reactos.git] / reactos / dll / opengl / mesa / main / state.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.3
4 *
5 * Copyright (C) 1999-2008 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
25
26 /**
27 * \file state.c
28 * State management.
29 *
30 * This file manages recalculation of derived values in struct gl_context.
31 */
32
33
34 #include "glheader.h"
35 #include "mtypes.h"
36 #include "context.h"
37 #include "macros.h"
38 #include "framebuffer.h"
39 #include "light.h"
40 #include "matrix.h"
41 #include "pixel.h"
42 #include "state.h"
43 #include "stencil.h"
44 #include "texobj.h"
45 #include "texstate.h"
46 #include "varray.h"
47
48
49 static void
50 update_separate_specular(struct gl_context *ctx)
51 {
52 if (_mesa_need_secondary_color(ctx))
53 ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
54 else
55 ctx->_TriangleCaps &= ~DD_SEPARATE_SPECULAR;
56 }
57
58
59 /**
60 * Helper for update_arrays().
61 * \return min(current min, array->_MaxElement).
62 */
63 static GLuint
64 update_min(GLuint min, struct gl_client_array *array)
65 {
66 _mesa_update_array_max_element(array);
67 return MIN2(min, array->_MaxElement);
68 }
69
70
71 /**
72 * Update ctx->Array._MaxElement (the max legal index into all enabled arrays).
73 * Need to do this upon new array state or new buffer object state.
74 */
75 static void
76 update_arrays( struct gl_context *ctx )
77 {
78 struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
79 GLuint min = ~0;
80
81 /* find min of _MaxElement values for all enabled arrays.
82 * Note that the generic arrays always take precedence over
83 * the legacy arrays.
84 */
85
86 /* 0 */
87 if (arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
88 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]);
89 }
90
91 /* 2 */
92 if (arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
93 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]);
94 }
95
96 /* 3 */
97 if (arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
98 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]);
99 }
100
101 /* 4 */
102 if (arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
103 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]);
104 }
105
106 /* 5 */
107 if (arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
108 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]);
109 }
110
111 /* 6 */
112 if (arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
113 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]);
114 }
115
116 /* 8 */
117 if (arrayObj->VertexAttrib[VERT_ATTRIB_TEX].Enabled) {
118 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_TEX]);
119 }
120
121 if (arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
122 min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]);
123 }
124
125 /* _MaxElement is one past the last legal array element */
126 arrayObj->_MaxElement = min;
127 }
128
129 static void
130 update_viewport_matrix(struct gl_context *ctx)
131 {
132 const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
133
134 ASSERT(depthMax > 0);
135
136 /* Compute scale and bias values. This is really driver-specific
137 * and should be maintained elsewhere if at all.
138 * NOTE: RasterPos uses this.
139 */
140 _math_matrix_viewport(&ctx->Viewport._WindowMap,
141 ctx->Viewport.X, ctx->Viewport.Y,
142 ctx->Viewport.Width, ctx->Viewport.Height,
143 ctx->Viewport.Near, ctx->Viewport.Far,
144 depthMax);
145 }
146
147
148 /*
149 * Check polygon state and set DD_TRI_CULL_FRONT_BACK and/or DD_TRI_OFFSET
150 * in ctx->_TriangleCaps if needed.
151 */
152 static void
153 update_polygon(struct gl_context *ctx)
154 {
155 ctx->_TriangleCaps &= ~(DD_TRI_CULL_FRONT_BACK | DD_TRI_OFFSET);
156
157 if (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
158 ctx->_TriangleCaps |= DD_TRI_CULL_FRONT_BACK;
159
160 if ( ctx->Polygon.OffsetPoint
161 || ctx->Polygon.OffsetLine
162 || ctx->Polygon.OffsetFill)
163 ctx->_TriangleCaps |= DD_TRI_OFFSET;
164 }
165
166
167 /**
168 * Update the ctx->_TriangleCaps bitfield.
169 * XXX that bitfield should really go away someday!
170 * This function must be called after other update_*() functions since
171 * there are dependencies on some other derived values.
172 */
173 #if 0
174 static void
175 update_tricaps(struct gl_context *ctx, GLbitfield new_state)
176 {
177 ctx->_TriangleCaps = 0;
178
179 /*
180 * Points
181 */
182 if (1/*new_state & _NEW_POINT*/) {
183 if (ctx->Point.SmoothFlag)
184 ctx->_TriangleCaps |= DD_POINT_SMOOTH;
185 if (ctx->Point._Attenuated)
186 ctx->_TriangleCaps |= DD_POINT_ATTEN;
187 }
188
189 /*
190 * Lines
191 */
192 if (1/*new_state & _NEW_LINE*/) {
193 if (ctx->Line.SmoothFlag)
194 ctx->_TriangleCaps |= DD_LINE_SMOOTH;
195 if (ctx->Line.StippleFlag)
196 ctx->_TriangleCaps |= DD_LINE_STIPPLE;
197 }
198
199 /*
200 * Polygons
201 */
202 if (1/*new_state & _NEW_POLYGON*/) {
203 if (ctx->Polygon.SmoothFlag)
204 ctx->_TriangleCaps |= DD_TRI_SMOOTH;
205 if (ctx->Polygon.StippleFlag)
206 ctx->_TriangleCaps |= DD_TRI_STIPPLE;
207 if (ctx->Polygon.FrontMode != GL_FILL
208 || ctx->Polygon.BackMode != GL_FILL)
209 ctx->_TriangleCaps |= DD_TRI_UNFILLED;
210 if (ctx->Polygon.CullFlag
211 && ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
212 ctx->_TriangleCaps |= DD_TRI_CULL_FRONT_BACK;
213 if (ctx->Polygon.OffsetPoint ||
214 ctx->Polygon.OffsetLine ||
215 ctx->Polygon.OffsetFill)
216 ctx->_TriangleCaps |= DD_TRI_OFFSET;
217 }
218
219 /*
220 * Lighting and shading
221 */
222 if (ctx->Light.Enabled && ctx->Light.Model.TwoSide)
223 ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
224 if (ctx->Light.ShadeModel == GL_FLAT)
225 ctx->_TriangleCaps |= DD_FLATSHADE;
226 if (_mesa_need_secondary_color(ctx))
227 ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
228 }
229 #endif
230
231
232 /**
233 * Compute derived GL state.
234 * If __struct gl_contextRec::NewState is non-zero then this function \b must
235 * be called before rendering anything.
236 *
237 * Calls dd_function_table::UpdateState to perform any internal state
238 * management necessary.
239 *
240 * \sa _mesa_update_modelview_project(), _mesa_update_texture(),
241 * _mesa_update_buffer_bounds(),
242 * _mesa_update_lighting() and _mesa_update_tnl_spaces().
243 */
244 void
245 _mesa_update_state_locked( struct gl_context *ctx )
246 {
247 GLbitfield new_state = ctx->NewState;
248
249 if (new_state == _NEW_CURRENT_ATTRIB)
250 goto out;
251
252 /*
253 * Now update derived state info
254 */
255
256 if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION))
257 _mesa_update_modelview_project( ctx, new_state );
258
259 if (new_state & (_NEW_TEXTURE|_NEW_TEXTURE_MATRIX))
260 _mesa_update_texture( ctx, new_state );
261
262 if (new_state & _NEW_BUFFERS)
263 _mesa_update_framebuffer(ctx);
264
265 if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT))
266 _mesa_update_draw_buffer_bounds( ctx );
267
268 if (new_state & _NEW_POLYGON)
269 update_polygon( ctx );
270
271 if (new_state & _NEW_LIGHT)
272 _mesa_update_lighting( ctx );
273
274 if (new_state & (_NEW_STENCIL | _NEW_BUFFERS))
275 _mesa_update_stencil( ctx );
276
277 if (new_state & _NEW_PIXEL)
278 _mesa_update_pixel( ctx, new_state );
279
280 if (new_state & _DD_NEW_SEPARATE_SPECULAR)
281 update_separate_specular( ctx );
282
283 if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT))
284 update_viewport_matrix(ctx);
285
286 #if 0
287 if (new_state & (_NEW_POINT | _NEW_LINE | _NEW_POLYGON | _NEW_LIGHT
288 | _NEW_STENCIL | _DD_NEW_SEPARATE_SPECULAR))
289 update_tricaps( ctx, new_state );
290 #endif
291
292 /* ctx->_NeedEyeCoords is now up to date.
293 *
294 * If the truth value of this variable has changed, update for the
295 * new lighting space and recompute the positions of lights and the
296 * normal transform.
297 *
298 * If the lighting space hasn't changed, may still need to recompute
299 * light positions & normal transforms for other reasons.
300 */
301 if (new_state & _MESA_NEW_NEED_EYE_COORDS)
302 _mesa_update_tnl_spaces( ctx, new_state );
303
304 if (new_state & (_NEW_ARRAY | _NEW_BUFFER_OBJECT))
305 update_arrays( ctx );
306
307 out:
308
309 /*
310 * Give the driver a chance to act upon the new_state flags.
311 * The driver might plug in different span functions, for example.
312 * Also, this is where the driver can invalidate the state of any
313 * active modules (such as swrast_setup, swrast, tnl, etc).
314 *
315 * Set ctx->NewState to zero to avoid recursion if
316 * Driver.UpdateState() has to call FLUSH_VERTICES(). (fixed?)
317 */
318 new_state = ctx->NewState;
319 ctx->NewState = 0;
320 ctx->Driver.UpdateState(ctx, new_state);
321 ctx->Array.NewState = 0;
322 if (!ctx->Array.RebindArrays)
323 ctx->Array.RebindArrays = (new_state & _NEW_ARRAY) != 0;
324 }
325
326
327 /* This is the usual entrypoint for state updates:
328 */
329 void
330 _mesa_update_state( struct gl_context *ctx )
331 {
332 _mesa_lock_context_textures(ctx);
333 _mesa_update_state_locked(ctx);
334 _mesa_unlock_context_textures(ctx);
335 }