Panda3D

dxShaderContext9.cxx

00001 // Filename: dxShaderContext9.cxx
00002 // Created by: jyelon (01Sep05), conversion aignacio (Jan-Mar06)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "dxGraphicsStateGuardian9.h"
00016 #include "dxShaderContext9.h"
00017 #include "dxVertexBufferContext9.h"
00018 
00019 #include <io.h>
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <fcntl.h>
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #ifdef HAVE_CG
00026 #include "Cg/cgD3D9.h"
00027 #endif
00028 
00029 #define DEBUG_SHADER 0
00030 
00031 TypeHandle CLP(ShaderContext)::_type_handle;
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: DXShaderContext9::Constructor
00035 //       Access: Public
00036 //  Description: xyz
00037 ////////////////////////////////////////////////////////////////////
00038 CLP(ShaderContext)::
00039 CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
00040 
00041   _vertex_element_array = NULL;
00042   _vertex_declaration = NULL;
00043 
00044   _num_bound_streams = 0;
00045 
00046   _name = s->get_filename ( );
00047 
00048 #ifdef HAVE_CG
00049   _cg_context = 0;
00050   if (s->get_language() == Shader::SL_Cg) {
00051     
00052     // Ask the shader to compile itself for us and 
00053     // to give us the resulting Cg program objects.
00054 
00055     if (!s->cg_compile_for(gsg->_shader_caps,
00056                            _cg_context,
00057                            _cg_vprogram,
00058                            _cg_fprogram, 
00059                            _cg_gprogram,        // CG2 CHANGE
00060                            _cg_parameter_map)) {
00061       return;
00062     }
00063         
00064     // Load the program.
00065 
00066     BOOL paramater_shadowing;
00067     DWORD assembly_flags;
00068     
00069     paramater_shadowing = FALSE;
00070     assembly_flags = 0;
00071     
00072 #if DEBUG_SHADER
00073     assembly_flags |= D3DXSHADER_DEBUG;
00074 #endif
00075 
00076     HRESULT hr;
00077     bool success = true;
00078     hr = cgD3D9LoadProgram(_cg_vprogram, paramater_shadowing, assembly_flags);
00079     if (FAILED (hr)) {
00080       dxgsg9_cat.error()
00081         << "vertex shader cgD3D9LoadProgram failed "
00082         << D3DERRORSTRING(hr);
00083       
00084       CGerror error = cgGetError();
00085       if (error != CG_NO_ERROR) {
00086         dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
00087       }
00088       success = false;
00089     }
00090     
00091     hr = cgD3D9LoadProgram(_cg_fprogram, paramater_shadowing, assembly_flags);
00092     if (FAILED (hr)) {
00093       dxgsg9_cat.error()
00094         << "pixel shader cgD3D9LoadProgram failed "
00095         << D3DERRORSTRING(hr);
00096       
00097       CGerror error = cgGetError();
00098       if (error != CG_NO_ERROR) {
00099         dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
00100       }
00101       success = false;
00102     }    
00103 
00104     // BEGIN CG2 CHANGE
00105     if (_cg_gprogram != 0)
00106     {
00107         hr = cgD3D9LoadProgram(_cg_gprogram, paramater_shadowing, assembly_flags);
00108         if (FAILED (hr)) {
00109           dxgsg9_cat.error()
00110             << "geometry shader cgD3D9LoadProgram failed "
00111             << D3DERRORSTRING(hr);
00112 
00113           CGerror error = cgGetError();
00114           if (error != CG_NO_ERROR) {
00115             dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
00116           }
00117           success = false;
00118         }
00119     }
00120     // END CG2 CHANGE
00121 
00122     if (!success) {
00123       release_resources();
00124     }
00125   }
00126 #endif
00127 }
00128 
00129 ////////////////////////////////////////////////////////////////////
00130 //     Function: DXShaderContext9::Destructor
00131 //       Access: Public
00132 //  Description: xyz
00133 ////////////////////////////////////////////////////////////////////
00134 CLP(ShaderContext)::
00135 ~CLP(ShaderContext)() {
00136   release_resources();
00137 
00138   if ( _vertex_declaration != NULL ) {
00139     _vertex_declaration->Release();
00140     _vertex_declaration = NULL;
00141   }
00142 
00143   if ( _vertex_element_array != NULL ) {
00144     delete _vertex_element_array;
00145     _vertex_element_array = NULL;
00146   }
00147 }
00148 
00149 // int save_file (int size, void *data, char *file_path)
00150 // {
00151 //   int state;
00152 //   int file_handle;
00153 // 
00154 //   state = false;
00155 //   file_handle = _open (file_path, _O_CREAT | _O_RDWR | _O_TRUNC, _S_IREAD | _S_IWRITE);
00156 //   if (file_handle != -1) {
00157 //     if (_write (file_handle, data, size) == size) {
00158 //       state = true;
00159 //     }
00160 //     _close (file_handle);
00161 //   }
00162 // 
00163 //   return state;
00164 // }
00165 // 
00166 //   if (dxgsg9_cat.is_debug()) {
00167 //     // DEBUG: output the generated program
00168 //     const char *vertex_program;
00169 //     const char *pixel_program;
00170 // 
00171 //     vertex_program = cgGetProgramString (_cg_program[0], CG_COMPILED_PROGRAM);
00172 //     pixel_program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM);
00173 // 
00174 //     dxgsg9_cat.debug() << vertex_program << "\n";
00175 //     dxgsg9_cat.debug() << pixel_program << "\n";
00176 // 
00177 //     // save the generated program to a file
00178 //     int size;
00179 //     char file_path [512];
00180 // 
00181 //     char drive[_MAX_DRIVE];
00182 //     char dir[_MAX_DIR];
00183 //     char fname[_MAX_FNAME];
00184 //     char ext[_MAX_EXT];
00185 // 
00186 //     _splitpath (_name.c_str ( ), drive, dir, fname, ext);
00187 // 
00188 //     size = strlen (vertex_program);
00189 //     sprintf (file_path, "%s.vasm", fname);
00190 //     save_file (size, (void *) vertex_program, file_path);
00191 // 
00192 //     size = strlen (pixel_program);
00193 //     sprintf (file_path, "%s.pasm", fname);
00194 //     save_file (size, (void *) pixel_program, file_path);
00195 //   }
00196 
00197 ////////////////////////////////////////////////////////////////////
00198 //     Function: DXShaderContext9::release_resources
00199 //       Access: Public
00200 //  Description: Should deallocate all system resources (such as
00201 //               vertex program handles or Cg contexts).
00202 ////////////////////////////////////////////////////////////////////
00203 void CLP(ShaderContext)::
00204 release_resources() {
00205 #ifdef HAVE_CG
00206   if (_cg_context) {
00207     cgDestroyContext(_cg_context);
00208     _cg_context = 0;
00209     _cg_vprogram = 0;
00210     _cg_fprogram = 0;
00211     _cg_gprogram = 0;   // CG2 CHANGE
00212     _cg_parameter_map.clear();
00213   }
00214 #endif
00215 
00216   // I think we need to call SetStreamSource for _num_bound_streams -- basically the logic from
00217   // disable_shader_vertex_arrays -- but to do that we need to introduce logic like the GL code
00218   // has to manage _last_gsg, so we can get at the device.  Sigh.
00219 }
00220 
00221 ////////////////////////////////////////////////////////////////////
00222 //     Function: DXShaderContext9::bind
00223 //       Access: Public
00224 //  Description: This function is to be called to enable a new
00225 //               shader.  It also initializes all of the shader's
00226 //               input parameters.
00227 ////////////////////////////////////////////////////////////////////
00228 bool CLP(ShaderContext)::
00229 bind(GSG *gsg) {
00230 
00231   bool bind_state;
00232 
00233   bind_state = false;
00234 #ifdef HAVE_CG
00235   if (_cg_context) {
00236     // clear the last cached FVF to make sure the next SetFVF call goes through
00237                                                            
00238     gsg -> _last_fvf = 0;
00239 
00240     // Pass in k-parameters and transform-parameters
00241     issue_parameters(gsg, Shader::SSD_general);
00242     
00243     HRESULT hr;
00244     
00245     // Bind the shaders.
00246     bind_state = true;
00247     hr = cgD3D9BindProgram(_cg_vprogram);
00248     if (FAILED (hr)) {
00249       dxgsg9_cat.error() << "cgD3D9BindProgram vertex shader failed " << D3DERRORSTRING(hr);
00250       
00251       CGerror error = cgGetError();
00252       if (error != CG_NO_ERROR) {
00253         dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
00254       }
00255       
00256       bind_state = false;
00257     }
00258     hr = cgD3D9BindProgram(_cg_fprogram);
00259     if (FAILED (hr)) {
00260       dxgsg9_cat.error() << "cgD3D9BindProgram pixel shader failed " << D3DERRORSTRING(hr);
00261       
00262       CGerror error = cgGetError();
00263       if (error != CG_NO_ERROR) {
00264         dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
00265       }
00266       
00267       bind_state = false;
00268     }
00269 
00270     // BEGIN CG2 CHANGE
00271     if (_cg_gprogram != 0)
00272     {
00273         hr = cgD3D9BindProgram(_cg_gprogram);
00274         if (FAILED (hr)) {
00275           dxgsg9_cat.error() << "cgD3D9BindProgram geometry shader failed " << D3DERRORSTRING(hr);
00276 
00277           CGerror error = cgGetError();
00278           if (error != CG_NO_ERROR) {
00279             dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
00280           }
00281 
00282           bind_state = false;
00283         }
00284     }
00285     // END CG2 CHANGE
00286   }
00287 #endif
00288 
00289   return bind_state;
00290 }
00291 
00292 ////////////////////////////////////////////////////////////////////
00293 //     Function: DXShaderContext9::unbind
00294 //       Access: Public
00295 //  Description: This function disables a currently-bound shader.
00296 ////////////////////////////////////////////////////////////////////
00297 void CLP(ShaderContext)::
00298 unbind(GSG *gsg) {
00299 
00300 #ifdef HAVE_CG
00301   if (_cg_context) {
00302     HRESULT hr;
00303 
00304     hr = gsg -> _d3d_device -> SetVertexShader (NULL);
00305     if (FAILED (hr)) {
00306       dxgsg9_cat.error()
00307         << "SetVertexShader (NULL) failed " << D3DERRORSTRING(hr);
00308     }
00309     hr = gsg -> _d3d_device -> SetPixelShader (NULL);
00310     if (FAILED (hr)) {
00311       dxgsg9_cat.error()
00312         << "SetPixelShader (NULL) failed " << D3DERRORSTRING(hr);
00313     }
00314   }
00315 #endif
00316 }
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: DXShaderContext9::issue_parameters
00320 //       Access: Public
00321 //  Description: This function gets called whenever the RenderState
00322 //               or TransformState has changed, but the Shader
00323 //               itself has not changed.  It loads new values into the
00324 //               shader's parameters.
00325 //
00326 //               If "altered" is false, that means you promise that
00327 //               the parameters for this shader context have already
00328 //               been issued once, and that since the last time the
00329 //               parameters were issued, no part of the render
00330 //               state has changed except the external and internal
00331 //               transforms.
00332 ////////////////////////////////////////////////////////////////////
00333 
00334 #if DEBUG_SHADER
00335 PN_stdfloat *global_data = 0;
00336 ShaderContext::ShaderMatSpec *global_shader_mat_spec = 0;
00337 InternalName *global_internal_name_0 = 0;
00338 InternalName *global_internal_name_1 = 0;
00339 #endif
00340 
00341 void CLP(ShaderContext)::
00342 issue_parameters(GSG *gsg, int altered)
00343 {
00344 #ifdef HAVE_CG
00345   if (_cg_context) {
00346 
00347   // Iterate through _ptr parameters
00348     for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
00349       if(altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])){
00350 #ifdef HAVE_CG
00351         const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i];
00352         Shader::ShaderPtrData* _ptr_data = 
00353           const_cast< Shader::ShaderPtrData*>(gsg->fetch_ptr_parameter(_ptr));
00354         
00355         if (_ptr_data == NULL){ //the input is not contained in ShaderPtrData
00356           release_resources();
00357           return;
00358         }
00359 
00360         CGparameter p = _cg_parameter_map[_ptr._id._seqno];
00361         
00362         switch(_ptr_data->_type) {
00363         case Shader::SPT_float:
00364           cgD3D9SetUniform(p, (PN_stdfloat*)_ptr_data->_ptr); 
00365           break;
00366 
00367         default: 
00368           dxgsg9_cat.error() 
00369             << _ptr._id._name << ":" << "unrecognized parameter type\n"; 
00370           release_resources(); 
00371           return;
00372         }
00373       }
00374 #endif
00375     }
00376 
00377     for (int i=0; i<(int)_shader->_mat_spec.size(); i++) {
00378       if (altered & (_shader->_mat_spec[i]._dep[0] | _shader->_mat_spec[i]._dep[1])) {
00379         CGparameter p = _cg_parameter_map[_shader->_mat_spec[i]._id._seqno];
00380         if (p == NULL) {
00381           continue;
00382         }        
00383         const LMatrix4 *val = gsg->fetch_specified_value(_shader->_mat_spec[i], altered);
00384         if (val) {
00385           HRESULT hr;
00386           PN_stdfloat v [4];
00387           LMatrix4f temp_matrix = LCAST(float, *val);
00388 
00389           hr = D3D_OK;
00390 
00391           const float *data;
00392           data = temp_matrix.get_data();
00393 
00394           #if DEBUG_SHADER
00395           // DEBUG
00396           global_data = (PN_stdfloat *) data;
00397           global_shader_mat_spec = &_shader->_mat_spec[i];
00398           global_internal_name_0 = global_shader_mat_spec -> _arg [0];
00399           global_internal_name_1 = global_shader_mat_spec -> _arg [1];
00400           #endif
00401 
00402           switch (_shader->_mat_spec[i]._piece) {
00403           case Shader::SMP_whole:
00404             // TRANSPOSE REQUIRED
00405             temp_matrix.transpose_in_place();
00406             data = temp_matrix.get_data();
00407 
00408             hr = cgD3D9SetUniform (p, data);
00409             break;
00410 
00411           case Shader::SMP_transpose:
00412             // NO TRANSPOSE REQUIRED
00413             hr = cgD3D9SetUniform (p, data);
00414             break;
00415 
00416           case Shader::SMP_row0:
00417             hr = cgD3D9SetUniform (p, data + 0);
00418             break;
00419           case Shader::SMP_row1:
00420             hr = cgD3D9SetUniform (p, data + 4);
00421             break;
00422           case Shader::SMP_row2:
00423             hr = cgD3D9SetUniform (p, data + 8);
00424             break;
00425           case Shader::SMP_row3x1:
00426           case Shader::SMP_row3x2:
00427           case Shader::SMP_row3x3:
00428           case Shader::SMP_row3:
00429             hr = cgD3D9SetUniform (p, data + 12);
00430             break;
00431 
00432           case Shader::SMP_col0:
00433             v[0] = data[0]; v[1] = data[4]; v[2] = data[8]; v[3] = data[12];
00434             hr = cgD3D9SetUniform (p, v);
00435             break;
00436           case Shader::SMP_col1:
00437             v[0] = data[1]; v[1] = data[5]; v[2] = data[9]; v[3] = data[13];
00438             hr = cgD3D9SetUniform (p, v);
00439             break;
00440           case Shader::SMP_col2:
00441             v[0] = data[2]; v[1] = data[6]; v[2] = data[10]; v[3] = data[14];
00442             hr = cgD3D9SetUniform (p, v);
00443             break;
00444           case Shader::SMP_col3:
00445             v[0] = data[3]; v[1] = data[7]; v[2] = data[11]; v[3] = data[15];
00446             hr = cgD3D9SetUniform (p, v);
00447             break;
00448 
00449           default:
00450             dxgsg9_cat.error()
00451               << "issue_parameters ( ) SMP parameter type not implemented " << _shader->_mat_spec[i]._piece << "\n";
00452             break;
00453           }
00454 
00455           if (FAILED (hr)) {
00456 
00457             string name = "unnamed";
00458 
00459             if (_shader->_mat_spec[i]._arg [0]) {
00460               name = _shader->_mat_spec[i]._arg [0] -> get_basename ( );
00461             }
00462 
00463             dxgsg9_cat.error()
00464               << "NAME  " << name << "\n"
00465               << "MAT TYPE  "
00466               << _shader->_mat_spec[i]._piece
00467               << " cgD3D9SetUniform failed "
00468               << D3DERRORSTRING(hr);
00469 
00470             CGerror error = cgGetError ();
00471             if (error != CG_NO_ERROR) {
00472               dxgsg9_cat.error() << "  CG ERROR: " << cgGetErrorString(error) << "\n";
00473             }
00474           }
00475         }
00476       }
00477     }
00478   }
00479 #endif
00480 }
00481 
00482 ////////////////////////////////////////////////////////////////////
00483 //     Function: DXShaderContext9::disable_shader_vertex_arrays
00484 //       Access: Public
00485 //  Description: Disable all the vertex arrays used by this shader.
00486 ////////////////////////////////////////////////////////////////////
00487 void CLP(ShaderContext)::
00488 disable_shader_vertex_arrays(GSG *gsg) {
00489   LPDIRECT3DDEVICE9 device = gsg->_screen->_d3d_device;
00490 
00491   for ( int array_index = 0; array_index < _num_bound_streams; ++array_index )
00492   {
00493     device->SetStreamSource( array_index, NULL, 0, 0 );
00494   }
00495   _num_bound_streams = 0;
00496 }
00497 
00498 ////////////////////////////////////////////////////////////////////
00499 //     Function: DXShaderContext9::update_shader_vertex_arrays
00500 //       Access: Public
00501 //  Description: Disables all vertex arrays used by the previous
00502 //               shader, then enables all the vertex arrays needed
00503 //               by this shader.  Extracts the relevant vertex array
00504 //               data from the gsg.
00505 //               The current implementation is inefficient, because
00506 //               it may unnecessarily disable arrays then immediately
00507 //               reenable them.  We may optimize this someday.
00508 ////////////////////////////////////////////////////////////////////
00509 bool CLP(ShaderContext)::
00510 update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg, bool force) {
00511   if (prev) prev->disable_shader_vertex_arrays(gsg);
00512 #ifdef HAVE_CG
00513   if (!_cg_context) {
00514     return true;
00515   }
00516 
00517 #ifdef SUPPORT_IMMEDIATE_MODE
00518 /*
00519     if (gsg->_use_sender) {
00520       dxgsg9_cat.error() << "immediate mode shaders not implemented yet\n";
00521     } else
00522 */
00523 #endif // SUPPORT_IMMEDIATE_MODE
00524   {
00525     int nvarying = _shader->_var_spec.size();
00526     LPDIRECT3DDEVICE9 device = gsg->_screen->_d3d_device;
00527     HRESULT hr;
00528 
00529     // Discard and recreate the VertexElementArray.  This thrashes pretty bad....
00530     if ( _vertex_element_array != NULL ) {
00531       delete _vertex_element_array;
00532     }
00533     _vertex_element_array = new VertexElementArray(nvarying + 2);
00534     VertexElementArray* vertex_element_array = _vertex_element_array;
00535 
00536     // Experimentally determined that DX doesn't like us crossing the streams!
00537     // It seems to be okay with out-of-order offsets in both source and destination,
00538     // but it wants all stream X entries grouped together, then all stream Y entries, etc.
00539     // To accomplish this out outer loop processes arrays ("streams"), and we repeatedly
00540     // iterate the parameters to pull out only those for a single stream.
00541 
00542     int number_of_arrays = gsg->_data_reader->get_num_arrays();
00543     for ( int array_index = 0; array_index < number_of_arrays; ++array_index ) {
00544       const GeomVertexArrayDataHandle* array_reader =
00545         gsg->_data_reader->get_array_reader( array_index );
00546       if ( array_reader == NULL ) {
00547         dxgsg9_cat.error() << "Unable to get reader for array " << array_index << "\n";
00548         continue;
00549       }
00550 
00551       for ( int var_index = 0; var_index < nvarying; ++var_index ) {
00552         CGparameter p = _cg_parameter_map[_shader->_var_spec[var_index]._id._seqno];
00553         if ( p == NULL ) {
00554           dxgsg9_cat.info() <<
00555             "No parameter in map for parameter " << var_index <<
00556             " (probably optimized away)\n";
00557           continue;
00558         }
00559 
00560         InternalName *name = _shader->_var_spec[var_index]._name;
00561 
00562         // This is copied from the GL version of this function, and I've yet to 100% convince
00563         // myself that it works properly....
00564         int texslot = _shader->_var_spec[var_index]._append_uv;
00565         if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) {
00566           TextureStage *stage = gsg->_state_texture->get_on_stage(texslot);
00567           InternalName *texname = stage->get_texcoord_name();
00568           if (name == InternalName::get_texcoord()) {
00569             name = texname;
00570           } else if (texname != InternalName::get_texcoord()) {
00571             name = name->append(texname->get_basename());
00572           }
00573         }
00574 
00575         const GeomVertexArrayDataHandle* param_array_reader;
00576         Geom::NumericType numeric_type;
00577         int num_values;
00578         int start;
00579         int stride;
00580         if ( gsg->_data_reader->get_array_info( name,
00581                                                 param_array_reader, num_values, numeric_type,
00582                                                 start, stride ) == false ) {
00583           // This is apparently not an error (actually I think it is, just not a fatal one).
00584           //
00585           // The GL implementation fails silently in this case, but the net result is that we
00586           // end up not supplying input for a shader parameter, which can cause Bad Things to
00587           // happen so I'd like to at least get a hint as to what's gone wrong.
00588           dxgsg9_cat.info() << "Geometry contains no data for shader parameter " << *name << "\n";
00589           continue;
00590         }
00591         
00592         // If not associated with the array we're working on, move on.
00593         if ( param_array_reader != array_reader ) {
00594           continue;
00595         }
00596 
00597         const char* semantic = cgGetParameterSemantic( p );
00598         if ( semantic == NULL ) {
00599           dxgsg9_cat.error() << "Unable to retrieve semantic for parameter " << var_index << "\n";
00600           continue;
00601         }
00602 
00603         if ( strncmp( semantic, "POSITION", strlen( "POSITION" ) ) == 0 ) {
00604           if (numeric_type == Geom::NT_float32) {
00605             switch (num_values) {
00606               case 3:
00607                 vertex_element_array->add_position_xyz_vertex_element(array_index, start);
00608                 break;
00609               case 4:
00610                 vertex_element_array->add_position_xyzw_vertex_element(array_index, start);
00611                 break;
00612               default:
00613                 dxgsg9_cat.error() << "VE ERROR: invalid number of vertex coordinate elements " << num_values << "\n";
00614                 break;
00615             }
00616           } else {
00617             dxgsg9_cat.error() << "VE ERROR: invalid vertex type " << numeric_type << "\n";
00618           }
00619         } else if ( strncmp( semantic, "TEXCOORD", strlen( "TEXCOORD" ) ) == 0 ) {
00620           int slot = atoi( semantic + strlen( "TEXCOORD" ) );
00621           if (numeric_type == Geom::NT_float32) {
00622             switch (num_values) {
00623               case 1:
00624                 vertex_element_array->add_u_vertex_element(array_index, start, slot);
00625                 break;
00626               case 2:
00627                 vertex_element_array->add_uv_vertex_element(array_index, start, slot);
00628                 break;
00629               case 3:
00630                 vertex_element_array->add_uvw_vertex_element(array_index, start, slot);
00631                 break;
00632               case 4:
00633                 vertex_element_array->add_xyzw_vertex_element(array_index, start, slot);
00634                 break;
00635               default:
00636                 dxgsg9_cat.error() << "VE ERROR: invalid number of vertex texture coordinate elements " << num_values <<  "\n";
00637                 break;
00638             }
00639           } else {
00640             dxgsg9_cat.error() << "VE ERROR: invalid texture coordinate type " << numeric_type << "\n";
00641           }
00642         } else if ( strncmp( semantic, "COLOR", strlen( "COLOR" ) ) == 0 ) {
00643           if (numeric_type == Geom::NT_packed_dcba ||
00644               numeric_type == Geom::NT_packed_dabc ||
00645               numeric_type == Geom::NT_uint8) {
00646             switch (num_values) {
00647               case 4:
00648                 vertex_element_array->add_diffuse_color_vertex_element(array_index, start);
00649                 break;
00650               default:
00651                 dxgsg9_cat.error() << "VE ERROR: invalid color coordinates " << num_values << "\n";
00652                 break;
00653             }
00654           } else {
00655             dxgsg9_cat.error() << "VE ERROR: invalid color type " << numeric_type << "\n";
00656           }
00657         } else if ( strncmp( semantic, "NORMAL", strlen( "NORMAL" ) ) == 0 ) {
00658           if (numeric_type == Geom::NT_float32) {
00659             switch (num_values) {
00660               case 3:
00661                 vertex_element_array->add_normal_vertex_element(array_index, start);
00662                 break;
00663               default:
00664                 dxgsg9_cat.error() << "VE ERROR: invalid number of normal coordinate elements " << num_values << "\n";
00665                 break;
00666             }
00667           } else {
00668             dxgsg9_cat.error() << "VE ERROR: invalid normal type " << numeric_type << "\n";
00669           }
00670         } else if ( strncmp( semantic, "BINORMAL", strlen( "BINORMAL" ) ) == 0 ) {
00671           if (numeric_type == Geom::NT_float32) {
00672             switch (num_values) {
00673               case 3:
00674                 vertex_element_array->add_binormal_vertex_element(array_index, start);
00675                 break;
00676               default:
00677                 dxgsg9_cat.error() << "VE ERROR: invalid number of binormal coordinate elements " << num_values << "\n";
00678                 break;
00679             }
00680           } else {
00681             dxgsg9_cat.error() << "VE ERROR: invalid binormal type " << numeric_type << "\n";
00682           }
00683         } else if ( strncmp( semantic, "TANGENT", strlen( "TANGENT" ) ) == 0 ) {
00684           if (numeric_type == Geom::NT_float32) {
00685             switch (num_values) {
00686               case 3:
00687                 vertex_element_array->add_tangent_vertex_element(array_index, start);
00688                 break;
00689               default:
00690                 dxgsg9_cat.error() << "VE ERROR: invalid number of tangent coordinate elements " << num_values << "\n";
00691                 break;
00692             }
00693           } else {
00694             dxgsg9_cat.error() << "VE ERROR: invalid tangent type " << numeric_type << "\n";
00695           }
00696         } else {
00697           dxgsg9_cat.error() << "Unsupported semantic " << semantic << " for parameter " << var_index << "\n";
00698         }
00699       }
00700 
00701       // Get the vertex buffer for this array.
00702       CLP(VertexBufferContext)* dvbc;
00703       if (!gsg->setup_array_data(dvbc, array_reader, force)) {
00704         dxgsg9_cat.error() << "Unable to setup vertex buffer for array " << array_index << "\n";
00705         continue;
00706       }
00707 
00708       // Bind this array as the data source for the corresponding stream.
00709       const GeomVertexArrayFormat* array_format = array_reader->get_array_format();
00710       hr = device->SetStreamSource( array_index, dvbc->_vbuffer, 0, array_format->get_stride() );
00711       if (FAILED(hr)) {
00712         dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr);
00713       }
00714     }
00715 
00716     _num_bound_streams = number_of_arrays;
00717 
00718     if (( _vertex_element_array != NULL ) &&
00719         ( _vertex_element_array->add_end_vertex_element() != false )) {
00720       if ( dxgsg9_cat.is_debug() ) {
00721         // Note that the currently generated vertex declaration works but never validates.
00722         // My theory is that this is due to the shader programs always using float4 whereas
00723         // the vertex declaration correctly sets the number of inputs (float2, float3, etc.).
00724         if (cgD3D9ValidateVertexDeclaration(_cg_vprogram,
00725                                             _vertex_element_array->_vertex_element_array) == CG_TRUE) {
00726           dxgsg9_cat.debug() << "cgD3D9ValidateVertexDeclaration succeeded\n";
00727         } else {
00728           dxgsg9_cat.debug() << "cgD3D9ValidateVertexDeclaration failed\n";
00729         }
00730       }
00731 
00732       // Discard the old VertexDeclaration.  This thrashes pretty bad....
00733       if ( _vertex_declaration != NULL ) {
00734         _vertex_declaration->Release();
00735         _vertex_declaration = NULL;
00736       }
00737 
00738       hr = device->CreateVertexDeclaration( _vertex_element_array->_vertex_element_array,
00739                                             &_vertex_declaration );
00740       if (FAILED (hr)) {
00741         dxgsg9_cat.error() << "CreateVertexDeclaration failed" << D3DERRORSTRING(hr);
00742       } else {
00743         hr = device->SetVertexDeclaration( _vertex_declaration );
00744         if (FAILED(hr)) {
00745           dxgsg9_cat.error() << "SetVertexDeclaration failed" << D3DERRORSTRING(hr);
00746         }
00747       }
00748     } else {
00749       dxgsg9_cat.error() << "VertexElementArray creation failed\n";
00750     }
00751   }
00752 #endif // HAVE_CG
00753 
00754   return true;
00755 }
00756 
00757 ////////////////////////////////////////////////////////////////////
00758 //     Function: DXShaderContext9::disable_shader_texture_bindings
00759 //       Access: Public
00760 //  Description: Disable all the texture bindings used by this shader.
00761 ////////////////////////////////////////////////////////////////////
00762 void CLP(ShaderContext)::
00763 disable_shader_texture_bindings(GSG *gsg)
00764 {
00765 #ifdef HAVE_CG
00766   if (_cg_context) {
00767     for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
00768       CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
00769       if (p == NULL) {
00770         continue;
00771       }        
00772       int texunit = cgGetParameterResourceIndex(p);
00773 
00774       HRESULT hr;
00775 
00776       hr = gsg -> _d3d_device -> SetTexture (texunit, NULL);
00777       if (FAILED (hr)) {
00778         dxgsg9_cat.error()
00779           << "SetTexture ("
00780           << texunit
00781           << ", NULL) failed "
00782           << D3DERRORSTRING(hr);
00783       }
00784     }
00785   }
00786 #endif
00787 }
00788 
00789 ////////////////////////////////////////////////////////////////////
00790 //     Function: DXShaderContext9::update_shader_texture_bindings
00791 //       Access: Public
00792 //  Description: Disables all texture bindings used by the previous
00793 //               shader, then enables all the texture bindings needed
00794 //               by this shader.  Extracts the relevant vertex array
00795 //               data from the gsg.
00796 //               The current implementation is inefficient, because
00797 //               it may unnecessarily disable textures then immediately
00798 //               reenable them.  We may optimize this someday.
00799 ////////////////////////////////////////////////////////////////////
00800 void CLP(ShaderContext)::
00801 update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg)
00802 {
00803   if (prev) prev->disable_shader_texture_bindings(gsg);
00804 
00805 #ifdef HAVE_CG
00806   if (_cg_context) {
00807 
00808     for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
00809       CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
00810       if (p == NULL) {
00811         continue;
00812       }        
00813       Texture *tex = 0;
00814       int view = gsg->get_current_tex_view_offset();
00815       InternalName *id = _shader->_tex_spec[i]._name;
00816       if (id != 0) {
00817         const ShaderInput *input = gsg->_target_shader->get_shader_input(id);
00818         tex = input->get_texture();
00819       } else {
00820         // We get the TextureAttrib directly from the _target_rs, not the
00821         // filtered TextureAttrib in _target_texture.
00822         const TextureAttrib *texattrib = DCAST(TextureAttrib, gsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
00823         nassertv(texattrib != (TextureAttrib *)NULL);
00824 
00825         if (_shader->_tex_spec[i]._stage >= texattrib->get_num_on_stages()) {
00826           continue;
00827         }
00828         TextureStage *stage = texattrib->get_on_stage(_shader->_tex_spec[i]._stage);
00829         tex = texattrib->get_on_texture(stage);
00830         view += stage->get_tex_view_offset();
00831       }
00832       if (_shader->_tex_spec[i]._suffix != 0) {
00833         // The suffix feature is inefficient. It is a temporary hack.
00834         if (tex == 0) {
00835           continue;
00836         }
00837         tex = tex->load_related(_shader->_tex_spec[i]._suffix);
00838       }
00839       if ((tex == 0) || (tex->get_texture_type() != _shader->_tex_spec[i]._desired_type)) {
00840         continue;
00841       }
00842       TextureContext *tc = tex->prepare_now(view, gsg->_prepared_objects, gsg);
00843       if (tc == (TextureContext*)NULL) {
00844         continue;
00845       }
00846       
00847       int texunit = cgGetParameterResourceIndex(p);
00848       
00849       gsg->apply_texture(texunit, tc);
00850     }
00851   }
00852 #endif
00853 }
00854 
00855 // DEBUG CODE TO TEST ASM CODE GENERATED BY Cg
00856 void assemble_shader_test(char *file_path)
00857 {
00858   int flags;
00859   D3DXMACRO *defines;
00860   LPD3DXINCLUDE include;
00861   LPD3DXBUFFER shader;
00862   LPD3DXBUFFER error_messages;
00863 
00864   flags = 0;
00865   defines = 0;
00866   include = 0;
00867   shader = 0;
00868   error_messages = 0;
00869 
00870   D3DXAssembleShaderFromFile (file_path, defines, include, flags, &shader, &error_messages);
00871   if (error_messages)
00872   {
00873     char *error_message;
00874 
00875     error_message = (char *) (error_messages -> GetBufferPointer ( ));
00876     if (error_message)
00877     {
00878       dxgsg9_cat.error() << error_message;
00879     }
00880 
00881     error_messages -> Release ( );
00882   }
00883 }
 All Classes Functions Variables Enumerations