Panda3D
 All Classes Functions Variables Enumerations
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  char version_arg[16];
1496  if (!cg_glsl_version.empty() && cgGetProfileProperty((CGprofile) active, CG_IS_GLSL_PROFILE)) {
1497  snprintf(version_arg, 16, "version=%s", cg_glsl_version.c_str());
1498  compiler_args[nargs++] = "-po";
1499  compiler_args[nargs++] = version_arg;
1500  }
1501 
1502  compiler_args[nargs] = 0;
1503 
1504  if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
1505  // Print out some debug information about what we're doing.
1506  if (shader_cat.is_debug()) {
1507  shader_cat.debug()
1508  << "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
1509  << " and active profile " << cgGetProfileString((CGprofile) active) << "\n";
1510 
1511  if (nargs > 0) {
1512  shader_cat.debug() << "Using compiler arguments:";
1513  for (int i = 0; i < nargs; ++i) {
1514  shader_cat.debug(false) << " " << compiler_args[i];
1515  }
1516  shader_cat.debug(false) << "\n";
1517  }
1518  }
1519 
1520  // Compile the shader with the active profile.
1521  prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1522  (CGprofile)active, entry, (const char **)compiler_args);
1523  err = cgGetError();
1524  if (err == CG_NO_ERROR) {
1525  return prog;
1526  }
1527  if (prog != 0) {
1528  cgDestroyProgram(prog);
1529  }
1530  if (shader_cat.is_debug()) {
1531  shader_cat.debug()
1532  << "Compilation with active profile failed: " << cgGetErrorString(err) << "\n";
1533  }
1534  }
1535 
1536  if (shader_cat.is_debug()) {
1537  shader_cat.debug()
1538  << "Compiling Cg shader " << get_filename(type) << " with entry point " << entry
1539  << " and ultimate profile " << cgGetProfileString((CGprofile) ultimate) << "\n";
1540  }
1541 
1542  // The active profile failed, so recompile it with the ultimate profile.
1543  prog = cgCreateProgram(context, CG_SOURCE, text.c_str(),
1544  (CGprofile)ultimate, entry, (const char **)NULL);
1545 
1546  // Extract the output listing.
1547  err = cgGetError();
1548  const char *listing = cgGetLastListing(context);
1549 
1550  if (err == CG_NO_ERROR && listing != NULL && strlen(listing) > 1) {
1551  shader_cat.warning()
1552  << "Encountered warnings during compilation of " << get_filename(type)
1553  << ":\n" << listing;
1554 
1555  } else if (err == CG_COMPILER_ERROR) {
1556  shader_cat.error()
1557  << "Failed to compile Cg shader " << get_filename(type);
1558  if (listing != NULL) {
1559  shader_cat.error(false) << ":\n" << listing;
1560  } else {
1561  shader_cat.error(false) << "!\n";
1562  }
1563  }
1564 
1565  if (err == CG_NO_ERROR) {
1566  return prog;
1567  }
1568 
1569  if (prog != 0) {
1570  cgDestroyProgram(prog);
1571  }
1572  return 0;
1573 }
1574 
1575 ////////////////////////////////////////////////////////////////////
1576 // Function: Shader::cg_compile_shader
1577 // Access: Private
1578 // Description: Compiles a Cg shader for a given set of capabilities.
1579 // If successful, the shader is stored in the instance
1580 // variables _cg_context, _cg_vprogram, _cg_fprogram.
1581 ////////////////////////////////////////////////////////////////////
1582 bool Shader::
1583 cg_compile_shader(const ShaderCaps &caps, CGcontext context) {
1584  _cg_last_caps = caps;
1585 
1586  if (!_text._separate || !_text._vertex.empty()) {
1587  _cg_vprogram = cg_compile_entry_point("vshader", caps, context, ST_vertex);
1588  if (_cg_vprogram == 0) {
1589  cg_release_resources();
1590  return false;
1591  }
1592  _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
1593  }
1594 
1595  if (!_text._separate || !_text._fragment.empty()) {
1596  _cg_fprogram = cg_compile_entry_point("fshader", caps, context, ST_fragment);
1597  if (_cg_fprogram == 0) {
1598  cg_release_resources();
1599  return false;
1600  }
1601  _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
1602  }
1603 
1604  if ((_text._separate && !_text._geometry.empty()) || (!_text._separate && _text._shared.find("gshader") != string::npos)) {
1605  _cg_gprogram = cg_compile_entry_point("gshader", caps, context, ST_geometry);
1606  if (_cg_gprogram == 0) {
1607  cg_release_resources();
1608  return false;
1609  }
1610  _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
1611  }
1612 
1613  if (_cg_vprogram == 0 && _cg_fprogram == 0 && _cg_gprogram == 0) {
1614  shader_cat.error() << "Shader must at least have one program!\n";
1615  cg_release_resources();
1616  return false;
1617  }
1618 
1619  // DEBUG: output the generated program
1620  if (shader_cat.is_debug()) {
1621  const char *vertex_program;
1622  const char *fragment_program;
1623  const char *geometry_program;
1624 
1625  if (_cg_vprogram != 0) {
1626  shader_cat.debug()
1627  << "Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) << "\n";
1628  vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
1629  shader_cat.debug() << vertex_program << "\n";
1630  }
1631  if (_cg_fprogram != 0) {
1632  shader_cat.debug()
1633  << "Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) << "\n";
1634  fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
1635  shader_cat.debug() << fragment_program << "\n";
1636  }
1637  if (_cg_gprogram != 0) {
1638  shader_cat.debug()
1639  << "Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) << "\n";
1640  geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
1641  shader_cat.debug() << geometry_program << "\n";
1642  }
1643  }
1644 
1645  return true;
1646 }
1647 
1648 ////////////////////////////////////////////////////////////////////
1649 // Function: Shader::cg_analyze_entry_point
1650 // Access: Private
1651 // Description:
1652 ////////////////////////////////////////////////////////////////////
1653 bool Shader::
1654 cg_analyze_entry_point(CGprogram prog, ShaderType type) {
1655  bool success = true;
1656 
1657  cg_recurse_parameters(cgGetFirstParameter(prog, CG_PROGRAM), type, success);
1658  return success;
1659 }
1660 
1661 ////////////////////////////////////////////////////////////////////
1662 // Function: Shader::cg_analyze_shader
1663 // Access: Private
1664 // Description: This subroutine analyzes the parameters of a Cg
1665 // shader. The output is stored in instance variables:
1666 // _mat_spec, _var_spec, and _tex_spec.
1667 //
1668 // In order to do this, it is necessary to compile the
1669 // shader. It would be a waste of CPU time to compile
1670 // the shader, analyze the parameters, and then discard
1671 // the compiled shader. This would force us to compile it
1672 // again later, when we need to build the ShaderContext.
1673 // Instead, we cache the compiled Cg program in instance
1674 // variables. Later, a ShaderContext can pull the
1675 // compiled shader from these instance vars.
1676 //
1677 // To compile a shader, you need to first choose a profile.
1678 // There are two contradictory objectives:
1679 //
1680 // 1. If you don't use the gsg's active profile,
1681 // then the cached compiled shader will not be useful to
1682 // the ShaderContext.
1683 //
1684 // 2. If you use too weak a profile, then the shader may
1685 // not compile. So to guarantee success, you should use
1686 // the ultimate profile.
1687 //
1688 // To resolve this conflict, we try the active profile
1689 // first, and if that doesn't work, we try the ultimate
1690 // profile.
1691 //
1692 ////////////////////////////////////////////////////////////////////
1693 bool Shader::
1694 cg_analyze_shader(const ShaderCaps &caps) {
1695 
1696  // Make sure we have a context for analyzing the shader.
1697  if (_cg_context == 0) {
1698  _cg_context = cgCreateContext();
1699  if (_cg_context == 0) {
1700  shader_cat.error()
1701  << "Could not create a Cg context object: "
1702  << cgGetErrorString(cgGetError()) << "\n";
1703  return false;
1704  }
1705  }
1706 
1707  if (!cg_compile_shader(caps, _cg_context)) {
1708  return false;
1709  }
1710 
1711  if (_cg_fprogram != 0) {
1712  if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
1713  cg_release_resources();
1714  clear_parameters();
1715  return false;
1716  }
1717  }
1718 
1719  if (_var_spec.size() != 0) {
1720  shader_cat.error() << "Cannot use vtx parameters in an fshader\n";
1721  cg_release_resources();
1722  clear_parameters();
1723  return false;
1724  }
1725 
1726  if (_cg_vprogram != 0) {
1727  if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
1728  cg_release_resources();
1729  clear_parameters();
1730  return false;
1731  }
1732  }
1733 
1734  if (_cg_gprogram != 0) {
1735  if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
1736  cg_release_resources();
1737  clear_parameters();
1738  return false;
1739  }
1740  }
1741 
1742  // Assign sequence numbers to all parameters.
1743  int seqno = 0;
1744  for (int i=0; i<(int)_mat_spec.size(); i++) {
1745  _mat_spec[i]._id._seqno = seqno++;
1746  }
1747  for (int i=0; i<(int)_tex_spec.size(); i++) {
1748  _tex_spec[i]._id._seqno = seqno++;
1749  }
1750  for (int i=0; i<(int)_var_spec.size(); i++) {
1751  _var_spec[i]._id._seqno = seqno++;
1752  }
1753 
1754  for (int i=0; i<(int)_ptr_spec.size(); i++) {
1755  _ptr_spec[i]._id._seqno = seqno++;
1756  _ptr_spec[i]._info._id = _ptr_spec[i]._id;
1757  }
1758 
1759  // // The following code is present to work around a bug in the Cg compiler.
1760  // // It does not generate correct code for shadow map lookups when using arbfp1.
1761  // // This is a particularly onerous limitation, given that arbfp1 is the only
1762  // // Cg target that works on radeons. I suspect this is an intentional
1763  // // omission on nvidia's part. The following code fetches the output listing,
1764  // // detects the error, repairs the code, and resumbits the repaired code to Cg.
1765  // if ((_cg_fprofile == CG_PROFILE_ARBFP1) && (gsghint->_supports_shadow_filter)) {
1766  // bool shadowunit[32];
1767  // bool anyshadow = false;
1768  // memset(shadowunit, 0, sizeof(shadowunit));
1769  // vector_string lines;
1770  // tokenize(cgGetProgramString(_cg_program[SHADER_type_frag],
1771  // CG_COMPILED_PROGRAM), lines, "\n");
1772  // // figure out which texture units contain shadow maps.
1773  // for (int lineno=0; lineno<(int)lines.size(); lineno++) {
1774  // if (lines[lineno].compare(0,21,"#var sampler2DSHADOW ")) {
1775  // continue;
1776  // }
1777  // vector_string fields;
1778  // tokenize(lines[lineno], fields, ":");
1779  // if (fields.size()!=5) {
1780  // continue;
1781  // }
1782  // vector_string words;
1783  // tokenize(trim(fields[2]), words, " ");
1784  // if (words.size()!=2) {
1785  // continue;
1786  // }
1787  // int unit = atoi(words[1].c_str());
1788  // if ((unit < 0)||(unit >= 32)) {
1789  // continue;
1790  // }
1791  // anyshadow = true;
1792  // shadowunit[unit] = true;
1793  // }
1794  // // modify all TEX statements that use the relevant texture units.
1795  // if (anyshadow) {
1796  // for (int lineno=0; lineno<(int)lines.size(); lineno++) {
1797  // if (lines[lineno].compare(0,4,"TEX ")) {
1798  // continue;
1799  // }
1800  // vector_string fields;
1801  // tokenize(lines[lineno], fields, ",");
1802  // if ((fields.size()!=4)||(trim(fields[3]) != "2D;")) {
1803  // continue;
1804  // }
1805  // vector_string texunitf;
1806  // tokenize(trim(fields[2]), texunitf, "[]");
1807  // if ((texunitf.size()!=3)||(texunitf[0] != "texture")||(texunitf[2]!="")) {
1808  // continue;
1809  // }
1810  // int unit = atoi(texunitf[1].c_str());
1811  // if ((unit < 0) || (unit >= 32) || (shadowunit[unit]==false)) {
1812  // continue;
1813  // }
1814  // lines[lineno] = fields[0]+","+fields[1]+","+fields[2]+", SHADOW2D;";
1815  // }
1816  // string result = "!!ARBfp1.0\nOPTION ARB_fragment_program_shadow;\n";
1817  // for (int lineno=1; lineno<(int)lines.size(); lineno++) {
1818  // result += (lines[lineno] + "\n");
1819  // }
1820  // _cg_program[2] = _cg_program[SHADER_type_frag];
1821  // _cg_program[SHADER_type_frag] =
1822  // cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(),
1823  // _cg_profile[SHADER_type_frag], "fshader", (const char**)NULL);
1824  // cg_report_errors(s->get_name(), _cg_context);
1825  // if (_cg_program[SHADER_type_frag]==0) {
1826  // release_resources();
1827  // return false;
1828  // }
1829  // }
1830  // }
1831 
1832  cg_release_resources();
1833  return true;
1834 }
1835 
1836 ////////////////////////////////////////////////////////////////////
1837 // Function: Shader::cg_program_from_shadertype
1838 // Access: Private
1839 // Description: Returns the CGprogram of the given shadertype
1840 // that belongs to this shader.
1841 ////////////////////////////////////////////////////////////////////
1842 CGprogram Shader::
1843 cg_program_from_shadertype(ShaderType type) {
1844  switch (type) {
1845  case ST_vertex:
1846  return _cg_vprogram;
1847 
1848  case ST_fragment:
1849  return _cg_fprogram;
1850 
1851  case ST_geometry:
1852  return _cg_gprogram;
1853 
1854  default:
1855  return 0;
1856  }
1857 }
1858 
1859 ////////////////////////////////////////////////////////////////////
1860 // Function: Shader::cg_compile_for
1861 // Access: Public
1862 // Description: This routine is used by the ShaderContext constructor
1863 // to compile the shader. The CGprogram
1864 // objects are turned over to the ShaderContext, we no
1865 // longer own them.
1866 ////////////////////////////////////////////////////////////////////
1867 bool Shader::
1868 cg_compile_for(const ShaderCaps &caps, CGcontext context,
1869  CGprogram &combined_program, pvector<CGparameter> &map) {
1870 
1871  // Initialize the return values to empty.
1872  combined_program = 0;
1873  map.clear();
1874 
1875  // Make sure the shader is compiled for the target caps.
1876  // Most of the time, it will already be - this is usually a no-op.
1877 
1878  _default_caps = caps;
1879  if (!cg_compile_shader(caps, context)) {
1880  return false;
1881  }
1882 
1883  // If the compile routine used the ultimate profile instead of the
1884  // active one, it means the active one isn't powerful enough to
1885  // compile the shader.
1886  if (_cg_vprogram != 0 && _cg_vprofile != caps._active_vprofile) {
1887  shader_cat.error() << "Cg vertex program not supported by profile "
1888  << cgGetProfileString((CGprofile) caps._active_vprofile) << ": "
1889  << get_filename(ST_vertex) << ". Try choosing a different profile.\n";
1890  return false;
1891  }
1892  if (_cg_fprogram != 0 && _cg_fprofile != caps._active_fprofile) {
1893  shader_cat.error() << "Cg fragment program not supported by profile "
1894  << cgGetProfileString((CGprofile) caps._active_fprofile) << ": "
1895  << get_filename(ST_fragment) << ". Try choosing a different profile.\n";
1896  return false;
1897  }
1898  if (_cg_gprogram != 0 && _cg_gprofile != caps._active_gprofile) {
1899  shader_cat.error() << "Cg geometry program not supported by profile "
1900  << cgGetProfileString((CGprofile) caps._active_gprofile) << ": "
1901  << get_filename(ST_geometry) << ". Try choosing a different profile.\n";
1902  return false;
1903  }
1904 
1905  // Gather the programs we will be combining.
1906  pvector<CGprogram> programs;
1907  if (_cg_vprogram != 0) {
1908  programs.push_back(_cg_vprogram);
1909  }
1910  if (_cg_fprogram != 0) {
1911  programs.push_back(_cg_fprogram);
1912  }
1913  if (_cg_gprogram != 0) {
1914  programs.push_back(_cg_gprogram);
1915  }
1916 
1917  // Combine the programs. This can be more optimal than loading them
1918  // individually, and it is even necessary for some profiles
1919  // (particularly GLSL profiles on non-NVIDIA GPUs).
1920  combined_program = cgCombinePrograms(programs.size(), &programs[0]);
1921 
1922  // Build a parameter map.
1923  int n_mat = (int)_mat_spec.size();
1924  int n_tex = (int)_tex_spec.size();
1925  int n_var = (int)_var_spec.size();
1926  int n_ptr = (int)_ptr_spec.size();
1927 
1928  map.resize(n_mat + n_tex + n_var + n_ptr);
1929 
1930  // This is a bit awkward, we have to go in and seperate out the
1931  // combined program, since all the parameter bindings have changed.
1932  CGprogram programs_by_type[ST_COUNT];
1933  for (int i = 0; i < cgGetNumProgramDomains(combined_program); ++i) {
1934  // Conveniently, the CGdomain enum overlaps with ShaderType.
1935  CGprogram program = cgGetProgramDomainProgram(combined_program, i);
1936  programs_by_type[cgGetProgramDomain(program)] = program;
1937  }
1938 
1939  for (int i = 0; i < n_mat; ++i) {
1940  const ShaderArgId &id = _mat_spec[i]._id;
1941  map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
1942  }
1943 
1944  for (int i = 0; i < n_tex; ++i) {
1945  const ShaderArgId &id = _tex_spec[i]._id;
1946  CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
1947 
1948  if (shader_cat.is_debug()) {
1949  const char *resource = cgGetParameterResourceName(p);
1950  if (resource != NULL) {
1951  shader_cat.debug() << "Texture parameter " << id._name
1952  << " is bound to resource " << resource << "\n";
1953  }
1954  }
1955  map[id._seqno] = p;
1956  }
1957 
1958  for (int i = 0; i < n_var; ++i) {
1959  const ShaderArgId &id = _var_spec[i]._id;
1960  CGparameter p = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
1961 
1962  const char *resource = cgGetParameterResourceName(p);
1963  if (shader_cat.is_debug() && resource != NULL) {
1964  shader_cat.debug()
1965  << "Varying parameter " << id._name << " is bound to resource "
1966  << cgGetParameterResourceName(p) << "\n";
1967  }
1968 
1969  if (cgGetParameterBaseResource(p) == CG_UNDEFINED) {
1970  // I really don't know what this means, but it happens when I
1971  // use the NORMAL0 semantic instead of NORMAL, or POSITION0
1972  // instead of POSITION, etc. Not catching this results in a
1973  // continuous stream of errors at the renderer side.
1974  shader_cat.error()
1975  << "Varying parameter " << id._name;
1976 
1977  const char *semantic = cgGetParameterSemantic(p);
1978  if (semantic != NULL) {
1979  shader_cat.error(false) << " : " << semantic;
1980  }
1981  if (resource != NULL) {
1982  shader_cat.error(false) << " (bound to resource " << resource << ")";
1983  }
1984  shader_cat.error(false) << " is invalid!\n";
1985 
1986 #ifndef NDEBUG
1987  // Let's try to give the developer a hint...
1988  if (semantic != NULL) {
1989  if (strcmp(semantic, "POSITION0") == 0) {
1990  shader_cat.error() << "Try using the semantic POSITION instead of POSITION0.\n";
1991  } else if (strcmp(semantic, "NORMAL0") == 0) {
1992  shader_cat.error() << "Try using the semantic NORMAL instead of NORMAL0.\n";
1993  } else if (strcmp(semantic, "DIFFUSE0") == 0) {
1994  shader_cat.error() << "Try using the semantic DIFFUSE instead of DIFFUSE0.\n";
1995  } else if (strcmp(semantic, "SPECULAR0") == 0) {
1996  shader_cat.error() << "Try using the semantic SPECULAR instead of SPECULAR0.\n";
1997  } else if (strcmp(semantic, "FOGCOORD0") == 0) {
1998  shader_cat.error() << "Try using the semantic FOGCOORD instead of FOGCOORD0.\n";
1999  } else if (strcmp(semantic, "PSIZE0") == 0) {
2000  shader_cat.error() << "Try using the semantic PSIZE instead of PSIZE0.\n";
2001  }
2002  }
2003 #endif // NDEBUG
2004  p = 0;
2005  }
2006  map[id._seqno] = p;
2007  }
2008 
2009  for (int i = 0; i < n_ptr; ++i) {
2010  const ShaderArgId &id = _ptr_spec[i]._id;
2011  map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str());
2012  }
2013 
2014  // Transfer ownership of the compiled shader.
2015  if (_cg_vprogram != 0) {
2016  cgDestroyProgram(_cg_vprogram);
2017  _cg_vprogram = 0;
2018  }
2019  if (_cg_fprogram != 0) {
2020  cgDestroyProgram(_cg_fprogram);
2021  _cg_fprogram = 0;
2022  }
2023  if (_cg_gprogram != 0) {
2024  cgDestroyProgram(_cg_gprogram);
2025  _cg_gprogram = 0;
2026  }
2027 
2028  _cg_last_caps.clear();
2029 
2030  return true;
2031 }
2032 #endif // HAVE_CG
2033 
2034 ////////////////////////////////////////////////////////////////////
2035 // Function: Shader::Constructor
2036 // Access: Private
2037 // Description: Construct a Shader that will be filled in using
2038 // fillin() or read() later.
2039 ////////////////////////////////////////////////////////////////////
2040 Shader::
2041 Shader(ShaderLanguage lang) :
2042  _error_flag(false),
2043  _parse(0),
2044  _loaded(false),
2045  _language(lang),
2046  _last_modified(0)
2047 {
2048 #ifdef HAVE_CG
2049  _cg_vprogram = 0;
2050  _cg_fprogram = 0;
2051  _cg_gprogram = 0;
2052  _cg_vprofile = CG_PROFILE_UNKNOWN;
2053  _cg_fprofile = CG_PROFILE_UNKNOWN;
2054  _cg_gprofile = CG_PROFILE_UNKNOWN;
2055  if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
2056  _default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
2057  _default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
2058  _default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
2059  _default_caps._ultimate_vprofile = cgGetProfile("glslv");
2060  _default_caps._ultimate_fprofile = cgGetProfile("glslf");
2061  _default_caps._ultimate_gprofile = cgGetProfile("glslg");
2062  if (_default_caps._ultimate_gprofile == CG_PROFILE_UNKNOWN) {
2063  _default_caps._ultimate_gprofile = cgGetProfile("gp4gp");
2064  }
2065  }
2066 #endif
2067 }
2068 
2069 ////////////////////////////////////////////////////////////////////
2070 // Function: Shader::read
2071 // Access: Private
2072 // Description: Reads the shader from the given filename(s).
2073 // Returns a boolean indicating success or failure.
2074 ////////////////////////////////////////////////////////////////////
2075 bool Shader::
2076 read(const ShaderFile &sfile) {
2077  _text._separate = sfile._separate;
2078 
2079  if (sfile._separate) {
2080  if (_language == SL_none) {
2081  shader_cat.error()
2082  << "No shader language was specified!\n";
2083  return false;
2084  }
2085 
2086  if (!sfile._vertex.empty() && !do_read_source(_text._vertex, sfile._vertex)) {
2087  return false;
2088  }
2089  if (!sfile._fragment.empty() && !do_read_source(_text._fragment, sfile._fragment)) {
2090  return false;
2091  }
2092  if (!sfile._geometry.empty() && !do_read_source(_text._geometry, sfile._geometry)) {
2093  return false;
2094  }
2095  if (!sfile._tess_control.empty() && !do_read_source(_text._tess_control, sfile._tess_control)) {
2096  return false;
2097  }
2098  if (!sfile._tess_evaluation.empty() && !do_read_source(_text._tess_evaluation, sfile._tess_evaluation)) {
2099  return false;
2100  }
2101  if (!sfile._compute.empty() && !do_read_source(_text._compute, sfile._compute)) {
2102  return false;
2103  }
2104  _filename = sfile;
2105 
2106  } else {
2107  if (!do_read_source(_text._shared, sfile._shared)) {
2108  return false;
2109  }
2110  _filename = sfile;
2111 
2112  // Determine which language the shader is written in.
2113  if (_language == SL_none) {
2114  string header;
2115  parse_init();
2116  parse_line(header, true, true);
2117  if (header == "//Cg") {
2118  _language = SL_Cg;
2119  } else {
2120  shader_cat.error()
2121  << "Unable to determine shader language of " << sfile._shared << "\n";
2122  return false;
2123  }
2124  } else if (_language == SL_GLSL) {
2125  shader_cat.error()
2126  << "GLSL shaders must have separate shader bodies!\n";
2127  return false;
2128  }
2129 
2130  // Determine which language the shader is written in.
2131  if (_language == SL_Cg) {
2132 #ifdef HAVE_CG
2133  cg_get_profile_from_header(_default_caps);
2134 
2135  if (!cg_analyze_shader(_default_caps)) {
2136  shader_cat.error()
2137  << "Shader encountered an error.\n";
2138  return false;
2139  }
2140 #else
2141  shader_cat.error()
2142  << "Tried to load Cg shader, but no Cg support is enabled.\n";
2143 #endif
2144  } else {
2145  shader_cat.error()
2146  << "Shader is not in a supported shader-language.\n";
2147  return false;
2148  }
2149  }
2150 
2151  _loaded = true;
2152  return true;
2153 }
2154 
2155 ////////////////////////////////////////////////////////////////////
2156 // Function: Shader::do_read_source
2157 // Access: Private
2158 // Description: Reads the shader file from the given path into the
2159 // given string.
2160 //
2161 // Returns false if there was an error with this shader
2162 // bad enough to consider it 'invalid'.
2163 ////////////////////////////////////////////////////////////////////
2164 bool Shader::
2165 do_read_source(string &into, const Filename &fn) {
2166  if (_language == SL_GLSL && glsl_preprocess) {
2167  // Preprocess the GLSL file as we read it.
2168  set<Filename> open_files;
2169  ostringstream sstr;
2170  if (!r_preprocess_source(sstr, fn, Filename(), open_files)) {
2171  return false;
2172  }
2173  into = sstr.str();
2174 
2175  } else {
2176  shader_cat.info() << "Reading shader file: " << fn << "\n";
2177 
2179  PT(VirtualFile) vf = vfs->find_file(fn, get_model_path());
2180  if (vf == NULL) {
2181  shader_cat.error()
2182  << "Could not find shader file: " << fn << "\n";
2183  return false;
2184  }
2185 
2186  if (!vf->read_file(into, true)) {
2187  shader_cat.error()
2188  << "Could not read shader file: " << fn << "\n";
2189  return false;
2190  }
2191 
2192  _last_modified = max(_last_modified, vf->get_timestamp());
2193  _source_files.push_back(vf->get_filename());
2194  }
2195  return true;
2196 }
2197 
2198 ////////////////////////////////////////////////////////////////////
2199 // Function: Shader::r_preprocess_source
2200 // Access: Private
2201 // Description: Loads a given GLSL file line by line, and processes
2202 // any #pragma include and once statements.
2203 //
2204 // The set keeps track of which files we have already
2205 // included, for checking recursive includes.
2206 ////////////////////////////////////////////////////////////////////
2207 bool Shader::
2208 r_preprocess_source(ostream &out, const Filename &fn,
2209  const Filename &source_dir,
2210  set<Filename> &once_files, int depth) {
2211 
2212  if (depth > glsl_include_recursion_limit) {
2213  shader_cat.error()
2214  << "#pragma include nested too deeply\n";
2215  return false;
2216  }
2217 
2218  DSearchPath path(get_model_path());
2219  if (!source_dir.empty()) {
2220  path.prepend_directory(source_dir);
2221  }
2222 
2224  PT(VirtualFile) vf = vfs->find_file(fn, path);
2225  if (vf == NULL) {
2226  shader_cat.error()
2227  << "Could not find shader file: " << fn << "\n";
2228  return false;
2229  }
2230 
2231  Filename full_fn = vf->get_filename();
2232  if (once_files.find(full_fn) != once_files.end()) {
2233  // If this file had a #pragma once, just move on.
2234  return true;
2235  }
2236 
2237  istream *source = vf->open_read_file(true);
2238  if (source == NULL) {
2239  shader_cat.error()
2240  << "Could not open shader file: " << fn << "\n";
2241  return false;
2242  }
2243 
2244  _last_modified = max(_last_modified, vf->get_timestamp());
2245  _source_files.push_back(full_fn);
2246 
2247  // We give each file an unique index. This is so that we can identify
2248  // a particular shader in the error output. We offset them by 2048
2249  // so that they are more recognizable. GLSL doesn't give us anything
2250  // more useful than that, unfortunately.
2251  //
2252  // Don't do this for the top-level file, though. We don't want
2253  // anything to get in before a potential #version directive.
2254  int fileno = 0;
2255  if (depth > 0) {
2256  fileno = 2048 + _included_files.size();
2257  // Write it into the vector so that we can substitute it later
2258  // when we are parsing the GLSL error log. Don't store the full
2259  // filename because it would just be too long to display.
2260  _included_files.push_back(fn);
2261 
2262  out << "#line 1 " << fileno << " // " << fn << "\n";
2263  if (shader_cat.is_debug()) {
2264  shader_cat.debug()
2265  << "Preprocessing shader include " << fileno << ": " << fn << "\n";
2266  }
2267  } else {
2268  shader_cat.info()
2269  << "Preprocessing shader file: " << fn << "\n";
2270  }
2271 
2272  // Iterate over the lines for things we may need to preprocess.
2273  string line;
2274  bool had_include = false;
2275  int lineno = 0;
2276  while (getline(*source, line)) {
2277  // We always forward the actual line - the GLSL compiler will
2278  // silently ignore #pragma lines anyway.
2279  ++lineno;
2280  out << line << "\n";
2281 
2282  // Check if this line contains a #pragma.
2283  char pragma[64];
2284  if (line.size() < 8 ||
2285  sscanf(line.c_str(), " # pragma %63s", pragma) != 1) {
2286 
2287  // One exception: check for an #endif after an include. We have
2288  // to restore the line number in case the include happened under
2289  // an #if block.
2290  int nread = 0;
2291  if (had_include && sscanf(line.c_str(), " # endif %n", &nread) == 0 && nread >= 6) {
2292  out << "#line " << (lineno + 1) << " " << fileno << "\n";
2293  }
2294  continue;
2295  }
2296 
2297  int nread = 0;
2298  if (strcmp(pragma, "include") == 0) {
2299  // Allow both double quotes and angle brackets.
2300  Filename incfn, source_dir;
2301  {
2302  char incfile[2048];
2303  if (sscanf(line.c_str(), " # pragma%*[ \t]include \"%2047[^\"]\" %n", incfile, &nread) == 1
2304  && nread == line.size()) {
2305  // A regular include, with double quotes. Probably a local file.
2306  source_dir = full_fn.get_dirname();
2307  incfn = incfile;
2308 
2309  } else if (sscanf(line.c_str(), " # pragma%*[ \t]include <%2047[^\"]> %n", incfile, &nread) == 1
2310  && nread == line.size()) {
2311  // Angled includes are also OK, but we don't search in the
2312  // directory of the source file.
2313  incfn = incfile;
2314 
2315  } else {
2316  // Couldn't parse it.
2317  shader_cat.error()
2318  << "Malformed #pragma include at line " << lineno
2319  << " of file " << fn << ":\n " << line << "\n";
2320  return false;
2321  }
2322  }
2323 
2324  // OK, great. Process the include.
2325  if (!r_preprocess_source(out, incfn, source_dir, once_files, depth + 1)) {
2326  // An error occurred. Pass on the failure.
2327  shader_cat.error(false) << "included at line "
2328  << lineno << " of file " << fn << ":\n " << line << "\n";
2329  return false;
2330  }
2331 
2332  // Restore the line counter.
2333  out << "#line " << (lineno + 1) << " " << fileno << " // " << fn << "\n";
2334  had_include = true;
2335 
2336  } else if (strcmp(pragma, "once") == 0) {
2337  // Do a stricter syntax check, just to be extra safe.
2338  if (sscanf(line.c_str(), " # pragma%*[ \t]once %n", &nread) != 0 ||
2339  nread != line.size()) {
2340  shader_cat.error()
2341  << "Malformed #pragma once at line " << lineno
2342  << " of file " << fn << ":\n " << line << "\n";
2343  return false;
2344  }
2345 
2346  once_files.insert(full_fn);
2347 
2348  } else if (strcmp(pragma, "optionNV") == 0) {
2349  // This is processed by NVIDIA drivers. Don't touch it.
2350 
2351  } else {
2352  shader_cat.warning()
2353  << "Ignoring unknown pragma directive \"" << pragma << "\" at line "
2354  << lineno << " of file " << fn << ":\n " << line << "\n";
2355  }
2356  }
2357 
2358  vf->close_read_file(source);
2359  return true;
2360 }
2361 
2362 ////////////////////////////////////////////////////////////////////
2363 // Function: Shader::check_modified
2364 // Access: Private
2365 // Description: Checks whether the shader or any of its dependent
2366 // files were modified on disk.
2367 ////////////////////////////////////////////////////////////////////
2368 bool Shader::
2369 check_modified() const {
2371 
2373  for (it = _source_files.begin(); it != _source_files.end(); ++it) {
2374  const Filename &fn = (*it);
2375 
2376  PT(VirtualFile) vfile = vfs->get_file(fn, true);
2377  if (vfile == (VirtualFile *)NULL || vfile->get_timestamp() > _last_modified) {
2378  return true;
2379  }
2380  }
2381 
2382  return false;
2383 }
2384 
2385 #ifdef HAVE_CG
2386 ////////////////////////////////////////////////////////////////////
2387 // Function: Shader::cg_get_profile_from_header
2388 // Access: Private
2389 // Description: Determines the appropriate active shader profile settings
2390 // based on any profile directives stored within the shader header
2391 ////////////////////////////////////////////////////////////////////
2392 void Shader::
2393 cg_get_profile_from_header(ShaderCaps& caps) {
2394  // Note this forces profile based on what is specified in the shader
2395  // header string. Should probably be relying on card caps eventually.
2396 
2397  string buf;
2398  parse_init();
2399 
2400  // Assume that if parse doesn't extend after a parse line then
2401  // we've reached the end of _text
2402  int lastParse;
2403 
2404  do {
2405  lastParse = _parse;
2406  parse_line(buf, true, true);
2407  int profilePos = buf.find("//Cg profile");
2408  if (profilePos >= 0) {
2409  // Scan the line for known cg2 vertex program profiles
2410  if ((int)buf.find("gp4vp") >= 0)
2411  caps._active_vprofile = cgGetProfile("gp4vp");
2412 
2413  if ((int)buf.find("gp5vp") >= 0)
2414  caps._active_vprofile = cgGetProfile("gp5vp");
2415 
2416  if ((int)buf.find("glslv") >= 0)
2417  caps._active_vprofile = cgGetProfile("glslv");
2418 
2419  if ((int)buf.find("arbvp1") >= 0)
2420  caps._active_vprofile = cgGetProfile("arbvp1");
2421 
2422  if ((int)buf.find("vp40") >= 0)
2423  caps._active_vprofile = cgGetProfile("vp40");
2424 
2425  if ((int)buf.find("vp30") >= 0)
2426  caps._active_vprofile = cgGetProfile("vp30");
2427 
2428  if ((int)buf.find("vp20") >= 0)
2429  caps._active_vprofile = cgGetProfile("vp20");
2430 
2431  if ((int)buf.find("vs_1_1") >= 0)
2432  caps._active_vprofile = cgGetProfile("vs_1_1");
2433 
2434  if ((int)buf.find("vs_2_0") >= 0)
2435  caps._active_vprofile = cgGetProfile("vs_2_0");
2436 
2437  if ((int)buf.find("vs_2_x") >= 0)
2438  caps._active_vprofile = cgGetProfile("vs_2_x");
2439 
2440  if ((int)buf.find("vs_3_0") >= 0)
2441  caps._active_vprofile = cgGetProfile("vs_3_0");
2442 
2443  if ((int)buf.find("vs_4_0") >= 0)
2444  caps._active_vprofile = cgGetProfile("vs_4_0");
2445 
2446  if ((int)buf.find("vs_5_0") >= 0)
2447  caps._active_vprofile = cgGetProfile("vs_5_0");
2448 
2449  // Scan the line for known cg2 fragment program profiles
2450  if ((int)buf.find("gp4fp") >= 0)
2451  caps._active_fprofile = cgGetProfile("gp4fp");
2452 
2453  if ((int)buf.find("gp5fp") >= 0)
2454  caps._active_fprofile = cgGetProfile("gp5fp");
2455 
2456  if ((int)buf.find("glslf") >= 0)
2457  caps._active_fprofile = cgGetProfile("glslf");
2458 
2459  if ((int)buf.find("arbfp1") >= 0)
2460  caps._active_fprofile = cgGetProfile("arbfp1");
2461 
2462  if ((int)buf.find("fp40") >= 0)
2463  caps._active_fprofile = cgGetProfile("fp40");
2464 
2465  if ((int)buf.find("fp30") >= 0)
2466  caps._active_fprofile = cgGetProfile("fp30");
2467 
2468  if ((int)buf.find("fp20") >= 0)
2469  caps._active_fprofile = cgGetProfile("fp20");
2470 
2471  if ((int)buf.find("ps_1_1") >= 0)
2472  caps._active_fprofile = cgGetProfile("ps_1_1");
2473 
2474  if ((int)buf.find("ps_1_2") >= 0)
2475  caps._active_fprofile = cgGetProfile("ps_1_2");
2476 
2477  if ((int)buf.find("ps_1_3") >= 0)
2478  caps._active_fprofile = cgGetProfile("ps_1_3");
2479 
2480  if ((int)buf.find("ps_2_0") >= 0)
2481  caps._active_fprofile = cgGetProfile("ps_2_0");
2482 
2483  if ((int)buf.find("ps_2_x") >= 0)
2484  caps._active_fprofile = cgGetProfile("ps_2_x");
2485 
2486  if ((int)buf.find("ps_3_0") >= 0)
2487  caps._active_fprofile = cgGetProfile("ps_3_0");
2488 
2489  if ((int)buf.find("ps_4_0") >= 0)
2490  caps._active_fprofile = cgGetProfile("ps_4_0");
2491 
2492  if ((int)buf.find("ps_5_0") >= 0)
2493  caps._active_fprofile = cgGetProfile("ps_5_0");
2494 
2495  // Scan the line for known cg2 geometry program profiles
2496  if ((int)buf.find("gp4gp") >= 0)
2497  caps._active_gprofile = cgGetProfile("gp4gp");
2498 
2499  if ((int)buf.find("gp5gp") >= 0)
2500  caps._active_gprofile = cgGetProfile("gp5gp");
2501 
2502  if ((int)buf.find("glslg") >= 0)
2503  caps._active_gprofile = cgGetProfile("glslg");
2504 
2505  if ((int)buf.find("gs_4_0") >= 0)
2506  caps._active_gprofile = cgGetProfile("gs_4_0");
2507 
2508  if ((int)buf.find("gs_5_0") >= 0)
2509  caps._active_gprofile = cgGetProfile("gs_5_0");
2510  }
2511  } while(_parse > lastParse);
2512 
2513 }
2514 #endif
2515 
2516 ////////////////////////////////////////////////////////////////////
2517 // Function: Shader::Destructor
2518 // Access: Public
2519 // Description: Delete the compiled code, if it exists.
2520 ////////////////////////////////////////////////////////////////////
2521 Shader::
2523  release_all();
2524  // Note: don't try to erase ourselves from the table. It currently
2525  // keeps a reference forever, and so the only place where this
2526  // constructor is called is in the destructor of the table itself.
2527  /*if (_loaded) {
2528  _load_table.erase(_filename);
2529  } else {
2530  _make_table.erase(_text);
2531  }*/
2532 }
2533 
2534 ////////////////////////////////////////////////////////////////////
2535 // Function: Shader::load
2536 // Access: Published, Static
2537 // Description: Loads the shader with the given filename.
2538 ////////////////////////////////////////////////////////////////////
2539 PT(Shader) Shader::
2540 load(const Filename &file, ShaderLanguage lang) {
2541  ShaderFile sfile(file);
2542  ShaderTable::const_iterator i = _load_table.find(sfile);
2543  if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2544  // But check that someone hasn't modified it in the meantime.
2545  if (i->second->check_modified()) {
2546  shader_cat.info()
2547  << "Shader " << file << " was modified on disk, reloading.\n";
2548  } else {
2549  shader_cat.debug()
2550  << "Shader " << file << " was found in shader cache.\n";
2551  return i->second;
2552  }
2553  }
2554 
2555  PT(Shader) shader = new Shader(lang);
2556  if (!shader->read(sfile)) {
2557  return NULL;
2558  }
2559 
2560  _load_table[sfile] = shader;
2561  return shader;
2562 }
2563 
2564 ////////////////////////////////////////////////////////////////////
2565 // Function: Shader::load
2566 // Access: Published, Static
2567 // Description: This variant of Shader::load loads all shader
2568 // programs separately.
2569 ////////////////////////////////////////////////////////////////////
2570 PT(Shader) Shader::
2571 load(ShaderLanguage lang, const Filename &vertex,
2572  const Filename &fragment, const Filename &geometry,
2573  const Filename &tess_control, const Filename &tess_evaluation) {
2574  ShaderFile sfile(vertex, fragment, geometry, tess_control, tess_evaluation);
2575  ShaderTable::const_iterator i = _load_table.find(sfile);
2576  if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2577  // But check that someone hasn't modified it in the meantime.
2578  if (i->second->check_modified()) {
2579  shader_cat.info()
2580  << "Shader was modified on disk, reloading.\n";
2581  } else {
2582  shader_cat.debug()
2583  << "Shader was found in shader cache.\n";
2584  return i->second;
2585  }
2586  }
2587 
2588  PT(Shader) shader = new Shader(lang);
2589  if (!shader->read(sfile)) {
2590  return NULL;
2591  }
2592 
2593  _load_table[sfile] = shader;
2594  return shader;
2595 }
2596 
2597 ////////////////////////////////////////////////////////////////////
2598 // Function: Shader::load_compute
2599 // Access: Published, Static
2600 // Description: Loads a compute shader.
2601 ////////////////////////////////////////////////////////////////////
2602 PT(Shader) Shader::
2603 load_compute(ShaderLanguage lang, const Filename &fn) {
2604  if (lang != SL_GLSL) {
2605  shader_cat.error()
2606  << "Only GLSL compute shaders are currently supported.\n";
2607  return NULL;
2608  }
2609 
2610  ShaderFile sfile;
2611  sfile._separate = true;
2612  sfile._compute = fn;
2613 
2614  ShaderTable::const_iterator i = _load_table.find(sfile);
2615  if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
2616  // But check that someone hasn't modified it in the meantime.
2617  if (i->second->check_modified()) {
2618  shader_cat.info()
2619  << "Compute shader " << fn << " was modified on disk, reloading.\n";
2620  } else {
2621  shader_cat.debug()
2622  << "Compute shader " << fn << " was found in shader cache.\n";
2623  return i->second;
2624  }
2625  }
2626 
2627  PT(Shader) shader = new Shader(lang);
2628  if (!shader->read(sfile)) {
2629  return NULL;
2630  }
2631 
2632  _load_table[sfile] = shader;
2633  return shader;
2634 }
2635 
2636 //////////////////////////////////////////////////////////////////////
2637 // Function: Shader::make
2638 // Access: Published, Static
2639 // Description: Loads the shader, using the string as shader body.
2640 //////////////////////////////////////////////////////////////////////
2641 PT(Shader) Shader::
2642 make(const string &body, ShaderLanguage lang) {
2643  if (lang == SL_GLSL) {
2644  shader_cat.error()
2645  << "GLSL shaders must have separate shader bodies!\n";
2646  return NULL;
2647 
2648  } else if (lang == SL_none) {
2649  shader_cat.warning()
2650  << "Shader::make() now requires an explicit shader language. Assuming Cg.\n";
2651  lang = SL_Cg;
2652  }
2653 #ifndef HAVE_CG
2654  if (lang == SL_Cg) {
2655  shader_cat.error() << "Support for Cg shaders is not enabled.\n";
2656  return NULL;
2657  }
2658 #endif
2659 
2660  ShaderFile sbody(body);
2661 
2662  if (cache_generated_shaders) {
2663  ShaderTable::const_iterator i = _make_table.find(sbody);
2664  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2665  return i->second;
2666  }
2667  }
2668 
2669  PT(Shader) shader = new Shader(lang);
2670  shader->_filename = ShaderFile("created-shader");
2671  shader->_text = sbody;
2672 
2673 #ifdef HAVE_CG
2674  if (lang == SL_Cg) {
2675  shader->cg_get_profile_from_header(_default_caps);
2676 
2677  if (!shader->cg_analyze_shader(_default_caps)) {
2678  shader_cat.error()
2679  << "Shader encountered an error.\n";
2680  return NULL;
2681  }
2682  }
2683 #endif
2684 
2685  if (cache_generated_shaders) {
2686  _make_table[sbody] = shader;
2687  }
2688 
2689  if (dump_generated_shaders) {
2690  ostringstream fns;
2691  int index = _shaders_generated ++;
2692  fns << "genshader" << index;
2693  string fn = fns.str();
2694  shader_cat.warning() << "Dumping shader: " << fn << "\n";
2695 
2696  pofstream s;
2697  s.open(fn.c_str(), ios::out | ios::trunc);
2698  s << body;
2699  s.close();
2700  }
2701  return shader;
2702 }
2703 
2704 //////////////////////////////////////////////////////////////////////
2705 // Function: Shader::make
2706 // Access: Published, Static
2707 // Description: Loads the shader, using the strings as shader bodies.
2708 //////////////////////////////////////////////////////////////////////
2709 PT(Shader) Shader::
2710 make(ShaderLanguage lang, const string &vertex, const string &fragment,
2711  const string &geometry, const string &tess_control,
2712  const string &tess_evaluation) {
2713 #ifndef HAVE_CG
2714  if (lang == SL_Cg) {
2715  shader_cat.error() << "Support for Cg shaders is not enabled.\n";
2716  return NULL;
2717  }
2718 #endif
2719  if (lang == SL_none) {
2720  shader_cat.error()
2721  << "Shader::make() requires an explicit shader language.\n";
2722  return NULL;
2723  }
2724 
2725  ShaderFile sbody(vertex, fragment, geometry, tess_control, tess_evaluation);
2726 
2727  if (cache_generated_shaders) {
2728  ShaderTable::const_iterator i = _make_table.find(sbody);
2729  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2730  return i->second;
2731  }
2732  }
2733 
2734  PT(Shader) shader = new Shader(lang);
2735  shader->_filename = ShaderFile("created-shader");
2736  shader->_text = sbody;
2737 
2738 #ifdef HAVE_CG
2739  if (lang == SL_Cg) {
2740  if (!shader->cg_analyze_shader(_default_caps)) {
2741  shader_cat.error()
2742  << "Shader encountered an error.\n";
2743  return NULL;
2744  }
2745  }
2746 #endif
2747 
2748  if (cache_generated_shaders) {
2749  _make_table[sbody] = shader;
2750  }
2751 
2752  return shader;
2753 }
2754 
2755 //////////////////////////////////////////////////////////////////////
2756 // Function: Shader::make_compute
2757 // Access: Published, Static
2758 // Description: Loads the compute shader from the given string.
2759 //////////////////////////////////////////////////////////////////////
2760 PT(Shader) Shader::
2761 make_compute(ShaderLanguage lang, const string &body) {
2762  if (lang != SL_GLSL) {
2763  shader_cat.error()
2764  << "Only GLSL compute shaders are currently supported.\n";
2765  return NULL;
2766  }
2767 
2768  ShaderFile sbody;
2769  sbody._separate = true;
2770  sbody._compute = body;
2771 
2772 
2773  if (cache_generated_shaders) {
2774  ShaderTable::const_iterator i = _make_table.find(sbody);
2775  if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
2776  return i->second;
2777  }
2778  }
2779 
2780  PT(Shader) shader = new Shader(lang);
2781  shader->_filename = ShaderFile("created-shader");
2782  shader->_text = sbody;
2783 
2784  if (cache_generated_shaders) {
2785  _make_table[sbody] = shader;
2786  }
2787 
2788  return shader;
2789 }
2790 
2791 ////////////////////////////////////////////////////////////////////
2792 // Function: Shader::parse_init
2793 // Access: Public
2794 // Description: Set a 'parse pointer' to the beginning of the shader.
2795 ////////////////////////////////////////////////////////////////////
2796 void Shader::
2798  _parse = 0;
2799 }
2800 
2801 ////////////////////////////////////////////////////////////////////
2802 // Function: Shader::parse_line
2803 // Access: Public
2804 // Description: Parse a line of text. If 'lt' is true, trim blanks
2805 // from the left end of the line. If 'rt' is true, trim
2806 // blanks from the right end (the newline is always
2807 // trimmed).
2808 ////////////////////////////////////////////////////////////////////
2809 void Shader::
2810 parse_line(string &result, bool lt, bool rt) {
2811  nassertv(!_text._separate);
2812  int len = _text._shared.size();
2813  int head = _parse;
2814  int tail = head;
2815  while ((tail < len) && (_text._shared[tail] != '\n')) {
2816  tail++;
2817  }
2818  if (tail < len) {
2819  _parse = tail+1;
2820  } else {
2821  _parse = tail;
2822  }
2823  if (lt) {
2824  while ((head < tail)&&(isspace(_text._shared[head]))) head++;
2825  while ((tail > head)&&(isspace(_text._shared[tail-1]))) tail--;
2826  }
2827  result = _text._shared.substr(head, tail-head);
2828 }
2829 
2830 ////////////////////////////////////////////////////////////////////
2831 // Function: Shader::parse_upto
2832 // Access: Public
2833 // Description: Parse lines until you read a line that matches the
2834 // specified pattern. Returns all the preceding lines,
2835 // and if the include flag is set, returns the final
2836 // line as well.
2837 ////////////////////////////////////////////////////////////////////
2838 void Shader::
2839 parse_upto(string &result, string pattern, bool include) {
2840  nassertv(!_text._separate);
2841  GlobPattern endpat(pattern);
2842  int start = _parse;
2843  int last = _parse;
2844  while (_parse < (int)(_text._shared.size())) {
2845  string t;
2846  parse_line(t, true, true);
2847  if (endpat.matches(t)) break;
2848  last = _parse;
2849  }
2850  if (include) {
2851  result = _text._shared.substr(start, _parse - start);
2852  } else {
2853  result = _text._shared.substr(start, last - start);
2854  }
2855 }
2856 
2857 ////////////////////////////////////////////////////////////////////
2858 // Function: Shader::parse_rest
2859 // Access: Public
2860 // Description: Returns the rest of the text from the current
2861 // parse location.
2862 ////////////////////////////////////////////////////////////////////
2863 void Shader::
2864 parse_rest(string &result) {
2865  nassertv(!_text._separate);
2866  result = _text._shared.substr(_parse, _text._shared.size() - _parse);
2867 }
2868 
2869 ////////////////////////////////////////////////////////////////////
2870 // Function: Shader::parse_eof
2871 // Access: Public
2872 // Description: Returns true if the parse pointer is at the end of
2873 // the shader.
2874 ////////////////////////////////////////////////////////////////////
2875 bool Shader::
2877  return (int)_text._shared.size() == _parse;
2878 }
2879 
2880 ////////////////////////////////////////////////////////////////////
2881 // Function: Shader::prepare
2882 // Access: Published
2883 // Description: Indicates that the shader should be enqueued to be
2884 // prepared in the indicated prepared_objects at the
2885 // beginning of the next frame. This will ensure the
2886 // texture is already loaded into texture memory if it
2887 // is expected to be rendered soon.
2888 //
2889 // Use this function instead of prepare_now() to preload
2890 // textures from a user interface standpoint.
2891 ////////////////////////////////////////////////////////////////////
2892 void Shader::
2893 prepare(PreparedGraphicsObjects *prepared_objects) {
2894  prepared_objects->enqueue_shader(this);
2895 }
2896 
2897 ////////////////////////////////////////////////////////////////////
2898 // Function: Shader::is_prepared
2899 // Access: Published
2900 // Description: Returns true if the shader has already been prepared
2901 // or enqueued for preparation on the indicated GSG,
2902 // false otherwise.
2903 ////////////////////////////////////////////////////////////////////
2904 bool Shader::
2905 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
2906  Contexts::const_iterator ci;
2907  ci = _contexts.find(prepared_objects);
2908  if (ci != _contexts.end()) {
2909  return true;
2910  }
2911  return prepared_objects->is_shader_queued(this);
2912 }
2913 
2914 ////////////////////////////////////////////////////////////////////
2915 // Function: Shader::release
2916 // Access: Published
2917 // Description: Frees the texture context only on the indicated object,
2918 // if it exists there. Returns true if it was released,
2919 // false if it had not been prepared.
2920 ////////////////////////////////////////////////////////////////////
2921 bool Shader::
2922 release(PreparedGraphicsObjects *prepared_objects) {
2923  Contexts::iterator ci;
2924  ci = _contexts.find(prepared_objects);
2925  if (ci != _contexts.end()) {
2926  ShaderContext *sc = (*ci).second;
2927  if (sc != (ShaderContext *)NULL) {
2928  prepared_objects->release_shader(sc);
2929  } else {
2930  _contexts.erase(ci);
2931  }
2932  return true;
2933  }
2934 
2935  // Maybe it wasn't prepared yet, but it's about to be.
2936  return prepared_objects->dequeue_shader(this);
2937 }
2938 
2939 ////////////////////////////////////////////////////////////////////
2940 // Function: Shader::prepare_now
2941 // Access: Published
2942 // Description: Creates a context for the shader on the particular
2943 // GSG, if it does not already exist. Returns the new
2944 // (or old) ShaderContext. This assumes that the
2945 // GraphicsStateGuardian is the currently active
2946 // rendering context and that it is ready to accept new
2947 // textures. If this is not necessarily the case, you
2948 // should use prepare() instead.
2949 //
2950 // Normally, this is not called directly except by the
2951 // GraphicsStateGuardian; a shader does not need to be
2952 // explicitly prepared by the user before it may be
2953 // rendered.
2954 ////////////////////////////////////////////////////////////////////
2958  Contexts::const_iterator ci;
2959  ci = _contexts.find(prepared_objects);
2960  if (ci != _contexts.end()) {
2961  return (*ci).second;
2962  }
2963 
2964  ShaderContext *tc = prepared_objects->prepare_shader_now(this, gsg);
2965  _contexts[prepared_objects] = tc;
2966 
2967  return tc;
2968 }
2969 
2970 ////////////////////////////////////////////////////////////////////
2971 // Function: Shader::clear_prepared
2972 // Access: Private
2973 // Description: Removes the indicated PreparedGraphicsObjects table
2974 // from the Shader's table, without actually releasing
2975 // the texture. This is intended to be called only from
2976 // PreparedGraphicsObjects::release_texture(); it should
2977 // never be called by user code.
2978 ////////////////////////////////////////////////////////////////////
2979 void Shader::
2980 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
2981  Contexts::iterator ci;
2982  ci = _contexts.find(prepared_objects);
2983  if (ci != _contexts.end()) {
2984  _contexts.erase(ci);
2985  } else {
2986  // If this assertion fails, clear_prepared() was given a
2987  // prepared_objects which the texture didn't know about.
2988  nassertv(false);
2989  }
2990 }
2991 
2992 ////////////////////////////////////////////////////////////////////
2993 // Function: Shader::release_all
2994 // Access: Published
2995 // Description: Frees the context allocated on all objects for which
2996 // the texture has been declared. Returns the number of
2997 // contexts which have been freed.
2998 ////////////////////////////////////////////////////////////////////
2999 int Shader::
3001  // We have to traverse a copy of the _contexts list, because the
3002  // PreparedGraphicsObjects object will call clear_prepared() in response
3003  // to each release_texture(), and we don't want to be modifying the
3004  // _contexts list while we're traversing it.
3005  Contexts temp = _contexts;
3006  int num_freed = (int)_contexts.size();
3007 
3008  Contexts::const_iterator ci;
3009  for (ci = temp.begin(); ci != temp.end(); ++ci) {
3010  PreparedGraphicsObjects *prepared_objects = (*ci).first;
3011  ShaderContext *sc = (*ci).second;
3012  if (sc != (ShaderContext *)NULL) {
3013  prepared_objects->release_shader(sc);
3014  }
3015  }
3016 
3017  // There might still be some outstanding contexts in the map, if
3018  // there were any NULL pointers there. Eliminate them.
3019  _contexts.clear();
3020 
3021  return num_freed;
3022 }
3023 
3024 ////////////////////////////////////////////////////////////////////
3025 // Function: Shader::ShaderCapabilities::clear()
3026 // Access: Public
3027 // Description:
3028 ////////////////////////////////////////////////////////////////////
3029 void Shader::ShaderCaps::
3030 clear() {
3031  _supports_glsl = false;
3032 
3033 #ifdef HAVE_CG
3034  _active_vprofile = CG_PROFILE_UNKNOWN;
3035  _active_fprofile = CG_PROFILE_UNKNOWN;
3036  _active_gprofile = CG_PROFILE_UNKNOWN;
3037  _active_fprofile = CG_PROFILE_UNKNOWN;
3038  _ultimate_vprofile = CG_PROFILE_UNKNOWN;
3039  _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3040  _ultimate_gprofile = CG_PROFILE_UNKNOWN;
3041  _ultimate_fprofile = CG_PROFILE_UNKNOWN;
3042 #endif
3043 }
3044 
3045 ////////////////////////////////////////////////////////////////////
3046 // Function: Shader::register_with_read_factory
3047 // Access: Public, Static
3048 // Description: Tells the BamReader how to create objects of type
3049 // Shader.
3050 ////////////////////////////////////////////////////////////////////
3051 void Shader::
3053  //BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
3054 }
3055 
3056 ////////////////////////////////////////////////////////////////////
3057 // Function: Shader::write_datagram
3058 // Access: Public, Virtual
3059 // Description: Writes the contents of this object to the datagram
3060 // for shipping out to a Bam file.
3061 ////////////////////////////////////////////////////////////////////
3062 void Shader::
3064  dg.add_uint8(_language);
3065  dg.add_bool(_loaded);
3066  _filename.write_datagram(dg);
3067  _text.write_datagram(dg);
3068 }
3069 
3070 ////////////////////////////////////////////////////////////////////
3071 // Function: Shader::make_from_bam
3072 // Access: Protected, Static
3073 // Description: This function is called by the BamReader's factory
3074 // when a new object of type Shader is encountered
3075 // in the Bam file. It should create the Shader
3076 // and extract its information from the file.
3077 ////////////////////////////////////////////////////////////////////
3078 TypedWritable *Shader::
3079 make_from_bam(const FactoryParams &params) {
3080  Shader *attrib = new Shader(SL_none);
3081  DatagramIterator scan;
3082  BamReader *manager;
3083 
3084  parse_params(params, scan, manager);
3085  attrib->fillin(scan, manager);
3086  return attrib;
3087 }
3088 
3089 ////////////////////////////////////////////////////////////////////
3090 // Function: Shader::fillin
3091 // Access: Protected
3092 // Description: This internal function is called by make_from_bam to
3093 // read in all of the relevant data from the BamFile for
3094 // the new Shader.
3095 ////////////////////////////////////////////////////////////////////
3096 void Shader::
3097 fillin(DatagramIterator &scan, BamReader *manager) {
3098  _language = (ShaderLanguage) scan.get_uint8();
3099  _loaded = scan.get_bool();
3100  _filename.read_datagram(scan);
3101  _text.read_datagram(scan);
3102 }
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 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:2905
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:3052
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
Filename get_filename(const ShaderType &type=ST_none) const
Return the Shader&#39;s filename for the given shader type.
Definition: shader.I:23
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 matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:157
string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:424
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 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_init()
Set a &#39;parse pointer&#39; to the beginning of the shader.
Definition: shader.cxx:2797
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:2839
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
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:3063
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
void parse_rest(string &result)
Returns the rest of the text from the current parse location.
Definition: shader.cxx:2864
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
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
~Shader()
Delete the compiled code, if it exists.
Definition: shader.cxx:2522
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:2893
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
ostream & error(bool prefix=true) const
A shorthand way to write out(NS_error).
int release_all()
Frees the context allocated on all objects for which the texture has been declared.
Definition: shader.cxx:3000
bool cp_errchk_parameter_in(ShaderArgInfo &arg)
Make sure the provided parameter has the &#39;in&#39; direction.
Definition: shader.cxx:135
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
Definition: shader.cxx:2922
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:2810
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
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:2876
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:2956
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
bool is_shader_queued(const Shader *shader) const
Returns true if the shader has been queued on this GSG, false otherwise.
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
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