Panda3D
shader.cxx
1 // Filename: shader.cxx
2 // Created by: jyelon (01Sep05)
3 // Updated by: fperazzi, PandaSE(06Apr10)
4 // Updated by: fperazzi, PandaSE(29Apr10) (added SAT_sampler2dArray)
5 ////////////////////////////////////////////////////////////////////
6 //
7 // PANDA 3D SOFTWARE
8 // Copyright (c) Carnegie Mellon University. All rights reserved.
9 //
10 // All use of this software is subject to the terms of the revised BSD
11 // license. You should have received a copy of this license along
12 // with this source code in a file named "LICENSE."
13 //
14 ////////////////////////////////////////////////////////////////////
15 
16 #include "pandabase.h"
17 #include "shader.h"
18 #include "preparedGraphicsObjects.h"
19 #include "virtualFileSystem.h"
20 #include "config_util.h"
21 
22 #ifdef HAVE_CG
23 #include <Cg/cg.h>
24 #endif
25 
26 TypeHandle Shader::_type_handle;
27 Shader::ShaderTable Shader::_load_table;
28 Shader::ShaderTable Shader::_make_table;
29 Shader::ShaderCaps Shader::_default_caps;
30 int Shader::_shaders_generated;
31 ShaderUtilization Shader::_shader_utilization = SUT_unspecified;
32 
33 #ifdef HAVE_CG
34 CGcontext Shader::_cg_context = 0;
35 #endif
36 
37 ////////////////////////////////////////////////////////////////////
38 // Function: Shader::cp_report_error
39 // Access: Public
40 // Description: Generate an error message including a description
41 // of the specified parameter.
42 ////////////////////////////////////////////////////////////////////
43 void Shader::
44 cp_report_error(ShaderArgInfo &p, const string &msg) {
45 
46  string vstr;
47  if (p._varying) {
48  vstr = "varying ";
49  } else {
50  vstr = "uniform ";
51  }
52 
53  string dstr = "unknown ";
54  if (p._direction == SAD_in) {
55  dstr = "in ";
56  } else if (p._direction == SAD_out) {
57  dstr = "out ";
58  } else if (p._direction == SAD_inout) {
59  dstr = "inout ";
60  }
61 
62  string tstr = "invalid ";
63  switch (p._type) {
64  case SAT_scalar: tstr = "scalar "; break;
65  case SAT_vec1: tstr = "vec1 "; break;
66  case SAT_vec2: tstr = "vec2 "; break;
67  case SAT_vec3: tstr = "vec3 "; break;
68  case SAT_vec4: tstr = "vec4 "; break;
69  case SAT_mat1x1: tstr = "mat1x1 "; break;
70  case SAT_mat1x2: tstr = "mat1x2 "; break;
71  case SAT_mat1x3: tstr = "mat1x3 "; break;
72  case SAT_mat1x4: tstr = "mat1x4 "; break;
73  case SAT_mat2x1: tstr = "mat2x1 "; break;
74  case SAT_mat2x2: tstr = "mat2x2 "; break;
75  case SAT_mat2x3: tstr = "mat2x3 "; break;
76  case SAT_mat2x4: tstr = "mat2x4 "; break;
77  case SAT_mat3x1: tstr = "mat3x1 "; break;
78  case SAT_mat3x2: tstr = "mat3x2 "; break;
79  case SAT_mat3x3: tstr = "mat3x3 "; break;
80  case SAT_mat3x4: tstr = "mat3x4 "; break;
81  case SAT_mat4x1: tstr = "mat4x1 "; break;
82  case SAT_mat4x2: tstr = "mat4x2 "; break;
83  case SAT_mat4x3: tstr = "mat4x3 "; break;
84  case SAT_mat4x4: tstr = "mat4x4 "; break;
85  case SAT_sampler1d: tstr = "sampler1d "; break;
86  case SAT_sampler2d: tstr = "sampler2d "; break;
87  case SAT_sampler3d: tstr = "sampler3d "; break;
88  case SAT_sampler2dArray: tstr = "sampler2dArray "; break;
89  case SAT_samplercube: tstr = "samplercube "; break;
90  default: tstr = "unknown "; break;
91  }
92 
93  string cstr = "invalid";
94  switch (p._class) {
95  case SAC_scalar: cstr = "scalar "; break;
96  case SAC_vector: cstr = "vector "; break;
97  case SAC_matrix: cstr = "matrix "; break;
98  case SAC_sampler: cstr = "sampler "; break;
99  case SAC_array: cstr = "array "; break;
100  default: cstr = "unknown "; break;
101  }
102 
103  Filename fn = get_filename(p._id._type);
104  p._cat->error() << fn << ": " << vstr << dstr << tstr <<
105  p._id._name << ": " << msg << "\n";
106 }
107 
108 ////////////////////////////////////////////////////////////////////
109 // Function: Shader::cp_errchk_parameter_words
110 // Access: Public, Static
111 // Description: Make sure the provided parameter contains
112 // the specified number of words. If not, print
113 // error message and return false.
114 ////////////////////////////////////////////////////////////////////
115 bool Shader::
117 {
118  vector_string words;
119  tokenize(p._id._name, words, "_");
120  if ((int)words.size() != len) {
121  cp_report_error(p, "parameter name has wrong number of words");
122  return false;
123  }
124  return true;
125 }
126 
127 ////////////////////////////////////////////////////////////////////
128 // Function: Shader::cp_errchk_parameter_in
129 // Access: Public, Static
130 // Description: Make sure the provided parameter has the
131 // 'in' direction. If not, print
132 // error message and return false.
133 ////////////////////////////////////////////////////////////////////
134 bool Shader::
136 {
137  if (p._direction != SAD_in) {
138  cp_report_error(p, "parameter should be declared 'in'");
139  return false;
140  }
141  return true;
142 }
143 
144 ////////////////////////////////////////////////////////////////////
145 // Function: Shader::cp_errchk_parameter_varying
146 // Access: Public, Static
147 // Description: Make sure the provided parameter has the
148 // correct variance. If not, print
149 // error message and return false.
150 ////////////////////////////////////////////////////////////////////
151 bool Shader::
153 {
154  if (!p._varying) {
155  cp_report_error(p, "parameter should be declared 'varying'");
156  return false;
157  }
158  return true;
159 }
160 
161 ////////////////////////////////////////////////////////////////////
162 // Function: Shader::cp_errchk_parameter_uniform
163 // Access: Public, Static
164 // Description: Make sure the provided parameter has the
165 // correct variance. If not, print
166 // error message and return false.
167 ////////////////////////////////////////////////////////////////////
168 bool Shader::
170 {
171  if (p._varying) {
172  cp_report_error(p, "parameter should be declared 'uniform'");
173  return false;
174  }
175  return true;
176 }
177 
178 ////////////////////////////////////////////////////////////////////
179 // Function: Shader::cp_errchk_parameter_float
180 // Access: Public, Static
181 // Description: Make sure the provided parameter has
182 // a floating point type. If not, print
183 // error message and return false.
184 ////////////////////////////////////////////////////////////////////
185 bool Shader::
187 {
188  int nfloat;
189  switch (p._type) {
190  case SAT_scalar: nfloat = 1; break;
191  case SAT_vec2: nfloat = 2; break;
192  case SAT_vec3: nfloat = 3; break;
193  case SAT_vec4: nfloat = 4; break;
194  case SAT_mat3x3: nfloat = 9; break;
195  case SAT_mat4x4: nfloat = 16; break;
196  default: nfloat = 0; break;
197  }
198  if ((nfloat < lo)||(nfloat > hi)) {
199  string msg = "wrong type for parameter:";
200  cp_report_error(p, msg);
201  return false;
202  }
203  return true;
204 }
205 
206 ////////////////////////////////////////////////////////////////////
207 // Function: Shader::cp_errchk_parameter_ptr
208 // Access: Public, Static
209 // Description:
210 ////////////////////////////////////////////////////////////////////
211 bool Shader::
212 cp_errchk_parameter_ptr(ShaderArgInfo &p) {
213  switch (p._class) {
214  case SAC_scalar: return true;
215  case SAC_vector: return true;
216  case SAC_matrix: return true;
217  case SAC_array:
218  switch (p._subclass) {
219  case SAC_scalar: return true;
220  case SAC_vector: return true;
221  case SAC_matrix: return true;
222  default:
223  string msg = "unsupported array subclass.";
224  cp_report_error(p, msg);
225  return false;
226  }
227  default:
228  string msg = "unsupported class.";
229  cp_report_error(p,msg);
230  return false;
231  }
232 }
233 
234 ////////////////////////////////////////////////////////////////////
235 // Function: Shader::cp_errchk_parameter_sampler
236 // Access: Public, Static
237 // Description: Make sure the provided parameter has
238 // a texture type. If not, print
239 // error message and return false.
240 ////////////////////////////////////////////////////////////////////
241 bool Shader::
243 {
244  if ((p._type!=SAT_sampler1d)&&
245  (p._type!=SAT_sampler2d)&&
246  (p._type!=SAT_sampler3d)&&
247  (p._type!=SAT_sampler2dArray)&&
248  (p._type!=SAT_samplercube)) {
249  cp_report_error(p, "parameter should have a 'sampler' type");
250  return false;
251  }
252  return true;
253 }
254 
255 ////////////////////////////////////////////////////////////////////
256 // Function: Shader::cp_parse_eol
257 // Access: Public
258 // Description: Make sure the next thing on the word list is EOL
259 ////////////////////////////////////////////////////////////////////
260 bool Shader::
261 cp_parse_eol(ShaderArgInfo &p, vector_string &words, int &next) {
262  if (words[next] != "") {
263  cp_report_error(p, "Too many words in parameter");
264  return false;
265  }
266  return true;
267 }
268 
269 ////////////////////////////////////////////////////////////////////
270 // Function: Shader::cp_parse_delimiter
271 // Access: Public
272 // Description: Pop a delimiter ('to' or 'rel') from the word list.
273 ////////////////////////////////////////////////////////////////////
274 bool Shader::
275 cp_parse_delimiter(ShaderArgInfo &p, vector_string &words, int &next) {
276  if ((words[next] != "to")&&(words[next] != "rel")) {
277  cp_report_error(p, "Keyword 'to' or 'rel' expected");
278  return false;
279  }
280  next += 1;
281  return true;
282 }
283 
284 ////////////////////////////////////////////////////////////////////
285 // Function: Shader::cp_parse_non_delimiter
286 // Access: Public
287 // Description: Pop a non-delimiter word from the word list.
288 // Delimiters are 'to' and 'rel.'
289 ////////////////////////////////////////////////////////////////////
290 string Shader::
291 cp_parse_non_delimiter(vector_string &words, int &next) {
292  const string &nword = words[next];
293  if ((nword == "")||(nword == "to")||(nword == "rel")) {
294  return "";
295  }
296  next += 1;
297  return nword;
298 }
299 
300 ////////////////////////////////////////////////////////////////////
301 // Function: Shader::cp_parse_coord_sys
302 // Access: Public
303 // Description: Convert a single-word coordinate system name into
304 // a PART/ARG of a ShaderMatSpec.
305 ////////////////////////////////////////////////////////////////////
306 bool Shader::
308  vector_string &pieces, int &next,
309  ShaderMatSpec &bind, bool fromflag) {
310 
311  string word1 = cp_parse_non_delimiter(pieces, next);
312  if (pieces[next] == "of") next++;
313  string word2 = cp_parse_non_delimiter(pieces, next);
314 
315  ShaderMatInput from_single;
316  ShaderMatInput from_double;
317  ShaderMatInput to_single;
318  ShaderMatInput to_double;
319 
320  if (word1 == "") {
321  cp_report_error(p, "Could not parse coordinate system name");
322  return false;
323  } else if (word1 == "world") {
324  from_single = SMO_world_to_view;
325  from_double = SMO_INVALID;
326  to_single = SMO_view_to_world;
327  to_double = SMO_INVALID;
328  } else if (word1 == "model") {
329  from_single = SMO_model_to_view;
330  from_double = SMO_view_x_to_view;
331  to_single = SMO_view_to_model;
332  to_double = SMO_view_to_view_x;
333  } else if (word1 == "clip") {
334  from_single = SMO_clip_to_view;
335  from_double = SMO_clip_x_to_view;
336  to_single = SMO_view_to_clip;
337  to_double = SMO_view_to_clip_x;
338  } else if (word1 == "view") {
339  from_single = SMO_identity;
340  from_double = SMO_view_x_to_view;
341  to_single = SMO_identity;
342  to_double = SMO_view_to_view_x;
343  } else if (word1 == "apiview") {
344  from_single = SMO_apiview_to_view;
345  from_double = SMO_apiview_x_to_view;
346  to_single = SMO_view_to_apiview;
347  to_double = SMO_view_to_apiview_x;
348  } else if (word1 == "apiclip") {
349  from_single = SMO_apiclip_to_view;
350  from_double = SMO_apiclip_x_to_view;
351  to_single = SMO_view_to_apiclip;
352  to_double = SMO_view_to_apiclip_x;
353  } else {
354  from_single = SMO_view_x_to_view;
355  from_double = SMO_view_x_to_view;
356  to_single = SMO_view_to_view_x;
357  to_double = SMO_view_to_view_x;
358  word2 = word1;
359  }
360 
361  if (fromflag) {
362  if (word2 == "") {
363  bind._part[0] = from_single;
364  bind._arg[0] = NULL;
365  } else {
366  if (from_double == SMO_INVALID) {
367  cp_report_error(p, "Could not parse coordinate system name");
368  return false;
369  }
370  bind._part[0] = from_double;
371  bind._arg[0] = InternalName::make(word2);
372  }
373  } else {
374  if (word2 == "") {
375  bind._part[1] = to_single;
376  bind._arg[1] = NULL;
377  } else {
378  if (to_double == SMO_INVALID) {
379  cp_report_error(p, "Could not parse coordinate system name");
380  return false;
381  }
382  bind._part[1] = to_double;
383  bind._arg[1] = InternalName::make(word2);
384  }
385  }
386  return true;
387 }
388 
389 ////////////////////////////////////////////////////////////////////
390 // Function: Shader::cp_dependency
391 // Access: Public
392 // Description: Given ShaderMatInput, returns an indication of what
393 // part or parts of the state_and_transform the
394 // ShaderMatInput depends upon.
395 ////////////////////////////////////////////////////////////////////
396 int Shader::
397 cp_dependency(ShaderMatInput inp) {
398 
399  int dep = SSD_general;
400 
401  if (inp == SMO_INVALID) {
402  return SSD_NONE;
403  }
404  if (inp == SMO_attr_material) {
405  dep |= SSD_material;
406  }
407  if (inp == SMO_attr_color) {
408  dep |= SSD_color;
409  }
410  if (inp == SMO_attr_colorscale) {
411  dep |= SSD_colorscale;
412  }
413  if (inp == SMO_attr_fog || inp == SMO_attr_fogcolor) {
414  dep |= SSD_fog;
415  }
416  if ((inp == SMO_model_to_view) ||
417  (inp == SMO_view_to_model) ||
418  (inp == SMO_model_to_apiview) ||
419  (inp == SMO_apiview_to_model)) {
420  dep |= SSD_transform;
421  }
422  if ((inp == SMO_texpad_x) ||
423  (inp == SMO_texpix_x) ||
424  (inp == SMO_alight_x) ||
425  (inp == SMO_dlight_x) ||
426  (inp == SMO_plight_x) ||
427  (inp == SMO_slight_x) ||
428  (inp == SMO_satten_x) ||
429  (inp == SMO_mat_constant_x) ||
430  (inp == SMO_vec_constant_x) ||
431  (inp == SMO_vec_constant_x_attrib) ||
432  (inp == SMO_view_x_to_view) ||
433  (inp == SMO_view_to_view_x) ||
434  (inp == SMO_apiview_x_to_view) ||
435  (inp == SMO_view_to_apiview_x) ||
436  (inp == SMO_clip_x_to_view) ||
437  (inp == SMO_view_to_clip_x) ||
438  (inp == SMO_apiclip_x_to_view) ||
439  (inp == SMO_view_to_apiclip_x)) {
440  dep |= SSD_shaderinputs;
441  }
442  if ((inp == SMO_light_ambient) ||
443  (inp == SMO_light_source_i_attrib)) {
444  dep |= SSD_light;
445  }
446  if ((inp == SMO_light_product_i_ambient) ||
447  (inp == SMO_light_product_i_diffuse) ||
448  (inp == SMO_light_product_i_specular)) {
449  dep |= (SSD_light | SSD_material);
450  }
451  if ((inp == SMO_clipplane_x) ||
452  (inp == SMO_apiview_clipplane_i)) {
453  dep |= SSD_clip_planes;
454  }
455 
456  return dep;
457 }
458 
459 ////////////////////////////////////////////////////////////////////
460 // Function: Shader::cp_optimize_mat_spec
461 // Access: Public
462 // Description: Analyzes a ShaderMatSpec and decides what it should
463 // use its cache for. It can cache the results of any
464 // one opcode, or, it can cache the entire result. This
465 // routine needs to be smart enough to know which
466 // data items can be correctly cached, and which cannot.
467 ////////////////////////////////////////////////////////////////////
468 void Shader::
470 
471  // If we're composing with identity, simplify.
472 
473  if (spec._func == SMF_first) {
474  spec._part[1] = SMO_INVALID;
475  spec._arg[1] = 0;
476  }
477  if (spec._func == SMF_compose) {
478  if (spec._part[1] == SMO_identity) {
479  spec._func = SMF_first;
480  }
481  }
482  if (spec._func == SMF_compose) {
483  if (spec._part[0] == SMO_identity) {
484  spec._func = SMF_first;
485  spec._part[0] = spec._part[1];
486  spec._arg[0] = spec._arg[1];
487  }
488 
489  // More optimal combinations for common matrices.
490 
491  if (spec._part[0] == SMO_model_to_view &&
492  spec._part[1] == SMO_view_to_apiclip) {
493  spec._part[0] = SMO_model_to_apiview;
494  spec._part[1] = SMO_apiview_to_apiclip;
495 
496  } else if (spec._part[0] == SMO_apiclip_to_view &&
497  spec._part[1] == SMO_view_to_model) {
498  spec._part[0] = SMO_apiclip_to_apiview;
499  spec._part[1] = SMO_apiview_to_model;
500 
501  } else if (spec._part[0] == SMO_apiview_to_view &&
502  spec._part[1] == SMO_view_to_apiclip) {
503  spec._func = SMF_first;
504  spec._part[0] = SMO_apiview_to_apiclip;
505  spec._part[1] = SMO_identity;
506 
507  } else if (spec._part[0] == SMO_apiclip_to_view &&
508  spec._part[1] == SMO_view_to_apiview) {
509  spec._func = SMF_first;
510  spec._part[0] = SMO_apiclip_to_apiview;
511  spec._part[1] = SMO_identity;
512 
513  } else if (spec._part[0] == SMO_apiview_to_view &&
514  spec._part[1] == SMO_view_to_model) {
515  spec._func = SMF_first;
516  spec._part[0] = SMO_apiview_to_model;
517  spec._part[1] = SMO_identity;
518 
519  } else if (spec._part[0] == SMO_model_to_view &&
520  spec._part[1] == SMO_view_to_apiview) {
521  spec._func = SMF_first;
522  spec._part[0] = SMO_model_to_apiview;
523  spec._part[1] = SMO_identity;
524  }
525  }
526 
527  // Calculate state and transform dependencies.
528 
529  spec._dep[0] = cp_dependency(spec._part[0]);
530  spec._dep[1] = cp_dependency(spec._part[1]);
531 }
532 
533 #ifdef HAVE_CG
534 ////////////////////////////////////////////////////////////////////
535 // Function: Shader::cg_recurse_parameters
536 // Access: Public
537 // Description:
538 ////////////////////////////////////////////////////////////////////
539 void Shader::
540 cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
541  bool &success) {
542 
543  if (parameter == 0) {
544  return;
545  }
546 
547  do {
548  if (cgIsParameterReferenced(parameter)) {
549  int arg_dim[] = {1,0,0};
550  ShaderArgDir arg_dir = cg_parameter_dir(parameter);
551  ShaderArgType arg_type = cg_parameter_type(parameter);
552  ShaderArgClass arg_class = cg_parameter_class(parameter);
553  ShaderArgClass arg_subclass = arg_class;
554 
555  CGenum vbl = cgGetParameterVariability(parameter);
556 
557  if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
558  switch (cgGetParameterType(parameter)) {
559  case CG_STRUCT:
560  cg_recurse_parameters(
561  cgGetFirstStructParameter(parameter), type, success);
562  break;
563 
564  case CG_ARRAY:
565  arg_type = cg_parameter_type(cgGetArrayParameter(parameter, 0));
566  arg_subclass = cg_parameter_class(cgGetArrayParameter(parameter, 0));
567 
568  arg_dim[0] = cgGetArraySize(parameter, 0);
569 
570  default: {
571  arg_dim[1] = cgGetParameterRows(parameter);
572  arg_dim[2] = cgGetParameterColumns(parameter);
573 
574  ShaderArgId id;
575  id._name = cgGetParameterName(parameter);
576  id._type = type;
577  id._seqno = -1;
578  success &= compile_parameter(id, arg_class, arg_subclass, arg_type,
579  arg_dir, (vbl == CG_VARYING), arg_dim, shader_cat.get_safe_ptr()); break;
580  }
581  }
582  }
583  } else if (shader_cat.is_debug()) {
584  shader_cat.debug()
585  << "Parameter " << cgGetParameterName(parameter)
586  << " is unreferenced within shader " << get_filename(type) << "\n";
587  }
588  } while((parameter = cgGetNextParameter(parameter))!= 0);
589 }
590 #endif // HAVE_CG
591 
592 ////////////////////////////////////////////////////////////////////
593 // Function: Shader::compile_parameter
594 // Access: Public
595 // Description: Analyzes a parameter and decides how to
596 // bind the parameter to some part of panda's
597 // internal state. Updates one of the bind
598 // arrays to cause the binding to occur.
599 //
600 // If there is an error, this routine will append
601 // an error message onto the error messages.
602 ////////////////////////////////////////////////////////////////////
603 bool Shader::
605  const ShaderArgClass &arg_class,
606  const ShaderArgClass &arg_subclass,
607  const ShaderArgType &arg_type,
608  const ShaderArgDir &arg_direction,
609  bool arg_varying,
610  int *arg_dim,
611  NotifyCategory *arg_cat)
612 {
613  ShaderArgInfo p;
614  p._id = arg_id;
615  p._class = arg_class;
616  p._subclass = arg_subclass;
617  p._type = arg_type;
618  p._direction = arg_direction;
619  p._varying = arg_varying;
620  p._cat = arg_cat;
621 
622  if (p._id._name.size() == 0) return true;
623  if (p._id._name[0] == '$') return true;
624 
625  // It could be inside a struct, strip off
626  // everything before the last dot.
627  size_t loc = p._id._name.find_last_of('.');
628 
629  string basename (p._id._name);
630  string struct_name ("");
631 
632  if (loc < string::npos) {
633  basename = p._id._name.substr(loc + 1);
634  struct_name = p._id._name.substr(0,loc+1);
635  }
636 
637  // Split it at the underscores.
638  vector_string pieces;
639  tokenize(basename, pieces, "_");
640 
641  if (basename.size() >= 2 && basename.substr(0, 2) == "__") {
642  return true;
643  }
644 
645  // Implement vtx parameters - the varying kind.
646  if (pieces[0] == "vtx") {
647  if ((!cp_errchk_parameter_in(p)) ||
649  (!cp_errchk_parameter_float(p, 1, 4))) {
650  return false;
651  }
652  ShaderVarSpec bind;
653  bind._id = arg_id;
654  bind._append_uv = -1;
655  bind._integer = false;
656 
657  if (pieces.size() == 2) {
658  if (pieces[1] == "position") {
659  bind._name = InternalName::get_vertex();
660  bind._append_uv = -1;
661  _var_spec.push_back(bind);
662  return true;
663  }
664  if (pieces[1].substr(0, 8) == "texcoord") {
665  bind._name = InternalName::get_texcoord();
666  if (pieces[1].size() > 8) {
667  bind._append_uv = atoi(pieces[1].c_str() + 8);
668  }
669  _var_spec.push_back(bind);
670  return true;
671  }
672  if (pieces[1].substr(0, 7) == "tangent") {
673  bind._name = InternalName::get_tangent();
674  if (pieces[1].size() > 7) {
675  bind._append_uv = atoi(pieces[1].c_str() + 7);
676  }
677  _var_spec.push_back(bind);
678  return true;
679  }
680  if (pieces[1].substr(0, 8) == "binormal") {
681  bind._name = InternalName::get_binormal();
682  if (pieces[1].size() > 8) {
683  bind._append_uv = atoi(pieces[1].c_str() + 8);
684  }
685  _var_spec.push_back(bind);
686  return true;
687  }
688  }
689 
690  bind._name = InternalName::get_root();
691  for (size_t i = 1; i < pieces.size(); ++i) {
692  bind._name = bind._name->append(pieces[i]);
693  }
694  _var_spec.push_back(bind);
695  return true;
696  }
697 
698  // Implement some macros. Macros work by altering the
699  // contents of the 'pieces' array, and then falling through.
700 
701  if (pieces[0] == "mstrans") {
702  pieces[0] = "trans";
703  pieces.push_back("to");
704  pieces.push_back("model");
705  }
706  if (pieces[0] == "wstrans") {
707  pieces[0] = "trans";
708  pieces.push_back("to");
709  pieces.push_back("world");
710  }
711  if (pieces[0] == "vstrans") {
712  pieces[0] = "trans";
713  pieces.push_back("to");
714  pieces.push_back("view");
715  }
716  if (pieces[0] == "cstrans") {
717  pieces[0] = "trans";
718  pieces.push_back("to");
719  pieces.push_back("clip");
720  }
721  if (pieces[0] == "mspos") {
722  pieces[0] = "row3";
723  pieces.push_back("to");
724  pieces.push_back("model");
725  }
726  if (pieces[0] == "wspos") {
727  pieces[0] = "row3";
728  pieces.push_back("to");
729  pieces.push_back("world");
730  }
731  if (pieces[0] == "vspos") {
732  pieces[0] = "row3";
733  pieces.push_back("to");
734  pieces.push_back("view");
735  }
736  if (pieces[0] == "cspos") {
737  pieces[0] = "row3";
738  pieces.push_back("to");
739  pieces.push_back("clip");
740  }
741 
742  // Implement the modelview macros.
743 
744  if ((pieces[0] == "mat")||(pieces[0] == "inv")||
745  (pieces[0] == "tps")||(pieces[0] == "itp")) {
746  if (!cp_errchk_parameter_words(p, 2)) {
747  return false;
748  }
749  string trans = pieces[0];
750  string matrix = pieces[1];
751  pieces.clear();
752  if (matrix == "modelview") {
753  tokenize("trans_model_to_apiview", pieces, "_");
754  } else if (matrix == "projection") {
755  tokenize("trans_apiview_to_apiclip", pieces, "_");
756  } else if (matrix == "modelproj") {
757  tokenize("trans_model_to_apiclip", pieces, "_");
758  } else {
759  cp_report_error(p,"unrecognized matrix name");
760  return false;
761  }
762  if (trans=="mat") {
763  pieces[0] = "trans";
764  } else if (trans=="inv") {
765  string t = pieces[1];
766  pieces[1] = pieces[3];
767  pieces[3] = t;
768  } else if (trans=="tps") {
769  pieces[0] = "tpose";
770  } else if (trans=="itp") {
771  string t = pieces[1];
772  pieces[1] = pieces[3];
773  pieces[3] = t;
774  pieces[0] = "tpose";
775  }
776  }
777 
778  // Implement the transform-matrix generator.
779 
780  if ((pieces[0]=="trans")||
781  (pieces[0]=="tpose")||
782  (pieces[0]=="row0")||
783  (pieces[0]=="row1")||
784  (pieces[0]=="row2")||
785  (pieces[0]=="row3")||
786  (pieces[0]=="col0")||
787  (pieces[0]=="col1")||
788  (pieces[0]=="col2")||
789  (pieces[0]=="col3")) {
790 
791  if ((!cp_errchk_parameter_in(p)) ||
793  return false;
794 
795  ShaderMatSpec bind;
796  bind._id = arg_id;
797  bind._func = SMF_compose;
798 
799  int next = 1;
800  pieces.push_back("");
801 
802  // Decide whether this is a matrix or vector.
803  if (pieces[0]=="trans") bind._piece = SMP_whole;
804  else if (pieces[0]=="tpose") bind._piece = SMP_transpose;
805  else if (pieces[0]=="row0") bind._piece = SMP_row0;
806  else if (pieces[0]=="row1") bind._piece = SMP_row1;
807  else if (pieces[0]=="row2") bind._piece = SMP_row2;
808  else if (pieces[0]=="row3") bind._piece = SMP_row3;
809  else if (pieces[0]=="col0") bind._piece = SMP_col0;
810  else if (pieces[0]=="col1") bind._piece = SMP_col1;
811  else if (pieces[0]=="col2") bind._piece = SMP_col2;
812  else if (pieces[0]=="col3") bind._piece = SMP_col3;
813  if ((bind._piece == SMP_whole)||(bind._piece == SMP_transpose)) {
814  if (p._type == SAT_mat3x3) {
815  if (!cp_errchk_parameter_float(p, 9, 9)) return false;
816 
817  if (bind._piece == SMP_transpose) {
818  bind._piece = SMP_transpose3x3;
819  } else {
820  bind._piece = SMP_upper3x3;
821  }
822  } else if (!cp_errchk_parameter_float(p, 16, 16)) {
823  return false;
824  }
825  } else {
826  if (!cp_errchk_parameter_float(p, 4, 4)) return false;
827  }
828 
829  if (!cp_parse_coord_sys(p, pieces, next, bind, true)) {
830  return false;
831  }
832  if (!cp_parse_delimiter(p, pieces, next)) {
833  return false;
834  }
835  if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
836  return false;
837  }
838  if (!cp_parse_eol(p, pieces, next)) {
839  return false;
840  }
841  cp_optimize_mat_spec(bind);
842  _mat_spec.push_back(bind);
843  return true;
844  }
845 
846  // Special parameter: attr_material or attr_color
847 
848  if (pieces[0] == "attr") {
849  if ((!cp_errchk_parameter_words(p,2)) ||
850  (!cp_errchk_parameter_in(p)) ||
852  return false;
853  }
854  ShaderMatSpec bind;
855  if (pieces[1] == "material") {
856  if (!cp_errchk_parameter_float(p,16,16)) {
857  return false;
858  }
859  bind._id = arg_id;
860  bind._piece = SMP_transpose;
861  bind._func = SMF_first;
862  bind._part[0] = SMO_attr_material;
863  bind._arg[0] = NULL;
864  bind._part[1] = SMO_identity;
865  bind._arg[1] = NULL;
866  } else if (pieces[1] == "color") {
867  if (!cp_errchk_parameter_float(p,3,4)) {
868  return false;
869  }
870  bind._id = arg_id;
871  bind._piece = SMP_row3;
872  bind._func = SMF_first;
873  bind._part[0] = SMO_attr_color;
874  bind._arg[0] = NULL;
875  bind._part[1] = SMO_identity;
876  bind._arg[1] = NULL;
877  } else if (pieces[1] == "colorscale") {
878  if (!cp_errchk_parameter_float(p,3,4)) {
879  return false;
880  }
881  bind._id = arg_id;
882  bind._piece = SMP_row3;
883  bind._func = SMF_first;
884  bind._part[0] = SMO_attr_colorscale;
885  bind._arg[0] = NULL;
886  bind._part[1] = SMO_identity;
887  bind._arg[1] = NULL;
888  } else if (pieces[1] == "fog") {
889  if (!cp_errchk_parameter_float(p,3,4)) {
890  return false;
891  }
892  bind._id = arg_id;
893  bind._piece = SMP_row3;
894  bind._func = SMF_first;
895  bind._part[0] = SMO_attr_fog;
896  bind._arg[0] = NULL;
897  bind._part[1] = SMO_identity;
898  bind._arg[1] = NULL;
899  } else if (pieces[1] == "fogcolor") {
900  if (!cp_errchk_parameter_float(p,3,4)) {
901  return false;
902  }
903  bind._id = arg_id;
904  bind._piece = SMP_row3;
905  bind._func = SMF_first;
906  bind._part[0] = SMO_attr_fogcolor;
907  bind._arg[0] = NULL;
908  bind._part[1] = SMO_identity;
909  bind._arg[1] = NULL;
910  } else {
911  cp_report_error(p,"Unknown attr parameter.");
912  return false;
913  }
914 
915  cp_optimize_mat_spec(bind);
916  _mat_spec.push_back(bind);
917  return true;
918  }
919 
920  if (pieces[0] == "color") {
921  if ((!cp_errchk_parameter_words(p,1)) ||
922  (!cp_errchk_parameter_in(p)) ||
924  return false;
925  }
926  ShaderMatSpec bind;
927 
928  cp_optimize_mat_spec(bind);
929  _mat_spec.push_back(bind);
930  return true;
931  }
932 
933  // Keywords to access light properties.
934 
935  if (pieces[0] == "alight") {
936  if ((!cp_errchk_parameter_words(p,2))||
937  (!cp_errchk_parameter_in(p)) ||
939  (!cp_errchk_parameter_float(p,3,4))) {
940  return false;
941  }
942  ShaderMatSpec bind;
943  bind._id = arg_id;
944  bind._piece = SMP_row3;
945  bind._func = SMF_first;
946  bind._part[0] = SMO_alight_x;
947  bind._arg[0] = InternalName::make(pieces[1]);
948  bind._part[1] = SMO_identity;
949  bind._arg[1] = NULL;
950 
951  cp_optimize_mat_spec(bind);
952  _mat_spec.push_back(bind);
953  return true;
954  }
955 
956  if (pieces[0] == "satten") {
957  if ((!cp_errchk_parameter_words(p,2))||
958  (!cp_errchk_parameter_in(p)) ||
960  (!cp_errchk_parameter_float(p,4,4))) {
961  return false;
962  }
963  ShaderMatSpec bind;
964  bind._id = arg_id;
965  bind._piece = SMP_row3;
966  bind._func = SMF_first;
967  bind._part[0] = SMO_satten_x;
968  bind._arg[0] = InternalName::make(pieces[1]);
969  bind._part[1] = SMO_identity;
970  bind._arg[1] = NULL;
971 
972  cp_optimize_mat_spec(bind);
973  _mat_spec.push_back(bind);
974  return true;
975  }
976 
977  if ((pieces[0]=="dlight")||(pieces[0]=="plight")||(pieces[0]=="slight")) {
978  if ((!cp_errchk_parameter_in(p)) ||
980  (!cp_errchk_parameter_float(p,16,16))) {
981  return false;
982  }
983  ShaderMatSpec bind;
984  bind._id = arg_id;
985  bind._piece = SMP_transpose;
986  int next = 1;
987  pieces.push_back("");
988  if (pieces[next] == "") {
989  cp_report_error(p, "Light name expected");
990  return false;
991  }
992  if (pieces[0] == "dlight") {
993  bind._func = SMF_transform_dlight;
994  bind._part[0] = SMO_dlight_x;
995  } else if (pieces[0] == "plight") {
996  bind._func = SMF_transform_plight;
997  bind._part[0] = SMO_plight_x;
998  } else if (pieces[0] == "slight") {
999  bind._func = SMF_transform_slight;
1000  bind._part[0] = SMO_slight_x;
1001  }
1002  bind._arg[0] = InternalName::make(pieces[next]);
1003  next += 1;
1004  if (!cp_parse_delimiter(p, pieces, next)) {
1005  return false;
1006  }
1007  if (!cp_parse_coord_sys(p, pieces, next, bind, false)) {
1008  return false;
1009  }
1010  if (!cp_parse_eol(p, pieces, next)) {
1011  return false;
1012  }
1013  cp_optimize_mat_spec(bind);
1014  _mat_spec.push_back(bind);
1015  return true;
1016  }
1017 
1018  if (pieces[0] == "texmat") {
1019  if ((!cp_errchk_parameter_words(p,2))||
1020  (!cp_errchk_parameter_in(p)) ||
1022  (!cp_errchk_parameter_float(p,16,16))) {
1023  return false;
1024  }
1025  ShaderMatSpec bind;
1026  bind._id = arg_id;
1027  bind._piece = SMP_whole;
1028  bind._func = SMF_first;
1029  bind._part[0] = SMO_texmat_x;
1030  bind._arg[0] = InternalName::make(pieces[1]);
1031  bind._part[1] = SMO_identity;
1032  bind._arg[1] = NULL;
1033 
1034  cp_optimize_mat_spec(bind);
1035  _mat_spec.push_back(bind);
1036  return true;
1037  }
1038 
1039  if (pieces[0] == "plane") {
1040  if ((!cp_errchk_parameter_words(p,2))||
1041  (!cp_errchk_parameter_in(p)) ||
1043  (!cp_errchk_parameter_float(p,4,4))) {
1044  return false;
1045  }
1046  ShaderMatSpec bind;
1047  bind._id = arg_id;
1048  bind._piece = SMP_row3;
1049  bind._func = SMF_first;
1050  bind._part[0] = SMO_plane_x;
1051  bind._arg[0] = InternalName::make(pieces[1]);
1052  bind._part[1] = SMO_identity;
1053  bind._arg[1] = NULL;
1054 
1055  cp_optimize_mat_spec(bind);
1056  _mat_spec.push_back(bind);
1057  return true;
1058  }
1059 
1060  if (pieces[0] == "clipplane") {
1061  if ((!cp_errchk_parameter_words(p,2))||
1062  (!cp_errchk_parameter_in(p)) ||
1064  (!cp_errchk_parameter_float(p,4,4))) {
1065  return false;
1066  }
1067  ShaderMatSpec bind;
1068  bind._id = arg_id;
1069  bind._piece = SMP_row3;
1070  bind._func = SMF_first;
1071  bind._part[0] = SMO_clipplane_x;
1072  bind._arg[0] = InternalName::make(pieces[1]);
1073  bind._part[1] = SMO_identity;
1074  bind._arg[1] = NULL;
1075 
1076  cp_optimize_mat_spec(bind);
1077  _mat_spec.push_back(bind);
1078  return true;
1079  }
1080 
1081  // Keywords to access unusual parameters.
1082 
1083  if (pieces[0] == "sys") {
1084  if ((!cp_errchk_parameter_words(p, 2)) ||
1085  (!cp_errchk_parameter_in(p)) ||
1087  return false;
1088  }
1089  ShaderMatSpec bind;
1090  bind._id = arg_id;
1091  bind._piece = SMP_row3;
1092  bind._func = SMF_first;
1093  bind._part[1] = SMO_identity;
1094  bind._arg[1] = NULL;
1095  if (pieces[1] == "pixelsize") {
1096  if (!cp_errchk_parameter_float(p, 2, 2)) {
1097  return false;
1098  }
1099  bind._part[0] = SMO_pixel_size;
1100  bind._arg[0] = NULL;
1101 
1102  } else if (pieces[1] == "windowsize") {
1103  if (!cp_errchk_parameter_float(p, 2, 2)) {
1104  return false;
1105  }
1106  bind._part[0] = SMO_window_size;
1107  bind._arg[0] = NULL;
1108 
1109  } else if (pieces[1] == "time") {
1110  if (!cp_errchk_parameter_float(p, 1, 1)) {
1111  return false;
1112  }
1113  bind._piece = SMP_row3x1;
1114  bind._part[0] = SMO_frame_time;
1115  bind._arg[0] = NULL;
1116 
1117  } else {
1118  cp_report_error(p, "unknown system parameter");
1119  return false;
1120  }
1121 
1122  cp_optimize_mat_spec(bind);
1123  _mat_spec.push_back(bind);
1124  return true;
1125  }
1126 
1127  // Keywords to access textures.
1128 
1129  if (pieces[0] == "tex") {
1130  if ((!cp_errchk_parameter_in(p)) ||
1133  return false;
1134  if ((pieces.size() != 2)&&(pieces.size() != 3)) {
1135  cp_report_error(p, "Invalid parameter name");
1136  return false;
1137  }
1138  ShaderTexSpec bind;
1139  bind._id = arg_id;
1140  bind._name = 0;
1141  bind._stage = atoi(pieces[1].c_str());
1142  switch (p._type) {
1143  case SAT_sampler1d: bind._desired_type = Texture::TT_1d_texture; break;
1144  case SAT_sampler2d: bind._desired_type = Texture::TT_2d_texture; break;
1145  case SAT_sampler3d: bind._desired_type = Texture::TT_3d_texture; break;
1146  case SAT_sampler2dArray: bind._desired_type = Texture::TT_2d_texture_array; break;
1147  case SAT_samplercube: bind._desired_type = Texture::TT_cube_map; break;
1148  default:
1149  cp_report_error(p, "Invalid type for a tex-parameter");
1150  return false;
1151  }
1152  if (pieces.size() == 3) {
1153  bind._suffix = InternalName::make(((string)"-") + pieces[2]);
1154  shader_cat.warning()
1155  << "Parameter " << p._id._name << ": use of a texture suffix is deprecated.\n";
1156  }
1157  _tex_spec.push_back(bind);
1158  return true;
1159  }
1160 
1161  // Keywords to fetch texture parameter data.
1162 
1163  if (pieces[0] == "texpad") {
1164  if ((!cp_errchk_parameter_words(p,2)) ||
1165  (!cp_errchk_parameter_in(p)) ||
1167  (!cp_errchk_parameter_float(p,3,4))) {
1168  return false;
1169  }
1170  ShaderMatSpec bind;
1171  bind._id = arg_id;
1172  bind._piece = SMP_row3;
1173  bind._func = SMF_first;
1174  bind._part[0] = SMO_texpad_x;
1175  bind._arg[0] = InternalName::make(pieces[1]);
1176  bind._part[1] = SMO_identity;
1177  bind._arg[1] = NULL;
1178  cp_optimize_mat_spec(bind);
1179  _mat_spec.push_back(bind);
1180  return true;
1181  }
1182 
1183  if (pieces[0] == "texpix") {
1184  if ((!cp_errchk_parameter_words(p,2)) ||
1185  (!cp_errchk_parameter_in(p)) ||
1187  (!cp_errchk_parameter_float(p,2,4))) {
1188  return false;
1189  }
1190  ShaderMatSpec bind;
1191  bind._id = arg_id;
1192  bind._piece = SMP_row3;
1193  bind._func = SMF_first;
1194  bind._part[0] = SMO_texpix_x;
1195  bind._arg[0] = InternalName::make(pieces[1]);
1196  bind._part[1] = SMO_identity;
1197  bind._arg[1] = NULL;
1198  cp_optimize_mat_spec(bind);
1199  _mat_spec.push_back(bind);
1200  return true;
1201  }
1202 
1203  if (pieces[0] == "l") {
1204  // IMPLEMENT THE ERROR CHECKING
1205  return true; // Cg handles this automatically.
1206  }
1207 
1208  if (pieces[0] == "o") {
1209  // IMPLEMENT THE ERROR CHECKING
1210  return true; // Cg handles this automatically.
1211  }
1212 
1213  // Fetch uniform parameters without prefix
1214 
1215  if ((!cp_errchk_parameter_in(p)) ||
1217  return false;
1218  }
1219  bool k_prefix = false;
1220 
1221  // solve backward compatibility issue
1222  if (pieces[0] == "k") {
1223  k_prefix = true;
1224  basename = basename.substr(2);
1225  }
1226 
1227  PT(InternalName) kinputname = InternalName::make(struct_name + basename);
1228 
1229  switch (p._class) {
1230  case SAC_vector:
1231  case SAC_matrix:
1232  case SAC_scalar:
1233  case SAC_array: {
1234  if (!cp_errchk_parameter_ptr(p))
1235  return false;
1236 
1237  ShaderPtrSpec bind;
1238  bind._id = arg_id;
1239  bind._arg = kinputname;
1240  bind._info = p;
1241  bind._dep[0] = SSD_general | SSD_shaderinputs;
1242  bind._dep[1] = SSD_general | SSD_NONE;
1243 
1244  memcpy(bind._dim,arg_dim,sizeof(int)*3);
1245 
1246  // if dim[0] = -1, glShaderContext will not check the param size
1247  if (k_prefix) bind._dim[0] = -1;
1248  _ptr_spec.push_back(bind);
1249  return true;
1250  }
1251 
1252  case SAC_sampler: {
1253  switch (p._type) {
1254  case SAT_sampler1d: {
1255  ShaderTexSpec bind;
1256  bind._id = arg_id;
1257  bind._name = kinputname;
1258  bind._desired_type = Texture::TT_1d_texture;
1259  _tex_spec.push_back(bind);
1260  return true;
1261  }
1262  case SAT_sampler2d: {
1263  ShaderTexSpec bind;
1264  bind._id = arg_id;
1265  bind._name = kinputname;
1266  bind._desired_type = Texture::TT_2d_texture;
1267  _tex_spec.push_back(bind);
1268  return true;
1269  }
1270  case SAT_sampler3d: {
1271  ShaderTexSpec bind;
1272  bind._id = arg_id;
1273  bind._name = kinputname;
1274  bind._desired_type = Texture::TT_3d_texture;
1275  _tex_spec.push_back(bind);
1276  return true;
1277  }
1278  case SAT_sampler2dArray: {
1279  ShaderTexSpec bind;
1280  bind._id = arg_id;
1281  bind._name = kinputname;
1282  bind._desired_type = Texture::TT_2d_texture_array;
1283  _tex_spec.push_back(bind);
1284  return true;
1285  }
1286  case SAT_samplercube: {
1287  ShaderTexSpec bind;
1288  bind._id = arg_id;
1289  bind._name = kinputname;
1290  bind._desired_type = Texture::TT_cube_map;
1291  _tex_spec.push_back(bind);
1292  return true;
1293  }
1294  default:
1295  cp_report_error(p, "invalid type for non-prefix parameter");
1296  return false;
1297  }
1298  }
1299  default:
1300  cp_report_error(p, "invalid class for non-prefix parameter");
1301  return false;
1302  }
1303 
1304  cp_report_error(p, "unrecognized parameter name");
1305  return false;
1306 }
1307 
1308 
1309 ////////////////////////////////////////////////////////////////////
1310 // Function: Shader::clear_parameters
1311 // Access: Private
1312 // Description:
1313 ////////////////////////////////////////////////////////////////////
1314 void Shader::
1315 clear_parameters() {
1316  _mat_spec.clear();
1317  _var_spec.clear();
1318  _tex_spec.clear();
1319 }
1320 
1321 #ifdef HAVE_CG
1322 ////////////////////////////////////////////////////////////////////
1323 // Function: Shader::cg_parameter_type
1324 // Access: Private
1325 // Description:
1326 ////////////////////////////////////////////////////////////////////
1327 Shader::ShaderArgType Shader::
1328 cg_parameter_type(CGparameter p) {
1329  switch (cgGetParameterClass(p)) {
1330  case CG_PARAMETERCLASS_SCALAR: return SAT_scalar;
1331  case CG_PARAMETERCLASS_VECTOR:
1332  switch (cgGetParameterColumns(p)) {
1333  case 1: return SAT_vec1;
1334  case 2: return SAT_vec2;
1335  case 3: return SAT_vec3;
1336  case 4: return SAT_vec4;
1337  default: return SAT_unknown;
1338  }
1339  case CG_PARAMETERCLASS_MATRIX:
1340  switch (cgGetParameterRows(p)) {
1341  case 1:
1342  switch (cgGetParameterColumns(p)) {
1343  case 1: return SAT_mat1x1;
1344  case 2: return SAT_mat1x2;
1345  case 3: return SAT_mat1x3;
1346  case 4: return SAT_mat1x4;
1347  default: return SAT_unknown;
1348  }
1349  case 2:
1350  switch (cgGetParameterColumns(p)) {
1351  case 1: return SAT_mat2x1;
1352  case 2: return SAT_mat2x2;
1353  case 3: return SAT_mat2x3;
1354  case 4: return SAT_mat2x4;
1355  default: return SAT_unknown;
1356  }
1357  case 3:
1358  switch (cgGetParameterColumns(p)) {
1359  case 1: return SAT_mat3x1;
1360  case 2: return SAT_mat3x2;
1361  case 3: return SAT_mat3x3;
1362  case 4: return SAT_mat3x4;
1363  default: return SAT_unknown;
1364  }
1365  case 4:
1366  switch (cgGetParameterColumns(p)) {
1367  case 1: return SAT_mat4x1;
1368  case 2: return SAT_mat4x2;
1369  case 3: return SAT_mat4x3;
1370  case 4: return SAT_mat4x4;
1371  default: return SAT_unknown;
1372  }
1373  default: return SAT_unknown;
1374  }
1375  case CG_PARAMETERCLASS_SAMPLER:
1376  switch (cgGetParameterType(p)) {
1377  case CG_SAMPLER1D: return Shader::SAT_sampler1d;
1378  case CG_SAMPLER2D: return Shader::SAT_sampler2d;
1379  case CG_SAMPLER3D: return Shader::SAT_sampler3d;
1380  case CG_SAMPLER2DARRAY: return Shader::SAT_sampler2dArray;
1381  case CG_SAMPLERCUBE: return Shader::SAT_samplercube;
1382  // CG_SAMPLER1DSHADOW and CG_SAMPLER2DSHADOW
1383  case 1313: return Shader::SAT_sampler1d;
1384  case 1314: return Shader::SAT_sampler2d;
1385  default: return SAT_unknown;
1386  }
1387  case CG_PARAMETERCLASS_ARRAY: return SAT_unknown;
1388  default: return SAT_unknown;
1389  }
1390 }
1391 
1392 ////////////////////////////////////////////////////////////////////
1393 // Function: Shader::cg_parameter_class
1394 // Access: Private
1395 // Description:
1396 ////////////////////////////////////////////////////////////////////
1397 Shader::ShaderArgClass Shader::cg_parameter_class(CGparameter p) {
1398  switch (cgGetParameterClass(p)) {
1399  case CG_PARAMETERCLASS_SCALAR: return Shader::SAC_scalar;
1400  case CG_PARAMETERCLASS_VECTOR: return Shader::SAC_vector;
1401  case CG_PARAMETERCLASS_MATRIX: return Shader::SAC_matrix;
1402  case CG_PARAMETERCLASS_SAMPLER: return Shader::SAC_sampler;
1403  case CG_PARAMETERCLASS_ARRAY: return Shader::SAC_array;
1404  default: return Shader::SAC_unknown;
1405  }
1406 }
1407 
1408 ////////////////////////////////////////////////////////////////////
1409 // Function: Shader::cg_parameter_dir
1410 // Access: Private
1411 // Description:
1412 ////////////////////////////////////////////////////////////////////
1413 Shader::ShaderArgDir Shader::
1414 cg_parameter_dir(CGparameter p) {
1415  switch (cgGetParameterDirection(p)) {
1416  case CG_IN: return Shader::SAD_in;
1417  case CG_OUT: return Shader::SAD_out;
1418  case CG_INOUT: return Shader::SAD_inout;
1419  default: return Shader::SAD_unknown;
1420  }
1421 }
1422 
1423 ////////////////////////////////////////////////////////////////////
1424 // Function: Shader::cg_release_resources
1425 // Access: Private
1426 // Description: xyz
1427 ////////////////////////////////////////////////////////////////////
1428 void Shader::
1429 cg_release_resources() {
1430  if (_cg_vprogram != 0) {
1431  cgDestroyProgram(_cg_vprogram);
1432  _cg_vprogram = 0;
1433  }
1434  if (_cg_fprogram != 0) {
1435  cgDestroyProgram(_cg_fprogram);
1436  _cg_fprogram = 0;
1437  }
1438  if (_cg_gprogram != 0) {
1439  cgDestroyProgram(_cg_gprogram);
1440  _cg_gprogram = 0;
1441  }
1442 }
1443 
1444 ////////////////////////////////////////////////////////////////////
1445 // Function: Shader::cg_compile_entry_point
1446 // Access: Private
1447 // Description: xyz
1448 ////////////////////////////////////////////////////////////////////
1449 CGprogram Shader::
1450 cg_compile_entry_point(const char *entry, const ShaderCaps &caps,
1451  CGcontext context, ShaderType type) {
1452  CGprogram prog;
1453  CGerror err;
1454  const char *compiler_args[100];
1455  const string text = get_text(type);
1456  int nargs = 0;
1457 
1458  int active, ultimate;
1459 
1460  switch (type) {
1461  case ST_vertex:
1462  active = caps._active_vprofile;
1463  ultimate = caps._ultimate_vprofile;
1464  break;
1465 
1466  case ST_fragment:
1467  active = caps._active_fprofile;
1468  ultimate = caps._ultimate_fprofile;
1469  break;
1470 
1471  case ST_geometry:
1472  active = caps._active_gprofile;
1473  ultimate = caps._ultimate_gprofile;
1474  break;
1475 
1476  case ST_tess_evaluation:
1477  case ST_tess_control:
1478  active = caps._active_tprofile;
1479  ultimate = caps._ultimate_tprofile;
1480  break;
1481 
1482  case ST_none:
1483  default:
1484  active = CG_PROFILE_UNKNOWN;
1485  ultimate = CG_PROFILE_UNKNOWN;
1486  };
1487 
1488  cgGetError();
1489 
1490  if (type == ST_fragment && caps._bug_list.count(SBUG_ati_draw_buffers)) {
1491  compiler_args[nargs++] = "-po";
1492  compiler_args[nargs++] = "ATI_draw_buffers";
1493  }
1494 
1495  string version_arg;
1496  if (!cg_glsl_version.empty() && active != CG_PROFILE_UNKNOWN &&
1497  cgGetProfileProperty((CGprofile) active, CG_IS_GLSL_PROFILE)) {
1498 
1499  version_arg = "version=";
1500  version_arg += cg_glsl_version;
1501 
1502  compiler_args[nargs++] = "-po";
1503  compiler_args[nargs++] = version_arg.c_str();
1504  }
1505 
1506  compiler_args[nargs] = 0;
1507 
1508  if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
1509  // Print out some debug information about what we're doing.
1510  if (shader_cat.is_debug()) {
1511  shader_cat.debug()
1512  << "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
1513  << " and active profile " << cgGetProfileString((CGprofile) active) << "\n";
1514 
1515  if (nargs > 0) {
1516  shader_cat.debug() << "Using compiler arguments:";
1517  for (int i = 0; i < nargs; ++i) {
1518  shader_cat.debug(false) << " " << compiler_args[i];
1519  }
1520  shader_cat.debug(false) << "\n";
1521  }
1522  }
1523 
1524  // Compile the shader with the active profile.
1525  prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1526  (CGprofile)active, entry, (const char **)compiler_args);
1527  err = cgGetError();
1528  if (err == CG_NO_ERROR) {
1529  return prog;
1530  }
1531  if (prog != 0) {
1532  cgDestroyProgram(prog);
1533  }
1534  if (shader_cat.is_debug()) {
1535  shader_cat.debug()
1536  << "Compilation with active profile failed: " << cgGetErrorString(err) << "\n";
1537  }
1538  }
1539 
1540  if (shader_cat.is_debug()) {
1541  shader_cat.debug()
1542  << "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
1543  << " and ultimate profile " << cgGetProfileString((CGprofile) ultimate) << "\n";
1544  }
1545 
1546  // The active profile failed, so recompile it with the ultimate profile.
1547  prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1548  (CGprofile)ultimate, entry, (const char **)NULL);
1549 
1550  // Extract the output listing.
1551  err = cgGetError();
1552  const char *listing = cgGetLastListing(context);
1553 
1554  if (err == CG_NO_ERROR && listing != NULL && strlen(listing) > 1) {
1555  shader_cat.warning()
1556  << "Encountered warnings during compilation of " << get_filename(type)
1557  << ":\n" << listing;
1558 
1559  } else if (err == CG_COMPILER_ERROR) {
1560  shader_cat.error()
1561  << "Failed to compile Cg shader " << get_filename(type);
1562  if (listing != NULL) {
1563  shader_cat.error(false) << ":\n" << listing;
1564  } else {
1565  shader_cat.error(false) << "!\n";
1566  }
1567  }
1568 
1569  if (err == CG_NO_ERROR) {
1570  return prog;
1571  }
1572 
1573  if (prog != 0) {
1574  cgDestroyProgram(prog);
1575  }
1576  return 0;
1577 }
1578 
1579 ////////////////////////////////////////////////////////////////////
1580 // Function: Shader::cg_compile_shader
1581 // Access: Private
1582 // Description: Compiles a Cg shader for a given set of capabilities.
1583 // If successful, the shader is stored in the instance
1584 // variables _cg_context, _cg_vprogram, _cg_fprogram.
1585 ////////////////////////////////////////////////////////////////////
1586 bool Shader::
1587 cg_compile_shader(const ShaderCaps &caps, CGcontext context) {
1588  _cg_last_caps = caps;
1589 
1590  if (!_text._separate || !_text._vertex.empty()) {
1591  _cg_vprogram = cg_compile_entry_point("vshader", caps, context, ST_vertex);
1592  if (_cg_vprogram == 0) {
1593  cg_release_resources();
1594  return false;
1595  }
1596  _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
1597  }
1598 
1599  if (!_text._separate || !_text._fragment.empty()) {
1600  _cg_fprogram = cg_compile_entry_point("fshader", caps, context, ST_fragment);
1601  if (_cg_fprogram == 0) {
1602  cg_release_resources();
1603  return false;
1604  }
1605  _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
1606  }
1607 
1608  if ((_text._separate && !_text._geometry.empty()) || (!_text._separate && _text._shared.find("gshader") != string::npos)) {
1609  _cg_gprogram = cg_compile_entry_point("gshader", caps, context, ST_geometry);
1610  if (_cg_gprogram == 0) {
1611  cg_release_resources();
1612  return false;
1613  }
1614  _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
1615  }
1616 
1617  if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
1618  shader_cat.error() << "Shader must at least have one program!\n";
1619  cg_release_resources();
1620  return false;
1621  }
1622 
1623  // This is present to work around a bug in the Cg compiler for Direct3D 9.
1624  // It generates "texld_sat" instructions that the result in an
1625  // D3DXERR_INVALIDDATA error when trying to load the shader, since the _sat
1626  // modifier may not be used on tex* instructions.
1627  if (_cg_fprofile == CG_PROFILE_PS_2_0 ||
1628  _cg_fprofile == CG_PROFILE_PS_2_X ||
1629  _cg_fprofile == CG_PROFILE_PS_3_0) {
1630  vector_string lines;
1631  tokenize(cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM), lines, "\n");
1632 
1633  ostringstream out;
1634  int num_modified = 0;
1635 
1636  for (size_t i = 0; i < lines.size(); ++i) {
1637  const string &line = lines[i];
1638 
1639  size_t space = line.find(' ');
1640  if (space == string::npos) {
1641  out << line << '\n';
1642  continue;
1643  }
1644 
1645  string instr = line.substr(0, space);
1646 
1647  // Look for a texld instruction with _sat modifier.
1648  if (instr.compare(0, 5, "texld") == 0 &&
1649  instr.compare(instr.size() - 4, 4, "_sat") == 0) {
1650  // Which destination register are we operating on?
1651  string reg = line.substr(space + 1, line.find(',', space) - space - 1);
1652 
1653  // Move the saturation operation to a separate instruction.
1654  instr.resize(instr.size() - 4);
1655  out << instr << ' ' << line.substr(space + 1) << '\n';
1656  out << "mov_sat " << reg << ", " << reg << '\n';
1657  ++num_modified;
1658  } else {
1659  out << line << '\n';
1660  }
1661  }
1662 
1663  if (num_modified > 0) {
1664  string result = out.str();
1665  CGprogram new_program;
1666  new_program = cgCreateProgram(context, CG_OBJECT, result.c_str(),
1667  (CGprofile)_cg_fprofile, "fshader",
1668  (const char**)NULL);
1669  if (new_program) {
1670  cgDestroyProgram(_cg_fprogram);
1671  _cg_fprogram = new_program;
1672 
1673  if (shader_cat.is_debug()) {
1674  shader_cat.debug()
1675  << "Replaced " << num_modified << " invalid texld_sat instruction"
1676  << ((num_modified == 1) ? "" : "s") << " in compiled shader\n";
1677  }
1678  } else {
1679  shader_cat.warning()
1680  << "Failed to load shader with fixed texld_sat instructions: "
1681  << cgGetErrorString(cgGetError()) << "\n";
1682  }
1683  }
1684  }
1685 
1686  // DEBUG: output the generated program
1687  if (shader_cat.is_debug()) {
1688  const char *vertex_program;
1689  const char *fragment_program;
1690  const char *geometry_program;
1691 
1692  if (_cg_vprogram != 0) {
1693  shader_cat.debug()
1694  << "Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) << "\n";
1695  vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
1696  shader_cat.debug() << vertex_program << "\n";
1697  }
1698  if (_cg_fprogram != 0) {
1699  shader_cat.debug()
1700  << "Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) << "\n";
1701  fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
1702  shader_cat.debug() << fragment_program << "\n";
1703  }
1704  if (_cg_gprogram != 0) {
1705  shader_cat.debug()
1706  << "Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) << "\n";
1707  geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
1708  shader_cat.debug() << geometry_program << "\n";
1709  }
1710  }
1711 
1712  return true;
1713 }
1714 
1715 ////////////////////////////////////////////////////////////////////
1716 // Function: Shader::cg_analyze_entry_point
1717 // Access: Private
1718 // Description:
1719 ////////////////////////////////////////////////////////////////////
1720 bool Shader::
1721 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
1722  bool success = true;
1723 
1724  cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM), type, success);
1725  return success;
1726 }
1727 
1728 ////////////////////////////////////////////////////////////////////
1729 // Function: Shader::cg_analyze_shader
1730 // Access: Private
1731 // Description: This subroutine analyzes the parameters of a Cg
1732 // shader. The output is stored in instance variables:
1733 // _mat_spec, _var_spec, and _tex_spec.
1734 //
1735 // In order to do this, it is necessary to compile the
1736 // shader. It would be a waste of CPU time to compile
1737 // the shader, analyze the parameters, and then discard
1738 // the compiled shader. This would force us to compile it
1739 // again later, when we need to build the ShaderContext.
1740 // Instead, we cache the compiled Cg program in instance
1741 // variables. Later, a ShaderContext can pull the
1742 // compiled shader from these instance vars.
1743 //
1744 // To compile a shader, you need to first choose a profile.
1745 // There are two contradictory objectives:
1746 //
1747 // 1. If you don't use the gsg's active profile,
1748 // then the cached compiled shader will not be useful to
1749 // the ShaderContext.
1750 //
1751 // 2. If you use too weak a profile, then the shader may
1752 // not compile. So to guarantee success, you should use
1753 // the ultimate profile.
1754 //
1755 // To resolve this conflict, we try the active profile
1756 // first, and if that doesn't work, we try the ultimate
1757 // profile.
1758 //
1759 ////////////////////////////////////////////////////////////////////
1760 bool Shader::
1761 cg_analyze_shader(const ShaderCaps &caps) {
1762 
1763  // Make sure we have a context for analyzing the shader.
1764  if (_cg_context == 0) {
1765  _cg_context = cgCreateContext();
1766  if (_cg_context == 0) {
1767  shader_cat.error()
1768  << "Could not create a Cg context object: "
1769  << cgGetErrorString(cgGetError()) << "\n";
1770  return false;
1771  }
1772  }
1773 
1774  if (!cg_compile_shader(caps, _cg_context)) {
1775  return false;
1776  }
1777 
1778  if (_cg_fprogram != 0) {
1779  if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
1780  cg_release_resources();
1781  clear_parameters();
1782  return false;
1783  }
1784  }
1785 
1786  if (_var_spec.size() != 0) {
1787  shader_cat.error() << "Cannot use vtx parameters in an fshader\n";
1788  cg_release_resources();
1789  clear_parameters();
1790  return false;
1791  }
1792 
1793  if (_cg_vprogram != 0) {
1794  if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
1795  cg_release_resources();
1796  clear_parameters();
1797  return false;
1798  }
1799  }
1800 
1801  if (_cg_gprogram != 0) {
1802  if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
1803  cg_release_resources();
1804  clear_parameters();
1805  return false;
1806  }
1807  }
1808 
1809  // Assign sequence numbers to all parameters.
1810  int seqno = 0;
1811  for (int i=0; i<(int)_mat_spec.size(); i++) {
1812  _mat_spec[i]._id._seqno = seqno++;
1813  }
1814  for (int i=0; i<(int)_tex_spec.size(); i++) {
1815  _tex_spec[i]._id._seqno = seqno++;
1816  }
1817  for (int i=0; i<(int)_var_spec.size(); i++) {
1818  _var_spec[i]._id._seqno = seqno++;
1819  }
1820 
1821  for (int i=0; i<(int)_ptr_spec.size(); i++) {
1822  _ptr_spec[i]._id._seqno = seqno++;
1823  _ptr_spec[i]._info._id = _ptr_spec[i]._id;
1824  }
1825 
1826  // // The following code is present to work around a bug in the Cg compiler.
1827  // // It does not generate correct code for shadow map lookups when using arbfp1.
1828  // // This is a particularly onerous limitation, given that arbfp1 is the only
1829  // // Cg target that works on radeons. I suspect this is an intentional
1830  // // omission on nvidia's part. The following code fetches the output listing,
1831  // // detects the error, repairs the code, and resumbits the repaired code to Cg.
1832  // if ((_cg_fprofile == CG_PROFILE_ARBFP1) && (gsghint->_supports_shadow_filter)) {
1833  // bool shadowunit[32];
1834  // bool anyshadow = false;
1835  // memset(shadowunit, 0, sizeof(shadowunit));
1836  // vector_string lines;
1837  // tokenize(cgGetProgramString(_cg_program[SHADER_type_frag],
1838  // CG_COMPILED_PROGRAM), lines, "\n");
1839  // // figure out which texture units contain shadow maps.
1840  // for (int lineno=0; lineno<(int)lines.size(); lineno++) {
1841  // if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) {
1842  // continue;
1843  // }
1844  // vector_string fields;
1845  // tokenize(lines[lineno], fields, ":");
1846  // if (fields.size()!=5) {
1847  // continue;
1848  // }
1849  // vector_string words;
1850  // tokenize(trim(fields[2]), words, " ");
1851  // if (words.size()!=2) {
1852  // continue;
1853  // }
1854  // int unit = atoi(words[1].c_str());
1855  // if ((unit < 0)||(unit >= 32)) {
1856  // continue;
1857  // }
1858  // anyshadow = true;
1859  // shadowunit[unit] = true;
1860  // }
1861  // // modify all TEX statements that use the relevant texture units.
1862  // if (anyshadow) {
1863  // for (int lineno=0; lineno<(int)lines.size(); lineno++) {
1864  // if (lines[lineno].compare(0,4,"TEX ")) {
1865  // continue;
1866  // }
1867  // vector_string fields;
1868  // tokenize(lines[lineno], fields, ",");
1869  // if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) {
1870  // continue;
1871  // }
1872  // vector_string texunitf;
1873  // tokenize(trim(fields[2]), texunitf, "[]");
1874  // if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) {
1875  // continue;
1876  // }
1877  // int unit = atoi(texunitf[1].c_str());
1878  // if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) {
1879  // continue;
1880  // }
1881  // lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;";
1882  // }
1883  // string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n";
1884  // for (int lineno=1; lineno<(int)lines.size(); lineno++) {
1885  // result += (lines[lineno] + "\n");
1886  // }
1887  // _cg_program[2] = _cg_program[SHADER_type_frag];
1888  // _cg_program[SHADER_type_frag] =
1889  // cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(),
1890  // _cg_profile[SHADER_type_frag], "fshader", (const char**)NULL);
1891  // cg_report_errors(s->get_name(), _cg_context);
1892  // if (_cg_program[SHADER_type_frag]==0) {
1893  // release_resources();
1894  // return false;
1895  // }
1896  // }
1897  // }
1898 
1899  cg_release_resources();
1900  return true;
1901 }
1902 
1903 ////////////////////////////////////////////////////////////////////
1904 // Function: Shader::cg_program_from_shadertype
1905 // Access: Private
1906 // Description: Returns the CGprogram of the given shadertype
1907 // that belongs to this shader.
1908 ////////////////////////////////////////////////////////////////////
1909 CGprogram Shader::
1910 cg_program_from_shadertype(ShaderType type) {
1911  switch (type) {
1912  case ST_vertex:
1913  return _cg_vprogram;
1914 
1915  case ST_fragment:
1916  return _cg_fprogram;
1917 
1918  case ST_geometry:
1919  return _cg_gprogram;
1920 
1921  default:
1922  return 0;
1923  }
1924 }
1925 
1926 ////////////////////////////////////////////////////////////////////
1927 // Function: Shader::cg_compile_for
1928 // Access: Public
1929 // Description: This routine is used by the ShaderContext constructor
1930 // to compile the shader. The CGprogram
1931 // objects are turned over to the ShaderContext, we no
1932 // longer own them.
1933 ////////////////////////////////////////////////////////////////////
1934 bool Shader::
1935 cg_compile_for(const ShaderCaps &caps, CGcontext context,
1936  CGprogram &combined_program, pvector<CGparameter> &map) {
1937 
1938  // Initialize the return values to empty.
1939  combined_program = 0;
1940  map.clear();
1941 
1942  // Make sure the shader is compiled for the target caps.
1943  // Most of the time, it will already be - this is usually a no-op.
1944 
1945  _default_caps = caps;
1946  if (!cg_compile_shader(caps, context)) {
1947  return false;
1948  }
1949 
1950  // If the compile routine used the ultimate profile instead of the
1951  // active one, it means the active one isn't powerful enough to
1952  // compile the shader.
1953  if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
1954  shader_cat.error() << "Cg vertex program not supported by profile "
1955  << cgGetProfileString((CGprofile) caps._active_vprofile) << ": "
1956  << get_filename(ST_vertex) << ". Try choosing a different profile.\n";
1957  return false;
1958  }
1959  if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
1960  shader_cat.error() << "Cg fragment program not supported by profile "
1961  << cgGetProfileString((CGprofile) caps._active_fprofile) << ": "
1962  << get_filename(ST_fragment) << ". Try choosing a different profile.\n";
1963  return false;
1964  }
1965  if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
1966  shader_cat.error() << "Cg geometry program not supported by profile "
1967  << cgGetProfileString((CGprofile) caps._active_gprofile) << ": "
1968  << get_filename(ST_geometry) << ". Try choosing a different profile.\n";
1969  return false;
1970  }
1971 
1972  // Gather the programs we will be combining.
1973  pvector<CGprogram> programs;
1974  if (_cg_vprogram != 0) {
1975  programs.push_back(_cg_vprogram);
1976  }
1977  if (_cg_fprogram != 0) {
1978  programs.push_back(_cg_fprogram);
1979  }
1980  if (_cg_gprogram != 0) {
1981  programs.push_back(_cg_gprogram);
1982  }
1983 
1984  // Combine the programs. This can be more optimal than loading them
1985  // individually, and it is even necessary for some profiles
1986  // (particularly GLSL profiles on non-NVIDIA GPUs).
1987  combined_program = cgCombinePrograms(programs.size(), &programs[0]);
1988 
1989  // Build a parameter map.
1990  int n_mat = (int)_mat_spec.size();
1991  int n_tex = (int)_tex_spec.size();
1992  int n_var = (int)_var_spec.size();
1993  int n_ptr = (int)_ptr_spec.size();
1994 
1995  map.resize(n_mat + n_tex + n_var + n_ptr);
1996 
1997  // This is a bit awkward, we have to go in and seperate out the
1998  // combined program, since all the parameter bindings have changed.
1999  CGprogram programs_by_type[ST_COUNT];
2000  for (int i = 0; i < cgGetNumProgramDomains(combined_program); ++i) {
2001  // Conveniently, the CGdomain enum overlaps with ShaderType.
2002  CGprogram program = cgGetProgramDomainProgram(combined_program, i);
2003  programs_by_type[cgGetProgramDomain(program)] = program;
2004  }
2005 
2006  for (int i = 0; i < n_mat; ++i) {
2007  const ShaderArgId &id = _mat_spec[i]._id;
2008  map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
2009  }
2010 
2011  for (int i = 0; i < n_tex; ++i) {
2012  const ShaderArgId &id = _tex_spec[i]._id;
2013  CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
2014 
2015  if (shader_cat.is_debug()) {
2016  const char *resource = cgGetParameterResourceName(p);
2017  if (resource != NULL) {
2018  shader_cat.debug() << "Texture parameter " << id._name
2019  << " is bound to resource " << resource << "\n";
2020  }
2021  }
2022  map[id._seqno] = p;
2023  }
2024 
2025  for (int i = 0; i < n_var; ++i) {
2026  const ShaderArgId &id = _var_spec[i]._id;
2027  CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
2028 
2029  const char *resource = cgGetParameterResourceName(p);
2030  if (shader_cat.is_debug() && resource != NULL) {
2031  shader_cat.debug()
2032  << "Varying parameter " << id._name << " is bound to resource "
2033  << cgGetParameterResourceName(p) << "\n";
2034  }
2035 
2036  if (cgGetParameterBaseResource(p) == CG_UNDEFINED) {
2037  // I really don't know what this means, but it happens when I
2038  // use the NORMAL0 semantic instead of NORMAL, or POSITION0
2039  // instead of POSITION, etc. Not catching this results in a
2040  // continuous stream of errors at the renderer side.
2041  shader_cat.error()
2042  << "Varying parameter " << id._name;
2043 
2044  const char *semantic = cgGetParameterSemantic(p);
2045  if (semantic != NULL) {
2046  shader_cat.error(false) << " : " << semantic;
2047  }
2048  if (resource != NULL) {
2049  shader_cat.error(false) << " (bound to resource " << resource << ")";
2050  }
2051  shader_cat.error(false) << " is invalid!\n";
2052 
2053 #ifndef NDEBUG
2054  // Let's try to give the developer a hint...
2055  if (semantic != NULL) {
2056  if (strcmp(semantic, "POSITION0") == 0) {
2057  shader_cat.error() << "Try using the semantic POSITION instead of POSITION0.\n";
2058  } else if (strcmp(semantic, "NORMAL0") == 0) {
2059  shader_cat.error() << "Try using the semantic NORMAL instead of NORMAL0.\n";
2060  } else if (strcmp(semantic, "DIFFUSE0") == 0) {
2061  shader_cat.error() << "Try using the semantic DIFFUSE instead of DIFFUSE0.\n";
2062  } else if (strcmp(semantic, "SPECULAR0") == 0) {
2063  shader_cat.error() << "Try using the semantic SPECULAR instead of SPECULAR0.\n";
2064  } else if (strcmp(semantic, "FOGCOORD0") == 0) {
2065  shader_cat.error() << "Try using the semantic FOGCOORD instead of FOGCOORD0.\n";
2066  } else if (strcmp(semantic, "PSIZE0") == 0) {
2067  shader_cat.error() << "Try using the semantic PSIZE instead of PSIZE0.\n";
2068  }
2069  }
2070 #endif // NDEBUG
2071  p = 0;
2072  }
2073  map[id._seqno] = p;
2074  }
2075 
2076  for (int i = 0; i < n_ptr; ++i) {
2077  const ShaderArgId &id = _ptr_spec[i]._id;
2078  map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
2079  }
2080 
2081  // Transfer ownership of the compiled shader.
2082  if (_cg_vprogram != 0) {
2083  cgDestroyProgram(_cg_vprogram);
2084  _cg_vprogram = 0;
2085  }
2086  if (_cg_fprogram != 0) {
2087  cgDestroyProgram(_cg_fprogram);
2088  _cg_fprogram = 0;
2089  }
2090  if (_cg_gprogram != 0) {
2091  cgDestroyProgram(_cg_gprogram);
2092  _cg_gprogram = 0;
2093  }
2094 
2095  _cg_last_caps.clear();
2096 
2097  return true;
2098 }
2099 #endif // HAVE_CG
2100 
2101 ////////////////////////////////////////////////////////////////////
2102 // Function: Shader::Constructor
2103 // Access: Private
2104 // Description: Construct a Shader that will be filled in using
2105 // fillin() or read() later.
2106 ////////////////////////////////////////////////////////////////////
2107 Shader::
2108 Shader(ShaderLanguage lang) :
2109  _error_flag(false),
2110  _parse(0),
2111  _loaded(false),
2112  _language(lang),
2113  _last_modified(0)
2114 {
2115 #ifdef HAVE_CG
2116  _cg_vprogram = 0;
2117  _cg_fprogram = 0;
2118  _cg_gprogram = 0;
2119  _cg_vprofile = CG_PROFILE_UNKNOWN;
2120  _cg_fprofile = CG_PROFILE_UNKNOWN;
2121  _cg_gprofile = CG_PROFILE_UNKNOWN;
2122  if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
2123  _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
2124  _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
2125  _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2126  _default_caps._ultimate_vprofile = cgGetProfile("glslv");
2127  _default_caps._ultimate_fprofile = cgGetProfile("glslf");
2128  _default_caps._ultimate_gprofile = cgGetProfile("glslg");
2129  if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
2130  _default_caps._ultimate_gprofile = cgGetProfile("gp4gp");
2131  }
2132  }
2133 #endif
2134 }
2135 
2136 ////////////////////////////////////////////////////////////////////
2137 // Function: Shader::read
2138 // Access: Private
2139 // Description: Reads the shader from the given filename(s).
2140 // Returns a boolean indicating success or failure.
2141 ////////////////////////////////////////////////////////////////////
2142 bool Shader::
2143 read(const ShaderFile &sfile) {
2144  _text._separate = sfile._separate;
2145 
2146  if (sfile._separate) {
2147  if (_language == SL_none) {
2148  shader_cat.error()
2149  << "No shader language was specified!\n";
2150  return false;
2151  }
2152 
2153  if (!sfile._vertex.empty() && !do_read_source(_text._vertex, sfile._vertex)) {
2154  return false;
2155  }
2156  if (!sfile._fragment.empty() && !do_read_source(_text._fragment, sfile._fragment)) {
2157  return false;
2158  }
2159  if (!sfile._geometry.empty() && !do_read_source(_text._geometry, sfile._geometry)) {
2160  return false;
2161  }
2162  if (!sfile._tess_control.empty() && !do_read_source(_text._tess_control, sfile._tess_control)) {
2163  return false;
2164  }
2165  if (!sfile._tess_evaluation.empty() && !do_read_source(_text._tess_evaluation, sfile._tess_evaluation)) {
2166  return false;
2167  }
2168  if (!sfile._compute.empty() && !do_read_source(_text._compute, sfile._compute)) {
2169  return false;
2170  }
2171  _filename = sfile;
2172 
2173  } else {
2174  if (!do_read_source(_text._shared, sfile._shared)) {
2175  return false;
2176  }
2177  _filename = sfile;
2178 
2179  // Determine which language the shader is written in.
2180  if (_language == SL_none) {
2181  string header;
2182  parse_init();
2183  parse_line(header, true, true);
2184  if (header == "//Cg") {
2185  _language = SL_Cg;
2186  } else {
2187  shader_cat.error()
2188  << "Unable to determine shader language of " << sfile._shared << "\n";
2189  return false;
2190  }
2191  } else if (_language == SL_GLSL) {
2192  shader_cat.error()
2193  << "GLSL shaders must have separate shader bodies!\n";
2194  return false;
2195  }
2196 
2197  // Determine which language the shader is written in.
2198  if (_language == SL_Cg) {
2199 #ifdef HAVE_CG
2200  cg_get_profile_from_header(_default_caps);
2201 
2202  if (!cg_analyze_shader(_default_caps)) {
2203  shader_cat.error()
2204  << "Shader encountered an error.\n";
2205  return false;
2206  }
2207 #else
2208  shader_cat.error()
2209  << "Tried to load Cg shader, but no Cg support is enabled.\n";
2210 #endif
2211  } else {
2212  shader_cat.error()
2213  << "Shader is not in a supported shader-language.\n";
2214  return false;
2215  }
2216  }
2217 
2218  _loaded = true;
2219  return true;
2220 }
2221 
2222 ////////////////////////////////////////////////////////////////////
2223 // Function: Shader::do_read_source
2224 // Access: Private
2225 // Description: Reads the shader file from the given path into the
2226 // given string.
2227 //
2228 // Returns false if there was an error with this shader
2229 // bad enough to consider it 'invalid'.
2230 ////////////////////////////////////////////////////////////////////
2231 bool Shader::
2232 do_read_source(string &into, const Filename &fn) {
2233  if (_language == SL_GLSL && glsl_preprocess) {
2234  // Preprocess the GLSL file as we read it.
2235  set<Filename> open_files;
2236  ostringstream sstr;
2237  if (!r_preprocess_source(sstr, fn, Filename(), open_files)) {
2238  return false;
2239  }
2240  into = sstr.str();
2241 
2242  } else {
2243  shader_cat.info() << "Reading shader file: " << fn << "\n";
2244 
2246  PT(VirtualFile) vf = vfs->find_file(fn, get_model_path());
2247  if (vf == NULL) {
2248  shader_cat.error()
2249  << "Could not find shader file: " << fn << "\n";
2250  return false;
2251  }
2252 
2253  if (!vf->read_file(into, true)) {
2254  shader_cat.error()
2255  << "Could not read shader file: " << fn << "\n";
2256  return false;
2257  }
2258 
2259  _last_modified = max(_last_modified, vf->get_timestamp());
2260  _source_files.push_back(vf->get_filename());
2261  }
2262  return true;
2263 }
2264 
2265 ////////////////////////////////////////////////////////////////////
2266 // Function: Shader::r_preprocess_source
2267 // Access: Private
2268 // Description: Loads a given GLSL file line by line, and processes
2269 // any #pragma include and once statements.
2270 //
2271 // The set keeps track of which files we have already
2272 // included, for checking recursive includes.
2273 ////////////////////////////////////////////////////////////////////
2274 bool Shader::
2275 r_preprocess_source(ostream &out, const Filename &fn,
2276  const Filename &source_dir,
2277  set<Filename> &once_files, int depth) {
2278 
2279  if (depth > glsl_include_recursion_limit) {
2280  shader_cat.error()
2281  << "#pragma include nested too deeply\n";
2282  return false;
2283  }
2284 
2285  DSearchPath path(get_model_path());
2286  if (!source_dir.empty()) {
2287  path.prepend_directory(source_dir);
2288  }
2289 
2291  PT(VirtualFile) vf = vfs->find_file(fn, path);
2292  if (vf == NULL) {
2293  shader_cat.error()
2294  << "Could not find shader file: " << fn << "\n";
2295  return false;
2296  }
2297 
2298  Filename full_fn = vf->get_filename();
2299  if (once_files.find(full_fn) != once_files.end()) {
2300  // If this file had a #pragma once, just move on.
2301  return true;
2302  }
2303 
2304  istream *source = vf->open_read_file(true);
2305  if (source == NULL) {
2306  shader_cat.error()
2307  << "Could not open shader file: " << fn << "\n";
2308  return false;
2309  }
2310 
2311  _last_modified = max(_last_modified, vf->get_timestamp());
2312  _source_files.push_back(full_fn);
2313 
2314  // We give each file an unique index. This is so that we can identify
2315  // a particular shader in the error output. We offset them by 2048
2316  // so that they are more recognizable. GLSL doesn't give us anything
2317  // more useful than that, unfortunately.
2318  //
2319  // Don't do this for the top-level file, though. We don't want
2320  // anything to get in before a potential #version directive.
2321  int fileno = 0;
2322  if (depth > 0) {
2323  fileno = 2048 + _included_files.size();
2324  // Write it into the vector so that we can substitute it later
2325  // when we are parsing the GLSL error log. Don't store the full
2326  // filename because it would just be too long to display.
2327  _included_files.push_back(fn);
2328 
2329  out << "#line 1 " << fileno << " // " << fn << "\n";
2330  if (shader_cat.is_debug()) {
2331  shader_cat.debug()
2332  << "Preprocessing shader include " << fileno << ": " << fn << "\n";
2333  }
2334  } else {
2335  shader_cat.info()
2336  << "Preprocessing shader file: " << fn << "\n";
2337  }
2338 
2339  // Iterate over the lines for things we may need to preprocess.
2340  string line;
2341  bool had_include = false;
2342  int lineno = 0;
2343  while (getline(*source, line)) {
2344  ++lineno;
2345 
2346  // Check if this line contains a #pragma.
2347  char pragma[64];
2348  if (line.size() < 8 ||
2349  sscanf(line.c_str(), " # pragma %63s", pragma) != 1) {
2350  // Just pass the line through unmodified.
2351  out << line << "\n";
2352 
2353  // One exception: check for an #endif after an include. We have
2354  // to restore the line number in case the include happened under
2355  // an #if block.
2356  int nread = 0;
2357  if (had_include && sscanf(line.c_str(), " # endif %n", &nread) == 0 && nread >= 6) {
2358  out << "#line " << (lineno + 1) << " " << fileno << "\n";
2359  }
2360  continue;
2361  }
2362 
2363  int nread = 0;
2364  if (strcmp(pragma, "include") == 0) {
2365  // Allow both double quotes and angle brackets.
2366  Filename incfn, source_dir;
2367  {
2368  char incfile[2048];
2369  if (sscanf(line.c_str(), " # pragma%*[ \t]include \"%2047[^\"]\" %n", incfile, &nread) == 1
2370  && nread == line.size()) {
2371  // A regular include, with double quotes. Probably a local file.
2372  source_dir = full_fn.get_dirname();
2373  incfn = incfile;
2374 
2375  } else if (sscanf(line.c_str(), " # pragma%*[ \t]include <%2047[^\"]> %n", incfile, &nread) == 1
2376  && nread == line.size()) {
2377  // Angled includes are also OK, but we don't search in the
2378  // directory of the source file.
2379  incfn = incfile;
2380 
2381  } else {
2382  // Couldn't parse it.
2383  shader_cat.error()
2384  << "Malformed #pragma include at line " << lineno
2385  << " of file " << fn << ":\n " << line << "\n";
2386  return false;
2387  }
2388  }
2389 
2390  // OK, great. Process the include.
2391  if (!r_preprocess_source(out, incfn, source_dir, once_files, depth + 1)) {
2392  // An error occurred. Pass on the failure.
2393  shader_cat.error(false) << "included at line "
2394  << lineno << " of file " << fn << ":\n " << line << "\n";
2395  return false;
2396  }
2397 
2398  // Restore the line counter.
2399  out << "#line " << (lineno + 1) << " " << fileno << " // " << fn << "\n";
2400  had_include = true;
2401 
2402  } else if (strcmp(pragma, "once") == 0) {
2403  // Do a stricter syntax check, just to be extra safe.
2404  if (sscanf(line.c_str(), " # pragma%*[ \t]once %n", &nread) != 0 ||
2405  nread != line.size()) {
2406  shader_cat.error()
2407  << "Malformed #pragma once at line " << lineno
2408  << " of file " << fn << ":\n " << line << "\n";
2409  return false;
2410  }
2411 
2412  once_files.insert(full_fn);
2413 
2414  } else if (strcmp(pragma, "optionNV") == 0) {
2415  // This is processed by NVIDIA drivers. Don't touch it.
2416  out << line << "\n";
2417 
2418  } else {
2419  // Forward it, the driver will ignore it if it doesn't know it.
2420  out << line << "\n";
2421  shader_cat.warning()
2422  << "Ignoring unknown pragma directive \"" << pragma << "\" at line "
2423  << lineno << " of file " << fn << ":\n " << line << "\n";
2424  }
2425  }
2426 
2427  vf->close_read_file(source);
2428  return true;
2429 }
2430 
2431 ////////////////////////////////////////////////////////////////////
2432 // Function: Shader::check_modified
2433 // Access: Private
2434 // Description: Checks whether the shader or any of its dependent
2435 // files were modified on disk.
2436 ////////////////////////////////////////////////////////////////////
2437 bool Shader::
2438 check_modified() const {
2440 
2442  for (it = _source_files.begin(); it != _source_files.end(); ++it) {
2443  const Filename &fn = (*it);
2444 
2445  PT(VirtualFile) vfile = vfs->get_file(fn, true);
2446  if (vfile == (VirtualFile *)NULL || vfile->get_timestamp() > _last_modified) {
2447  return true;
2448  }
2449  }
2450 
2451  return false;
2452 }
2453 
2454 #ifdef HAVE_CG
2455 ////////////////////////////////////////////////////////////////////
2456 // Function: Shader::cg_get_profile_from_header
2457 // Access: Private
2458 // Description: Determines the appropriate active shader profile settings
2459 // based on any profile directives stored within the shader header
2460 ////////////////////////////////////////////////////////////////////
2461 void Shader::
2462 cg_get_profile_from_header(ShaderCaps& caps) {
2463  // Note this forces profile based on what is specified in the shader
2464  // header string. Should probably be relying on card caps eventually.
2465 
2466  string buf;
2467  parse_init();
2468 
2469  // Assume that if parse doesn't extend after a parse line then
2470  // we've reached the end of _text
2471  int lastParse;
2472 
2473  do {
2474  lastParse = _parse;
2475  parse_line(buf, true, true);
2476  int profilePos = buf.find("//Cg profile");
2477  if (profilePos >= 0) {
2478  // Scan the line for known cg2 vertex program profiles
2479  if ((int)buf.find("gp4vp") >= 0)
2480  caps._active_vprofile = cgGetProfile("gp4vp");
2481 
2482  if ((int)buf.find("gp5vp") >= 0)
2483  caps._active_vprofile = cgGetProfile("gp5vp");
2484 
2485  if ((int)buf.find("glslv") >= 0)
2486  caps._active_vprofile = cgGetProfile("glslv");
2487 
2488  if ((int)buf.find("arbvp1") >= 0)
2489  caps._active_vprofile = cgGetProfile("arbvp1");
2490 
2491  if ((int)buf.find("vp40") >= 0)
2492  caps._active_vprofile = cgGetProfile("vp40");
2493 
2494  if ((int)buf.find("vp30") >= 0)
2495  caps._active_vprofile = cgGetProfile("vp30");
2496 
2497  if ((int)buf.find("vp20") >= 0)
2498  caps._active_vprofile = cgGetProfile("vp20");
2499 
2500  if ((int)buf.find("vs_1_1") >= 0)
2501  caps._active_vprofile = cgGetProfile("vs_1_1");
2502 
2503  if ((int)buf.find("vs_2_0") >= 0)
2504  caps._active_vprofile = cgGetProfile("vs_2_0");
2505 
2506  if ((int)buf.find("vs_2_x") >= 0)
2507  caps._active_vprofile = cgGetProfile("vs_2_x");
2508 
2509  if ((int)buf.find("vs_3_0") >= 0)
2510  caps._active_vprofile = cgGetProfile("vs_3_0");
2511 
2512  if ((int)buf.find("vs_4_0") >= 0)
2513  caps._active_vprofile = cgGetProfile("vs_4_0");
2514 
2515  if ((int)buf.find("vs_5_0") >= 0)
2516  caps._active_vprofile = cgGetProfile("vs_5_0");
2517 
2518  // Scan the line for known cg2 fragment program profiles
2519  if ((int)buf.find("gp4fp") >= 0)
2520  caps._active_fprofile = cgGetProfile("gp4fp");
2521 
2522  if ((int)buf.find("gp5fp") >= 0)
2523  caps._active_fprofile = cgGetProfile("gp5fp");
2524 
2525  if ((int)buf.find("glslf") >= 0)
2526  caps._active_fprofile = cgGetProfile("glslf");
2527 
2528  if ((int)buf.find("arbfp1") >= 0)
2529  caps._active_fprofile = cgGetProfile("arbfp1");
2530 
2531  if ((int)buf.find("fp40") >= 0)
2532  caps._active_fprofile = cgGetProfile("fp40");
2533 
2534  if ((int)buf.find("fp30") >= 0)
2535  caps._active_fprofile = cgGetProfile("fp30");
2536 
2537  if ((int)buf.find("fp20") >= 0)
2538  caps._active_fprofile = cgGetProfile("fp20");
2539 
2540  if ((int)buf.find("ps_1_1") >= 0)
2541  caps._active_fprofile = cgGetProfile("ps_1_1");
2542 
2543  if ((int)buf.find("ps_1_2") >= 0)
2544  caps._active_fprofile = cgGetProfile("ps_1_2");
2545 
2546  if ((int)buf.find("ps_1_3") >= 0)
2547  caps._active_fprofile = cgGetProfile("ps_1_3");
2548 
2549  if ((int)buf.find("ps_2_0") >= 0)
2550  caps._active_fprofile = cgGetProfile("ps_2_0");
2551 
2552  if ((int)buf.find("ps_2_x") >= 0)
2553  caps._active_fprofile = cgGetProfile("ps_2_x");
2554 
2555  if ((int)buf.find("ps_3_0") >= 0)
2556  caps._active_fprofile = cgGetProfile("ps_3_0");
2557 
2558  if ((int)buf.find("ps_4_0") >= 0)
2559  caps._active_fprofile = cgGetProfile("ps_4_0");
2560 
2561  if ((int)buf.find("ps_5_0") >= 0)
2562  caps._active_fprofile = cgGetProfile("ps_5_0");
2563 
2564  // Scan the line for known cg2 geometry program profiles
2565  if ((int)buf.find("gp4gp") >= 0)
2566  caps._active_gprofile = cgGetProfile("gp4gp");
2567 
2568  if ((int)buf.find("gp5gp") >= 0)
2569  caps._active_gprofile = cgGetProfile("gp5gp");
2570 
2571  if ((int)buf.find("glslg") >= 0)
2572  caps._active_gprofile = cgGetProfile("glslg");
2573 
2574  if ((int)buf.find("gs_4_0") >= 0)
2575  caps._active_gprofile = cgGetProfile("gs_4_0");
2576 
2577  if ((int)buf.find("gs_5_0") >= 0)
2578  caps._active_gprofile = cgGetProfile("gs_5_0");
2579  }
2580  } while(_parse > lastParse);
2581 
2582 }
2583 #endif
2584 
2585 ////////////////////////////////////////////////////////////////////
2586 // Function: Shader::Destructor
2587 // Access: Public
2588 // Description: Delete the compiled code, if it exists.
2589 ////////////////////////////////////////////////////////////////////
2590 Shader::
2592  release_all();
2593  // Note: don't try to erase ourselves from the table. It currently
2594  // keeps a reference forever, and so the only place where this
2595  // constructor is called is in the destructor of the table itself.
2596  /*if (_loaded) {
2597  _load_table.erase(_filename);
2598  } else {
2599  _make_table.erase(_text);
2600  }*/
2601 }
2602 
2603 ////////////////////////////////////////////////////////////////////
2604 // Function: Shader::load
2605 // Access: Published, Static
2606 // Description: Loads the shader with the given filename.
2607 ////////////////////////////////////////////////////////////////////
2608 PT(Shader) Shader::
2609 load(const Filename &file, ShaderLanguage lang) {
2610  ShaderFile sfile(file);
2611  ShaderTable::const_iterator i = _load_table.find(sfile);
2612  if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2613  // But check that someone hasn't modified it in the meantime.
2614  if (i->second->check_modified()) {
2615  shader_cat.info()
2616  << "Shader " << file << " was modified on disk, reloading.\n";
2617  } else {
2618  shader_cat.debug()
2619  << "Shader " << file << " was found in shader cache.\n";
2620  return i->second;
2621  }
2622  }
2623 
2624  PT(Shader) shader = new Shader(lang);
2625  if (!shader->read(sfile)) {
2626  return NULL;
2627  }
2628 
2629  _load_table[sfile] = shader;
2630  return shader;
2631 }
2632 
2633 ////////////////////////////////////////////////////////////////////
2634 // Function: Shader::load
2635 // Access: Published, Static
2636 // Description: This variant of Shader::load loads all shader
2637 // programs separately.
2638 ////////////////////////////////////////////////////////////////////
2639 PT(Shader) Shader::
2640 load(ShaderLanguage lang, const Filename &vertex,
2641  const Filename &fragment, const Filename &geometry,
2642  const Filename &tess_control, const Filename &tess_evaluation) {
2643  ShaderFile sfile(vertex, fragment, geometry, tess_control, tess_evaluation);
2644  ShaderTable::const_iterator i = _load_table.find(sfile);
2645  if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2646  // But check that someone hasn't modified it in the meantime.
2647  if (i->second->check_modified()) {
2648  shader_cat.info()
2649  << "Shader was modified on disk, reloading.\n";
2650  } else {
2651  shader_cat.debug()
2652  << "Shader was found in shader cache.\n";
2653  return i->second;
2654  }
2655  }
2656 
2657  PT(Shader) shader = new Shader(lang);
2658  if (!shader->read(sfile)) {
2659  return NULL;
2660  }
2661 
2662  _load_table[sfile] = shader;
2663  return shader;
2664 }
2665 
2666 ////////////////////////////////////////////////////////////////////
2667 // Function: Shader::load_compute
2668 // Access: Published, Static
2669 // Description: Loads a compute shader.
2670 ////////////////////////////////////////////////////////////////////
2671 PT(Shader) Shader::
2672 load_compute(ShaderLanguage lang, const Filename &fn) {
2673  if (lang != SL_GLSL) {
2674  shader_cat.error()
2675  << "Only GLSL compute shaders are currently supported.\n";
2676  return NULL;
2677  }
2678 
2679  ShaderFile sfile;
2680  sfile._separate = true;
2681  sfile._compute = fn;
2682 
2683  ShaderTable::const_iterator i = _load_table.find(sfile);
2684  if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2685  // But check that someone hasn't modified it in the meantime.
2686  if (i->second->check_modified()) {
2687  shader_cat.info()
2688  << "Compute shader " << fn << " was modified on disk, reloading.\n";
2689  } else {
2690  shader_cat.debug()
2691  << "Compute shader " << fn << " was found in shader cache.\n";
2692  return i->second;
2693  }
2694  }
2695 
2696  PT(Shader) shader = new Shader(lang);
2697  if (!shader->read(sfile)) {
2698  return NULL;
2699  }
2700 
2701  _load_table[sfile] = shader;
2702  return shader;
2703 }
2704 
2705 //////////////////////////////////////////////////////////////////////
2706 // Function: Shader::make
2707 // Access: Published, Static
2708 // Description: Loads the shader, using the string as shader body.
2709 //////////////////////////////////////////////////////////////////////
2710 PT(Shader) Shader::
2711 make(const string &body, ShaderLanguage lang) {
2712  if (lang == SL_GLSL) {
2713  shader_cat.error()
2714  << "GLSL shaders must have separate shader bodies!\n";
2715  return NULL;
2716 
2717  } else if (lang == SL_none) {
2718  shader_cat.warning()
2719  << "Shader::make() now requires an explicit shader language. Assuming Cg.\n";
2720  lang = SL_Cg;
2721  }
2722 #ifndef HAVE_CG
2723  if (lang == SL_Cg) {
2724  shader_cat.error() << "Support for Cg shaders is not enabled.\n";
2725  return NULL;
2726  }
2727 #endif
2728 
2729  ShaderFile sbody(body);
2730 
2731  if (cache_generated_shaders) {
2732  ShaderTable::const_iterator i = _make_table.find(sbody);
2733  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2734  return i->second;
2735  }
2736  }
2737 
2738  PT(Shader) shader = new Shader(lang);
2739  shader->_filename = ShaderFile("created-shader");
2740  shader->_text = sbody;
2741 
2742 #ifdef HAVE_CG
2743  if (lang == SL_Cg) {
2744  shader->cg_get_profile_from_header(_default_caps);
2745 
2746  if (!shader->cg_analyze_shader(_default_caps)) {
2747  shader_cat.error()
2748  << "Shader encountered an error.\n";
2749  return NULL;
2750  }
2751  }
2752 #endif
2753 
2754  if (cache_generated_shaders) {
2755  _make_table[sbody] = shader;
2756  }
2757 
2758  if (dump_generated_shaders) {
2759  ostringstream fns;
2760  int index = _shaders_generated ++;
2761  fns << "genshader" << index;
2762  string fn = fns.str();
2763  shader_cat.warning() << "Dumping shader: " << fn << "\n";
2764 
2765  pofstream s;
2766  s.open(fn.c_str(), ios::out | ios::trunc);
2767  s << body;
2768  s.close();
2769  }
2770  return shader;
2771 }
2772 
2773 //////////////////////////////////////////////////////////////////////
2774 // Function: Shader::make
2775 // Access: Published, Static
2776 // Description: Loads the shader, using the strings as shader bodies.
2777 //////////////////////////////////////////////////////////////////////
2778 PT(Shader) Shader::
2779 make(ShaderLanguage lang, const string &vertex, const string &fragment,
2780  const string &geometry, const string &tess_control,
2781  const string &tess_evaluation) {
2782 #ifndef HAVE_CG
2783  if (lang == SL_Cg) {
2784  shader_cat.error() << "Support for Cg shaders is not enabled.\n";
2785  return NULL;
2786  }
2787 #endif
2788  if (lang == SL_none) {
2789  shader_cat.error()
2790  << "Shader::make() requires an explicit shader language.\n";
2791  return NULL;
2792  }
2793 
2794  ShaderFile sbody(vertex, fragment, geometry, tess_control, tess_evaluation);
2795 
2796  if (cache_generated_shaders) {
2797  ShaderTable::const_iterator i = _make_table.find(sbody);
2798  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2799  return i->second;
2800  }
2801  }
2802 
2803  PT(Shader) shader = new Shader(lang);
2804  shader->_filename = ShaderFile("created-shader");
2805  shader->_text = sbody;
2806 
2807 #ifdef HAVE_CG
2808  if (lang == SL_Cg) {
2809  if (!shader->cg_analyze_shader(_default_caps)) {
2810  shader_cat.error()
2811  << "Shader encountered an error.\n";
2812  return NULL;
2813  }
2814  }
2815 #endif
2816 
2817  if (cache_generated_shaders) {
2818  _make_table[sbody] = shader;
2819  }
2820 
2821  return shader;
2822 }
2823 
2824 //////////////////////////////////////////////////////////////////////
2825 // Function: Shader::make_compute
2826 // Access: Published, Static
2827 // Description: Loads the compute shader from the given string.
2828 //////////////////////////////////////////////////////////////////////
2829 PT(Shader) Shader::
2830 make_compute(ShaderLanguage lang, const string &body) {
2831  if (lang != SL_GLSL) {
2832  shader_cat.error()
2833  << "Only GLSL compute shaders are currently supported.\n";
2834  return NULL;
2835  }
2836 
2837  ShaderFile sbody;
2838  sbody._separate = true;
2839  sbody._compute = body;
2840 
2841 
2842  if (cache_generated_shaders) {
2843  ShaderTable::const_iterator i = _make_table.find(sbody);
2844  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2845  return i->second;
2846  }
2847  }
2848 
2849  PT(Shader) shader = new Shader(lang);
2850  shader->_filename = ShaderFile("created-shader");
2851  shader->_text = sbody;
2852 
2853  if (cache_generated_shaders) {
2854  _make_table[sbody] = shader;
2855  }
2856 
2857  return shader;
2858 }
2859 
2860 ////////////////////////////////////////////////////////////////////
2861 // Function: Shader::parse_init
2862 // Access: Public
2863 // Description: Set a 'parse pointer' to the beginning of the shader.
2864 ////////////////////////////////////////////////////////////////////
2865 void Shader::
2867  _parse = 0;
2868 }
2869 
2870 ////////////////////////////////////////////////////////////////////
2871 // Function: Shader::parse_line
2872 // Access: Public
2873 // Description: Parse a line of text. If 'lt' is true, trim blanks
2874 // from the left end of the line. If 'rt' is true, trim
2875 // blanks from the right end (the newline is always
2876 // trimmed).
2877 ////////////////////////////////////////////////////////////////////
2878 void Shader::
2879 parse_line(string &result, bool lt, bool rt) {
2880  nassertv(!_text._separate);
2881  int len = _text._shared.size();
2882  int head = _parse;
2883  int tail = head;
2884  while ((tail < len) && (_text._shared[tail] != '\n')) {
2885  tail++;
2886  }
2887  if (tail < len) {
2888  _parse = tail+1;
2889  } else {
2890  _parse = tail;
2891  }
2892  if (lt) {
2893  while ((head < tail)&&(isspace(_text._shared[head]))) head++;
2894  while ((tail > head)&&(isspace(_text._shared[tail-1]))) tail--;
2895  }
2896  result = _text._shared.substr(head, tail-head);
2897 }
2898 
2899 ////////////////////////////////////////////////////////////////////
2900 // Function: Shader::parse_upto
2901 // Access: Public
2902 // Description: Parse lines until you read a line that matches the
2903 // specified pattern. Returns all the preceding lines,
2904 // and if the include flag is set, returns the final
2905 // line as well.
2906 ////////////////////////////////////////////////////////////////////
2907 void Shader::
2908 parse_upto(string &result, string pattern, bool include) {
2909  nassertv(!_text._separate);
2910  GlobPattern endpat(pattern);
2911  int start = _parse;
2912  int last = _parse;
2913  while (_parse < (int)(_text._shared.size())) {
2914  string t;
2915  parse_line(t, true, true);
2916  if (endpat.matches(t)) break;
2917  last = _parse;
2918  }
2919  if (include) {
2920  result = _text._shared.substr(start, _parse - start);
2921  } else {
2922  result = _text._shared.substr(start, last - start);
2923  }
2924 }
2925 
2926 ////////////////////////////////////////////////////////////////////
2927 // Function: Shader::parse_rest
2928 // Access: Public
2929 // Description: Returns the rest of the text from the current
2930 // parse location.
2931 ////////////////////////////////////////////////////////////////////
2932 void Shader::
2933 parse_rest(string &result) {
2934  nassertv(!_text._separate);
2935  result = _text._shared.substr(_parse, _text._shared.size() - _parse);
2936 }
2937 
2938 ////////////////////////////////////////////////////////////////////
2939 // Function: Shader::parse_eof
2940 // Access: Public
2941 // Description: Returns true if the parse pointer is at the end of
2942 // the shader.
2943 ////////////////////////////////////////////////////////////////////
2944 bool Shader::
2946  return (int)_text._shared.size() == _parse;
2947 }
2948 
2949 ////////////////////////////////////////////////////////////////////
2950 // Function: Shader::prepare
2951 // Access: Published
2952 // Description: Indicates that the shader should be enqueued to be
2953 // prepared in the indicated prepared_objects at the
2954 // beginning of the next frame. This will ensure the
2955 // texture is already loaded into texture memory if it
2956 // is expected to be rendered soon.
2957 //
2958 // Use this function instead of prepare_now() to preload
2959 // textures from a user interface standpoint.
2960 ////////////////////////////////////////////////////////////////////
2961 void Shader::
2962 prepare(PreparedGraphicsObjects *prepared_objects) {
2963  prepared_objects->enqueue_shader(this);
2964 }
2965 
2966 ////////////////////////////////////////////////////////////////////
2967 // Function: Shader::is_prepared
2968 // Access: Published
2969 // Description: Returns true if the shader has already been prepared
2970 // or enqueued for preparation on the indicated GSG,
2971 // false otherwise.
2972 ////////////////////////////////////////////////////////////////////
2973 bool Shader::
2974 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
2975  Contexts::const_iterator ci;
2976  ci = _contexts.find(prepared_objects);
2977  if (ci != _contexts.end()) {
2978  return true;
2979  }
2980  return prepared_objects->is_shader_queued(this);
2981 }
2982 
2983 ////////////////////////////////////////////////////////////////////
2984 // Function: Shader::release
2985 // Access: Published
2986 // Description: Frees the texture context only on the indicated object,
2987 // if it exists there. Returns true if it was released,
2988 // false if it had not been prepared.
2989 ////////////////////////////////////////////////////////////////////
2990 bool Shader::
2991 release(PreparedGraphicsObjects *prepared_objects) {
2992  Contexts::iterator ci;
2993  ci = _contexts.find(prepared_objects);
2994  if (ci != _contexts.end()) {
2995  ShaderContext *sc = (*ci).second;
2996  if (sc != (ShaderContext *)NULL) {
2997  prepared_objects->release_shader(sc);
2998  } else {
2999  _contexts.erase(ci);
3000  }
3001  return true;
3002  }
3003 
3004  // Maybe it wasn't prepared yet, but it's about to be.
3005  return prepared_objects->dequeue_shader(this);
3006 }
3007 
3008 ////////////////////////////////////////////////////////////////////
3009 // Function: Shader::prepare_now
3010 // Access: Published
3011 // Description: Creates a context for the shader on the particular
3012 // GSG, if it does not already exist. Returns the new
3013 // (or old) ShaderContext. This assumes that the
3014 // GraphicsStateGuardian is the currently active
3015 // rendering context and that it is ready to accept new
3016 // textures. If this is not necessarily the case, you
3017 // should use prepare() instead.
3018 //
3019 // Normally, this is not called directly except by the
3020 // GraphicsStateGuardian; a shader does not need to be
3021 // explicitly prepared by the user before it may be
3022 // rendered.
3023 ////////////////////////////////////////////////////////////////////
3027  Contexts::const_iterator ci;
3028  ci = _contexts.find(prepared_objects);
3029  if (ci != _contexts.end()) {
3030  return (*ci).second;
3031  }
3032 
3033  ShaderContext *tc = prepared_objects->prepare_shader_now(this, gsg);
3034  _contexts[prepared_objects] = tc;
3035 
3036  return tc;
3037 }
3038 
3039 ////////////////////////////////////////////////////////////////////
3040 // Function: Shader::clear_prepared
3041 // Access: Private
3042 // Description: Removes the indicated PreparedGraphicsObjects table
3043 // from the Shader's table, without actually releasing
3044 // the texture. This is intended to be called only from
3045 // PreparedGraphicsObjects::release_texture(); it should
3046 // never be called by user code.
3047 ////////////////////////////////////////////////////////////////////
3048 void Shader::
3049 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
3050  Contexts::iterator ci;
3051  ci = _contexts.find(prepared_objects);
3052  if (ci != _contexts.end()) {
3053  _contexts.erase(ci);
3054  } else {
3055  // If this assertion fails, clear_prepared() was given a
3056  // prepared_objects which the texture didn't know about.
3057  nassertv(false);
3058  }
3059 }
3060 
3061 ////////////////////////////////////////////////////////////////////
3062 // Function: Shader::release_all
3063 // Access: Published
3064 // Description: Frees the context allocated on all objects for which
3065 // the texture has been declared. Returns the number of
3066 // contexts which have been freed.
3067 ////////////////////////////////////////////////////////////////////
3068 int Shader::
3070  // We have to traverse a copy of the _contexts list, because the
3071  // PreparedGraphicsObjects object will call clear_prepared() in response
3072  // to each release_texture(), and we don't want to be modifying the
3073  // _contexts list while we're traversing it.
3074  Contexts temp = _contexts;
3075  int num_freed = (int)_contexts.size();
3076 
3077  Contexts::const_iterator ci;
3078  for (ci = temp.begin(); ci != temp.end(); ++ci) {
3079  PreparedGraphicsObjects *prepared_objects = (*ci).first;
3080  ShaderContext *sc = (*ci).second;
3081  if (sc != (ShaderContext *)NULL) {
3082  prepared_objects->release_shader(sc);
3083  }
3084  }
3085 
3086  // There might still be some outstanding contexts in the map, if
3087  // there were any NULL pointers there. Eliminate them.
3088  _contexts.clear();
3089 
3090  return num_freed;
3091 }
3092 
3093 ////////////////////////////////////////////////////////////////////
3094 // Function: Shader::ShaderCapabilities::clear()
3095 // Access: Public
3096 // Description:
3097 ////////////////////////////////////////////////////////////////////
3098 void Shader::ShaderCaps::
3099 clear() {
3100  _supports_glsl = false;
3101 
3102 #ifdef HAVE_CG
3103  _active_vprofile = CG_PROFILE_UNKNOWN;
3104  _active_fprofile = CG_PROFILE_UNKNOWN;
3105  _active_gprofile = CG_PROFILE_UNKNOWN;
3106  _active_fprofile = CG_PROFILE_UNKNOWN;
3107  _ultimate_vprofile = CG_PROFILE_UNKNOWN;
3108  _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3109  _ultimate_gprofile = CG_PROFILE_UNKNOWN;
3110  _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3111 #endif
3112 }
3113 
3114 ////////////////////////////////////////////////////////////////////
3115 // Function: Shader::register_with_read_factory
3116 // Access: Public, Static
3117 // Description: Tells the BamReader how to create objects of type
3118 // Shader.
3119 ////////////////////////////////////////////////////////////////////
3120 void Shader::
3122  //BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
3123 }
3124 
3125 ////////////////////////////////////////////////////////////////////
3126 // Function: Shader::write_datagram
3127 // Access: Public, Virtual
3128 // Description: Writes the contents of this object to the datagram
3129 // for shipping out to a Bam file.
3130 ////////////////////////////////////////////////////////////////////
3131 void Shader::
3133  dg.add_uint8(_language);
3134  dg.add_bool(_loaded);
3135  _filename.write_datagram(dg);
3136  _text.write_datagram(dg);
3137 }
3138 
3139 ////////////////////////////////////////////////////////////////////
3140 // Function: Shader::make_from_bam
3141 // Access: Protected, Static
3142 // Description: This function is called by the BamReader's factory
3143 // when a new object of type Shader is encountered
3144 // in the Bam file. It should create the Shader
3145 // and extract its information from the file.
3146 ////////////////////////////////////////////////////////////////////
3147 TypedWritable *Shader::
3148 make_from_bam(const FactoryParams &params) {
3149  Shader *attrib = new Shader(SL_none);
3150  DatagramIterator scan;
3151  BamReader *manager;
3152 
3153  parse_params(params, scan, manager);
3154  attrib->fillin(scan, manager);
3155  return attrib;
3156 }
3157 
3158 ////////////////////////////////////////////////////////////////////
3159 // Function: Shader::fillin
3160 // Access: Protected
3161 // Description: This internal function is called by make_from_bam to
3162 // read in all of the relevant data from the BamFile for
3163 // the new Shader.
3164 ////////////////////////////////////////////////////////////////////
3165 void Shader::
3166 fillin(DatagramIterator &scan, BamReader *manager) {
3167  _language = (ShaderLanguage) scan.get_uint8();
3168  _loaded = scan.get_bool();
3169  _filename.read_datagram(scan);
3170  _text.read_datagram(scan);
3171 }
string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:424
PointerTo< VirtualFile > find_file(const Filename &filename, const DSearchPath &searchpath, bool status_only=false) const
Uses the indicated search path to find the file within the file system.
bool matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:157
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:138
void release_shader(ShaderContext *sc)
Indicates that a shader context, created by a previous call to prepare_shader(), is no longer needed...
bool cp_errchk_parameter_varying(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
Definition: shader.cxx:152
This is our own Panda specialization on the default STL map.
Definition: pmap.h:52
bool get_bool()
Extracts a boolean value.
static void register_with_read_factory()
Tells the BamReader how to create objects of type Shader.
Definition: shader.cxx:3121
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
Definition: shader.h:50
void enqueue_shader(Shader *shader)
Indicates that a shader would like to be put on the list to be prepared when the GSG is next ready to...
int cp_dependency(ShaderMatInput inp)
Given ShaderMatInput, returns an indication of what part or parts of the state_and_transform the Shad...
Definition: shader.cxx:397
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
bool cp_errchk_parameter_sampler(ShaderArgInfo &arg)
Make sure the provided parameter has a texture type.
Definition: shader.cxx:242
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:37
A table of objects that are saved within the graphics context for reference by handle later...
void parse_init()
Set a &#39;parse pointer&#39; to the beginning of the shader.
Definition: shader.cxx:2866
bool cp_parse_eol(ShaderArgInfo &arg, vector_string &pieces, int &next)
Make sure the next thing on the word list is EOL.
Definition: shader.cxx:261
void cp_optimize_mat_spec(ShaderMatSpec &spec)
Analyzes a ShaderMatSpec and decides what it should use its cache for.
Definition: shader.cxx:469
The ShaderContext is meant to contain the compiled version of a shader string.
Definition: shaderContext.h:35
A particular category of error messages.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
ShaderContext * prepare_shader_now(Shader *shader, GraphicsStateGuardianBase *gsg)
Immediately creates a new ShaderContext for the indicated shader and returns it.
void read_datagram(DatagramIterator &source)
Reads the object from a Datagram.
Definition: shader.I:802
bool cp_errchk_parameter_uniform(ShaderArgInfo &arg)
Make sure the provided parameter has the correct variance.
Definition: shader.cxx:169
void parse_upto(string &result, string pattern, bool include)
Parse lines until you read a line that matches the specified pattern.
Definition: shader.cxx:2908
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
ostream & error(bool prefix=true) const
A shorthand way to write out(NS_error).
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: shader.cxx:3132
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
void write_datagram(Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: shader.I:781
void parse_rest(string &result)
Returns the rest of the text from the current parse location.
Definition: shader.cxx:2933
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
bool cp_parse_coord_sys(ShaderArgInfo &arg, vector_string &pieces, int &next, ShaderMatSpec &spec, bool fromflag)
Convert a single-word coordinate system name into a PART/ARG of a ShaderMatSpec.
Definition: shader.cxx:307
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
~Shader()
Delete the compiled code, if it exists.
Definition: shader.cxx:2591
void cp_report_error(ShaderArgInfo &arg, const string &msg)
Generate an error message including a description of the specified parameter.
Definition: shader.cxx:44
bool dequeue_shader(Shader *shader)
Removes a shader from the queued list of shaders to be prepared.
string cp_parse_non_delimiter(vector_string &pieces, int &next)
Pop a non-delimiter word from the word list.
Definition: shader.cxx:291
void prepare(PreparedGraphicsObjects *prepared_objects)
Indicates that the shader should be enqueued to be prepared in the indicated prepared_objects at the ...
Definition: shader.cxx:2962
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
const string & get_text(const ShaderType &type=ST_none) const
Return the Shader&#39;s text for the given shader type.
Definition: shader.I:62
Filename get_filename(const ShaderType &type=ST_none) const
Return the Shader&#39;s filename for the given shader type.
Definition: shader.I:23
int release_all()
Frees the context allocated on all objects for which the texture has been declared.
Definition: shader.cxx:3069
bool cp_errchk_parameter_in(ShaderArgInfo &arg)
Make sure the provided parameter has the &#39;in&#39; direction.
Definition: shader.cxx:135
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the shader has already been prepared or enqueued for preparation on the indicated GSG...
Definition: shader.cxx:2974
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
Definition: shader.cxx:2991
This class stores a list of directories that can be searched, in order, to locate a particular file...
Definition: dSearchPath.h:32
void parse_line(string &result, bool rt, bool lt)
Parse a line of text.
Definition: shader.cxx:2879
bool compile_parameter(const ShaderArgId &arg_id, const ShaderArgClass &arg_class, const ShaderArgClass &arg_subclass, const ShaderArgType &arg_type, const ShaderArgDir &arg_direction, bool arg_varying, int *arg_dim, NotifyCategory *arg_cat)
Analyzes a parameter and decides how to bind the parameter to some part of panda&#39;s internal state...
Definition: shader.cxx:604
void prepend_directory(const Filename &directory)
Adds a new directory to the front of the search list.
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
bool parse_eof()
Returns true if the parse pointer is at the end of the shader.
Definition: shader.cxx:2945
bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len)
Make sure the provided parameter contains the specified number of words.
Definition: shader.cxx:116
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
ShaderContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the shader on the particular GSG, if it does not already exist.
Definition: shader.cxx:3025
bool cp_parse_delimiter(ShaderArgInfo &arg, vector_string &pieces, int &next)
Pop a delimiter (&#39;to&#39; or &#39;rel&#39;) from the word list.
Definition: shader.cxx:275
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
bool is_shader_queued(const Shader *shader) const
Returns true if the shader has been queued on this GSG, false otherwise.
bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi)
Make sure the provided parameter has a floating point type.
Definition: shader.cxx:186