check for null paramList
[mesa.git] / src / mesa / main / program.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.0
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
25 /**
26 * \file program.c
27 * Vertex and fragment program support functions.
28 * \author Brian Paul
29 */
30
31
32 #include "glheader.h"
33 #include "context.h"
34 #include "hash.h"
35 #include "imports.h"
36 #include "macros.h"
37 #include "mtypes.h"
38 #include "program.h"
39 #include "nvfragparse.h"
40 #include "nvfragprog.h"
41 #include "nvvertparse.h"
42
43
44 /**********************************************************************/
45 /* Utility functions */
46 /**********************************************************************/
47
48
49 /**
50 * Init context's program state
51 */
52 void
53 _mesa_init_program(GLcontext *ctx)
54 {
55 GLuint i;
56
57 ctx->Program.ErrorPos = -1;
58 ctx->Program.ErrorString = _mesa_strdup("");
59
60 #if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
61 ctx->VertexProgram.Enabled = GL_FALSE;
62 ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
63 ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
64 ctx->VertexProgram.Current = NULL;
65 ctx->VertexProgram.Current = (struct vertex_program *) ctx->Shared->DefaultVertexProgram;
66 assert(ctx->VertexProgram.Current);
67 ctx->VertexProgram.Current->Base.RefCount++;
68 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
69 ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
70 ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
71 }
72 #endif
73
74 #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
75 ctx->FragmentProgram.Enabled = GL_FALSE;
76 ctx->FragmentProgram.Current = (struct fragment_program *) ctx->Shared->DefaultFragmentProgram;
77 assert(ctx->FragmentProgram.Current);
78 ctx->FragmentProgram.Current->Base.RefCount++;
79 #endif
80 }
81
82
83 /**
84 * Set the vertex/fragment program error state (position and error string).
85 * This is generally called from within the parsers.
86 */
87 void
88 _mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
89 {
90 ctx->Program.ErrorPos = pos;
91 _mesa_free((void *) ctx->Program.ErrorString);
92 if (!string)
93 string = "";
94 ctx->Program.ErrorString = _mesa_strdup(string);
95 }
96
97
98 /**
99 * Find the line number and column for 'pos' within 'string'.
100 * Return a copy of the line which contains 'pos'. Free the line with
101 * _mesa_free().
102 * \param string the program string
103 * \param pos the position within the string
104 * \param line returns the line number corresponding to 'pos'.
105 * \param col returns the column number corresponding to 'pos'.
106 * \return copy of the line containing 'pos'.
107 */
108 const GLubyte *
109 _mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
110 GLint *line, GLint *col)
111 {
112 const GLubyte *lineStart = string;
113 const GLubyte *p = string;
114 GLubyte *s;
115 int len;
116
117 *line = 1;
118
119 while (p != pos) {
120 if (*p == (GLubyte) '\n') {
121 (*line)++;
122 lineStart = p + 1;
123 }
124 p++;
125 }
126
127 *col = (pos - lineStart) + 1;
128
129 /* return copy of this line */
130 while (*p != 0 && *p != '\n')
131 p++;
132 len = p - lineStart;
133 s = (GLubyte *) _mesa_malloc(len + 1);
134 _mesa_memcpy(s, lineStart, len);
135 s[len] = 0;
136
137 return s;
138 }
139
140
141 static struct program * _mesa_init_program_struct( GLcontext *ctx,
142 struct program *prog,
143 GLenum target, GLuint id)
144 {
145 if (prog) {
146 prog->Id = id;
147 prog->Target = target;
148 prog->Resident = GL_TRUE;
149 prog->RefCount = 1;
150 }
151
152 return prog;
153 }
154
155 struct program * _mesa_init_fragment_program( GLcontext *ctx,
156 struct fragment_program *prog,
157 GLenum target, GLuint id)
158 {
159 if (prog)
160 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
161 else
162 return NULL;
163 }
164
165 struct program * _mesa_init_vertex_program( GLcontext *ctx,
166 struct vertex_program *prog,
167 GLenum target, GLuint id)
168 {
169 if (prog)
170 return _mesa_init_program_struct( ctx, &prog->Base, target, id );
171 else
172 return NULL;
173 }
174
175
176 /**
177 * Allocate and initialize a new fragment/vertex program object but
178 * don't put it into the program hash table. Called via
179 * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a
180 * device driver function to implement OO deriviation with additional
181 * types not understood by this function.
182 *
183 * \param ctx context
184 * \param id program id/number
185 * \param target program target/type
186 * \return pointer to new program object
187 */
188 struct program *
189 _mesa_new_program(GLcontext *ctx, GLenum target, GLuint id)
190 {
191 switch (target) {
192 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
193 return _mesa_init_vertex_program( ctx, CALLOC_STRUCT(vertex_program),
194 target, id );
195
196 case GL_FRAGMENT_PROGRAM_NV:
197 case GL_FRAGMENT_PROGRAM_ARB:
198 return _mesa_init_fragment_program( ctx, CALLOC_STRUCT(fragment_program),
199 target, id );
200
201 default:
202 _mesa_problem(ctx, "bad target in _mesa_new_program");
203 return NULL;
204 }
205 }
206
207
208 /**
209 * Delete a program and remove it from the hash table, ignoring the
210 * reference count.
211 * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation)
212 * by a device driver function.
213 */
214 void
215 _mesa_delete_program(GLcontext *ctx, struct program *prog)
216 {
217 ASSERT(prog);
218
219 if (prog->String)
220 _mesa_free(prog->String);
221 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
222 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
223 struct vertex_program *vprog = (struct vertex_program *) prog;
224 if (vprog->Instructions)
225 _mesa_free(vprog->Instructions);
226 }
227 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
228 prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
229 struct fragment_program *fprog = (struct fragment_program *) prog;
230 if (fprog->Instructions)
231 _mesa_free(fprog->Instructions);
232 if (fprog->Parameters) {
233 _mesa_free_parameter_list(fprog->Parameters);
234 }
235 }
236 _mesa_free(prog);
237 }
238
239
240
241 /**********************************************************************/
242 /* Program parameter functions */
243 /**********************************************************************/
244
245 struct program_parameter_list *
246 _mesa_new_parameter_list(void)
247 {
248 return (struct program_parameter_list *)
249 _mesa_calloc(sizeof(struct program_parameter_list));
250 }
251
252
253 /**
254 * Free a parameter list and all its parameters
255 */
256 void
257 _mesa_free_parameter_list(struct program_parameter_list *paramList)
258 {
259 _mesa_free_parameters(paramList);
260 _mesa_free(paramList);
261 }
262
263
264 /**
265 * Free all the parameters in the given list, but don't free the
266 * paramList structure itself.
267 */
268 void
269 _mesa_free_parameters(struct program_parameter_list *paramList)
270 {
271 GLuint i;
272 for (i = 0; i < paramList->NumParameters; i++) {
273 _mesa_free((void *) paramList->Parameters[i].Name);
274 }
275 _mesa_free(paramList->Parameters);
276 paramList->NumParameters = 0;
277 paramList->Parameters = NULL;
278 }
279
280
281 /**
282 * Helper function used by the functions below.
283 */
284 static GLint
285 add_parameter(struct program_parameter_list *paramList,
286 const char *name, const GLfloat values[4],
287 enum parameter_type type)
288 {
289 const GLuint n = paramList->NumParameters;
290
291 paramList->Parameters = (struct program_parameter *)
292 _mesa_realloc(paramList->Parameters,
293 n * sizeof(struct program_parameter),
294 (n + 1) * sizeof(struct program_parameter));
295 if (!paramList->Parameters) {
296 /* out of memory */
297 paramList->NumParameters = 0;
298 return -1;
299 }
300 else {
301 paramList->NumParameters = n + 1;
302 paramList->Parameters[n].Name = _mesa_strdup(name);
303 paramList->Parameters[n].Type = type;
304 if (values)
305 COPY_4V(paramList->Parameters[n].Values, values);
306 return (GLint) n;
307 }
308 }
309
310
311 /**
312 * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
313 * \return index of the new entry in the parameter list
314 */
315 GLint
316 _mesa_add_named_parameter(struct program_parameter_list *paramList,
317 const char *name, const GLfloat values[4])
318 {
319 return add_parameter(paramList, name, values, NAMED_PARAMETER);
320 }
321
322
323 /**
324 * Add a new unnamed constant to the parameter list.
325 * \param paramList - the parameter list
326 * \param values - four float values
327 * \return index of the new parameter.
328 */
329 GLint
330 _mesa_add_named_constant(struct program_parameter_list *paramList,
331 const char *name, const GLfloat values[4])
332 {
333 return add_parameter(paramList, name, values, CONSTANT);
334 }
335
336
337 /**
338 * Add a new unnamed constant to the parameter list.
339 * \param paramList - the parameter list
340 * \param values - four float values
341 * \return index of the new parameter.
342 */
343 GLint
344 _mesa_add_unnamed_constant(struct program_parameter_list *paramList,
345 const GLfloat values[4])
346 {
347 /* generate a new dummy name */
348 static GLuint n = 0;
349 char name[20];
350 _mesa_sprintf(name, "constant%d", n);
351 n++;
352 /* store it */
353 return add_parameter(paramList, name, values, CONSTANT);
354 }
355
356
357 /**
358 * Add a new state reference to the parameter list.
359 * \param paramList - the parameter list
360 * \param state - an array of 6 state tokens
361 *
362 * \return index of the new parameter.
363 */
364 GLint
365 _mesa_add_state_reference(struct program_parameter_list *paramList,
366 GLint *stateTokens)
367 {
368 /* XXX Should we parse <stateString> here and produce the parameter's
369 * list of STATE_* tokens here, or in the parser?
370 */
371 GLint a, idx;
372
373 idx = add_parameter(paramList, "Some State", NULL, STATE);
374
375 for (a=0; a<6; a++)
376 paramList->Parameters[idx].StateIndexes[a] = (enum state_index) stateTokens[a];
377
378 return idx;
379 }
380
381
382 /**
383 * Lookup a parameter value by name in the given parameter list.
384 * \return pointer to the float[4] values.
385 */
386 GLfloat *
387 _mesa_lookup_parameter_value(struct program_parameter_list *paramList,
388 GLsizei nameLen, const char *name)
389 {
390 GLuint i;
391
392 if (!paramList)
393 return NULL;
394
395 if (nameLen == -1) {
396 /* name is null-terminated */
397 for (i = 0; i < paramList->NumParameters; i++) {
398 if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
399 return paramList->Parameters[i].Values;
400 }
401 }
402 else {
403 /* name is not null-terminated, use nameLen */
404 for (i = 0; i < paramList->NumParameters; i++) {
405 if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
406 && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
407 return paramList->Parameters[i].Values;
408 }
409 }
410 return NULL;
411 }
412
413
414 /**
415 * Lookup a parameter index by name in the given parameter list.
416 * \return index of parameter in the list.
417 */
418 GLint
419 _mesa_lookup_parameter_index(struct program_parameter_list *paramList,
420 GLsizei nameLen, const char *name)
421 {
422 GLint i;
423
424 if (!paramList)
425 return -1;
426
427 if (nameLen == -1) {
428 /* name is null-terminated */
429 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
430 if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
431 return i;
432 }
433 }
434 else {
435 /* name is not null-terminated, use nameLen */
436 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
437 if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
438 && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
439 return i;
440 }
441 }
442 return -1;
443 }
444
445
446 /**
447 * Use the list of tokens in the state[] array to find global GL state
448 * and return it in <value>. Usually, four values are returned in <value>
449 * but matrix queries may return as many as 16 values.
450 * This function is used for ARB vertex/fragment programs.
451 * The program parser will produce the state[] values.
452 */
453 static void
454 _mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
455 GLfloat *value)
456 {
457 switch (state[0]) {
458 case STATE_MATERIAL:
459 {
460 /* state[1] is either 0=front or 1=back side */
461 const GLuint face = (GLuint) state[1];
462 /* state[2] is the material attribute */
463 switch (state[2]) {
464 case STATE_AMBIENT:
465 if (face == 0)
466 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
467 else
468 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]);
469 return;
470 case STATE_DIFFUSE:
471 if (face == 0)
472 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]);
473 else
474 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]);
475 return;
476 case STATE_SPECULAR:
477 if (face == 0)
478 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]);
479 else
480 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]);
481 return;
482 case STATE_EMISSION:
483 if (face == 0)
484 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
485 else
486 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]);
487 return;
488 case STATE_SHININESS:
489 if (face == 0)
490 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
491 else
492 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
493 value[1] = 0.0F;
494 value[2] = 0.0F;
495 value[3] = 1.0F;
496 return;
497 default:
498 _mesa_problem(ctx, "Invalid material state in fetch_state");
499 return;
500 }
501 };
502 return;
503 case STATE_LIGHT:
504 {
505 /* state[1] is the light number */
506 const GLuint ln = (GLuint) state[1];
507 /* state[2] is the light attribute */
508 switch (state[2]) {
509 case STATE_AMBIENT:
510 COPY_4V(value, ctx->Light.Light[ln].Ambient);
511 return;
512 case STATE_DIFFUSE:
513 COPY_4V(value, ctx->Light.Light[ln].Diffuse);
514 return;
515 case STATE_SPECULAR:
516 COPY_4V(value, ctx->Light.Light[ln].Specular);
517 return;
518 case STATE_POSITION:
519 COPY_4V(value, ctx->Light.Light[ln].EyePosition);
520 return;
521 case STATE_ATTENUATION:
522 value[0] = ctx->Light.Light[ln].ConstantAttenuation;
523 value[1] = ctx->Light.Light[ln].LinearAttenuation;
524 value[2] = ctx->Light.Light[ln].QuadraticAttenuation;
525 value[3] = ctx->Light.Light[ln].SpotExponent;
526 return;
527 case STATE_SPOT_DIRECTION:
528 COPY_4V(value, ctx->Light.Light[ln].EyeDirection);
529 return;
530 case STATE_HALF:
531 {
532 GLfloat eye_z[] = {0, 0, 1};
533
534 /* Compute infinite half angle vector:
535 * half-vector = light_position + (0, 0, 1)
536 * and then normalize. w = 0
537 *
538 * light.EyePosition.w should be 0 for infinite lights.
539 */
540 ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
541 NORMALIZE_3FV(value);
542 value[3] = 0;
543 }
544 return;
545 default:
546 _mesa_problem(ctx, "Invalid light state in fetch_state");
547 return;
548 }
549 }
550 return;
551 case STATE_LIGHTMODEL_AMBIENT:
552 COPY_4V(value, ctx->Light.Model.Ambient);
553 return;
554 case STATE_LIGHTMODEL_SCENECOLOR:
555 if (state[1] == 0) {
556 /* front */
557 GLint i;
558 for (i = 0; i < 4; i++) {
559 value[i] = ctx->Light.Model.Ambient[i]
560 * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
561 + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
562 }
563 }
564 else {
565 /* back */
566 GLint i;
567 for (i = 0; i < 4; i++) {
568 value[i] = ctx->Light.Model.Ambient[i]
569 * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
570 + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
571 }
572 }
573 return;
574 case STATE_LIGHTPROD:
575 {
576 const GLuint ln = (GLuint) state[1];
577 const GLuint face = (GLuint) state[2];
578 GLint i;
579 ASSERT(face == 0 || face == 1);
580 switch (state[3]) {
581 case STATE_AMBIENT:
582 for (i = 0; i < 3; i++) {
583 value[i] = ctx->Light.Light[ln].Ambient[i] *
584 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i];
585 }
586 /* [3] = material alpha */
587 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
588 return;
589 case STATE_DIFFUSE:
590 for (i = 0; i < 3; i++) {
591 value[i] = ctx->Light.Light[ln].Diffuse[i] *
592 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i];
593 }
594 /* [3] = material alpha */
595 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
596 return;
597 case STATE_SPECULAR:
598 for (i = 0; i < 3; i++) {
599 value[i] = ctx->Light.Light[ln].Specular[i] *
600 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i];
601 }
602 /* [3] = material alpha */
603 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
604 return;
605 default:
606 _mesa_problem(ctx, "Invalid lightprod state in fetch_state");
607 return;
608 }
609 }
610 return;
611 case STATE_TEXGEN:
612 {
613 /* state[1] is the texture unit */
614 const GLuint unit = (GLuint) state[1];
615 /* state[2] is the texgen attribute */
616 switch (state[2]) {
617 case STATE_TEXGEN_EYE_S:
618 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneS);
619 return;
620 case STATE_TEXGEN_EYE_T:
621 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneT);
622 return;
623 case STATE_TEXGEN_EYE_R:
624 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneR);
625 return;
626 case STATE_TEXGEN_EYE_Q:
627 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneQ);
628 return;
629 case STATE_TEXGEN_OBJECT_S:
630 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneS);
631 return;
632 case STATE_TEXGEN_OBJECT_T:
633 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneT);
634 return;
635 case STATE_TEXGEN_OBJECT_R:
636 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneR);
637 return;
638 case STATE_TEXGEN_OBJECT_Q:
639 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneQ);
640 return;
641 default:
642 _mesa_problem(ctx, "Invalid texgen state in fetch_state");
643 return;
644 }
645 }
646 return;
647 case STATE_TEXENV_COLOR:
648 {
649 /* state[1] is the texture unit */
650 const GLuint unit = (GLuint) state[1];
651 COPY_4V(value, ctx->Texture.Unit[unit].EnvColor);
652 }
653 return;
654 case STATE_FOG_COLOR:
655 COPY_4V(value, ctx->Fog.Color);
656 return;
657 case STATE_FOG_PARAMS:
658 value[0] = ctx->Fog.Density;
659 value[1] = ctx->Fog.Start;
660 value[2] = ctx->Fog.End;
661 value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
662 return;
663 case STATE_CLIPPLANE:
664 {
665 const GLuint plane = (GLuint) state[1];
666 COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
667 }
668 return;
669 case STATE_POINT_SIZE:
670 value[0] = ctx->Point.Size;
671 value[1] = ctx->Point.MinSize;
672 value[2] = ctx->Point.MaxSize;
673 value[3] = ctx->Point.Threshold;
674 return;
675 case STATE_POINT_ATTENUATION:
676 value[0] = ctx->Point.Params[0];
677 value[1] = ctx->Point.Params[1];
678 value[2] = ctx->Point.Params[2];
679 value[3] = 1.0F;
680 return;
681 case STATE_MATRIX:
682 {
683 /* state[1] = modelview, projection, texture, etc. */
684 /* state[2] = which texture matrix or program matrix */
685 /* state[3] = first column to fetch */
686 /* state[4] = last column to fetch */
687 /* state[5] = transpose, inverse or invtrans */
688
689 const GLmatrix *matrix;
690 const enum state_index mat = state[1];
691 const GLuint index = (GLuint) state[2];
692 const GLuint first = (GLuint) state[3];
693 const GLuint last = (GLuint) state[4];
694 const enum state_index modifier = state[5];
695 const GLfloat *m;
696 GLuint row, i;
697 if (mat == STATE_MODELVIEW) {
698 matrix = ctx->ModelviewMatrixStack.Top;
699 }
700 else if (mat == STATE_PROJECTION) {
701 matrix = ctx->ProjectionMatrixStack.Top;
702 }
703 else if (mat == STATE_MVP) {
704 matrix = &ctx->_ModelProjectMatrix;
705 }
706 else if (mat == STATE_TEXTURE) {
707 matrix = ctx->TextureMatrixStack[index].Top;
708 }
709 else if (mat == STATE_PROGRAM) {
710 matrix = ctx->ProgramMatrixStack[index].Top;
711 }
712 else {
713 _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()");
714 return;
715 }
716 if (modifier == STATE_MATRIX_INVERSE ||
717 modifier == STATE_MATRIX_INVTRANS) {
718 /* XXX be sure inverse is up to date */
719 m = matrix->inv;
720 }
721 else {
722 m = matrix->m;
723 }
724 if (modifier == STATE_MATRIX_TRANSPOSE ||
725 modifier == STATE_MATRIX_INVTRANS) {
726 for (i = 0, row = first; row <= last; row++) {
727 value[i++] = m[row * 4 + 0];
728 value[i++] = m[row * 4 + 1];
729 value[i++] = m[row * 4 + 2];
730 value[i++] = m[row * 4 + 3];
731 }
732 }
733 else {
734 for (i = 0, row = first; row <= last; row++) {
735 value[i++] = m[row + 0];
736 value[i++] = m[row + 4];
737 value[i++] = m[row + 8];
738 value[i++] = m[row + 12];
739 }
740 }
741 }
742 return;
743 case STATE_DEPTH_RANGE:
744 value[0] = ctx->Viewport.Near; /* near */
745 value[1] = ctx->Viewport.Far; /* far */
746 value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
747 value[3] = 0;
748 return;
749 case STATE_FRAGMENT_PROGRAM:
750 {
751 /* state[1] = {STATE_ENV, STATE_LOCAL} */
752 /* state[2] = parameter index */
753 int idx = state[2];
754
755 switch (state[1]) {
756 case STATE_ENV:
757 COPY_4V(value, ctx->FragmentProgram.Parameters[idx]);
758 break;
759
760 case STATE_LOCAL:
761 COPY_4V(value, ctx->FragmentProgram.Current->Base.LocalParams[idx]);
762 break;
763 default:
764 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
765 return;
766 }
767 }
768 return;
769
770 case STATE_VERTEX_PROGRAM:
771 {
772 /* state[1] = {STATE_ENV, STATE_LOCAL} */
773 /* state[2] = parameter index */
774 int idx = state[2];
775
776 switch (state[1]) {
777 case STATE_ENV:
778 COPY_4V(value, ctx->VertexProgram.Parameters[idx]);
779 break;
780
781 case STATE_LOCAL:
782 COPY_4V(value, ctx->VertexProgram.Current->Base.LocalParams[idx]);
783 break;
784 default:
785 _mesa_problem(ctx, "Bad state switch in _mesa_fetch_state()");
786 return;
787 }
788 }
789 return;
790 default:
791 _mesa_problem(ctx, "Invalid state in fetch_state");
792 return;
793 }
794 }
795
796
797 /**
798 * Loop over all the parameters in a parameter list. If the parameter
799 * is a GL state reference, look up the current value of that state
800 * variable and put it into the parameter's Value[4] array.
801 * This would be called at glBegin time when using a fragment program.
802 */
803 void
804 _mesa_load_state_parameters(GLcontext *ctx,
805 struct program_parameter_list *paramList)
806 {
807 GLuint i;
808
809 if (!paramList)
810 return;
811
812 for (i = 0; i < paramList->NumParameters; i++) {
813 if (paramList->Parameters[i].Type == STATE) {
814 _mesa_fetch_state(ctx, paramList->Parameters[i].StateIndexes,
815 paramList->Parameters[i].Values);
816 }
817 }
818 }
819
820
821
822 /**********************************************************************/
823 /* API functions */
824 /**********************************************************************/
825
826
827 /**
828 * Bind a program (make it current)
829 * \note Called from the GL API dispatcher by both glBindProgramNV
830 * and glBindProgramARB.
831 */
832 void GLAPIENTRY
833 _mesa_BindProgram(GLenum target, GLuint id)
834 {
835 struct program *prog;
836 GET_CURRENT_CONTEXT(ctx);
837 ASSERT_OUTSIDE_BEGIN_END(ctx);
838
839 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
840
841 if ((target == GL_VERTEX_PROGRAM_NV
842 && ctx->Extensions.NV_vertex_program) ||
843 (target == GL_VERTEX_PROGRAM_ARB
844 && ctx->Extensions.ARB_vertex_program)) {
845 if (ctx->VertexProgram.Current &&
846 ctx->VertexProgram.Current->Base.Id == id)
847 return;
848 /* decrement refcount on previously bound vertex program */
849 if (ctx->VertexProgram.Current) {
850 ctx->VertexProgram.Current->Base.RefCount--;
851 /* and delete if refcount goes below one */
852 if (ctx->VertexProgram.Current->Base.RefCount <= 0) {
853 ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base));
854 _mesa_HashRemove(ctx->Shared->Programs, id);
855 }
856 }
857 }
858 else if ((target == GL_FRAGMENT_PROGRAM_NV
859 && ctx->Extensions.NV_fragment_program) ||
860 (target == GL_FRAGMENT_PROGRAM_ARB
861 && ctx->Extensions.ARB_fragment_program)) {
862 if (ctx->FragmentProgram.Current &&
863 ctx->FragmentProgram.Current->Base.Id == id)
864 return;
865 /* decrement refcount on previously bound fragment program */
866 if (ctx->FragmentProgram.Current) {
867 ctx->FragmentProgram.Current->Base.RefCount--;
868 /* and delete if refcount goes below one */
869 if (ctx->FragmentProgram.Current->Base.RefCount <= 0) {
870 ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base));
871 _mesa_HashRemove(ctx->Shared->Programs, id);
872 }
873 }
874 }
875 else {
876 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
877 return;
878 }
879
880 /* NOTE: binding to a non-existant program is not an error.
881 * That's supposed to be caught in glBegin.
882 */
883 if (id == 0) {
884 /* default program */
885 prog = NULL;
886 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB)
887 prog = ctx->Shared->DefaultVertexProgram;
888 else
889 prog = ctx->Shared->DefaultFragmentProgram;
890 }
891 else {
892 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
893 if (prog) {
894 if (prog->Target == 0) {
895 /* prog was allocated with glGenProgramsNV */
896 prog->Target = target;
897 }
898 else if (prog->Target != target) {
899 _mesa_error(ctx, GL_INVALID_OPERATION,
900 "glBindProgramNV/ARB(target mismatch)");
901 return;
902 }
903 }
904 else {
905 /* allocate a new program now */
906 prog = ctx->Driver.NewProgram(ctx, target, id);
907 if (!prog) {
908 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
909 return;
910 }
911 prog->Id = id;
912 prog->Target = target;
913 prog->Resident = GL_TRUE;
914 prog->RefCount = 1;
915 _mesa_HashInsert(ctx->Shared->Programs, id, prog);
916 }
917 }
918
919 /* bind now */
920 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) {
921 ctx->VertexProgram.Current = (struct vertex_program *) prog;
922 }
923 else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
924 ctx->FragmentProgram.Current = (struct fragment_program *) prog;
925 }
926
927 if (prog)
928 prog->RefCount++;
929
930 if (ctx->Driver.BindProgram)
931 ctx->Driver.BindProgram(ctx, target, prog);
932 }
933
934
935 /**
936 * Delete a list of programs.
937 * \note Not compiled into display lists.
938 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
939 */
940 void GLAPIENTRY
941 _mesa_DeletePrograms(GLsizei n, const GLuint *ids)
942 {
943 GLint i;
944 GET_CURRENT_CONTEXT(ctx);
945 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
946
947 if (n < 0) {
948 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
949 return;
950 }
951
952 for (i = 0; i < n; i++) {
953 if (ids[i] != 0) {
954 struct program *prog = (struct program *)
955 _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
956 if (prog) {
957 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
958 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
959 if (ctx->VertexProgram.Current &&
960 ctx->VertexProgram.Current->Base.Id == ids[i]) {
961 /* unbind this currently bound program */
962 _mesa_BindProgram(prog->Target, 0);
963 }
964 }
965 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
966 prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
967 if (ctx->FragmentProgram.Current &&
968 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
969 /* unbind this currently bound program */
970 _mesa_BindProgram(prog->Target, 0);
971 }
972 }
973 else {
974 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
975 return;
976 }
977 prog->RefCount--;
978 if (prog->RefCount <= 0) {
979 ctx->Driver.DeleteProgram(ctx, prog);
980 }
981 }
982 else {
983 /* This is necessary as we can't tell from HashLookup
984 * whether the entry exists with data == 0, or if it
985 * doesn't exist at all. As GenPrograms creates the first
986 * case below, need to call Remove() to avoid memory leak:
987 */
988 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
989 }
990 }
991 }
992 }
993
994
995 /**
996 * Generate a list of new program identifiers.
997 * \note Not compiled into display lists.
998 * \note Called by both glGenProgramsNV and glGenProgramsARB.
999 */
1000 void GLAPIENTRY
1001 _mesa_GenPrograms(GLsizei n, GLuint *ids)
1002 {
1003 GLuint first;
1004 GLuint i;
1005 GET_CURRENT_CONTEXT(ctx);
1006 ASSERT_OUTSIDE_BEGIN_END(ctx);
1007
1008 if (n < 0) {
1009 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
1010 return;
1011 }
1012
1013 if (!ids)
1014 return;
1015
1016 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
1017
1018 for (i = 0; i < (GLuint) n; i++) {
1019 _mesa_HashInsert(ctx->Shared->Programs, first + i, 0);
1020 }
1021
1022 /* Return the program names */
1023 for (i = 0; i < (GLuint) n; i++) {
1024 ids[i] = first + i;
1025 }
1026 }
1027
1028
1029 /**
1030 * Determine if id names a program.
1031 * \note Not compiled into display lists.
1032 * \note Called from both glIsProgramNV and glIsProgramARB.
1033 * \param id is the program identifier
1034 * \return GL_TRUE if id is a program, else GL_FALSE.
1035 */
1036 GLboolean GLAPIENTRY
1037 _mesa_IsProgram(GLuint id)
1038 {
1039 GET_CURRENT_CONTEXT(ctx);
1040 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1041
1042 if (id == 0)
1043 return GL_FALSE;
1044
1045 if (_mesa_HashLookup(ctx->Shared->Programs, id))
1046 return GL_TRUE;
1047 else
1048 return GL_FALSE;
1049 }
1050
1051
1052
1053 /**********************************************************************/
1054 /* GL_MESA_program_debug extension */
1055 /**********************************************************************/
1056
1057
1058 /* XXX temporary */
1059 void
1060 glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1061 GLvoid *data)
1062 {
1063 _mesa_ProgramCallbackMESA(target, callback, data);
1064 }
1065
1066
1067 void
1068 _mesa_ProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback,
1069 GLvoid *data)
1070 {
1071 GET_CURRENT_CONTEXT(ctx);
1072
1073 switch (target) {
1074 case GL_FRAGMENT_PROGRAM_ARB:
1075 if (!ctx->Extensions.ARB_fragment_program) {
1076 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1077 return;
1078 }
1079 ctx->FragmentProgram.Callback = callback;
1080 ctx->FragmentProgram.CallbackData = data;
1081 break;
1082 case GL_FRAGMENT_PROGRAM_NV:
1083 if (!ctx->Extensions.NV_fragment_program) {
1084 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1085 return;
1086 }
1087 ctx->FragmentProgram.Callback = callback;
1088 ctx->FragmentProgram.CallbackData = data;
1089 break;
1090 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
1091 if (!ctx->Extensions.ARB_vertex_program &&
1092 !ctx->Extensions.NV_vertex_program) {
1093 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1094 return;
1095 }
1096 ctx->VertexProgram.Callback = callback;
1097 ctx->VertexProgram.CallbackData = data;
1098 break;
1099 default:
1100 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramCallbackMESA(target)");
1101 return;
1102 }
1103 }
1104
1105
1106 /* XXX temporary */
1107 void
1108 glGetProgramRegisterfvMESA(GLenum target,
1109 GLsizei len, const GLubyte *registerName,
1110 GLfloat *v)
1111 {
1112 _mesa_GetProgramRegisterfvMESA(target, len, registerName, v);
1113 }
1114
1115
1116 void
1117 _mesa_GetProgramRegisterfvMESA(GLenum target,
1118 GLsizei len, const GLubyte *registerName,
1119 GLfloat *v)
1120 {
1121 char reg[1000];
1122 GET_CURRENT_CONTEXT(ctx);
1123
1124 /* We _should_ be inside glBegin/glEnd */
1125 #if 0
1126 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
1127 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramRegisterfvMESA");
1128 return;
1129 }
1130 #endif
1131
1132 /* make null-terminated copy of registerName */
1133 len = MIN2((unsigned int) len, sizeof(reg) - 1);
1134 _mesa_memcpy(reg, registerName, len);
1135 reg[len] = 0;
1136
1137 switch (target) {
1138 case GL_VERTEX_PROGRAM_NV:
1139 if (!ctx->Extensions.ARB_vertex_program &&
1140 !ctx->Extensions.NV_vertex_program) {
1141 _mesa_error(ctx, GL_INVALID_ENUM,
1142 "glGetProgramRegisterfvMESA(target)");
1143 return;
1144 }
1145 if (!ctx->VertexProgram.Enabled) {
1146 _mesa_error(ctx, GL_INVALID_OPERATION,
1147 "glGetProgramRegisterfvMESA");
1148 return;
1149 }
1150 /* GL_NV_vertex_program */
1151 if (reg[0] == 'R') {
1152 /* Temp register */
1153 GLint i = _mesa_atoi(reg + 1);
1154 if (i >= (GLint)ctx->Const.MaxVertexProgramTemps) {
1155 _mesa_error(ctx, GL_INVALID_VALUE,
1156 "glGetProgramRegisterfvMESA(registerName)");
1157 return;
1158 }
1159 COPY_4V(v, ctx->VertexProgram.Temporaries[i]);
1160 }
1161 else if (reg[0] == 'v' && reg[1] == '[') {
1162 /* Vertex Input attribute */
1163 GLuint i;
1164 for (i = 0; i < ctx->Const.MaxVertexProgramAttribs; i++) {
1165 const char *name = _mesa_nv_vertex_input_register_name(i);
1166 char number[10];
1167 sprintf(number, "%d", i);
1168 if (_mesa_strncmp(reg + 2, name, 4) == 0 ||
1169 _mesa_strncmp(reg + 2, number, _mesa_strlen(number)) == 0) {
1170 COPY_4V(v, ctx->VertexProgram.Inputs[i]);
1171 return;
1172 }
1173 }
1174 _mesa_error(ctx, GL_INVALID_VALUE,
1175 "glGetProgramRegisterfvMESA(registerName)");
1176 return;
1177 }
1178 else if (reg[0] == 'o' && reg[1] == '[') {
1179 /* Vertex output attribute */
1180 }
1181 /* GL_ARB_vertex_program */
1182 else if (_mesa_strncmp(reg, "vertex.", 7) == 0) {
1183
1184 }
1185 else {
1186 _mesa_error(ctx, GL_INVALID_VALUE,
1187 "glGetProgramRegisterfvMESA(registerName)");
1188 return;
1189 }
1190 break;
1191 case GL_FRAGMENT_PROGRAM_ARB:
1192 if (!ctx->Extensions.ARB_fragment_program) {
1193 _mesa_error(ctx, GL_INVALID_ENUM,
1194 "glGetProgramRegisterfvMESA(target)");
1195 return;
1196 }
1197 if (!ctx->FragmentProgram.Enabled) {
1198 _mesa_error(ctx, GL_INVALID_OPERATION,
1199 "glGetProgramRegisterfvMESA");
1200 return;
1201 }
1202 /* XXX to do */
1203 break;
1204 case GL_FRAGMENT_PROGRAM_NV:
1205 if (!ctx->Extensions.NV_fragment_program) {
1206 _mesa_error(ctx, GL_INVALID_ENUM,
1207 "glGetProgramRegisterfvMESA(target)");
1208 return;
1209 }
1210 if (!ctx->FragmentProgram.Enabled) {
1211 _mesa_error(ctx, GL_INVALID_OPERATION,
1212 "glGetProgramRegisterfvMESA");
1213 return;
1214 }
1215 if (reg[0] == 'R') {
1216 /* Temp register */
1217 GLint i = _mesa_atoi(reg + 1);
1218 if (i >= (GLint)ctx->Const.MaxFragmentProgramTemps) {
1219 _mesa_error(ctx, GL_INVALID_VALUE,
1220 "glGetProgramRegisterfvMESA(registerName)");
1221 return;
1222 }
1223 COPY_4V(v, ctx->FragmentProgram.Machine.Temporaries[i]);
1224 }
1225 else if (reg[0] == 'f' && reg[1] == '[') {
1226 /* Fragment input attribute */
1227 GLuint i;
1228 for (i = 0; i < ctx->Const.MaxFragmentProgramAttribs; i++) {
1229 const char *name = _mesa_nv_fragment_input_register_name(i);
1230 if (_mesa_strncmp(reg + 2, name, 4) == 0) {
1231 COPY_4V(v, ctx->FragmentProgram.Machine.Inputs[i]);
1232 return;
1233 }
1234 }
1235 _mesa_error(ctx, GL_INVALID_VALUE,
1236 "glGetProgramRegisterfvMESA(registerName)");
1237 return;
1238 }
1239 else if (_mesa_strcmp(reg, "o[COLR]") == 0) {
1240 /* Fragment output color */
1241 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_COLR]);
1242 }
1243 else if (_mesa_strcmp(reg, "o[COLH]") == 0) {
1244 /* Fragment output color */
1245 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_COLH]);
1246 }
1247 else if (_mesa_strcmp(reg, "o[DEPR]") == 0) {
1248 /* Fragment output depth */
1249 COPY_4V(v, ctx->FragmentProgram.Machine.Outputs[FRAG_OUTPUT_DEPR]);
1250 }
1251 else {
1252 /* try user-defined identifiers */
1253 const GLfloat *value = _mesa_lookup_parameter_value(
1254 ctx->FragmentProgram.Current->Parameters, -1, reg);
1255 if (value) {
1256 COPY_4V(v, value);
1257 }
1258 else {
1259 _mesa_error(ctx, GL_INVALID_VALUE,
1260 "glGetProgramRegisterfvMESA(registerName)");
1261 return;
1262 }
1263 }
1264 break;
1265 default:
1266 _mesa_error(ctx, GL_INVALID_ENUM,
1267 "glGetProgramRegisterfvMESA(target)");
1268 return;
1269 }
1270
1271 }