fix fog.End error
[mesa.git] / src / mesa / main / program.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 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
40
41 /**********************************************************************/
42 /* Utility functions */
43 /**********************************************************************/
44
45
46 /**
47 * Init context's program state
48 */
49 void
50 _mesa_init_program(GLcontext *ctx)
51 {
52 GLuint i;
53
54 ctx->Program.ErrorPos = -1;
55 ctx->Program.ErrorString = _mesa_strdup("");
56
57 #if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program
58 ctx->VertexProgram.Enabled = GL_FALSE;
59 ctx->VertexProgram.PointSizeEnabled = GL_FALSE;
60 ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
61 ctx->VertexProgram.Current = NULL;
62 ctx->VertexProgram.Current = (struct vertex_program *) ctx->Shared->DefaultVertexProgram;
63 assert(ctx->VertexProgram.Current);
64 ctx->VertexProgram.Current->Base.RefCount++;
65 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
66 ctx->VertexProgram.TrackMatrix[i] = GL_NONE;
67 ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV;
68 }
69 #endif
70
71 #if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program
72 ctx->FragmentProgram.Enabled = GL_FALSE;
73 ctx->FragmentProgram.Current = (struct fragment_program *) ctx->Shared->DefaultFragmentProgram;
74 assert(ctx->FragmentProgram.Current);
75 ctx->FragmentProgram.Current->Base.RefCount++;
76 #endif
77 }
78
79
80 /**
81 * Set the vertex/fragment program error state (position and error string).
82 * This is generally called from within the parsers.
83 */
84 void
85 _mesa_set_program_error(GLcontext *ctx, GLint pos, const char *string)
86 {
87 ctx->Program.ErrorPos = pos;
88 _mesa_free((void *) ctx->Program.ErrorString);
89 if (!string)
90 string = "";
91 ctx->Program.ErrorString = _mesa_strdup(string);
92 }
93
94
95 /**
96 * Find the line number and column for 'pos' within 'string'.
97 * Return a copy of the line which contains 'pos'. Free the line with
98 * _mesa_free().
99 * \param string the program string
100 * \param pos the position within the string
101 * \param line returns the line number corresponding to 'pos'.
102 * \param col returns the column number corresponding to 'pos'.
103 * \return copy of the line containing 'pos'.
104 */
105 const GLubyte *
106 _mesa_find_line_column(const GLubyte *string, const GLubyte *pos,
107 GLint *line, GLint *col)
108 {
109 const GLubyte *lineStart = string;
110 const GLubyte *p = string;
111 GLubyte *s;
112 int len;
113
114 *line = 1;
115
116 while (p != pos) {
117 if (*p == (GLubyte) '\n') {
118 (*line)++;
119 lineStart = p + 1;
120 }
121 p++;
122 }
123
124 *col = (pos - lineStart) + 1;
125
126 /* return copy of this line */
127 while (*p != 0 && *p != '\n')
128 p++;
129 len = p - lineStart;
130 s = (GLubyte *) _mesa_malloc(len + 1);
131 _mesa_memcpy(s, lineStart, len);
132 s[len] = 0;
133
134 return s;
135 }
136
137
138
139 /**
140 * Allocate and initialize a new fragment/vertex program object
141 * \param ctx context
142 * \param id program id/number
143 * \param target program target/type
144 * \return pointer to new program object
145 */
146 struct program *
147 _mesa_alloc_program(GLcontext *ctx, GLenum target, GLuint id)
148 {
149 struct program *prog;
150
151 if (target == GL_VERTEX_PROGRAM_NV
152 || target == GL_VERTEX_PROGRAM_ARB) {
153 struct vertex_program *vprog = CALLOC_STRUCT(vertex_program);
154 if (!vprog) {
155 return NULL;
156 }
157 prog = &(vprog->Base);
158 }
159 else if (target == GL_FRAGMENT_PROGRAM_NV
160 || target == GL_FRAGMENT_PROGRAM_ARB) {
161 struct fragment_program *fprog = CALLOC_STRUCT(fragment_program);
162 if (!fprog) {
163 return NULL;
164 }
165 prog = &(fprog->Base);
166 }
167 else {
168 _mesa_problem(ctx, "bad target in _mesa_alloc_program");
169 return NULL;
170 }
171 prog->Id = id;
172 prog->Target = target;
173 prog->Resident = GL_TRUE;
174 prog->RefCount = 1;
175 return prog;
176 }
177
178
179 /**
180 * Delete a program and remove it from the hash table, ignoring the
181 * reference count.
182 * \note Called from the GL API dispatcher.
183 */
184 void
185 _mesa_delete_program(GLcontext *ctx, struct program *prog)
186 {
187 ASSERT(prog);
188
189 if (prog->String)
190 _mesa_free(prog->String);
191 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
192 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
193 struct vertex_program *vprog = (struct vertex_program *) prog;
194 if (vprog->Instructions)
195 _mesa_free(vprog->Instructions);
196 }
197 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) {
198 struct fragment_program *fprog = (struct fragment_program *) prog;
199 if (fprog->Instructions)
200 _mesa_free(fprog->Instructions);
201 if (fprog->Parameters) {
202 _mesa_free_parameter_list(fprog->Parameters);
203 }
204 }
205 _mesa_free(prog);
206 }
207
208
209
210 /**********************************************************************/
211 /* Program parameter functions */
212 /**********************************************************************/
213
214 struct program_parameter_list *
215 _mesa_new_parameter_list(void)
216 {
217 return (struct program_parameter_list *)
218 _mesa_calloc(sizeof(struct program_parameter_list));
219 }
220
221
222 /**
223 * Free a parameter list and all its parameters
224 */
225 void
226 _mesa_free_parameter_list(struct program_parameter_list *paramList)
227 {
228 _mesa_free_parameters(paramList);
229 _mesa_free(paramList);
230 }
231
232
233 /**
234 * Free all the parameters in the given list, but don't free the
235 * paramList structure itself.
236 */
237 void
238 _mesa_free_parameters(struct program_parameter_list *paramList)
239 {
240 GLuint i;
241 for (i = 0; i < paramList->NumParameters; i++) {
242 _mesa_free((void *) paramList->Parameters[i].Name);
243 }
244 _mesa_free(paramList->Parameters);
245 paramList->NumParameters = 0;
246 paramList->Parameters = NULL;
247 }
248
249
250 /**
251 * Helper function used by the functions below.
252 */
253 static GLint
254 add_parameter(struct program_parameter_list *paramList,
255 const char *name, const GLfloat values[4],
256 enum parameter_type type)
257 {
258 const GLuint n = paramList->NumParameters;
259
260 paramList->Parameters = _mesa_realloc(paramList->Parameters,
261 n * sizeof(struct program_parameter),
262 (n + 1) * sizeof(struct program_parameter));
263 if (!paramList->Parameters) {
264 /* out of memory */
265 paramList->NumParameters = 0;
266 return -1;
267 }
268 else {
269 paramList->NumParameters = n + 1;
270 paramList->Parameters[n].Name = _mesa_strdup(name);
271 paramList->Parameters[n].Type = type;
272 if (values)
273 COPY_4V(paramList->Parameters[n].Values, values);
274 return (GLint) n;
275 }
276 }
277
278
279 /**
280 * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
281 * \return index of the new entry in the parameter list
282 */
283 GLint
284 _mesa_add_named_parameter(struct program_parameter_list *paramList,
285 const char *name, const GLfloat values[4])
286 {
287 return add_parameter(paramList, name, values, NAMED_PARAMETER);
288 }
289
290
291 /**
292 * Add a new unnamed constant to the parameter list.
293 * \param paramList - the parameter list
294 * \param values - four float values
295 * \return index of the new parameter.
296 */
297 GLint
298 _mesa_add_named_constant(struct program_parameter_list *paramList,
299 const char *name, const GLfloat values[4])
300 {
301 return add_parameter(paramList, name, values, CONSTANT);
302 }
303
304
305 /**
306 * Add a new unnamed constant to the parameter list.
307 * \param paramList - the parameter list
308 * \param values - four float values
309 * \return index of the new parameter.
310 */
311 GLint
312 _mesa_add_unnamed_constant(struct program_parameter_list *paramList,
313 const GLfloat values[4])
314 {
315 /* generate a new dummy name */
316 static GLuint n = 0;
317 char name[20];
318 _mesa_sprintf(name, "constant%d", n);
319 n++;
320 /* store it */
321 return add_parameter(paramList, name, values, CONSTANT);
322 }
323
324
325 /**
326 * Add a new state reference to the parameter list.
327 * \param paramList - the parameter list
328 * \param values - four float values
329 * \return index of the new parameter.
330 */
331 GLint
332 _mesa_add_state_reference(struct program_parameter_list *paramList,
333 const char *stateString)
334 {
335 /* XXX Should we parse <stateString> here and produce the parameter's
336 * list of STATE_* tokens here, or in the parser?
337 */
338 return add_parameter(paramList, stateString, NULL, STATE);
339 }
340
341
342 /**
343 * Lookup a parameter value by name in the given parameter list.
344 * \return pointer to the float[4] values.
345 */
346 GLfloat *
347 _mesa_lookup_parameter_value(struct program_parameter_list *paramList,
348 GLsizei nameLen, const char *name)
349 {
350 GLuint i;
351
352 if (nameLen == -1) {
353 /* name is null-terminated */
354 for (i = 0; i < paramList->NumParameters; i++) {
355 if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
356 return paramList->Parameters[i].Values;
357 }
358 }
359 else {
360 /* name is not null-terminated, use nameLen */
361 for (i = 0; i < paramList->NumParameters; i++) {
362 if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
363 && _mesa_strlen(paramList->Parameters[i].Name) == nameLen)
364 return paramList->Parameters[i].Values;
365 }
366 }
367 return NULL;
368 }
369
370
371 /**
372 * Lookup a parameter index by name in the given parameter list.
373 * \return index of parameter in the list.
374 */
375 GLint
376 _mesa_lookup_parameter_index(struct program_parameter_list *paramList,
377 GLsizei nameLen, const char *name)
378 {
379 GLint i;
380
381 if (nameLen == -1) {
382 /* name is null-terminated */
383 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
384 if (_mesa_strcmp(paramList->Parameters[i].Name, name) == 0)
385 return i;
386 }
387 }
388 else {
389 /* name is not null-terminated, use nameLen */
390 for (i = 0; i < (GLint) paramList->NumParameters; i++) {
391 if (_mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
392 && _mesa_strlen(paramList->Parameters[i].Name) == nameLen)
393 return i;
394 }
395 }
396 return -1;
397 }
398
399
400 /**
401 * Use the list of tokens in the state[] array to find global GL state
402 * and return it in <value>. Usually, four values are returned in <value>
403 * but matrix queries may return as many as 16 values.
404 * This function is used for ARB vertex/fragment programs.
405 * The program parser will produce the state[] values.
406 */
407 static void
408 _mesa_fetch_state(GLcontext *ctx, const enum state_index state[],
409 GLfloat *value)
410 {
411 switch (state[0]) {
412 case STATE_MATERIAL:
413 {
414 /* state[1] is either 0=front or 1=back side */
415 const GLuint face = (GLuint) state[1];
416 /* state[2] is the material attribute */
417 switch (state[2]) {
418 case STATE_AMBIENT:
419 if (face == 0)
420 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]);
421 else
422 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT]);
423 return;
424 case STATE_DIFFUSE:
425 if (face == 0)
426 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE]);
427 else
428 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE]);
429 return;
430 case STATE_SPECULAR:
431 if (face == 0)
432 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR]);
433 else
434 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SPECULAR]);
435 return;
436 case STATE_EMISSION:
437 if (face == 0)
438 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]);
439 else
440 COPY_4V(value, ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION]);
441 return;
442 case STATE_SHININESS:
443 if (face == 0)
444 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
445 else
446 value[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
447 value[1] = 0.0F;
448 value[2] = 0.0F;
449 value[3] = 1.0F;
450 return;
451 default:
452 _mesa_problem(ctx, "Invalid material state in fetch_state");
453 return;
454 }
455 };
456 return;
457 case STATE_LIGHT:
458 {
459 /* state[1] is the light number */
460 const GLuint ln = (GLuint) state[1];
461 /* state[2] is the light attribute */
462 switch (state[2]) {
463 case STATE_AMBIENT:
464 COPY_4V(value, ctx->Light.Light[ln].Ambient);
465 return;
466 case STATE_DIFFUSE:
467 COPY_4V(value, ctx->Light.Light[ln].Diffuse);
468 return;
469 case STATE_SPECULAR:
470 COPY_4V(value, ctx->Light.Light[ln].Specular);
471 return;
472 case STATE_POSITION:
473 COPY_4V(value, ctx->Light.Light[ln].EyePosition);
474 return;
475 case STATE_ATTENUATION:
476 value[0] = ctx->Light.Light[ln].ConstantAttenuation;
477 value[1] = ctx->Light.Light[ln].LinearAttenuation;
478 value[2] = ctx->Light.Light[ln].QuadraticAttenuation;
479 value[3] = ctx->Light.Light[ln].SpotExponent;
480 return;
481 case STATE_SPOT_DIRECTION:
482 COPY_4V(value, ctx->Light.Light[ln].EyeDirection);
483 return;
484 default:
485 _mesa_problem(ctx, "Invalid light state in fetch_state");
486 return;
487 }
488 }
489 return;
490 case STATE_LIGHTMODEL_AMBIENT:
491 COPY_4V(value, ctx->Light.Model.Ambient);
492 return;
493 case STATE_LIGHTMODEL_SCENECOLOR:
494 if (state[1] == 0) {
495 /* front */
496 GLint i;
497 for (i = 0; i < 4; i++) {
498 value[i] = ctx->Light.Model.Ambient[i]
499 * ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT][i]
500 + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION][i];
501 }
502 }
503 else {
504 /* back */
505 GLint i;
506 for (i = 0; i < 4; i++) {
507 value[i] = ctx->Light.Model.Ambient[i]
508 * ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_AMBIENT][i]
509 + ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_EMISSION][i];
510 }
511 }
512 return;
513 case STATE_LIGHTPROD:
514 {
515 const GLuint ln = (GLuint) state[1];
516 const GLuint face = (GLuint) state[2];
517 GLint i;
518 ASSERT(face == 0 || face == 1);
519 switch (state[3]) {
520 case STATE_AMBIENT:
521 for (i = 0; i < 3; i++) {
522 value[i] = ctx->Light.Light[ln].Ambient[i] *
523 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i];
524 }
525 /* [3] = material alpha */
526 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
527 return;
528 case STATE_DIFFUSE:
529 for (i = 0; i < 3; i++) {
530 value[i] = ctx->Light.Light[ln].Diffuse[i] *
531 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][i];
532 }
533 /* [3] = material alpha */
534 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
535 return;
536 case STATE_SPECULAR:
537 for (i = 0; i < 3; i++) {
538 value[i] = ctx->Light.Light[ln].Specular[i] *
539 ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i];
540 }
541 /* [3] = material alpha */
542 value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
543 return;
544 default:
545 _mesa_problem(ctx, "Invalid lightprod state in fetch_state");
546 return;
547 }
548 }
549 return;
550 case STATE_TEXGEN:
551 {
552 /* state[1] is the texture unit */
553 const GLuint unit = (GLuint) state[1];
554 /* state[2] is the texgen attribute */
555 switch (state[2]) {
556 case STATE_TEXGEN_EYE_S:
557 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneS);
558 return;
559 case STATE_TEXGEN_EYE_T:
560 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneT);
561 return;
562 case STATE_TEXGEN_EYE_R:
563 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneR);
564 return;
565 case STATE_TEXGEN_EYE_Q:
566 COPY_4V(value, ctx->Texture.Unit[unit].EyePlaneQ);
567 return;
568 case STATE_TEXGEN_OBJECT_S:
569 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneS);
570 return;
571 case STATE_TEXGEN_OBJECT_T:
572 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneT);
573 return;
574 case STATE_TEXGEN_OBJECT_R:
575 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneR);
576 return;
577 case STATE_TEXGEN_OBJECT_Q:
578 COPY_4V(value, ctx->Texture.Unit[unit].ObjectPlaneQ);
579 return;
580 default:
581 _mesa_problem(ctx, "Invalid texgen state in fetch_state");
582 return;
583 }
584 }
585 return;
586 case STATE_FOG_COLOR:
587 COPY_4V(value, ctx->Fog.Color);
588 return;
589 case STATE_FOG_PARAMS:
590 value[0] = ctx->Fog.Density;
591 value[1] = ctx->Fog.Start;
592 value[2] = ctx->Fog.End;
593 value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
594 return;
595 case STATE_CLIPPLANE:
596 {
597 const GLuint plane = (GLuint) state[1];
598 COPY_4V(value, ctx->Transform.EyeUserPlane[plane]);
599 }
600 return;
601 case STATE_POINT_SIZE:
602 value[0] = ctx->Point.Size;
603 value[1] = ctx->Point.MinSize;
604 value[2] = ctx->Point.MaxSize;
605 value[3] = ctx->Point.Threshold;
606 return;
607 case STATE_POINT_ATTENUATION:
608 value[0] = ctx->Point.Params[0];
609 value[1] = ctx->Point.Params[1];
610 value[2] = ctx->Point.Params[2];
611 value[3] = 1.0F;
612 return;
613 case STATE_MATRIX:
614 {
615 /* state[1] = modelview, projection, texture, etc. */
616 /* state[2] = which texture matrix or program matrix */
617 /* state[3] = first column to fetch */
618 /* state[4] = last column to fetch */
619 /* state[5] = transpose, inverse or invtrans */
620
621 const GLmatrix *matrix;
622 const enum state_index mat = state[1];
623 const GLuint index = (GLuint) state[2];
624 const GLuint first = (GLuint) state[3];
625 const GLuint last = (GLuint) state[4];
626 const enum state_index modifier = state[5];
627 const GLfloat *m;
628 GLuint row, i;
629 if (mat == STATE_MODELVIEW) {
630 matrix = ctx->ModelviewMatrixStack.Top;
631 }
632 else if (mat == STATE_PROJECTION) {
633 matrix = ctx->ProjectionMatrixStack.Top;
634 }
635 else if (mat == STATE_MVP) {
636 matrix = &ctx->_ModelProjectMatrix;
637 }
638 else if (mat == STATE_TEXTURE) {
639 matrix = ctx->TextureMatrixStack[index].Top;
640 }
641 else if (mat == STATE_PROGRAM) {
642 matrix = ctx->ProgramMatrixStack[index].Top;
643 }
644 else {
645 _mesa_problem(ctx, "Bad matrix name in _mesa_fetch_state()");
646 return;
647 }
648 if (modifier == STATE_MATRIX_INVERSE ||
649 modifier == STATE_MATRIX_INVTRANS) {
650 /* XXX be sure inverse is up to date */
651 m = matrix->inv;
652 }
653 else {
654 m = matrix->m;
655 }
656 if (modifier == STATE_MATRIX_TRANSPOSE ||
657 modifier == STATE_MATRIX_INVTRANS) {
658 for (i = 0, row = first; row <= last; row++) {
659 value[i++] = m[row * 4 + 0];
660 value[i++] = m[row * 4 + 1];
661 value[i++] = m[row * 4 + 2];
662 value[i++] = m[row * 4 + 3];
663 }
664 }
665 else {
666 for (i = 0, row = first; row <= last; row++) {
667 value[i++] = m[row + 0];
668 value[i++] = m[row + 4];
669 value[i++] = m[row + 8];
670 value[i++] = m[row + 12];
671 }
672 }
673 }
674 return;
675 default:
676 _mesa_problem(ctx, "Invalid state in fetch_state");
677 return;
678 }
679 }
680
681
682 /**
683 * Loop over all the parameters in a parameter list. If the parameter
684 * is a GL state reference, look up the current value of that state
685 * variable and put it into the parameter's Value[4] array.
686 * This would be called at glBegin time when using a fragment program.
687 */
688 void
689 _mesa_load_state_parameters(GLcontext *ctx,
690 struct program_parameter_list *paramList)
691 {
692 GLuint i;
693 for (i = 0; i < paramList->NumParameters; i++) {
694 if (paramList->Parameters[i].Type == STATE) {
695 _mesa_fetch_state(ctx, paramList->Parameters[i].StateIndexes,
696 paramList->Parameters[i].Values);
697 }
698 }
699 }
700
701
702
703 /**********************************************************************/
704 /* API functions */
705 /**********************************************************************/
706
707
708 /**
709 * Bind a program (make it current)
710 * \note Called from the GL API dispatcher by both glBindProgramNV
711 * and glBindProgramARB.
712 */
713 void
714 _mesa_BindProgram(GLenum target, GLuint id)
715 {
716 struct program *prog;
717 GET_CURRENT_CONTEXT(ctx);
718 ASSERT_OUTSIDE_BEGIN_END(ctx);
719
720 if ((target == GL_VERTEX_PROGRAM_NV
721 && ctx->Extensions.NV_vertex_program) ||
722 (target == GL_VERTEX_PROGRAM_ARB
723 && ctx->Extensions.ARB_vertex_program)) {
724 if (ctx->VertexProgram.Current &&
725 ctx->VertexProgram.Current->Base.Id == id)
726 return;
727 /* decrement refcount on previously bound vertex program */
728 if (ctx->VertexProgram.Current) {
729 ctx->VertexProgram.Current->Base.RefCount--;
730 /* and delete if refcount goes below one */
731 if (ctx->VertexProgram.Current->Base.RefCount <= 0) {
732 _mesa_delete_program(ctx, &(ctx->VertexProgram.Current->Base));
733 _mesa_HashRemove(ctx->Shared->Programs, id);
734 }
735 }
736 }
737 else if ((target == GL_FRAGMENT_PROGRAM_NV
738 && ctx->Extensions.NV_fragment_program) ||
739 (target == GL_FRAGMENT_PROGRAM_ARB
740 && ctx->Extensions.ARB_fragment_program)) {
741 if (ctx->FragmentProgram.Current &&
742 ctx->FragmentProgram.Current->Base.Id == id)
743 return;
744 /* decrement refcount on previously bound fragment program */
745 if (ctx->FragmentProgram.Current) {
746 ctx->FragmentProgram.Current->Base.RefCount--;
747 /* and delete if refcount goes below one */
748 if (ctx->FragmentProgram.Current->Base.RefCount <= 0) {
749 _mesa_delete_program(ctx, &(ctx->FragmentProgram.Current->Base));
750 _mesa_HashRemove(ctx->Shared->Programs, id);
751 }
752 }
753 }
754 else {
755 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
756 return;
757 }
758
759 /* NOTE: binding to a non-existant program is not an error.
760 * That's supposed to be caught in glBegin.
761 */
762 if (id == 0) {
763 /* default program */
764 prog = NULL;
765 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB)
766 prog = ctx->Shared->DefaultVertexProgram;
767 else
768 prog = ctx->Shared->DefaultFragmentProgram;
769 }
770 else {
771 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
772 if (prog) {
773 if (prog->Target == 0) {
774 /* prog was allocated with glGenProgramsNV */
775 prog->Target = target;
776 }
777 else if (prog->Target != target) {
778 _mesa_error(ctx, GL_INVALID_OPERATION,
779 "glBindProgramNV/ARB(target mismatch)");
780 return;
781 }
782 }
783 else {
784 /* allocate a new program now */
785 prog = _mesa_alloc_program(ctx, target, id);
786 if (!prog) {
787 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
788 return;
789 }
790 prog->Id = id;
791 prog->Target = target;
792 prog->Resident = GL_TRUE;
793 prog->RefCount = 1;
794 _mesa_HashInsert(ctx->Shared->Programs, id, prog);
795 }
796 }
797
798 /* bind now */
799 if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) {
800 ctx->VertexProgram.Current = (struct vertex_program *) prog;
801 }
802 else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) {
803 ctx->FragmentProgram.Current = (struct fragment_program *) prog;
804 }
805
806 if (prog)
807 prog->RefCount++;
808 }
809
810
811 /**
812 * Delete a list of programs.
813 * \note Not compiled into display lists.
814 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
815 */
816 void
817 _mesa_DeletePrograms(GLsizei n, const GLuint *ids)
818 {
819 GLint i;
820 GET_CURRENT_CONTEXT(ctx);
821 ASSERT_OUTSIDE_BEGIN_END(ctx);
822
823 if (n < 0) {
824 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
825 return;
826 }
827
828 for (i = 0; i < n; i++) {
829 if (ids[i] != 0) {
830 struct program *prog = (struct program *)
831 _mesa_HashLookup(ctx->Shared->Programs, ids[i]);
832 if (prog) {
833 if (prog->Target == GL_VERTEX_PROGRAM_NV ||
834 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
835 if (ctx->VertexProgram.Current &&
836 ctx->VertexProgram.Current->Base.Id == ids[i]) {
837 /* unbind this currently bound program */
838 _mesa_BindProgram(prog->Target, 0);
839 }
840 }
841 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV) {
842 if (ctx->FragmentProgram.Current &&
843 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
844 /* unbind this currently bound program */
845 _mesa_BindProgram(prog->Target, 0);
846 }
847 }
848 else {
849 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
850 return;
851 }
852 prog->RefCount--;
853 if (prog->RefCount <= 0) {
854 _mesa_delete_program(ctx, prog);
855 }
856 }
857 }
858 }
859 }
860
861
862 /**
863 * Generate a list of new program identifiers.
864 * \note Not compiled into display lists.
865 * \note Called by both glGenProgramsNV and glGenProgramsARB.
866 */
867 void
868 _mesa_GenPrograms(GLsizei n, GLuint *ids)
869 {
870 GLuint first;
871 GLuint i;
872 GET_CURRENT_CONTEXT(ctx);
873 ASSERT_OUTSIDE_BEGIN_END(ctx);
874
875 if (n < 0) {
876 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
877 return;
878 }
879
880 if (!ids)
881 return;
882
883 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
884
885 for (i = 0; i < (GLuint) n; i++) {
886 const int bytes = MAX2(sizeof(struct vertex_program),
887 sizeof(struct fragment_program));
888 struct program *prog = (struct program *) _mesa_calloc(bytes);
889 if (!prog) {
890 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPrograms");
891 return;
892 }
893 prog->RefCount = 1;
894 prog->Id = first + i;
895 _mesa_HashInsert(ctx->Shared->Programs, first + i, prog);
896 }
897
898 /* Return the program names */
899 for (i = 0; i < (GLuint) n; i++) {
900 ids[i] = first + i;
901 }
902 }
903
904
905 /**
906 * Determine if id names a program.
907 * \note Not compiled into display lists.
908 * \note Called from both glIsProgramNV and glIsProgramARB.
909 * \param id is the program identifier
910 * \return GL_TRUE if id is a program, else GL_FALSE.
911 */
912 GLboolean
913 _mesa_IsProgram(GLuint id)
914 {
915 struct program *prog;
916 GET_CURRENT_CONTEXT(ctx);
917 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
918
919 if (id == 0)
920 return GL_FALSE;
921
922 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
923 if (prog && prog->Target)
924 return GL_TRUE;
925 else
926 return GL_FALSE;
927 }