From 129cef9f629e99cfd62ff2d30ef506d608bb4760 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Mon, 27 Feb 2006 21:52:36 +0000 Subject: [PATCH] Major overhaul to shader subsystem --- doc/makepanda/makepanda.py | 4 +- panda/src/display/graphicsStateGuardian.cxx | 235 ++++ panda/src/display/graphicsStateGuardian.h | 13 +- panda/src/dxgsg9/dxShaderContext9.cxx | 80 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 82 +- .../src/glstuff/glGraphicsStateGuardian_src.h | 2 +- panda/src/glstuff/glShaderContext_src.cxx | 1011 +++-------------- panda/src/glstuff/glShaderContext_src.h | 80 +- panda/src/gobj/lens.I | 32 + panda/src/gobj/lens.h | 3 + panda/src/gobj/shaderContext.cxx | 631 ++++++++++ panda/src/gobj/shaderContext.h | 126 +- 12 files changed, 1261 insertions(+), 1038 deletions(-) diff --git a/doc/makepanda/makepanda.py b/doc/makepanda/makepanda.py index 804af5f700..ebbabf8f13 100755 --- a/doc/makepanda/makepanda.py +++ b/doc/makepanda/makepanda.py @@ -2296,7 +2296,7 @@ EnqueueIgate(ipath=IPATH, opts=OPTS, outd='libpstatclient.in', obj='libpstatclie # IPATH=['panda/src/gobj'] -OPTS=['BUILDING_PANDA', 'NSPR'] +OPTS=['BUILDING_PANDA', 'NSPR', 'NVIDIACG'] CopyAllHeaders('panda/src/gobj') EnqueueCxx(ipath=IPATH, opts=OPTS, src='gobj_composite1.cxx', obj='gobj_composite1.obj') EnqueueCxx(ipath=IPATH, opts=OPTS, src='gobj_composite2.cxx', obj='gobj_composite2.obj') @@ -2572,7 +2572,7 @@ CopyAllHeaders('panda/src/physics') CopyAllHeaders('panda/src/particlesystem') IPATH=['panda/metalibs/panda'] OPTS=['BUILDING_PANDA', 'ZLIB', 'VRPN', 'JPEG', 'PNG', 'TIFF', 'NSPR', 'FREETYPE', 'HELIX', 'FFTW', 'OPENCV', - 'ADVAPI', 'WINSOCK2', 'WINUSER', 'WINMM'] + 'ADVAPI', 'WINSOCK2', 'WINUSER', 'WINMM', 'NVIDIACG'] INFILES=['librecorder.in', 'libpgraph.in', 'libgrutil.in', 'libchan.in', 'libpstatclient.in', 'libchar.in', 'libcollide.in', 'libdevice.in', 'libdgraph.in', 'libdisplay.in', 'libevent.in', 'libgobj.in', 'libgsgbase.in', 'liblinmath.in', 'libmathutil.in', 'libparametrics.in', diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index a4bfbe9a2f..0c42f80ba2 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -103,6 +103,11 @@ GraphicsStateGuardian(const FrameBufferProperties &properties, _current_display_region = (DisplayRegion*)0L; _current_stereo_channel = Lens::SC_mono; _current_lens = (Lens *)NULL; + _projection_mat = TransformState::make_identity(); + _projection_mat_inv = TransformState::make_identity(); + _clip_to_view = TransformState::make_identity(); + _view_to_clip = TransformState::make_identity(); + _needs_reset = true; _is_valid = false; _closing_gsg = false; @@ -363,6 +368,15 @@ set_scene(SceneSetup *scene_setup) { return false; } + _projection_mat = calc_projection_mat(_current_lens); + if (_projection_mat == 0) { + return false; + } + _projection_mat_inv = _projection_mat->get_inverse(); + _view_to_clip = TransformState::make_mat(_current_lens-> + get_projection_mat(_coordinate_system, _current_stereo_channel)); + _clip_to_view = TransformState::make_mat(_current_lens-> + get_projection_mat_inv(_coordinate_system, _current_stereo_channel)); return prepare_lens(); } @@ -636,6 +650,206 @@ clear(DrawableRegion *clearable) { } } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::fetch_specified_value +// Access: Public +// Description: The gsg contains a large number of useful matrices: +// +// * the world transform, +// * the modelview matrix, +// * the cs_transform, +// * etc, etc. +// +// A shader can request any of these values, and +// furthermore, it can request that various compositions, +// inverses, and transposes be performed. The +// ShaderMatSpec is a data structure indicating what +// datum is desired and what conversions to perform. +// This routine, fetch_specified_value, is responsible for +// doing the actual retrieval and conversions. +// +// Some values, like the following, aren't matrices: +// +// * window size +// * texture coordinates of card center +// +// This routine can fetch these values as well, by +// shoehorning them into a matrix. In this way, we avoid +// the need for a separate routine to fetch these values. +// +// This routine is actually a simple pcode-interpreter, +// and the ShaderMatSpec is actually a small pcode-array. +// This makes it possible to express requests for a +// large variety of values, and a large variety of +// possible conversions. +//////////////////////////////////////////////////////////////////// +bool GraphicsStateGuardian:: +fetch_specified_value(const ShaderContext::ShaderMatSpec &spec, LMatrix4f &result) { + pvector stack; + int pc = 0; + int ac = 0; + while (pc < (int)spec._opcodes.size()) { + int opcode = spec._opcodes[pc++]; + switch(opcode) { + case ShaderContext::SMO_identity: { + stack.push_back(LMatrix4f::ident_mat()); + break; + } + case ShaderContext::SMO_modelview: { + stack.push_back(_internal_transform->get_mat()); + break; + } + case ShaderContext::SMO_projection: { + stack.push_back(_projection_mat->get_mat()); + break; + } + case ShaderContext::SMO_modelproj: { + stack.push_back(_internal_transform->get_mat() * _projection_mat->get_mat()); + break; + } + case ShaderContext::SMO_window_size: { + stack.push_back(LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), + _current_display_region->get_pixel_height(), + 0.0)); + break; + } + case ShaderContext::SMO_pixel_size: { + stack.push_back(LMatrix4f::translate_mat(_current_display_region->get_pixel_width(), + _current_display_region->get_pixel_height(), + 0.0)); + break; + } + case ShaderContext::SMO_card_center: { + int px = _current_display_region->get_pixel_width(); + int py = _current_display_region->get_pixel_height(); + stack.push_back(LMatrix4f::translate_mat((px*0.5) / Texture::up_to_power_2(px), + (py*0.5) / Texture::up_to_power_2(py), + 0.0)); + break; + } + case ShaderContext::SMO_mat_constant_x: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + if (input->get_nodepath().is_empty()) { + return false; + } + stack.push_back(input->get_nodepath().node()->get_transform()->get_mat()); + break; + } + case ShaderContext::SMO_vec_constant_x: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + const float *data = input->get_vector().get_data(); + stack.push_back(LMatrix4f(data[0],data[1],data[2],data[3], + data[0],data[1],data[2],data[3], + data[0],data[1],data[2],data[3], + data[0],data[1],data[2],data[3])); + break; + } + case ShaderContext::SMO_world_to_view: { + stack.push_back(get_scene()->get_world_transform()->get_mat()); + break; + } + case ShaderContext::SMO_view_to_world_C: { + stack.back() *= get_scene()->get_camera_transform()->get_mat(); + break; + } + case ShaderContext::SMO_model_to_view: { + stack.push_back(_external_transform->get_mat()); + break; + } + case ShaderContext::SMO_view_to_model_C: { + stack.back() *= invert(_external_transform->get_mat()); + break; + } + case ShaderContext::SMO_apiview_to_view: { + stack.push_back(_inv_cs_transform->get_mat()); + break; + } + case ShaderContext::SMO_view_to_apiview_C: { + stack.back() *= _cs_transform->get_mat(); + break; + } + case ShaderContext::SMO_clip_to_view: { + stack.push_back(_clip_to_view->get_mat()); + break; + } + case ShaderContext::SMO_view_to_clip_C: { + stack.back() *= _view_to_clip->get_mat(); + break; + } + case ShaderContext::SMO_apiclip_to_view: { + stack.push_back(_projection_mat_inv->get_mat() * _inv_cs_transform->get_mat()); + break; + } + case ShaderContext::SMO_view_to_apiclip_C: { + stack.back() *= _cs_transform->get_mat() * _projection_mat->get_mat(); + break; + } + case ShaderContext::SMO_view_x_to_view: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + nassertr(!input->get_nodepath().is_empty(), false); + stack.push_back(input->get_nodepath().get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat()); + break; + } + case ShaderContext::SMO_view_to_view_x_C: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + nassertr(!input->get_nodepath().is_empty(), false); + stack.back()*= (get_scene()->get_camera_transform()->get_mat() * + invert(input->get_nodepath().get_net_transform()->get_mat())); + break; + } + case ShaderContext::SMO_apiview_x_to_view: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + nassertr(!input->get_nodepath().is_empty(), false); + stack.push_back(LMatrix4f::convert_mat(_internal_coordinate_system, _coordinate_system) * + input->get_nodepath().get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat()); + break; + } + case ShaderContext::SMO_view_to_apiview_x_C: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + nassertr(!input->get_nodepath().is_empty(), false); + stack.back()*= (get_scene()->get_camera_transform()->get_mat() * + invert(input->get_nodepath().get_net_transform()->get_mat()) * + LMatrix4f::convert_mat(_coordinate_system, _internal_coordinate_system)); + break; + } + case ShaderContext::SMO_clip_x_to_view: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + nassertr(!input->get_nodepath().is_empty(), false); + Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); + stack.push_back(lens->get_projection_mat_inv(_coordinate_system, _current_stereo_channel) * + input->get_nodepath().get_net_transform()->get_mat() * + get_scene()->get_world_transform()->get_mat()); + break; + } + case ShaderContext::SMO_view_to_clip_x_C: { + const ShaderInput *input = _target._shader->get_shader_input(spec._args[ac++]); + nassertr(!input->get_nodepath().is_empty(), false); + Lens *lens = DCAST(LensNode, input->get_nodepath().node())->get_lens(); + stack.back()*= (get_scene()->get_camera_transform()->get_mat() * + invert(input->get_nodepath().get_net_transform()->get_mat()) * + lens->get_projection_mat(_coordinate_system, _current_stereo_channel)); + break; + } + case ShaderContext::SMO_apiclip_x_to_view: { + // NOT IMPLEMENTED + break; + } + case ShaderContext::SMO_view_to_apiclip_x_C: { + // NOT IMPLEMENTED + break; + } + + case ShaderContext::SMO_transpose: + stack.back().transpose_in_place(); + break; + } + } + result = stack.back(); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::prepare_display_region // Access: Public, Virtual @@ -1832,3 +2046,24 @@ traverse_prepared_textures(bool (*pertex_callbackfn)(TextureContext *,void *),vo return; } } + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::calc_projection_mat +// Access: Public, Virtual +// Description: Given a lens, this function calculates the appropriate +// projection matrix for this gsg. The result depends +// on the peculiarities of the rendering API. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) GraphicsStateGuardian:: +calc_projection_mat(const Lens *lens) { + if (lens == (Lens *)NULL) { + return NULL; + } + + if (!lens->is_linear()) { + return NULL; + } + + return TransformState::make_identity(); +} + diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index c24e65badc..7d74d48be4 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -42,6 +42,7 @@ #include "notify.h" #include "pvector.h" #include "attribSlots.h" +#include "shaderContext.h" class DrawableRegion; class GraphicsEngine; @@ -158,8 +159,12 @@ public: void clear(DrawableRegion *clearable); + bool fetch_specified_value(const ShaderContext::ShaderMatSpec &spec, LMatrix4f &result); + virtual void prepare_display_region(DisplayRegion *dr, Lens::StereoChannel stereo_channel); + + virtual CPT(TransformState) calc_projection_mat(const Lens *lens); virtual bool prepare_lens(); virtual bool begin_frame(); @@ -198,7 +203,7 @@ public: INLINE const TransformState *get_cs_transform() const; INLINE const TransformState *get_inv_cs_transform() const; - + void do_issue_clip_plane(); void do_issue_color(); void do_issue_color_scale(); @@ -288,7 +293,11 @@ protected: CPT(DisplayRegion) _current_display_region; Lens::StereoChannel _current_stereo_channel; CPT(Lens) _current_lens; - + CPT(TransformState) _projection_mat; + CPT(TransformState) _projection_mat_inv; + CPT(TransformState) _view_to_clip; + CPT(TransformState) _clip_to_view; + CoordinateSystem _coordinate_system; CoordinateSystem _internal_coordinate_system; CPT(TransformState) _cs_transform; diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index 4cdc7fb5a8..18e929491a 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -2058,22 +2058,22 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) data = total->get_mat().get_data(); switch (stb.trans_piece) { /* - case SHADER_data_matrix: cgD3D9SetMatrixParameterfc(stb.parameter, data); break; - case SHADER_data_transpose: cgD3D9SetMatrixParameterfr(stb.parameter, data); break; - case SHADER_data_row0: cgD3D9SetParameter4fv(stb.parameter, data+ 0); break; - case SHADER_data_row1: cgD3D9SetParameter4fv(stb.parameter, data+ 4); break; - case SHADER_data_row2: cgD3D9SetParameter4fv(stb.parameter, data+ 8); break; - case SHADER_data_row3: cgD3D9SetParameter4fv(stb.parameter, data+12); break; - case SHADER_data_col0: cgD3D9SetParameter4f(stb.parameter, data[0], data[4], data[ 8], data[12]); break; - case SHADER_data_col1: cgD3D9SetParameter4f(stb.parameter, data[1], data[5], data[ 9], data[13]); break; - case SHADER_data_col2: cgD3D9SetParameter4f(stb.parameter, data[2], data[6], data[10], data[14]); break; - case SHADER_data_col3: cgD3D9SetParameter4f(stb.parameter, data[3], data[7], data[11], data[15]); break; + case SMP_whole: cgD3D9SetMatrixParameterfc(stb.parameter, data); break; + case SMP_transpose: cgD3D9SetMatrixParameterfr(stb.parameter, data); break; + case SMP_row0: cgD3D9SetParameter4fv(stb.parameter, data+ 0); break; + case SMP_row1: cgD3D9SetParameter4fv(stb.parameter, data+ 4); break; + case SMP_row2: cgD3D9SetParameter4fv(stb.parameter, data+ 8); break; + case SMP_row3: cgD3D9SetParameter4fv(stb.parameter, data+12); break; + case SMP_col0: cgD3D9SetParameter4f(stb.parameter, data[0], data[4], data[ 8], data[12]); break; + case SMP_col1: cgD3D9SetParameter4f(stb.parameter, data[1], data[5], data[ 9], data[13]); break; + case SMP_col2: cgD3D9SetParameter4f(stb.parameter, data[2], data[6], data[10], data[14]); break; + case SMP_col3: cgD3D9SetParameter4f(stb.parameter, data[3], data[7], data[11], data[15]); break; */ float vector [4]; float matrix [16]; - case SHADER_data_matrix: + case SMP_whole: if (_cg_shader) { cgD3D9SetUniform (stb.parameter, data); } @@ -2081,7 +2081,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, data, gsg -> _d3d_device); } break; - case SHADER_data_transpose: + case SMP_transpose: matrix [0] = data[0]; matrix [1] = data[4]; matrix [2] = data[8]; @@ -2105,7 +2105,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, matrix, gsg -> _d3d_device); } break; - case SHADER_data_row0: + case SMP_row0: if (_cg_shader) { cgD3D9SetUniform (stb.parameter, data); } @@ -2113,7 +2113,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, data, gsg -> _d3d_device); } break; - case SHADER_data_row1: + case SMP_row1: if (_cg_shader) { cgD3D9SetUniform (stb.parameter, data + 4); } @@ -2121,7 +2121,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, data + 4, gsg -> _d3d_device); } break; - case SHADER_data_row2: + case SMP_row2: if (_cg_shader) { cgD3D9SetUniform (stb.parameter, data + 8); } @@ -2129,7 +2129,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, data + 8, gsg -> _d3d_device); } break; - case SHADER_data_row3: + case SMP_row3: if (_cg_shader) { cgD3D9SetUniform (stb.parameter, data + 12); } @@ -2137,7 +2137,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, data + 12, gsg -> _d3d_device); } break; - case SHADER_data_col0: + case SMP_col0: vector [0] = data[0]; vector [1] = data[4]; vector [2] = data[8]; @@ -2149,7 +2149,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, vector, gsg -> _d3d_device); } break; - case SHADER_data_col1: + case SMP_col1: vector [0] = data[1]; vector [1] = data[5]; vector [2] = data[9]; @@ -2161,7 +2161,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, vector, gsg -> _d3d_device); } break; - case SHADER_data_col2: + case SMP_col2: vector [0] = data[2]; vector [1] = data[6]; vector [2] = data[10]; @@ -2173,7 +2173,7 @@ bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) set_dx_shader_parameter_float (stb.dx_parameter, vector, gsg -> _d3d_device); } break; - case SHADER_data_col3: + case SMP_col3: vector [0] = data[3]; vector [1] = data[7]; vector [2] = data[11]; @@ -2499,21 +2499,21 @@ compile_cg_parameter(CGparameter p, DX_PARAMETER *dx_parameter) bind.parameter = p; bind.dx_parameter = dx_parameter; - if (pieces[0]=="trans") bind.trans_piece = SHADER_data_matrix; - else if (pieces[0]=="tpose") bind.trans_piece = SHADER_data_transpose; - else if (pieces[0]=="row0") bind.trans_piece = SHADER_data_row0; - else if (pieces[0]=="row1") bind.trans_piece = SHADER_data_row1; - else if (pieces[0]=="row2") bind.trans_piece = SHADER_data_row2; - else if (pieces[0]=="row3") bind.trans_piece = SHADER_data_row3; - else if (pieces[0]=="col0") bind.trans_piece = SHADER_data_col0; - else if (pieces[0]=="col1") bind.trans_piece = SHADER_data_col1; - else if (pieces[0]=="col2") bind.trans_piece = SHADER_data_col2; - else if (pieces[0]=="col3") bind.trans_piece = SHADER_data_col3; + if (pieces[0]=="trans") bind.trans_piece = SMP_whole; + else if (pieces[0]=="tpose") bind.trans_piece = SMP_transpose; + else if (pieces[0]=="row0") bind.trans_piece = SMP_row0; + else if (pieces[0]=="row1") bind.trans_piece = SMP_row1; + else if (pieces[0]=="row2") bind.trans_piece = SMP_row2; + else if (pieces[0]=="row3") bind.trans_piece = SMP_row3; + else if (pieces[0]=="col0") bind.trans_piece = SMP_col0; + else if (pieces[0]=="col1") bind.trans_piece = SMP_col1; + else if (pieces[0]=="col2") bind.trans_piece = SMP_col2; + else if (pieces[0]=="col3") bind.trans_piece = SMP_col3; bind.src_name = InternalName::make(pieces[1]); bind.rel_name = InternalName::make(pieces[3]); - if ((bind.trans_piece == SHADER_data_matrix)||(bind.trans_piece == SHADER_data_transpose)) { + if ((bind.trans_piece == SMP_whole)||(bind.trans_piece == SMP_transpose)) { if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false; } else { if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false; @@ -2541,18 +2541,18 @@ compile_cg_parameter(CGparameter p, DX_PARAMETER *dx_parameter) bind.parameter = p; bind.dx_parameter = dx_parameter; - if (pieces[0]=="wstrans") { bind.rel_name = InternalName::get_world(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="vstrans") { bind.rel_name = InternalName::get_view(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="cstrans") { bind.rel_name = InternalName::get_camera(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="mstrans") { bind.rel_name = InternalName::get_model(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="wspos") { bind.rel_name = InternalName::get_world(); bind.trans_piece = SHADER_data_row3; } - else if (pieces[0]=="vspos") { bind.rel_name = InternalName::get_view(); bind.trans_piece = SHADER_data_row3; } - else if (pieces[0]=="cspos") { bind.rel_name = InternalName::get_camera(); bind.trans_piece = SHADER_data_row3; } - else if (pieces[0]=="mspos") { bind.rel_name = InternalName::get_model(); bind.trans_piece = SHADER_data_row3; } + if (pieces[0]=="wstrans") { bind.rel_name = InternalName::get_world(); bind.trans_piece = SMP_whole; } + else if (pieces[0]=="vstrans") { bind.rel_name = InternalName::get_view(); bind.trans_piece = SMP_whole; } + else if (pieces[0]=="cstrans") { bind.rel_name = InternalName::get_camera(); bind.trans_piece = SMP_whole; } + else if (pieces[0]=="mstrans") { bind.rel_name = InternalName::get_model(); bind.trans_piece = SMP_whole; } + else if (pieces[0]=="wspos") { bind.rel_name = InternalName::get_world(); bind.trans_piece = SMP_row3; } + else if (pieces[0]=="vspos") { bind.rel_name = InternalName::get_view(); bind.trans_piece = SMP_row3; } + else if (pieces[0]=="cspos") { bind.rel_name = InternalName::get_camera(); bind.trans_piece = SMP_row3; } + else if (pieces[0]=="mspos") { bind.rel_name = InternalName::get_model(); bind.trans_piece = SMP_row3; } bind.src_name = InternalName::make(pieces[1]); - if ((bind.trans_piece == SHADER_data_matrix)||(bind.trans_piece == SHADER_data_transpose)) { + if ((bind.trans_piece == SMP_whole)||(bind.trans_piece == SMP_transpose)) { if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false; } else { if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index bd330b9a39..58de52de92 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -845,8 +845,6 @@ reset() { << "max clip planes = " << _max_clip_planes << "\n"; } - _projection_mat = LMatrix4f::ident_mat(); - if (_supports_multitexture) { GLint max_texture_stages; GLP(GetIntegerv)(GL_MAX_TEXTURE_UNITS, &max_texture_stages); @@ -986,6 +984,48 @@ prepare_display_region(DisplayRegion *dr, Lens::StereoChannel stereo_channel) { do_point_size(); } +//////////////////////////////////////////////////////////////////// +// Function: GLGraphicsStateGuardian::calc_projection_mat +// Access: Public, Virtual +// Description: Given a lens, calculates the appropriate projection +// matrix for use with this gsg. Note that the +// projection matrix depends a lot upon the coordinate +// system of the rendering API. +// +// The return value is a TransformState if the lens is +// acceptable, NULL if it is not. +//////////////////////////////////////////////////////////////////// +CPT(TransformState) CLP(GraphicsStateGuardian):: +calc_projection_mat(const Lens *lens) { + if (lens == (Lens *)NULL) { + return NULL; + } + + if (!lens->is_linear()) { + return NULL; + } + + // The projection matrix must always be right-handed Y-up, even if + // our coordinate system of choice is otherwise, because certain GL + // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of + // a coordinate system. Sigh. In order to implement a Z-up (or + // other arbitrary) coordinate system, we'll use a Y-up projection + // matrix, and store the conversion to our coordinate system of + // choice in the modelview matrix. + + LMatrix4f &result = + LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) * + lens->get_projection_mat(_current_stereo_channel); + + if (_scene_setup->get_inverted()) { + // If the scene is supposed to be inverted, then invert the + // projection matrix. + result *= LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f); + } + + return TransformState::make_mat(result); +} + //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::prepare_lens // Access: Public, Virtual @@ -1000,40 +1040,12 @@ prepare_display_region(DisplayRegion *dr, Lens::StereoChannel stereo_channel) { //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: prepare_lens() { - if (_current_lens == (Lens *)NULL) { - return false; - } - - if (!_current_lens->is_linear()) { - return false; - } - - const LMatrix4f &lens_mat = _current_lens->get_projection_mat(_current_stereo_channel); - - // The projection matrix must always be right-handed Y-up, even if - // our coordinate system of choice is otherwise, because certain GL - // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of - // a coordinate system. Sigh. In order to implement a Z-up (or - // other arbitrary) coordinate system, we'll use a Y-up projection - // matrix, and store the conversion to our coordinate system of - // choice in the modelview matrix. - _projection_mat = - LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) * - lens_mat; - - if (_scene_setup->get_inverted()) { - // If the scene is supposed to be inverted, then invert the - // projection matrix. - static LMatrix4f invert_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f); - _projection_mat *= invert_mat; - } - if (GLCAT.is_spam()) { GLCAT.spam() - << "glMatrixMode(GL_PROJECTION): " << _projection_mat << endl; + << "glMatrixMode(GL_PROJECTION): " << _projection_mat->get_mat() << endl; } GLP(MatrixMode)(GL_PROJECTION); - GLP(LoadMatrixf)(_projection_mat.get_data()); + GLP(LoadMatrixf)(_projection_mat->get_mat().get_data()); report_my_gl_errors(); do_point_size(); @@ -2745,7 +2757,7 @@ do_issue_transform() { } if (_current_shader_context) - _current_shader_context->issue_transform(this); + _current_shader_context->issue_parameters(this, false); report_my_gl_errors(); } @@ -2818,7 +2830,7 @@ do_issue_shader() { } } else { // Use the same shader as before, but with new input arguments. - context->issue_parameters(this); + context->issue_parameters(this, true); } report_my_gl_errors(); @@ -5965,7 +5977,7 @@ do_point_size() { // scaling factor based on the current viewport and projection // matrix. LVector3f height(0.0f, _point_size, 1.0f); - height = height * _projection_mat; + height = height * _projection_mat->get_mat(); float s = height[1] * _viewport_height / _point_size; if (_current_lens->is_orthographic()) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 6c7976c2ef..6614971aa8 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -85,6 +85,7 @@ public: virtual void do_clear(const RenderBuffer &buffer); virtual void prepare_display_region(DisplayRegion *dr, Lens::StereoChannel stereo_channel); + virtual CPT(TransformState) calc_projection_mat(const Lens *lens); virtual bool prepare_lens(); virtual bool begin_frame(); @@ -305,7 +306,6 @@ protected: bool _dithering_enabled; - LMatrix4f _projection_mat; int _viewport_width; int _viewport_height; bool _auto_antialias_mode; diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index c45fd9ea93..1401503a76 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -45,7 +45,7 @@ CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg) : ShaderContext(s) { _cg_context = cgCreateContext(); if (_cg_context == 0) { release_resources(); - cerr << "Cg not supported by this video card.\n"; + GLCAT.error() << "Cg not supported by this video card.\n"; return; } @@ -72,18 +72,17 @@ CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg) : ShaderContext(s) { if ((_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN)|| (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN)) { release_resources(); - cerr << "Cg not supported by this video card.\n"; + GLCAT.error() << "Cg not supported by this video card.\n"; return; } // Compile the program. try_cg_compile(s, gsg); - cerr << _cg_errors; return; } #endif - cerr << s->get_name() << ": unrecognized shader language " << header << "\n"; + GLCAT.error() << s->get_name() << ": unrecognized shader language " << header << "\n"; } //////////////////////////////////////////////////////////////////// @@ -106,7 +105,7 @@ suggest_cg_profile(const string &vpro, const string &fpro) _cg_profile[SHADER_type_frag] = parse_cg_profile(fpro, false); if ((_cg_profile[SHADER_type_vert] == CG_PROFILE_UNKNOWN)|| (_cg_profile[SHADER_type_frag] == CG_PROFILE_UNKNOWN)) { - cerr << "Cg: unrecognized profile name: " << vpro << " " << fpro << "\n"; + GLCAT.error() << "Cg: unrecognized profile name: " << vpro << " " << fpro << "\n"; _cg_profile[SHADER_type_vert] = CG_PROFILE_UNKNOWN; _cg_profile[SHADER_type_frag] = CG_PROFILE_UNKNOWN; return; @@ -161,19 +160,17 @@ parse_cg_profile(const string &id, bool vertex) bool CLP(ShaderContext):: try_cg_compile(ShaderExpansion *s, GSG *gsg) { - _cg_errors = ""; - cgGetError(); _cg_program[0] = cgCreateProgram(_cg_context, CG_SOURCE, s->_text.c_str(), _cg_profile[0], "vshader", (const char**)NULL); - print_cg_compile_errors(s->get_name(), _cg_context); + report_cg_compile_errors(s->get_name(), _cg_context, GLCAT.get_safe_ptr()); cgGetError(); _cg_program[1] = cgCreateProgram(_cg_context, CG_SOURCE, s->_text.c_str(), _cg_profile[1], "fshader", (const char**)NULL); - print_cg_compile_errors(s->get_name(), _cg_context); + report_cg_compile_errors(s->get_name(), _cg_context, GLCAT.get_safe_ptr()); if ((_cg_program[SHADER_type_vert]==0)||(_cg_program[SHADER_type_frag]==0)) { release_resources(); @@ -186,7 +183,7 @@ try_cg_compile(ShaderExpansion *s, GSG *gsg) const char *program; program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM); - glgsg_cat.debug ( ) << program << "\n"; + GLCAT.debug() << program << "\n"; } #endif @@ -254,7 +251,7 @@ try_cg_compile(ShaderExpansion *s, GSG *gsg) _cg_program[1] = cgCreateProgram(_cg_context, CG_OBJECT, result.c_str(), _cg_profile[1], "fshader", (const char**)NULL); - print_cg_compile_errors(s->get_name(), _cg_context); + report_cg_compile_errors(s->get_name(), _cg_context, GLCAT.get_safe_ptr()); if (_cg_program[SHADER_type_frag]==0) { release_resources(); return false; @@ -265,10 +262,15 @@ try_cg_compile(ShaderExpansion *s, GSG *gsg) bool success = true; CGparameter parameter; for (int progindex=0; progindex<2; progindex++) { + int nvtx = _var_spec.size(); for (parameter = cgGetFirstLeafParameter(_cg_program[progindex],CG_PROGRAM); parameter != 0; parameter = cgGetNextLeafParameter(parameter)) { - success &= compile_cg_parameter(parameter); + success &= compile_cg_parameter(parameter, GLCAT.get_safe_ptr()); + } + if ((progindex == SHADER_type_frag) && (nvtx != _var_spec.size())) { + GLCAT.error() << "Cannot use vtx parameters in an fshader\n"; + success = false; } } if (!success) { @@ -279,10 +281,6 @@ try_cg_compile(ShaderExpansion *s, GSG *gsg) cgGLLoadProgram(_cg_program[SHADER_type_vert]); cgGLLoadProgram(_cg_program[SHADER_type_frag]); - _cg_errors = s->get_name() + ": compiled to " - + cgGetProfileString(_cg_profile[SHADER_type_vert]) + " " - + cgGetProfileString(_cg_profile[SHADER_type_frag]) + "\n"; - _state = true; return true; @@ -332,7 +330,7 @@ bind(GSG *gsg) { if (_cg_context != 0) { // Pass in k-parameters and transform-parameters - issue_parameters(gsg); + issue_parameters(gsg, true); // Bind the shaders. cgGLEnableProfile(_cg_profile[SHADER_type_vert]); @@ -359,166 +357,44 @@ unbind() #endif } -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::issue_cg_auto_bind -// Access: Public -// Description: Pass a single system parameter into the shader. -//////////////////////////////////////////////////////////////////// -#ifdef HAVE_CGGL -void CLP(ShaderContext):: -issue_cg_auto_bind(const ShaderAutoBind &bind, GSG *gsg) -{ - LVecBase4f t; float xhi,yhi; int px,py; - - CGparameter p = bind.parameter; - switch(bind.value) { - case SIC_mat_modelview: - case SIC_inv_modelview: - case SIC_tps_modelview: - case SIC_itp_modelview: - case SIC_mat_projection: - case SIC_inv_projection: - case SIC_tps_projection: - case SIC_itp_projection: - case SIC_mat_texture: - case SIC_inv_texture: - case SIC_tps_texture: - case SIC_itp_texture: - case SIC_mat_modelproj: - case SIC_inv_modelproj: - case SIC_tps_modelproj: - case SIC_itp_modelproj: - -/* - float data [16]; - - glGetFloatv (GL_MODELVIEW_MATRIX, data); - glgsg_cat.debug ( ) << "MODELVIEW MATRIX \n" << - data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << - data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << - data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << - data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n"; - - glGetFloatv (GL_PROJECTION_MATRIX, data); - glgsg_cat.debug ( ) << "PROJECTION MATRIX \n" << - data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << - data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << - data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << - data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n"; -*/ - - cgGLSetStateMatrixParameter(p, (CGGLenum)((bind.value >> 2)+4), (CGGLenum)(bind.value & 3)); - return; - case SIC_sys_windowsize: - t[0] = gsg->_current_display_region->get_pixel_width(); - t[1] = gsg->_current_display_region->get_pixel_height(); - t[2] = 1; - t[3] = 1; - cgGLSetParameter4fv(p, t.get_data()); - return; - case SIC_sys_pixelsize: - t[0] = 1.0 / gsg->_current_display_region->get_pixel_width(); - t[1] = 1.0 / gsg->_current_display_region->get_pixel_height(); - t[2] = 1; - t[3] = 1; - cgGLSetParameter4fv(p, t.get_data()); - return; - case SIC_sys_cardcenter: - px = gsg->_current_display_region->get_pixel_width(); - py = gsg->_current_display_region->get_pixel_height(); - xhi = (px*1.0) / Texture::up_to_power_2(px); - yhi = (py*1.0) / Texture::up_to_power_2(py); - t[0] = xhi*0.5; - t[1] = yhi*0.5; - t[2] = 1; - t[3] = 1; - cgGLSetParameter4fv(p, t.get_data()); - return; - } -} -#endif - //////////////////////////////////////////////////////////////////// // Function: GLShaderContext::issue_parameters // Access: Public // Description: This function gets called whenever the RenderState -// has changed, but the ShaderExpansion itself has not -// changed. It loads new parameters into the -// already-bound shader. +// or TransformState has changed, but the ShaderExpansion +// itself has not changed. It loads new values into the +// shader's parameters. The flag "all" is false if the +// only thing that has changed is the modelview matrix. +// In this case, only the transform-dependent parameters +// are reloaded. //////////////////////////////////////////////////////////////////// void CLP(ShaderContext):: -issue_parameters(GSG *gsg) +issue_parameters(GSG *gsg, bool all) { #ifdef HAVE_CGGL - if (_cg_context != 0) { - // Pass in k-float parameters. - for (int i=0; i<(int)_cg_fbind.size(); i++) { - InternalName *id = _cg_fbind[i].name; - const ShaderInput *input = gsg->_target._shader->get_shader_input(id); - cgGLSetParameter4fv(_cg_fbind[i].parameter, input->get_vector().get_data()); - -#if DEBUG_GL_SHADER - // DEBUG - { - const float *data; - char string [256]; - - data = input->get_vector().get_data(); - sprintf (string, "%f %f %f %f \n", data [0], data [1], data [2], data [3]); - - glgsg_cat.debug ( ) << "SHADER: issue_parameters, _cg_fbind " << id -> get_name ( ) << "\n"; - glgsg_cat.debug ( ) << string; - } -#endif - } - - // Pass in k-float4x4 parameters. - for (int i=0; i<(int)_cg_npbind.size(); i++) { - InternalName *id = _cg_npbind[i].name; - const ShaderInput *input = gsg->_target._shader->get_shader_input(id); - const float *dat; - if (input->get_nodepath().is_empty()) { - dat = LMatrix4f::ident_mat().get_data(); - } else { - dat = input->get_nodepath().node()->get_transform()->get_mat().get_data(); - } - cgGLSetMatrixParameterfc(_cg_npbind[i].parameter, dat); - } - - // Pass in system parameters - for (int i=0; i<(int)_cg_auto_param.size(); i++) { - issue_cg_auto_bind(_cg_auto_param[i], gsg); - } - - // Pass in trans,tpose,row,col,xvec,yvec,zvec,pos parameters - for (int i=0; i<(int)_cg_parameter_bind.size(); i++) { - bind_cg_transform(_cg_parameter_bind[i], gsg); - } + if (_cg_context == 0) { + return; } -#endif - issue_transform(gsg); -} - -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::issue_transform -// Access: Public -// Description: This function gets called whenever the RenderState -// or the TransformState has changed, but the -// ShaderExpansion itself has not changed. It loads -// new parameters into the already-bound shader. -//////////////////////////////////////////////////////////////////// -void CLP(ShaderContext):: -issue_transform(GSG *gsg) -{ -#ifdef HAVE_CGGL - if (_cg_context != 0) { - // Pass in modelview, projection, etc. - for (int i=0; i<(int)_cg_auto_trans.size(); i++) { - issue_cg_auto_bind(_cg_auto_trans[i], gsg); - } - // Pass in trans,tpose,row,col,xvec,yvec,zvec,pos parameters - for (int i=0; i<(int)_cg_transform_bind.size(); i++) { - bind_cg_transform(_cg_transform_bind[i], gsg); + + for (int i=0; i<(int)_mat_spec.size(); i++) { + if (all || _mat_spec[i]._trans_dependent) { + LMatrix4f result; + CGparameter p = (CGparameter)(_mat_spec[i]._parameter); + if (gsg->fetch_specified_value(_mat_spec[i], result)) { + const float *data = result.get_data(); + switch (_mat_spec[i]._piece) { + case SMP_whole: cgGLSetMatrixParameterfc(p, data); break; + case SMP_transpose: cgGLSetMatrixParameterfr(p, data); break; + case SMP_row0: cgGLSetParameter4fv(p, data+ 0); break; + case SMP_row1: cgGLSetParameter4fv(p, data+ 4); break; + case SMP_row2: cgGLSetParameter4fv(p, data+ 8); break; + case SMP_row3: cgGLSetParameter4fv(p, data+12); break; + case SMP_col0: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); break; + case SMP_col1: cgGLSetParameter4f(p, data[1], data[5], data[ 9], data[13]); break; + case SMP_col2: cgGLSetParameter4f(p, data[2], data[6], data[10], data[14]); break; + case SMP_col3: cgGLSetParameter4f(p, data[3], data[7], data[11], data[15]); break; + } + } } } #endif @@ -533,9 +409,14 @@ void CLP(ShaderContext):: disable_shader_vertex_arrays(GSG *gsg) { #ifdef HAVE_CGGL - if (_cg_context) - for (int i=0; i<(int)_cg_varying.size(); i++) - cgGLDisableClientState(_cg_varying[i].parameter); + if (_cg_context == 0) { + return; + } + + for (int i=0; i<(int)_var_spec.size(); i++) { + CGparameter p = (CGparameter)(_var_spec[i]._parameter); + cgGLDisableClientState(p); + } #endif } @@ -555,44 +436,47 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg) { if (prev) prev->disable_shader_vertex_arrays(gsg); #ifdef HAVE_CGGL - if (_cg_context) { + if (_cg_context == 0) { + return; + } + #ifdef SUPPORT_IMMEDIATE_MODE - if (gsg->_use_sender) { - cerr << "immediate mode shaders not implemented yet\n"; - } else + if (gsg->_use_sender) { + GLCAT.error() << "immediate mode shaders not implemented yet\n"; + } else #endif // SUPPORT_IMMEDIATE_MODE - { - const GeomVertexArrayData *array_data; - Geom::NumericType numeric_type; - int start, stride, num_values; - int nvarying = _cg_varying.size(); - for (int i=0; i= 0) { - const Geom::ActiveTextureStages &active_stages = - gsg->_state._texture->get_on_stages(); - if (texslot < (int)active_stages.size()) { - TextureStage *stage = active_stages[texslot]; - InternalName *texname = stage->get_texcoord_name(); - if (name == InternalName::get_texcoord()) { - name = texname; - } else if (texname != InternalName::get_texcoord()) { - name = name->append(texname->get_basename()); - } + { + const GeomVertexArrayData *array_data; + Geom::NumericType numeric_type; + int start, stride, num_values; + int nvarying = _var_spec.size(); + for (int i=0; i= 0) { + const Geom::ActiveTextureStages &active_stages = + gsg->_state._texture->get_on_stages(); + if (texslot < (int)active_stages.size()) { + TextureStage *stage = active_stages[texslot]; + InternalName *texname = stage->get_texcoord_name(); + if (name == InternalName::get_texcoord()) { + name = texname; + } else if (texname != InternalName::get_texcoord()) { + name = name->append(texname->get_basename()); } } - if (gsg->_vertex_data->get_array_info(name, - array_data, num_values, numeric_type, - start, stride)) { - const unsigned char *client_pointer = gsg->setup_array_data(array_data); - cgGLSetParameterPointer(_cg_varying[i].parameter, - num_values, gsg->get_numeric_type(numeric_type), - stride, client_pointer + start); - cgGLEnableClientState(_cg_varying[i].parameter); - } else { - cgGLDisableClientState(_cg_varying[i].parameter); - } + } + if (gsg->_vertex_data->get_array_info(name, + array_data, num_values, numeric_type, + start, stride)) { + const unsigned char *client_pointer = gsg->setup_array_data(array_data); + cgGLSetParameterPointer(p, + num_values, gsg->get_numeric_type(numeric_type), + stride, client_pointer + start); + cgGLEnableClientState(p); + } else { + cgGLDisableClientState(p); } } } @@ -608,21 +492,24 @@ void CLP(ShaderContext):: disable_shader_texture_bindings(GSG *gsg) { #ifdef HAVE_CGGL - if (_cg_context) { - for (int i=0; i<(int)_cg_texbind.size(); i++) { - int texunit = cgGetParameterResourceIndex(_cg_texbind[i].parameter); - gsg->_glActiveTexture(GL_TEXTURE0 + texunit); - GLP(Disable)(GL_TEXTURE_1D); - GLP(Disable)(GL_TEXTURE_2D); - if (gsg->_supports_3d_texture) { - GLP(Disable)(GL_TEXTURE_3D); - } - if (gsg->_supports_cube_map) { - GLP(Disable)(GL_TEXTURE_CUBE_MAP); - } - // This is probably faster - but maybe not as safe? - // cgGLDisableTextureParameter(_cg_texbind[i].parameter); + if (_cg_context == 0) { + return; + } + + for (int i=0; i<(int)_tex_spec.size(); i++) { + CGparameter p = (CGparameter)(_tex_spec[i]._parameter); + int texunit = cgGetParameterResourceIndex(p); + gsg->_glActiveTexture(GL_TEXTURE0 + texunit); + GLP(Disable)(GL_TEXTURE_1D); + GLP(Disable)(GL_TEXTURE_2D); + if (gsg->_supports_3d_texture) { + GLP(Disable)(GL_TEXTURE_3D); } + if (gsg->_supports_cube_map) { + GLP(Disable)(GL_TEXTURE_CUBE_MAP); + } + // This is probably faster - but maybe not as safe? + // cgGLDisableTextureParameter(p); } #endif } @@ -643,657 +530,51 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) { if (prev) prev->disable_shader_texture_bindings(gsg); #ifdef HAVE_CGGL - if (_cg_context) { - for (int i=0; i<(int)_cg_texbind.size(); i++) { - Texture *tex = 0; - InternalName *id = _cg_texbind[i].name; - if (id != 0) { - const ShaderInput *input = gsg->_target._shader->get_shader_input(id); - tex = input->get_texture(); - } else { - if (_cg_texbind[i].stage >= gsg->_target._texture->get_num_on_stages()) { - continue; - } - TextureStage *stage = gsg->_target._texture->get_on_stage(_cg_texbind[i].stage); - tex = gsg->_target._texture->get_on_texture(stage); - } - if (_cg_texbind[i].suffix != 0) { - // The suffix feature is inefficient. It is a temporary hack. - if (tex == 0) { - continue; - } - tex = tex->load_related(_cg_texbind[i].suffix); - } - if ((tex == 0) || (tex->get_texture_type() != _cg_texbind[i].desiredtype)) { - continue; - } - TextureContext *tc = tex->prepare_now(gsg->_prepared_objects, gsg); - if (tc == (TextureContext*)NULL) { - continue; - } - int texunit = cgGetParameterResourceIndex(_cg_texbind[i].parameter); - gsg->_glActiveTexture(GL_TEXTURE0 + texunit); + if (_cg_context == 0) { + return; + } - GLenum target = gsg->get_texture_target(tex->get_texture_type()); - if (target == GL_NONE) { - // Unsupported texture mode. + for (int i=0; i<(int)_tex_spec.size(); i++) { + CGparameter p = (CGparameter)(_tex_spec[i]._parameter); + Texture *tex = 0; + InternalName *id = _tex_spec[i]._name; + if (id != 0) { + const ShaderInput *input = gsg->_target._shader->get_shader_input(id); + tex = input->get_texture(); + } else { + if (_tex_spec[i]._stage >= gsg->_target._texture->get_num_on_stages()) { continue; } - GLP(Enable)(target); - - gsg->apply_texture(tc); + TextureStage *stage = gsg->_target._texture->get_on_stage(_tex_spec[i]._stage); + tex = gsg->_target._texture->get_on_texture(stage); } + if (_tex_spec[i]._suffix != 0) { + // The suffix feature is inefficient. It is a temporary hack. + if (tex == 0) { + continue; + } + tex = tex->load_related(_tex_spec[i]._suffix); + } + if ((tex == 0) || (tex->get_texture_type() != _tex_spec[i]._desired_type)) { + continue; + } + TextureContext *tc = tex->prepare_now(gsg->_prepared_objects, gsg); + if (tc == (TextureContext*)NULL) { + continue; + } + + int texunit = cgGetParameterResourceIndex(p); + gsg->_glActiveTexture(GL_TEXTURE0 + texunit); + + GLenum target = gsg->get_texture_target(tex->get_texture_type()); + if (target == GL_NONE) { + // Unsupported texture mode. + continue; + } + GLP(Enable)(target); + + gsg->apply_texture(tc); } #endif } -#ifdef HAVE_CGGL -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::bind_cg_transform -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -void CLP(ShaderContext):: -bind_cg_transform(const ShaderTransBind &stb, GSG *gsg) -{ - const float *data; - CPT(TransformState) src; - CPT(TransformState) rel; - - if (stb.src_name == InternalName::get_camera()) { - src = TransformState::make_identity(); - } else if (stb.src_name == InternalName::get_view()) { - src = gsg->_inv_cs_transform; - } else if (stb.src_name == InternalName::get_model()) { - src = gsg->get_transform(); - } else if (stb.src_name == InternalName::get_world()) { - src = gsg->get_scene()->get_world_transform(); - } else { - const ShaderInput *input = gsg->_target._shader->get_shader_input(stb.src_name); - if (input->get_nodepath().is_empty()) { - src = gsg->get_scene()->get_world_transform(); - } else { - src = gsg->get_scene()->get_world_transform()-> - compose(input->get_nodepath().get_net_transform()); - } - } - - if (stb.rel_name == InternalName::get_camera()) { - rel = TransformState::make_identity(); - } else if (stb.rel_name == InternalName::get_view()) { - rel = gsg->_inv_cs_transform; - } else if (stb.rel_name == InternalName::get_model()) { - rel = gsg->get_transform(); - } else if (stb.rel_name == InternalName::get_world()) { - rel = gsg->get_scene()->get_world_transform(); - } else { - const ShaderInput *input = gsg->_target._shader->get_shader_input(stb.rel_name); - if (input->get_nodepath().is_empty()) { - rel = gsg->get_scene()->get_world_transform(); - } else { - rel = gsg->get_scene()->get_world_transform()-> - compose(input->get_nodepath().get_net_transform()); - } - } - - CPT(TransformState) total = rel->invert_compose(src); - - // data = src->get_mat().get_data(); - // cerr << "Src for " << cgGetParameterName(stb.parameter) << " is\n" << - // data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << - // data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << - // data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << - // data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n"; - // data = rel->get_mat().get_data(); - // cerr << "Rel for " << cgGetParameterName(stb.parameter) << " is\n" << - // data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << - // data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << - // data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << - // data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n"; - // data = total->get_mat().get_data(); - // cerr << "Total for " << cgGetParameterName(stb.parameter) << " is\n" << - // data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << - // data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << - // data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << - // data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n"; - // data = gsg->_cs_transform->get_mat().get_data(); - // cerr << "cs_transform is\n" << - // data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << - // data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << - // data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << - // data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n"; - // data = gsg->_internal_transform->get_mat().get_data(); - // cerr << "internal_transform is\n" << - // data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" << - // data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" << - // data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" << - // data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n"; - - data = total->get_mat().get_data(); - switch (stb.trans_piece) { - case SHADER_data_matrix: cgGLSetMatrixParameterfc(stb.parameter, data); break; - case SHADER_data_transpose: cgGLSetMatrixParameterfr(stb.parameter, data); break; - case SHADER_data_row0: cgGLSetParameter4fv(stb.parameter, data+ 0); break; - case SHADER_data_row1: cgGLSetParameter4fv(stb.parameter, data+ 4); break; - case SHADER_data_row2: cgGLSetParameter4fv(stb.parameter, data+ 8); break; - case SHADER_data_row3: cgGLSetParameter4fv(stb.parameter, data+12); break; - case SHADER_data_col0: cgGLSetParameter4f(stb.parameter, data[0], data[4], data[ 8], data[12]); break; - case SHADER_data_col1: cgGLSetParameter4f(stb.parameter, data[1], data[5], data[ 9], data[13]); break; - case SHADER_data_col2: cgGLSetParameter4f(stb.parameter, data[2], data[6], data[10], data[14]); break; - case SHADER_data_col3: cgGLSetParameter4f(stb.parameter, data[3], data[7], data[11], data[15]); break; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_parameter_words -// Access: Public, Static -// Description: Make sure the provided Cg parameter contains -// the specified number of words. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -errchk_cg_parameter_words(CGparameter p, int len) -{ - vector_string words; - tokenize(cgGetParameterName(p), words, "_"); - if (words.size() != len) { - errchk_cg_output(p, "parameter name has wrong number of words"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_parameter_direction -// Access: Public, Static -// Description: Make sure the provided Cg parameter has the -// correct direction. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -errchk_cg_parameter_direction(CGparameter p, CGenum dir) -{ - if (cgGetParameterDirection(p) != dir) { - if (dir == CG_IN) errchk_cg_output(p, "parameter should be declared 'in'"); - if (dir == CG_OUT) errchk_cg_output(p, "parameter should be declared 'out'"); - if (dir == CG_INOUT) errchk_cg_output(p, "parameter should be declared 'inout'"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_parameter_variance -// Access: Public, Static -// Description: Make sure the provided Cg parameter has the -// correct variance. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -errchk_cg_parameter_variance(CGparameter p, CGenum var) -{ - if (cgGetParameterVariability(p) != var) { - if (var == CG_UNIFORM) - errchk_cg_output(p, "parameter should be declared 'uniform'"); - if (var == CG_VARYING) - errchk_cg_output(p, "parameter should be declared 'varying'"); - if (var == CG_CONSTANT) - errchk_cg_output(p, "parameter should be declared 'const'"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_parameter_prog -// Access: Public, Static -// Description: Make sure the provided Cg parameter is a part -// of the correct program. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -errchk_cg_parameter_prog(CGparameter p, CGprogram prog, const string &msg) -{ - if (cgGetParameterProgram(p) != prog) { - string fmsg = "parameter can only be used in a "; - errchk_cg_output(p, fmsg+msg+" program"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_parameter_type -// Access: Public, Static -// Description: Make sure the provided Cg parameter has the -// correct type. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -errchk_cg_parameter_type(CGparameter p, CGtype dt) -{ - if (cgGetParameterType(p) != dt) { - string msg = "parameter should be of type "; - errchk_cg_output(p, msg + cgGetTypeString(dt)); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_parameter_float -// Access: Public, Static -// Description: Make sure the provided Cg parameter has -// a floating point type. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -errchk_cg_parameter_float(CGparameter p) -{ - CGtype t = cgGetParameterType(p); - if ((t != CG_FLOAT1)&&(t != CG_FLOAT2)&&(t != CG_FLOAT3)&&(t != CG_FLOAT4)) { - errchk_cg_output(p, "parameter should have a float type"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_parameter_sampler -// Access: Public, Static -// Description: Make sure the provided Cg parameter has -// a texture type. If not, print -// error message and return false. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -errchk_cg_parameter_sampler(CGparameter p) -{ - CGtype t = cgGetParameterType(p); - if ((t!=CG_SAMPLER1D)&& - (t!=CG_SAMPLER2D)&& - (t!=CG_SAMPLER3D)&& - (t!=CG_SAMPLERCUBE)) { - errchk_cg_output(p, "parameter should have a 'sampler' type"); - return false; - } - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::errchk_cg_output -// Access: Public, Static -// Description: Print an error message including a description -// of the specified Cg parameter. -//////////////////////////////////////////////////////////////////// -void CLP(ShaderContext):: -errchk_cg_output(CGparameter p, const string &msg) -{ - string vstr; - CGenum v = cgGetParameterVariability(p); - if (v == CG_UNIFORM) vstr = "uniform "; - if (v == CG_VARYING) vstr = "varying "; - if (v == CG_CONSTANT) vstr = "const "; - - string dstr; - CGenum d = cgGetParameterDirection(p); - if (d == CG_IN) dstr = "in "; - if (d == CG_OUT) dstr = "out "; - if (d == CG_INOUT) dstr = "inout "; - - const char *ts = cgGetTypeString(cgGetParameterType(p)); - - string err; - string fn = _shader_expansion->get_name(); - err = fn + ": " + msg + " (" + vstr + dstr + ts + " " + cgGetParameterName(p) + ")\n"; - _cg_errors = _cg_errors + err + "\n"; -} - -//////////////////////////////////////////////////////////////////// -// Function: Shader::print_cg_compile_errors -// Access: Public, Static -// Description: Used only after a Cg compile command, to print -// out any error messages that may have occurred -// during the Cg shader compilation. The 'file' -// is the name of the file containing the Cg code. -//////////////////////////////////////////////////////////////////// -void CLP(ShaderContext):: -print_cg_compile_errors(const string &file, CGcontext ctx) -{ - CGerror err = cgGetError(); - if (err != CG_NO_ERROR) { - if (err == CG_COMPILER_ERROR) { - string listing = cgGetLastListing(ctx); - vector_string errlines; - tokenize(listing, errlines, "\n"); - for (int i=0; i<(int)errlines.size(); i++) { - string line = trim(errlines[i]); - if (line != "") { - _cg_errors += file + " " + errlines[i] + "\n"; - } - } - } else { - _cg_errors += file + ": " + cgGetErrorString(err) + "\n"; - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: GLShaderContext::compile_cg_parameter -// Access: Public -// Description: Analyzes a Cg parameter and decides how to -// bind the parameter to some part of panda's -// internal state. Updates one of the cg bind -// arrays to cause the binding to occur. -//////////////////////////////////////////////////////////////////// -bool CLP(ShaderContext):: -compile_cg_parameter(CGparameter p) -{ - string pname = cgGetParameterName(p); - if (pname.size() == 0) return true; - if (pname[0] == '$') return true; - vector_string pieces; - tokenize(pname, pieces, "_"); - - if (pieces.size() < 2) { - errchk_cg_output(p,"invalid parameter name"); - return false; - } - - if (pieces[0] == "vtx") { - if ((!errchk_cg_parameter_direction(p, CG_IN)) || - (!errchk_cg_parameter_variance(p, CG_VARYING)) || - (!errchk_cg_parameter_float(p)) || - (!errchk_cg_parameter_prog(p, _cg_program[SHADER_type_vert], "vertex"))) - return false; - ShaderVarying bind; - bind.parameter = p; - if (pieces.size() == 2) { - if (pieces[1]=="position") { - bind.name = InternalName::get_vertex(); - bind.append_uv = -1; - _cg_varying.push_back(bind); - return true; - } - if (pieces[1].substr(0,8)=="texcoord") { - bind.name = InternalName::get_texcoord(); - bind.append_uv = atoi(pieces[1].c_str()+8); - _cg_varying.push_back(bind); - return true; - } - if (pieces[1].substr(0,7)=="tangent") { - bind.name = InternalName::get_tangent(); - bind.append_uv = atoi(pieces[1].c_str()+7); - _cg_varying.push_back(bind); - return true; - } - if (pieces[1].substr(0,8)=="binormal") { - bind.name = InternalName::get_binormal(); - bind.append_uv = atoi(pieces[1].c_str()+8); - _cg_varying.push_back(bind); - return true; - } - } - bind.name = InternalName::get_root(); - bind.append_uv = -1; - for (int i=1; i<(int)(pieces.size()-0); i++) - bind.name = bind.name->append(pieces[i]); - _cg_varying.push_back(bind); - return true; - } - - if ((pieces[0] == "trans")|| - (pieces[0] == "tpose")|| - (pieces[0] == "row0")|| - (pieces[0] == "row1")|| - (pieces[0] == "row2")|| - (pieces[0] == "row3")|| - (pieces[0] == "col0")|| - (pieces[0] == "col1")|| - (pieces[0] == "col2")|| - (pieces[0] == "col3")) { - if ((!errchk_cg_parameter_words(p,4)) || - (!errchk_cg_parameter_direction(p, CG_IN)) || - (!errchk_cg_parameter_variance(p, CG_UNIFORM))) - return false; - if ((pieces[2] != "rel")&&(pieces[2] != "to")) { - errchk_cg_output(p, "syntax error"); - return false; - } - ShaderTransBind bind; - bind.parameter = p; - - if (pieces[0]=="trans") bind.trans_piece = SHADER_data_matrix; - else if (pieces[0]=="tpose") bind.trans_piece = SHADER_data_transpose; - else if (pieces[0]=="row0") bind.trans_piece = SHADER_data_row0; - else if (pieces[0]=="row1") bind.trans_piece = SHADER_data_row1; - else if (pieces[0]=="row2") bind.trans_piece = SHADER_data_row2; - else if (pieces[0]=="row3") bind.trans_piece = SHADER_data_row3; - else if (pieces[0]=="col0") bind.trans_piece = SHADER_data_col0; - else if (pieces[0]=="col1") bind.trans_piece = SHADER_data_col1; - else if (pieces[0]=="col2") bind.trans_piece = SHADER_data_col2; - else if (pieces[0]=="col3") bind.trans_piece = SHADER_data_col3; - - bind.src_name = InternalName::make(pieces[1]); - bind.rel_name = InternalName::make(pieces[3]); - - if ((bind.trans_piece == SHADER_data_matrix)||(bind.trans_piece == SHADER_data_transpose)) { - if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false; - } else { - if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false; - } - - _cg_parameter_bind.push_back(bind); - if ((bind.src_name == InternalName::get_model()) || - (bind.rel_name == InternalName::get_model())) { - _cg_transform_bind.push_back(bind); - } - return true; - } - - if ((pieces[0]=="mstrans")|| - (pieces[0]=="cstrans")|| - (pieces[0]=="wstrans")|| - (pieces[0]=="vstrans")|| - (pieces[0]=="mspos")|| - (pieces[0]=="cspos")|| - (pieces[0]=="wspos")|| - (pieces[0]=="vspos")) { - if ((!errchk_cg_parameter_words(p,2)) || - (!errchk_cg_parameter_direction(p, CG_IN)) || - (!errchk_cg_parameter_variance(p, CG_UNIFORM))) - return false; - ShaderTransBind bind; - bind.parameter = p; - - if (pieces[0]=="wstrans") { bind.rel_name = InternalName::get_world(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="vstrans") { bind.rel_name = InternalName::get_view(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="cstrans") { bind.rel_name = InternalName::get_camera(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="mstrans") { bind.rel_name = InternalName::get_model(); bind.trans_piece = SHADER_data_matrix; } - else if (pieces[0]=="wspos") { bind.rel_name = InternalName::get_world(); bind.trans_piece = SHADER_data_row3; } - else if (pieces[0]=="vspos") { bind.rel_name = InternalName::get_view(); bind.trans_piece = SHADER_data_row3; } - else if (pieces[0]=="cspos") { bind.rel_name = InternalName::get_camera(); bind.trans_piece = SHADER_data_row3; } - else if (pieces[0]=="mspos") { bind.rel_name = InternalName::get_model(); bind.trans_piece = SHADER_data_row3; } - - bind.src_name = InternalName::make(pieces[1]); - - if ((bind.trans_piece == SHADER_data_matrix)||(bind.trans_piece == SHADER_data_transpose)) { - if (!errchk_cg_parameter_type(p, CG_FLOAT4x4)) return false; - } else { - if (!errchk_cg_parameter_type(p, CG_FLOAT4)) return false; - } - _cg_parameter_bind.push_back(bind); - if ((bind.src_name == InternalName::get_model()) || - (bind.rel_name == InternalName::get_model())) { - _cg_transform_bind.push_back(bind); - } - return true; - } - - if ((pieces[0]=="mat")|| - (pieces[0]=="inv")|| - (pieces[0]=="tps")|| - (pieces[0]=="itp")) { - if ((!errchk_cg_parameter_words(p,2)) || - (!errchk_cg_parameter_direction(p, CG_IN)) || - (!errchk_cg_parameter_variance(p, CG_UNIFORM)) || - (!errchk_cg_parameter_type(p, CG_FLOAT4x4))) - return false; - ShaderAutoBind bind; - bind.parameter = p; - bind.value = 0; - if (pieces[1] == "modelview") bind.value += 0; - else if (pieces[1] == "projection") bind.value += 4; - else if (pieces[1] == "texmatrix") bind.value += 8; - else if (pieces[1] == "modelproj") bind.value += 12; - else { - errchk_cg_output(p, "unrecognized matrix name"); - return false; - } - if (pieces[0]=="mat") bind.value += 0; - else if (pieces[0]=="inv") bind.value += 1; - else if (pieces[0]=="tps") bind.value += 2; - else if (pieces[0]=="itp") bind.value += 3; - _cg_auto_trans.push_back(bind); - return true; - } - - if (pieces[0] == "sys") { - if ((!errchk_cg_parameter_words(p,2)) || - (!errchk_cg_parameter_direction(p, CG_IN)) || - (!errchk_cg_parameter_variance(p, CG_UNIFORM))) { - return false; - } - ShaderAutoBind bind; - bind.parameter = p; - if (pieces[1] == "pixelsize") { - if (!errchk_cg_parameter_type(p, CG_FLOAT2)) { - return false; - } - bind.value = SIC_sys_pixelsize; - _cg_auto_param.push_back(bind); - return true; - } - if (pieces[1] == "windowsize") { - if (!errchk_cg_parameter_type(p, CG_FLOAT2)) { - return false; - } - bind.value = SIC_sys_windowsize; - _cg_auto_param.push_back(bind); - return true; - } - if (pieces[1] == "cardcenter") { - if (!errchk_cg_parameter_type(p, CG_FLOAT2)) { - return false; - } - bind.value = SIC_sys_cardcenter; - _cg_auto_param.push_back(bind); - return true; - } - errchk_cg_output(p,"unknown system parameter"); - return false; - } - - if (pieces[0] == "tex") { - if ((!errchk_cg_parameter_direction(p, CG_IN)) || - (!errchk_cg_parameter_variance(p, CG_UNIFORM)) || - (!errchk_cg_parameter_sampler(p))) - return false; - if ((pieces.size() != 2)&&(pieces.size() != 3)) { - errchk_cg_output(p, "Invalid parameter name"); - return false; - } - ShaderTexBind bind; - bind.parameter = p; - bind.name = 0; - bind.stage = atoi(pieces[1].c_str()); - switch (cgGetParameterType(p)) { - case CG_SAMPLER1D: bind.desiredtype = Texture::TT_1d_texture; break; - case CG_SAMPLER2D: bind.desiredtype = Texture::TT_2d_texture; break; - case CG_SAMPLER3D: bind.desiredtype = Texture::TT_3d_texture; break; - case CG_SAMPLERCUBE: bind.desiredtype = Texture::TT_cube_map; break; - default: - errchk_cg_output(p, "Invalid type for a tex-parameter"); - return false; - } - if (pieces.size()==3) { - bind.suffix = InternalName::make(((string)"-") + pieces[2]); - } - _cg_texbind.push_back(bind); - return true; - } - - if (pieces[0] == "k") { - if ((!errchk_cg_parameter_words(p,2)) || - (!errchk_cg_parameter_direction(p, CG_IN)) || - (!errchk_cg_parameter_variance(p, CG_UNIFORM))) - return false; - switch (cgGetParameterType(p)) { - case CG_FLOAT4: { - ShaderArgBind bind; - bind.parameter = p; - bind.name = InternalName::make(pieces[1]); - _cg_fbind.push_back(bind); - break; - } - case CG_FLOAT4x4: { - ShaderArgBind bind; - bind.parameter = p; - bind.name = InternalName::make(pieces[1]); - _cg_npbind.push_back(bind); - break; - } - case CG_SAMPLER1D: { - ShaderTexBind bind; - bind.parameter = p; - bind.name = InternalName::make(pieces[1]); - bind.desiredtype=Texture::TT_1d_texture; - _cg_texbind.push_back(bind); - break; - } - case CG_SAMPLER2D: { - ShaderTexBind bind; - bind.parameter = p; - bind.name = InternalName::make(pieces[1]); - bind.desiredtype=Texture::TT_2d_texture; - _cg_texbind.push_back(bind); - break; - } - case CG_SAMPLER3D: { - ShaderTexBind bind; - bind.parameter = p; - bind.name = InternalName::make(pieces[1]); - bind.desiredtype=Texture::TT_3d_texture; - _cg_texbind.push_back(bind); - break; - } - case CG_SAMPLERCUBE: { - ShaderTexBind bind; - bind.parameter = p; - bind.name = InternalName::make(pieces[1]); - bind.desiredtype = Texture::TT_cube_map; - _cg_texbind.push_back(bind); - break; - } - default: - errchk_cg_output(p, "Invalid type for a k-parameter"); - return false; - } - return true; - } - - if (pieces[0] == "l") { - // IMPLEMENT THE ERROR CHECKING - return true; // Cg handles this automatically. - } - - if (pieces[0] == "o") { - // IMPLEMENT THE ERROR CHECKING - return true; // Cg handles this automatically. - } - - errchk_cg_output(p, "unrecognized parameter name"); - return false; -} -#endif - - diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index 2433442fa7..c5fe272f1f 100755 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -42,102 +42,26 @@ public: INLINE bool valid(void); void bind(GSG *gsg); void unbind(); - void issue_parameters(GSG *gsg); - void issue_transform(GSG *gsg); + void issue_parameters(GSG *gsg, bool all); void disable_shader_vertex_arrays(GSG *gsg); void update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg); void disable_shader_texture_bindings(GSG *gsg); void update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg); - bool _state; private: #ifdef HAVE_CGGL - enum ShaderAutoValue { - // This first batch of constants cleverly lines up - // with the Cg constant values. Don't insert anything. - SIC_mat_modelview, - SIC_inv_modelview, - SIC_tps_modelview, - SIC_itp_modelview, - SIC_mat_projection, - SIC_inv_projection, - SIC_tps_projection, - SIC_itp_projection, - SIC_mat_texture, - SIC_inv_texture, - SIC_tps_texture, - SIC_itp_texture, - SIC_mat_modelproj, - SIC_inv_modelproj, - SIC_tps_modelproj, - SIC_itp_modelproj, - // From this point forward, it's okay to insert stuff. - SIC_sys_windowsize, - SIC_sys_pixelsize, - SIC_sys_cardcenter, - }; - struct ShaderAutoBind { - CGparameter parameter; - int value; - }; - struct ShaderArgBind { - CGparameter parameter; - PT(InternalName) name; - }; - struct ShaderTexBind { - CGparameter parameter; - PT(InternalName) name; - int stage; - int desiredtype; - PT(InternalName) suffix; - }; - struct ShaderTransBind { - CGparameter parameter; - PT(InternalName) src_name; - PT(InternalName) rel_name; - int trans_piece; - }; - struct ShaderVarying { - CGparameter parameter; - PT(InternalName) name; - int append_uv; - }; CGcontext _cg_context; CGprofile _cg_profile[2]; CGprogram _cg_program[2]; - string _cg_errors; - - // These arrays contain lists of "bindings." They - // tell us how to fill the shader's input parameters. - vector _cg_auto_trans; - vector _cg_auto_param; - vector _cg_fbind; - vector _cg_npbind; - vector _cg_texbind; - vector _cg_transform_bind; - vector _cg_parameter_bind; - vector _cg_varying; bool try_cg_compile(ShaderExpansion *s, GSG *gsg); - void bind_cg_transform(const ShaderTransBind &stb, - CLP(GraphicsStateGuardian) *gsg); void suggest_cg_profile(const string &vpro, const string &fpro); CGprofile parse_cg_profile(const string &id, bool vertex); - void issue_cg_auto_bind(const ShaderAutoBind &bind, GSG *gsg); - bool compile_cg_parameter(CGparameter p); - bool errchk_cg_parameter_words(CGparameter p, int len); - bool errchk_cg_parameter_direction(CGparameter p, CGenum dir); - bool errchk_cg_parameter_variance(CGparameter p, CGenum var); - bool errchk_cg_parameter_prog(CGparameter p, CGprogram prog, const string &msg); - bool errchk_cg_parameter_type(CGparameter p, CGtype dt); - bool errchk_cg_parameter_float(CGparameter p); - bool errchk_cg_parameter_sampler(CGparameter p); - void errchk_cg_output(CGparameter p, const string &msg); void print_cg_compile_errors(const string &file, CGcontext ctx); #endif - + void release_resources(void); public: diff --git a/panda/src/gobj/lens.I b/panda/src/gobj/lens.I index 0ea64cc8ad..ccc9cdd503 100644 --- a/panda/src/gobj/lens.I +++ b/panda/src/gobj/lens.I @@ -442,3 +442,35 @@ operator << (ostream &out, const Lens &lens) { lens.output(out); return out; } + +//////////////////////////////////////////////////////////////////// +// Function: Lens::get_projection_mat +// Access: Published +// Description: Returns the complete transformation matrix from a 3-d +// point in space to a point on the film, if such a +// matrix exists, or the identity matrix if the lens is +// nonlinear, in the specified coordinate system. +//////////////////////////////////////////////////////////////////// +const LMatrix4f Lens:: +get_projection_mat(CoordinateSystem cs, StereoChannel channel) const { + return + LMatrix4f::convert_mat(cs, _cs) * + get_projection_mat(channel) * + LMatrix4f::convert_mat(CS_yup_right, cs); +} + +//////////////////////////////////////////////////////////////////// +// Function: Lens::get_projection_mat_inv +// Access: Published +// Description: Returns the matrix that transforms from a 2-d point +// on the film to a 3-d vector in space, if such a +// matrix exists, in the specified coordinate system. +//////////////////////////////////////////////////////////////////// +const LMatrix4f Lens:: +get_projection_mat_inv(CoordinateSystem cs, StereoChannel channel) const { + return + LMatrix4f::convert_mat(cs, CS_yup_right) * + get_projection_mat_inv(channel) * + LMatrix4f::convert_mat(_cs, cs); +} + diff --git a/panda/src/gobj/lens.h b/panda/src/gobj/lens.h index 91a739e935..ec3c72ee49 100644 --- a/panda/src/gobj/lens.h +++ b/panda/src/gobj/lens.h @@ -155,6 +155,9 @@ PUBLISHED: const LMatrix4f &get_projection_mat(StereoChannel channel = SC_mono) const; const LMatrix4f &get_projection_mat_inv(StereoChannel channel = SC_mono) const; + INLINE const LMatrix4f get_projection_mat(CoordinateSystem cs, StereoChannel channel) const; + INLINE const LMatrix4f get_projection_mat_inv(CoordinateSystem cs, StereoChannel channel) const; + const LMatrix4f &get_film_mat() const; const LMatrix4f &get_film_mat_inv() const; diff --git a/panda/src/gobj/shaderContext.cxx b/panda/src/gobj/shaderContext.cxx index aa6e0c7693..388bec3d8f 100755 --- a/panda/src/gobj/shaderContext.cxx +++ b/panda/src/gobj/shaderContext.cxx @@ -18,3 +18,634 @@ TypeHandle ShaderContext::_type_handle; +#ifdef HAVE_CG +#include "Cg/cg.h" + +//////////////////////////////////////////////////////////////////// +// Function: Shader::report_cg_compile_errors +// Access: Public, Static +// Description: Used only after a Cg compile command, to print +// out any error messages that may have occurred +// during the Cg shader compilation. The 'file' +// is the name of the file containing the Cg code. +//////////////////////////////////////////////////////////////////// +void ShaderContext:: +report_cg_compile_errors(const string &file, CGcontext ctx, + NotifyCategory *cat) +{ + CGerror err = cgGetError(); + if (err != CG_NO_ERROR) { + if (err == CG_COMPILER_ERROR) { + string listing = cgGetLastListing(ctx); + vector_string errlines; + tokenize(listing, errlines, "\n"); + for (int i=0; i<(int)errlines.size(); i++) { + string line = trim(errlines[i]); + if (line != "") { + cat->error() << file << " " << errlines[i] << "\n"; + } + } + } else { + cat->error() << file << ": " << cgGetErrorString(err) << "\n"; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::report_cg_parameter_error +// Access: Public +// Description: Generate an error message including a description +// of the specified Cg parameter. +//////////////////////////////////////////////////////////////////// +void ShaderContext:: +report_cg_parameter_error(CGparameter p, const string &msg) +{ + string vstr; + CGenum v = cgGetParameterVariability(p); + if (v == CG_UNIFORM) vstr = "uniform "; + if (v == CG_VARYING) vstr = "varying "; + if (v == CG_CONSTANT) vstr = "const "; + + string dstr; + CGenum d = cgGetParameterDirection(p); + if (d == CG_IN) dstr = "in "; + if (d == CG_OUT) dstr = "out "; + if (d == CG_INOUT) dstr = "inout "; + + const char *ts = cgGetTypeString(cgGetParameterType(p)); + + string err; + string fn = _shader_expansion->get_name(); + _cg_report_cat->error() << fn << ": " << msg << " (" << + vstr << dstr << ts << " " << cgGetParameterName(p) << ")\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_words +// Access: Public, Static +// Description: Make sure the provided Cg parameter contains +// the specified number of words. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +errchk_cg_parameter_words(CGparameter p, int len) +{ + vector_string words; + tokenize(cgGetParameterName(p), words, "_"); + if (words.size() != len) { + report_cg_parameter_error(p, "parameter name has wrong number of words"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_in +// Access: Public, Static +// Description: Make sure the provided Cg parameter has the +// CG_IN direction. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +errchk_cg_parameter_in(CGparameter p) +{ + if (cgGetParameterDirection(p) != CG_IN) { + report_cg_parameter_error(p, "parameter should be declared 'in'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_varying +// Access: Public, Static +// Description: Make sure the provided Cg parameter has the +// correct variance. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +errchk_cg_parameter_varying(CGparameter p) +{ + if (cgGetParameterVariability(p) != CG_VARYING) { + report_cg_parameter_error(p, "parameter should be declared 'varying'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_uniform +// Access: Public, Static +// Description: Make sure the provided Cg parameter has the +// correct variance. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +errchk_cg_parameter_uniform(CGparameter p) +{ + if (cgGetParameterVariability(p) != CG_UNIFORM) { + report_cg_parameter_error(p, "parameter should be declared 'uniform'"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_float +// Access: Public, Static +// Description: Make sure the provided Cg parameter has +// a floating point type. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +errchk_cg_parameter_float(CGparameter p, int lo, int hi) +{ + CGtype t = cgGetParameterType(p); + int nfloat = 0; + switch (t) { + case CG_FLOAT1: nfloat = 1; break; + case CG_FLOAT2: nfloat = 2; break; + case CG_FLOAT3: nfloat = 3; break; + case CG_FLOAT4: nfloat = 4; break; + case CG_FLOAT4x4: nfloat = 16; break; + } + if ((nfloat < lo)||(nfloat > hi)) { + report_cg_parameter_error(p, "wrong float-type for parameter"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: Shader::errchk_cg_parameter_sampler +// Access: Public, Static +// Description: Make sure the provided Cg parameter has +// a texture type. If not, print +// error message and return false. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +errchk_cg_parameter_sampler(CGparameter p) +{ + CGtype t = cgGetParameterType(p); + if ((t!=CG_SAMPLER1D)&& + (t!=CG_SAMPLER2D)&& + (t!=CG_SAMPLER3D)&& + (t!=CG_SAMPLERCUBE)) { + report_cg_parameter_error(p, "parameter should have a 'sampler' type"); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GLShaderContext::parse_cg_trans_clause +// Access: Public +// Description: Parses a single clause of a "trans" parameter. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +parse_cg_trans_clause(CGparameter p, ShaderMatSpec &spec, const vector_string &pieces, + int &next, ShaderMatOp ofop, ShaderMatOp op) { + if (pieces[next+1]=="of") { + if (pieces[next+2]=="") { + report_cg_parameter_error(p, "'of' should be followed by a name"); + return false; + } + if (ofop != SMO_noop) { + spec._opcodes.push_back(ofop); + spec._args.push_back(InternalName::make(pieces[next+2])); + } + next += 3; + return true; + } else { + if (op != SMO_noop) { + spec._opcodes.push_back(op); + } + next += 1; + return true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GLShaderContext::compile_cg_parameter +// Access: Public +// Description: Analyzes a Cg parameter and decides how to +// bind the parameter to some part of panda's +// internal state. Updates one of the cg bind +// arrays to cause the binding to occur. +// +// If there is an error, this routine will append +// an error message onto the error messages. +//////////////////////////////////////////////////////////////////// +bool ShaderContext:: +compile_cg_parameter(CGparameter p, NotifyCategory *cat) +{ + _cg_report_cat = cat; + string pname = cgGetParameterName(p); + if (pname.size() == 0) return true; + if (pname[0] == '$') return true; + vector_string pieces; + tokenize(pname, pieces, "_"); + + if (pieces.size() < 2) { + report_cg_parameter_error(p, "invalid parameter name"); + return false; + } + + // Implement vtx parameters - the varying kind. + + if (pieces[0] == "vtx") { + if ((!errchk_cg_parameter_in(p)) || + (!errchk_cg_parameter_varying(p)) || + (!errchk_cg_parameter_float(p, 1, 4))) { + return false; + } + ShaderVarSpec bind; + bind._parameter = (void*)p; + if (pieces.size() == 2) { + if (pieces[1]=="position") { + bind._name = InternalName::get_vertex(); + bind._append_uv = -1; + _var_spec.push_back(bind); + return true; + } + if (pieces[1].substr(0,8)=="texcoord") { + bind._name = InternalName::get_texcoord(); + bind._append_uv = atoi(pieces[1].c_str()+8); + _var_spec.push_back(bind); + return true; + } + if (pieces[1].substr(0,7)=="tangent") { + bind._name = InternalName::get_tangent(); + bind._append_uv = atoi(pieces[1].c_str()+7); + _var_spec.push_back(bind); + return true; + } + if (pieces[1].substr(0,8)=="binormal") { + bind._name = InternalName::get_binormal(); + bind._append_uv = atoi(pieces[1].c_str()+8); + _var_spec.push_back(bind); + return true; + } + } + bind._name = InternalName::get_root(); + bind._append_uv = -1; + for (int i=1; i<(int)(pieces.size()-0); i++) + bind._name = bind._name->append(pieces[i]); + _var_spec.push_back(bind); + return true; + } + + // Implement some macros. Macros work by altering the + // contents of the 'pieces' array, and then falling through. + + if (pieces[0] == "mstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("model"); + } + if (pieces[0] == "wstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("world"); + } + if (pieces[0] == "vstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("view"); + } + if (pieces[0] == "cstrans") { + pieces[0] = "trans"; + pieces.push_back("to"); + pieces.push_back("clip"); + } + if (pieces[0] == "mspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("model"); + } + if (pieces[0] == "wspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("world"); + } + if (pieces[0] == "vspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("view"); + } + if (pieces[0] == "cspos") { + pieces[0] = "row3"; + pieces.push_back("to"); + pieces.push_back("clip"); + } + + // Implement the modelview macros. + + if ((pieces[0] == "mat")||(pieces[0] == "inv")|| + (pieces[0] == "tps")||(pieces[0] == "itp")) { + if (!errchk_cg_parameter_words(p, 2)) { + return false; + } + string trans = pieces[0]; + string matrix = pieces[1]; + pieces.clear(); + if (matrix == "modelview") { + tokenize("trans_model_to_apiview", pieces, "_"); + } else if (matrix == "projection") { + tokenize("trans_apiview_to_apiclip", pieces, "_"); + } else if (matrix == "modelproj") { + tokenize("trans_model_to_apiclip", pieces, "_"); + } else { + report_cg_parameter_error(p,"unrecognized matrix name"); + return false; + } + if (trans=="mat") { + pieces[0] = "trans"; + } else if (trans=="inv") { + string t = pieces[1]; + pieces[1] = pieces[3]; + pieces[3] = t; + } else if (trans=="tps") { + pieces[0] = "tpose"; + } else if (trans=="itp") { + string t = pieces[1]; + pieces[1] = pieces[3]; + pieces[3] = t; + pieces[0] = "tpose"; + } + } + + // Implement the transform-matrix generator. + + if ((pieces[0]=="trans")|| + (pieces[0]=="tpose")|| + (pieces[0]=="row0")|| + (pieces[0]=="row1")|| + (pieces[0]=="row2")|| + (pieces[0]=="row3")|| + (pieces[0]=="col0")|| + (pieces[0]=="col1")|| + (pieces[0]=="col2")|| + (pieces[0]=="col3")) { + + if ((!errchk_cg_parameter_in(p)) || + (!errchk_cg_parameter_uniform(p))) + return false; + + ShaderMatSpec bind; + bind._parameter = (void*)p; + bind._trans_dependent = false; + + int next = 1; + pieces.push_back(""); + + // Decide whether this is a matrix or vector. + if (pieces[0]=="trans") bind._piece = SMP_whole; + else if (pieces[0]=="tpose") bind._piece = SMP_whole; + else if (pieces[0]=="row0") bind._piece = SMP_row0; + else if (pieces[0]=="row1") bind._piece = SMP_row1; + else if (pieces[0]=="row2") bind._piece = SMP_row2; + else if (pieces[0]=="row3") bind._piece = SMP_row3; + else if (pieces[0]=="col0") bind._piece = SMP_col0; + else if (pieces[0]=="col1") bind._piece = SMP_col1; + else if (pieces[0]=="col2") bind._piece = SMP_col2; + else if (pieces[0]=="col3") bind._piece = SMP_col3; + if (bind._piece == SMP_whole) { + if (!errchk_cg_parameter_float(p, 16, 16)) return false; + } else { + if (!errchk_cg_parameter_float(p, 4, 4)) return false; + } + + // Parse the first half of the clause. + bool ok = true; + if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ + report_cg_parameter_error(p, "argument missing"); + return false; + } else if (pieces[next] == "world") { + bind._opcodes.push_back(SMO_world_to_view); + next += 1; + } else if (pieces[next] == "model") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_view_x_to_view, SMO_model_to_view); + } else if (pieces[next] == "clip") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_clip_x_to_view, SMO_clip_to_view); + } else if (pieces[next] == "view") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_view_x_to_view, SMO_identity); + } else if (pieces[next] == "apiview") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_apiview_x_to_view, SMO_apiview_to_view); + } else if (pieces[next] == "apiclip") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_apiclip_x_to_view, SMO_apiclip_to_view); + } else { + bind._opcodes.push_back(SMO_view_x_to_view); + bind._args.push_back(InternalName::make(pieces[next])); + next += 1; + } + + // Check for errors in the first clause. + if (!ok) { + return false; + } + + // Check for transform-dependence. + if (bind._opcodes.back() == SMO_model_to_view) { + bind._trans_dependent = true; + } + + // Check for syntactic well-formed-ness. + if (pieces[next] != "to") { + report_cg_parameter_error(p, "keyword 'to' expected"); + return false; + } else { + next += 1; + } + + // Parse the second half of the clause. + if ((pieces[next]=="")||(pieces[next]=="of")||(pieces[next]=="to")){ + report_cg_parameter_error(p, "argument missing"); + return false; + } else if (pieces[next] == "world") { + bind._opcodes.push_back(SMO_view_to_world_C); + next += 1; + } else if (pieces[next] == "model") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_view_to_view_x_C, SMO_view_to_model_C); + } else if (pieces[next] == "clip") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_view_to_clip_x_C, SMO_view_to_clip_C); + } else if (pieces[next] == "view") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_view_to_view_x_C, SMO_noop); + } else if (pieces[next] == "apiview") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_view_to_apiview_x_C, SMO_view_to_apiview_C); + } else if (pieces[next] == "apiclip") { + ok &= parse_cg_trans_clause(p, bind, pieces, next, SMO_view_to_apiclip_x_C, SMO_view_to_apiclip_C); + } else { + bind._opcodes.push_back(SMO_view_to_view_x_C); + bind._args.push_back(InternalName::make(pieces[next])); + next += 1; + } + + // Check for errors in the second clause. + if (!ok) { + return false; + } + + // Check for transform-dependence. + if (bind._opcodes.back() == SMO_view_to_model_C) { + bind._trans_dependent = true; + } + + // Check for syntactic well-formed-ness. + if (pieces[next] != "") { + report_cg_parameter_error(p, "end of line expected"); + return false; + } + + _mat_spec.push_back(bind); + return true; + } + + // Keywords to access unusual parameters. + + if (pieces[0] == "sys") { + if ((!errchk_cg_parameter_words(p,2)) || + (!errchk_cg_parameter_in(p)) || + (!errchk_cg_parameter_uniform(p))) { + return false; + } + ShaderMatSpec bind; + bind._parameter = (void*)p; + bind._trans_dependent = false; + bind._piece = SMP_row3; + if (pieces[1] == "pixelsize") { + if (!errchk_cg_parameter_float(p, 2, 2)) { + return false; + } + bind._opcodes.push_back(SMO_pixel_size); + } else if (pieces[1] == "windowsize") { + if (!errchk_cg_parameter_float(p, 2, 2)) { + return false; + } + bind._opcodes.push_back(SMO_window_size); + } else if (pieces[1] == "cardcenter") { + if (!errchk_cg_parameter_float(p, 2, 2)) { + return false; + } + bind._opcodes.push_back(SMO_card_center); + } else { + report_cg_parameter_error(p,"unknown system parameter"); + return false; + } + _mat_spec.push_back(bind); + return true; + } + + // Keywords to access textures. + + if (pieces[0] == "tex") { + if ((!errchk_cg_parameter_in(p)) || + (!errchk_cg_parameter_uniform(p)) || + (!errchk_cg_parameter_sampler(p))) + return false; + if ((pieces.size() != 2)&&(pieces.size() != 3)) { + report_cg_parameter_error(p, "Invalid parameter name"); + return false; + } + ShaderTexSpec bind; + bind._parameter = (void*)p; + bind._name = 0; + bind._stage = atoi(pieces[1].c_str()); + switch (cgGetParameterType(p)) { + case CG_SAMPLER1D: bind._desired_type = Texture::TT_1d_texture; break; + case CG_SAMPLER2D: bind._desired_type = Texture::TT_2d_texture; break; + case CG_SAMPLER3D: bind._desired_type = Texture::TT_3d_texture; break; + case CG_SAMPLERCUBE: bind._desired_type = Texture::TT_cube_map; break; + default: + report_cg_parameter_error(p, "Invalid type for a tex-parameter"); + return false; + } + if (pieces.size()==3) { + bind._suffix = InternalName::make(((string)"-") + pieces[2]); + } + _tex_spec.push_back(bind); + return true; + } + + // Keywords to access constants. + + if (pieces[0] == "k") { + if ((!errchk_cg_parameter_words(p,2)) || + (!errchk_cg_parameter_in(p)) || + (!errchk_cg_parameter_uniform(p))) + return false; + switch (cgGetParameterType(p)) { + case CG_FLOAT4: { + ShaderMatSpec bind; + bind._parameter = (void*)p; + bind._trans_dependent = false; + bind._piece = SMP_row3; + bind._opcodes.push_back(SMO_vec_constant_x); + bind._args.push_back(InternalName::make(pieces[1])); + _mat_spec.push_back(bind); + break; + } + case CG_FLOAT4x4: { + ShaderMatSpec bind; + bind._parameter = (void*)p; + bind._trans_dependent = false; + bind._piece = SMP_whole; + bind._opcodes.push_back(SMO_mat_constant_x); + bind._args.push_back(InternalName::make(pieces[1])); + _mat_spec.push_back(bind); + break; + } + case CG_SAMPLER1D: { + ShaderTexSpec bind; + bind._parameter = (void*)p; + bind._name = InternalName::make(pieces[1]); + bind._desired_type=Texture::TT_1d_texture; + _tex_spec.push_back(bind); + break; + } + case CG_SAMPLER2D: { + ShaderTexSpec bind; + bind._parameter = (void*)p; + bind._name = InternalName::make(pieces[1]); + bind._desired_type=Texture::TT_2d_texture; + _tex_spec.push_back(bind); + break; + } + case CG_SAMPLER3D: { + ShaderTexSpec bind; + bind._parameter = (void*)p; + bind._name = InternalName::make(pieces[1]); + bind._desired_type=Texture::TT_3d_texture; + _tex_spec.push_back(bind); + break; + } + case CG_SAMPLERCUBE: { + ShaderTexSpec bind; + bind._parameter = (void*)p; + bind._name = InternalName::make(pieces[1]); + bind._desired_type = Texture::TT_cube_map; + _tex_spec.push_back(bind); + break; + } + default: + report_cg_parameter_error(p, "Invalid type for a k-parameter"); + return false; + } + return true; + } + + if (pieces[0] == "l") { + // IMPLEMENT THE ERROR CHECKING + return true; // Cg handles this automatically. + } + + if (pieces[0] == "o") { + // IMPLEMENT THE ERROR CHECKING + return true; // Cg handles this automatically. + } + + report_cg_parameter_error(p, "unrecognized parameter name"); + return false; +} + +#endif // HAVE_CG diff --git a/panda/src/gobj/shaderContext.h b/panda/src/gobj/shaderContext.h index a45278febf..f243a00f2a 100755 --- a/panda/src/gobj/shaderContext.h +++ b/panda/src/gobj/shaderContext.h @@ -23,6 +23,13 @@ #include "internalName.h" #include "savedContext.h" #include "shaderExpansion.h" +#ifdef HAVE_CG +// Instead of including the whole header file, just include these stubs. +typedef struct _CGcontext *CGcontext; +typedef struct _CGprogram *CGprogram; +typedef struct _CGparameter *CGparameter; +#endif + //////////////////////////////////////////////////////////////////// // Class : ShaderContext @@ -41,28 +48,117 @@ public: INLINE ShaderContext(ShaderExpansion *se); ShaderExpansion *_shader_expansion; - + public: - // The following declarations represent useful routines - // and constants that can be used by shader implementations. - enum { SHADER_type_vert=0, SHADER_type_frag=1, SHADER_type_both=2, }; - enum { - SHADER_data_matrix, - SHADER_data_transpose, - SHADER_data_row0, - SHADER_data_row1, - SHADER_data_row2, - SHADER_data_row3, - SHADER_data_col0, - SHADER_data_col1, - SHADER_data_col2, - SHADER_data_col3, + enum ShaderMatOp { + SMO_identity, + + SMO_modelview, + SMO_projection, + SMO_modelproj, + + SMO_window_size, + SMO_pixel_size, + SMO_card_center, + + SMO_mat_constant_x, + SMO_vec_constant_x, + + SMO_world_to_view, + SMO_view_to_world_C, + + SMO_model_to_view, + SMO_view_to_model_C, + + SMO_apiview_to_view, + SMO_view_to_apiview_C, + + SMO_clip_to_view, + SMO_view_to_clip_C, + + SMO_apiclip_to_view, + SMO_view_to_apiclip_C, + + SMO_view_x_to_view, + SMO_view_to_view_x_C, + + SMO_apiview_x_to_view, + SMO_view_to_apiview_x_C, + + SMO_clip_x_to_view, + SMO_view_to_clip_x_C, + + SMO_apiclip_x_to_view, + SMO_view_to_apiclip_x_C, + + SMO_transpose, + SMO_noop, }; + enum ShaderMatPiece { + SMP_whole, + SMP_transpose, + SMP_row0, + SMP_row1, + SMP_row2, + SMP_row3, + SMP_col0, + SMP_col1, + SMP_col2, + SMP_col3, + }; + struct ShaderMatSpec { + pvector _opcodes; + pvector _args; + ShaderMatPiece _piece; + bool _trans_dependent; + void *_parameter; + }; + struct ShaderTexSpec { + PT(InternalName) _name; + int _stage; + int _desired_type; + PT(InternalName) _suffix; + void *_parameter; + }; + struct ShaderVarSpec { + PT(InternalName) _name; + int _append_uv; + void *_parameter; + }; + +protected: + pvector _mat_spec; + pvector _tex_spec; + pvector _var_spec; + +#ifdef HAVE_CG +private: + // These functions are only called by 'compile_cg_parameter' + NotifyCategory *_cg_report_cat; + void report_cg_parameter_error(CGparameter p, const string &msg); + bool errchk_cg_parameter_words(CGparameter p, int len); + bool errchk_cg_parameter_in(CGparameter p); + bool errchk_cg_parameter_varying(CGparameter p); + bool errchk_cg_parameter_uniform(CGparameter p); + bool errchk_cg_parameter_float(CGparameter p, int lo, int hi); + bool errchk_cg_parameter_sampler(CGparameter p); + bool parse_cg_trans_clause(CGparameter p, + ShaderMatSpec &spec, + const vector_string &pieces, + int &next, + ShaderMatOp ofop, + ShaderMatOp op); + +protected: + void report_cg_compile_errors(const string &file, CGcontext ctx, + NotifyCategory *cat); + bool compile_cg_parameter(CGparameter p, NotifyCategory *cat); +#endif public: static TypeHandle get_class_type() {