diff options
author | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-17 06:26:52 +0000 |
---|---|---|
committer | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-17 06:26:52 +0000 |
commit | 1dc3ba84c3da4edfeaf22cedf65750533a20de00 (patch) | |
tree | 936325e6f2dd07667fc4161ac524f1ab076aa5bf | |
parent | 3d476cf047d6a463d5706f70bfdf5e3787f863ee (diff) | |
download | chromium_src-1dc3ba84c3da4edfeaf22cedf65750533a20de00.zip chromium_src-1dc3ba84c3da4edfeaf22cedf65750533a20de00.tar.gz chromium_src-1dc3ba84c3da4edfeaf22cedf65750533a20de00.tar.bz2 |
adding svn:ignore properties to ignore .o3dtgz
files as well as scons-out etc...
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18599 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | o3d/core/cross/effect.cc | 7 | ||||
-rw-r--r-- | o3d/core/cross/effect_test.cc | 73 | ||||
-rw-r--r-- | o3d/core/cross/gl/effect_gl.cc | 2 | ||||
-rw-r--r-- | o3d/core/cross/gl/param_cache_gl.cc | 272 | ||||
-rw-r--r-- | o3d/core/win/d3d9/effect_d3d9.cc | 442 | ||||
-rw-r--r-- | o3d/documentation/jsdoc-toolkit-templates/publish.js | 65 | ||||
-rw-r--r-- | o3d/plugin/idl/client.idl | 6 | ||||
-rw-r--r-- | o3d/plugin/idl/pack.idl | 8 | ||||
-rw-r--r-- | o3d/plugin/mac/main_mac.mm | 22 | ||||
-rw-r--r-- | o3d/plugin/o3d_binding.py | 16 | ||||
-rw-r--r-- | o3d/samples/o3djs/base.js | 11 | ||||
-rw-r--r-- | o3d/samples/o3djs/effect.js | 33 | ||||
-rw-r--r-- | o3d/samples/o3djs/particles.js | 392 | ||||
-rw-r--r-- | o3d/samples/o3djs/serialization.js | 195 | ||||
-rw-r--r-- | o3d/samples/o3djs/simple.js | 336 | ||||
-rw-r--r-- | o3d/samples/particles.html | 106 | ||||
-rw-r--r-- | o3d/samples/shader-test.html | 61 | ||||
-rwxr-xr-x | o3d/samples/shaders/toon.shader | 98 | ||||
-rw-r--r-- | o3d/tests/selenium/javascript_unit_test_list.txt | 4 | ||||
-rw-r--r-- | o3d/tests/selenium/tests/param-array-test.html | 307 | ||||
-rw-r--r-- | o3d/tests/selenium/tests/texture-set-test.html | 9 |
21 files changed, 2143 insertions, 322 deletions
diff --git a/o3d/core/cross/effect.cc b/o3d/core/cross/effect.cc index 9c271fb..64b109d 100644 --- a/o3d/core/cross/effect.cc +++ b/o3d/core/cross/effect.cc @@ -125,12 +125,11 @@ void Effect::CreateSpecifiedParameters(ParamObject* param_object, bool sas) { param = param_object->CreateParamByClass( param_info.name(), param_info.sas_class_type() ? param_info.sas_class_type() : - param_info.class_type()); + param_info.class_type()); } else { // Array type - param = param_object->CreateParamByClass( - param_info.name(), - ParamParamArray::GetApparentClass()); + param = + param_object->CreateParam<ParamParamArray>(param_info.name()); } if (!param) { errors += String(errors.empty() ? "" : "\n") + diff --git a/o3d/core/cross/effect_test.cc b/o3d/core/cross/effect_test.cc index af028e6..b26f632 100644 --- a/o3d/core/cross/effect_test.cc +++ b/o3d/core/cross/effect_test.cc @@ -34,6 +34,7 @@ #include "core/cross/effect.h" #include "core/cross/primitive.h" #include "core/cross/standard_param.h" +#include "core/cross/param_array.h" #include "core/cross/stream.h" #include "tests/common/win/testing_common.h" @@ -161,7 +162,7 @@ uint32 kIndexBlock[4] = { 0, 1, 2, 3 }; -bool IsExpectedParam(const EffectParameterInfo& info) { +bool IsExpectedParamInfo(const EffectParameterInfo& info) { for (unsigned ii = 0; ii < arraysize(expected_params); ++ii) { const ParamInfo& expected_info = expected_params[ii]; if (info.name().compare(expected_info.name) == 0) { @@ -333,7 +334,75 @@ TEST_F(EffectTest, GetEffectParameters) { EXPECT_EQ(arraysize(expected_params), info.size()); for (EffectParameterInfoArray::size_type ii = 0; ii < info.size(); ++ii) { - EXPECT_TRUE(IsExpectedParam(info[ii])); + EXPECT_TRUE(IsExpectedParamInfo(info[ii])); + } + + // Clean up. + object_manager()->DestroyPack(pack); +} + +TEST_F(EffectTest, CreateUniformParameters) { + Pack* pack = object_manager()->CreatePack(); + ASSERT_TRUE(pack != NULL); + + // load an effect + Effect *fx = pack->Create<Effect>(); + ASSERT_TRUE(fx != NULL); + EXPECT_TRUE(fx->LoadFromFXString(String(kLambertEffect))); + + ParamObject* param_object = pack->Create<ParamObject>(); + ASSERT_TRUE(param_object != NULL); + + // Check that we get the correct params + fx->CreateUniformParameters(param_object); + + for (unsigned ii = 0; ii < arraysize(expected_params); ++ii) { + const ParamInfo& expected_info = expected_params[ii]; + Param* param = param_object->GetUntypedParam(expected_info.name); + if (expected_info.sas_type) { + ASSERT_TRUE(param == NULL); + } else { + ASSERT_TRUE(param != NULL); + if (expected_info.num_elements > 0) { + ASSERT_TRUE(param->IsA(ParamParamArray::GetApparentClass())); + } else { + EXPECT_TRUE(param->IsA(expected_info.type)); + } + } + } + + // Clean up. + object_manager()->DestroyPack(pack); +} + +TEST_F(EffectTest, CreateSASParameters) { + Pack* pack = object_manager()->CreatePack(); + ASSERT_TRUE(pack != NULL); + + // load an effect + Effect *fx = pack->Create<Effect>(); + ASSERT_TRUE(fx != NULL); + EXPECT_TRUE(fx->LoadFromFXString(String(kLambertEffect))); + + ParamObject* param_object = pack->Create<ParamObject>(); + ASSERT_TRUE(param_object != NULL); + + // Check that we get the correct params + fx->CreateSASParameters(param_object); + + for (unsigned ii = 0; ii < arraysize(expected_params); ++ii) { + const ParamInfo& expected_info = expected_params[ii]; + Param* param = param_object->GetUntypedParam(expected_info.name); + if (expected_info.sas_type) { + ASSERT_TRUE(param != NULL); + if (expected_info.num_elements > 0) { + ASSERT_TRUE(param->IsA(ParamParamArray::GetApparentClass())); + } else { + EXPECT_TRUE(param->IsA(expected_info.sas_type)); + } + } else { + ASSERT_TRUE(param == NULL); + } } // Clean up. diff --git a/o3d/core/cross/gl/effect_gl.cc b/o3d/core/cross/gl/effect_gl.cc index 9fe940e..d8c24d4 100644 --- a/o3d/core/cross/gl/effect_gl.cc +++ b/o3d/core/cross/gl/effect_gl.cc @@ -75,6 +75,7 @@ static const ObjectBase::Class* CgTypeToParamType(CGtype cg_type) { case CG_FLOAT2 : return ParamFloat2::GetApparentClass(); case CG_FLOAT3 : return ParamFloat3::GetApparentClass(); case CG_FLOAT4 : return ParamFloat4::GetApparentClass(); + case CG_INT : return ParamInteger::GetApparentClass(); case CG_INT1 : return ParamInteger::GetApparentClass(); case CG_FLOAT4x4 : return ParamMatrix4::GetApparentClass(); case CG_BOOL : @@ -82,6 +83,7 @@ static const ObjectBase::Class* CgTypeToParamType(CGtype cg_type) { case CG_SAMPLER : case CG_SAMPLER1D : case CG_SAMPLER2D : + case CG_SAMPLER3D : case CG_SAMPLERCUBE : return ParamSampler::GetApparentClass(); default : { DLOG(ERROR) << "Cannot convert CGtype " diff --git a/o3d/core/cross/gl/param_cache_gl.cc b/o3d/core/cross/gl/param_cache_gl.cc index b91245e..8b46da2 100644 --- a/o3d/core/cross/gl/param_cache_gl.cc +++ b/o3d/core/cross/gl/param_cache_gl.cc @@ -179,8 +179,7 @@ class EffectParamHandlerForSamplersGL : public EffectParamHandlerGL { SamplerGL* sampler_gl = down_cast<SamplerGL*>(param_->value()); if (!sampler_gl) { // Use the error sampler. - sampler_gl = down_cast<SamplerGL*>( - renderer->error_sampler()); + sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler()); // If no error texture is set then generate an error. if (!renderer->error_texture()) { O3D_ERROR(param_->service_locator()) @@ -191,41 +190,220 @@ class EffectParamHandlerForSamplersGL : public EffectParamHandlerGL { } virtual void ResetEffectParam(RendererGL* renderer, CGparameter cg_param) { SamplerGL* sampler_gl = down_cast<SamplerGL*>(param_->value()); - if (sampler_gl) { - sampler_gl->ResetTexture(cg_param); + if (!sampler_gl) { + sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler()); } + sampler_gl->ResetTexture(cg_param); } private: ParamSampler* param_; }; -class EffectParamFloatArrayHandlerGL : public EffectParamHandlerGL { +template <typename T> +class EffectParamArrayHandlerGL : public EffectParamHandlerGL { public: - explicit EffectParamFloatArrayHandlerGL(ParamParamArray* param) + explicit EffectParamArrayHandlerGL(ParamParamArray* param) : param_(param) { } - virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param); + virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) { + ParamArray* param = param_->value(); + if (param) { + int size = cgGetArraySize(cg_param, 0); + if (size != static_cast<int>(param->size())) { + O3D_ERROR(param->service_locator()) + << "number of params in ParamArray does not match number of params " + << "needed by shader array"; + } else { + for (int i = 0; i < size; ++i) { + Param* untyped_element = param->GetUntypedParam(i); + // TODO: Make this check happen when building the param cache. + // To do that would require that ParamParamArray mark it's owner + // as changed if a Param in it's ParamArray changes. + if (untyped_element->IsA(T::GetApparentClass())) { + CGparameter cg_element = cgGetArrayParameter(cg_param, i); + SetElement(cg_element, down_cast<T*>(untyped_element)); + } else { + O3D_ERROR(param->service_locator()) + << "Param in ParamArray at index " << i << " is not a " + << T::GetApparentClassName(); + } + } + } + } + } + void SetElement(CGparameter cg_element, T* param); + private: ParamParamArray* param_; }; -void EffectParamFloatArrayHandlerGL::SetEffectParam( - RendererGL* renderer, - CGparameter cg_param) { - ParamArray* param = param_->value(); - if (param) { - int cg_size = cgGetArraySize(cg_param, 0); - int size = std::min(static_cast<int>(param->size()), cg_size); - for (int i = 0; i < size; ++i) { - ParamFloat* element = param->GetParam<ParamFloat>(i); - CGparameter cg_element = cgGetArrayParameter(cg_param, i); - if (element) { - cgSetParameter1f(cg_element, element->value()); +template <bool column_major> +class EffectParamArrayMatrix4HandlerGL : public EffectParamHandlerGL { + public: + explicit EffectParamArrayMatrix4HandlerGL(ParamParamArray* param) + : param_(param) { + } + virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) { + ParamArray* param = param_->value(); + if (param) { + int size = cgGetArraySize(cg_param, 0); + if (size != static_cast<int>(param->size())) { + O3D_ERROR(param->service_locator()) + << "number of params in ParamArray does not match number of params " + << "needed by shader array"; } else { - cgSetParameter1f(cg_element, 0.0f); + for (int i = 0; i < size; ++i) { + Param* untyped_element = param->GetUntypedParam(i); + // TODO: Make this check happen when building the param cache. + // To do that would require that ParamParamArray mark it's owner + // as changed if a Param in it's ParamArray changes. + if (untyped_element->IsA(ParamMatrix4::GetApparentClass())) { + CGparameter cg_element = cgGetArrayParameter(cg_param, i); + SetElement(cg_element, down_cast<ParamMatrix4*>(untyped_element)); + } else { + O3D_ERROR(param->service_locator()) + << "Param in ParamArray at index " << i + << " is not a ParamMatrix4"; + } + } + } + } + } + void SetElement(CGparameter cg_element, ParamMatrix4* param); + + private: + ParamParamArray* param_; +}; + +class EffectParamArraySamplerHandlerGL : public EffectParamHandlerGL { + public: + explicit EffectParamArraySamplerHandlerGL(ParamParamArray* param) + : param_(param) { + } + virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) { + ParamArray* param = param_->value(); + if (param) { + int size = cgGetArraySize(cg_param, 0); + if (size != static_cast<int>(param->size())) { + O3D_ERROR(param->service_locator()) + << "number of params in ParamArray does not match number of params " + << "needed by shader array"; + } else { + for (int i = 0; i < size; ++i) { + Param* untyped_element = param->GetUntypedParam(i); + // TODO: Make this check happen when building the param cache. + // To do that would require that ParamParamArray mark it's owner + // as changed if a Param in it's ParamArray changes. + if (untyped_element->IsA(ParamSampler::GetApparentClass())) { + CGparameter cg_element = cgGetArrayParameter(cg_param, i); + ParamSampler* element = down_cast<ParamSampler*>(untyped_element); + SamplerGL* sampler_gl = down_cast<SamplerGL*>(element->value()); + if (!sampler_gl) { + // Use the error sampler. + sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler()); + // If no error texture is set then generate an error. + if (!renderer->error_texture()) { + O3D_ERROR(param_->service_locator()) + << "Missing Sampler for ParamSampler '" << param_->name() + << "' index " << i; + } + } + sampler_gl->SetTextureAndStates(cg_element); + } else { + O3D_ERROR(param->service_locator()) + << "Param in ParamArray at index " << i + << " is not a ParamSampler"; + } + } + } + } + } + virtual void ResetEffectParam(RendererGL* renderer, CGparameter cg_param) { + ParamArray* param = param_->value(); + if (param) { + int size = cgGetArraySize(cg_param, 0); + if (size == static_cast<int>(param->size())) { + for (int i = 0; i < size; ++i) { + Param* untyped_element = param->GetUntypedParam(i); + if (untyped_element->IsA(ParamSampler::GetApparentClass())) { + CGparameter cg_element = cgGetArrayParameter(cg_param, i); + ParamSampler* element = down_cast<ParamSampler*>(untyped_element); + SamplerGL* sampler_gl = down_cast<SamplerGL*>(element->value()); + if (!sampler_gl) { + sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler()); + } + sampler_gl->ResetTexture(cg_param); + } + } } } } + + private: + ParamParamArray* param_; +}; + +template<> +void EffectParamArrayHandlerGL<ParamFloat>::SetElement( + CGparameter cg_element, + ParamFloat* param) { + cgSetParameter1f(cg_element, param->value()); +} + +template<> +void EffectParamArrayHandlerGL<ParamFloat2>::SetElement( + CGparameter cg_element, + ParamFloat2* param) { + Float2 f = param->value(); + cgSetParameter2fv(cg_element, f.GetFloatArray()); +} + +template<> +void EffectParamArrayHandlerGL<ParamFloat3>::SetElement( + CGparameter cg_element, + ParamFloat3* param) { + Float3 f = param->value(); + cgSetParameter3fv(cg_element, f.GetFloatArray()); +} + +template<> +void EffectParamArrayHandlerGL<ParamFloat4>::SetElement( + CGparameter cg_element, + ParamFloat4* param) { + Float4 f = param->value(); + cgSetParameter4fv(cg_element, f.GetFloatArray()); +} + +template<> +void EffectParamArrayMatrix4HandlerGL<false>::SetElement( + CGparameter cg_element, + ParamMatrix4* param) { + // set the data as floats in row major order. + Matrix4 mat = param->value(); + cgSetMatrixParameterfr(cg_element, &mat[0][0]); +} + +template<> +void EffectParamArrayMatrix4HandlerGL<true>::SetElement( + CGparameter cg_element, + ParamMatrix4* param) { + // set the data as floats in column major order. + Matrix4 mat = param->value(); + cgSetMatrixParameterfc(cg_element, &mat[0][0]); +} + +template<> +void EffectParamArrayHandlerGL<ParamInteger>::SetElement( + CGparameter cg_element, + ParamInteger* param) { + cgSetParameter1i(cg_element, param->value()); +} + +template<> +void EffectParamArrayHandlerGL<ParamBoolean>::SetElement( + CGparameter cg_element, + ParamBoolean* param) { + cgSetParameter1i(cg_element, param->value()); } static EffectParamHandlerGL::Ref GetHandlerFromParamAndCgType( @@ -234,10 +412,52 @@ static EffectParamHandlerGL::Ref GetHandlerFromParamAndCgType( CGtype cg_type) { EffectParamHandlerGL::Ref handler; if (param->IsA(ParamParamArray::GetApparentClass())) { - if (cg_type == CG_FLOAT) { - handler = EffectParamHandlerGL::Ref( - new EffectParamFloatArrayHandlerGL( - down_cast<ParamParamArray*>(param))); + ParamParamArray* param_param_array = down_cast<ParamParamArray*>(param); + switch (cg_type) { + case CG_FLOAT: + case CG_FLOAT1: + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayHandlerGL<ParamFloat>(param_param_array)); + break; + case CG_FLOAT2: + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayHandlerGL<ParamFloat2>(param_param_array)); + break; + case CG_FLOAT3: + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayHandlerGL<ParamFloat3>(param_param_array)); + break; + case CG_FLOAT4: + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayHandlerGL<ParamFloat4>(param_param_array)); + break; + case CG_FLOAT4x4: + if (effect_gl->matrix_load_order() == Effect::COLUMN_MAJOR) { + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayMatrix4HandlerGL<true>(param_param_array)); + } else { + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayMatrix4HandlerGL<false>(param_param_array)); + } + break; + case CG_INT: + case CG_INT1: + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayHandlerGL<ParamInteger>(param_param_array)); + break; + case CG_BOOL: + case CG_BOOL1: + handler = EffectParamHandlerGL::Ref( + new EffectParamArrayHandlerGL<ParamBoolean>(param_param_array)); + break; + case CG_SAMPLER: + case CG_SAMPLER1D: + case CG_SAMPLER2D: + case CG_SAMPLER3D: + case CG_SAMPLERCUBE: + handler = EffectParamHandlerGL::Ref( + new EffectParamArraySamplerHandlerGL(param_param_array)); + break; } } else if (param->IsA(ParamMatrix4::GetApparentClass())) { if (cg_type == CG_FLOAT4x4) { @@ -279,13 +499,13 @@ static EffectParamHandlerGL::Ref GetHandlerFromParamAndCgType( down_cast<ParamFloat4*>(param))); } } else if (param->IsA(ParamInteger::GetApparentClass())) { - if (cg_type == CG_INT) { + if (cg_type == CG_INT || cg_type == CG_INT1) { handler = EffectParamHandlerGL::Ref( new TypedEffectParamHandlerGL<ParamInteger>( down_cast<ParamInteger*>(param))); } } else if (param->IsA(ParamBoolean::GetApparentClass())) { - if (cg_type == CG_BOOL) { + if (cg_type == CG_BOOL || cg_type == CG_BOOL1) { handler = EffectParamHandlerGL::Ref( new TypedEffectParamHandlerGL<ParamBoolean>( down_cast<ParamBoolean*>(param))); diff --git a/o3d/core/win/d3d9/effect_d3d9.cc b/o3d/core/win/d3d9/effect_d3d9.cc index 216e6b9..566145f 100644 --- a/o3d/core/win/d3d9/effect_d3d9.cc +++ b/o3d/core/win/d3d9/effect_d3d9.cc @@ -32,6 +32,8 @@ // This file contains the definition of EffectD3D9. +// TODO: Most of the D3DXHANDLE lookup could be cached. + #include "core/cross/precompile.h" #include "core/win/d3d9/effect_d3d9.h" @@ -53,6 +55,18 @@ namespace o3d { +namespace { + +inline bool IsSamplerType(D3DXPARAMETER_TYPE type) { + return type == D3DXPT_SAMPLER || + type == D3DXPT_SAMPLER1D || + type == D3DXPT_SAMPLER2D || + type == D3DXPT_SAMPLER3D || + type == D3DXPT_SAMPLERCUBE; +} + +} // anonymous namespace + // A 'mostly' typesafe class to set an effect parameter from an O3D // Param. The phandle must match the type of Param to be typesafe. That is // handled when these are created. @@ -69,22 +83,329 @@ class TypedEffectParamHandlerD3D9 : public EffectParamHandlerD3D9 { D3DXHANDLE phandle_; }; -class EffectParamFloatArrayHandlerD3D9 : public EffectParamHandlerD3D9 { +template <typename T> +class EffectParamArrayHandlerD3D9 : public EffectParamHandlerD3D9 { public: - EffectParamFloatArrayHandlerD3D9(ParamParamArray* param, D3DXHANDLE phandle) + EffectParamArrayHandlerD3D9(ParamParamArray* param, + D3DXHANDLE phandle, + unsigned num_elements) : param_(param), - phandle_(phandle) { + phandle_(phandle), + num_elements_(num_elements) { } - virtual void SetEffectParam(RendererD3D9* renderer, ID3DXEffect* d3d_effect); + virtual void SetEffectParam(RendererD3D9* renderer, ID3DXEffect* d3d_effect) { + ParamArray* param = param_->value(); + if (param) { + int size = param->size(); + if (size != num_elements_) { + O3D_ERROR(param->service_locator()) + << "number of params in ParamArray does not match number of params " + << "needed by shader array"; + } else { + for (int i = 0; i < size; ++i) { + Param* untyped_element = param->GetUntypedParam(i); + // TODO: Make this check happen when building the param cache. + // To do that would require that ParamParamArray mark it's owner + // as changed if a Param in it's ParamArray changes. + if (untyped_element->IsA(T::GetApparentClass())) { + D3DXHANDLE dx_element = + d3d_effect->GetParameterElement(phandle_, i); + SetElement(d3d_effect, dx_element, down_cast<T*>(untyped_element)); + } else { + O3D_ERROR(param->service_locator()) + << "Param in ParamArray at index " << i << " is not a " + << T::GetApparentClassName(); + } + } + } + } + } + void SetElement(ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + T* element); + private: ParamParamArray* param_; D3DXHANDLE phandle_; + unsigned num_elements_; }; // Number of h/w sampler units in the same shader using a single sampler. // Eight should be enough! static const int kMaxUnitsPerSampler = 8; +template <bool column_major> +class EffectParamMatrix4ArrayHandlerD3D9 : public EffectParamHandlerD3D9 { + public: + EffectParamMatrix4ArrayHandlerD3D9(ParamParamArray* param, + D3DXHANDLE phandle, + unsigned num_elements) + : param_(param), + phandle_(phandle), + num_elements_(num_elements) { + } + virtual void SetEffectParam(RendererD3D9* renderer, ID3DXEffect* d3d_effect) { + ParamArray* param = param_->value(); + if (param) { + int size = param->size(); + if (size != num_elements_) { + O3D_ERROR(param->service_locator()) + << "number of params in ParamArray does not match number of params " + << "needed by shader array"; + } else { + for (int i = 0; i < size; ++i) { + Param* untyped_element = param->GetUntypedParam(i); + // TODO: Make this check happen when building the param cache. + // To do that would require that ParamParamArray mark it's owner + // as changed if a Param in it's ParamArray changes. + if (untyped_element->IsA(ParamMatrix4::GetApparentClass())) { + D3DXHANDLE dx_element = + d3d_effect->GetParameterElement(phandle_, i); + SetElement(d3d_effect, + dx_element, + down_cast<ParamMatrix4*>(untyped_element)); + } else { + O3D_ERROR(param->service_locator()) + << "Param in ParamArray at index " << i << " is not a " + << ParamMatrix4::GetApparentClassName(); + } + } + } + } + } + void SetElement(ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamMatrix4* element); + + private: + ParamParamArray* param_; + D3DXHANDLE phandle_; + unsigned num_elements_; +}; + +// A class for setting the the appropriate d3d sampler states from an array of +// o3d Sampler object. +class EffectParamSamplerArrayHandlerD3D9 : public EffectParamHandlerD3D9 { + public: + EffectParamSamplerArrayHandlerD3D9(ParamParamArray* param, + D3DXHANDLE phandle, + const D3DXPARAMETER_DESC& pdesc, + LPD3DXCONSTANTTABLE fs_constant_table, + LPDIRECT3DDEVICE9 d3d_device) + : param_(param), + phandle_(phandle), + sampler_unit_index_arrays_(pdesc.Elements) { + if (!fs_constant_table) { + DLOG(ERROR) << "Fragment shader constant table is NULL"; + return; + } + D3DXHANDLE sampler_array_handle = fs_constant_table->GetConstantByName( + NULL, + pdesc.Name); + if (!sampler_array_handle) { + DLOG(ERROR) << "Sampler " << pdesc.Name << + " not found in fragment shader"; + return; + } + for (unsigned ii = 0; ii < pdesc.Elements; ++ii) { + D3DXHANDLE sampler_handle = fs_constant_table->GetConstantElement( + sampler_array_handle, + ii); + if (!sampler_handle) { + DLOG(ERROR) << "Sampler " << pdesc.Name << " index " << ii + << " not found in fragment shader"; + } else { + D3DXCONSTANT_DESC desc_array[kMaxUnitsPerSampler]; + UINT num_desc = kMaxUnitsPerSampler; + fs_constant_table->GetConstantDesc( + sampler_handle, desc_array, &num_desc); + // We have no good way of querying how many descriptions would really be + // returned as we're capping the number to kMaxUnitsPerSampler (which + // should be more than sufficient). If however we do end up with the + // max number there's a chance that there were actually more so let's + // log it. + if (num_desc == kMaxUnitsPerSampler) { + DLOG(WARNING) << "Number of constant descriptions might have " + << "exceeded the maximum of " << kMaxUnitsPerSampler; + } + SamplerUnitIndexArray& index_array = sampler_unit_index_arrays_[ii]; + + for (UINT desc_index = 0; desc_index < num_desc; desc_index++) { + D3DXCONSTANT_DESC constant_desc = desc_array[desc_index]; + if (constant_desc.Class == D3DXPC_OBJECT && + IsSamplerType(constant_desc.Type)) { + index_array.push_back(constant_desc.RegisterIndex); + } + } + if (index_array.empty()) { + DLOG(ERROR) << "No matching sampler units found for " << + pdesc.Name; + } + } + } + } + + virtual void SetEffectParam(RendererD3D9* renderer, ID3DXEffect* d3d_effect) { + ParamArray* param = param_->value(); + if (param) { + unsigned size = param->size(); + if (size != sampler_unit_index_arrays_.size()) { + O3D_ERROR(param->service_locator()) + << "number of params in ParamArray does not match number of params " + << "needed by shader array"; + } else { + for (int i = 0; i < size; ++i) { + SamplerUnitIndexArray& index_array = sampler_unit_index_arrays_[i]; + Param* untyped_element = param->GetUntypedParam(i); + // TODO: Make this check happen when building the param cache. + // To do that would require that ParamParamArray mark it's owner + // as changed if a Param in it's ParamArray changes. + if (untyped_element->IsA(ParamSampler::GetApparentClass())) { + D3DXHANDLE dx_element = + d3d_effect->GetParameterElement(phandle_, i); + // Find the texture associated with the sampler first. + Sampler* sampler = + down_cast<ParamSampler*>(untyped_element)->value(); + if (!sampler) { + sampler = renderer->error_sampler(); + if (!renderer->error_texture()) { + O3D_ERROR(param->service_locator()) + << "Missing Sampler for ParamSampler " + << param->name(); + } + } + + SamplerD3D9* d3d_sampler = down_cast<SamplerD3D9*>(sampler); + for (unsigned stage = 0; stage < index_array.size(); stage++) { + d3d_sampler->SetTextureAndStates(index_array[stage]); + } + } else { + O3D_ERROR(param->service_locator()) + << "Param in ParamArray at index " << i << " is not a " + << ParamSampler::GetApparentClassName(); + } + } + } + } + } + + // Resets the value of the parameter to default. Currently this is used + // to unbind textures contained in Sampler params. + virtual void ResetEffectParam(RendererD3D9* renderer, + ID3DXEffect* d3d_effect) { + ParamArray* param = param_->value(); + if (param) { + unsigned size = param->size(); + if (size == sampler_unit_index_arrays_.size()) { + for (int i = 0; i < size; ++i) { + SamplerUnitIndexArray& index_array = sampler_unit_index_arrays_[i]; + Param* untyped_element = param->GetUntypedParam(i); + // TODO: Make this check happen when building the param cache. + // To do that would require that ParamParamArray mark it's owner + // as changed if a Param in it's ParamArray changes. + if (untyped_element->IsA(ParamSampler::GetApparentClass())) { + D3DXHANDLE dx_element = + d3d_effect->GetParameterElement(phandle_, i); + // Find the texture associated with the sampler first. + Sampler* sampler = + down_cast<ParamSampler*>(untyped_element)->value(); + if (!sampler) { + sampler = renderer->error_sampler(); + } + + SamplerD3D9* d3d_sampler = down_cast<SamplerD3D9*>(sampler); + for (unsigned stage = 0; stage < index_array.size(); stage++) { + d3d_sampler->ResetTexture(index_array[stage]); + } + } + } + } + } + } + + private: + typedef std::vector<int> SamplerUnitIndexArray; + typedef std::vector<SamplerUnitIndexArray> SamplerIndexArrayArray; + + ParamParamArray* param_; + D3DXHANDLE phandle_; + // An array of arrays of sampler unit indices. + SamplerIndexArrayArray sampler_unit_index_arrays_; +}; + +template<> +void EffectParamArrayHandlerD3D9<ParamFloat>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamFloat* element) { + d3dx_effect->SetFloat(dx_element, element->value()); +} + +template<> +void EffectParamArrayHandlerD3D9<ParamFloat2>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamFloat2* element) { + Float2 float2 = element->value(); + HR(d3dx_effect->SetFloatArray(dx_element, float2.GetFloatArray(), 2)); +} + +template<> +void EffectParamArrayHandlerD3D9<ParamFloat3>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamFloat3* element) { + Float3 float3 = element->value(); + HR(d3dx_effect->SetFloatArray(dx_element, float3.GetFloatArray(), 3)); +} + +template<> +void EffectParamArrayHandlerD3D9<ParamFloat4>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamFloat4* element) { + Float4 float4 = element->value(); + HR(d3dx_effect->SetFloatArray(dx_element, float4.GetFloatArray(), 4)); +} + +template<> +void EffectParamArrayHandlerD3D9<ParamBoolean>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamBoolean* element) { + HR(d3dx_effect->SetBool(dx_element, element->value())); +} + +template<> +void EffectParamArrayHandlerD3D9<ParamInteger>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamInteger* element) { + HR(d3dx_effect->SetInt(dx_element, element->value())); +} + +template<> +void EffectParamMatrix4ArrayHandlerD3D9<false>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamMatrix4* element) { + Matrix4 param_matrix = element->value(); + HR(d3dx_effect->SetMatrix( + dx_element, + reinterpret_cast<D3DXMATRIX*>(¶m_matrix[0][0]))); +} + +template<> +void EffectParamMatrix4ArrayHandlerD3D9<true>::SetElement( + ID3DXEffect* d3dx_effect, + D3DXHANDLE dx_element, + ParamMatrix4* element) { + Matrix4 param_matrix = transpose(element->value()); + HR(d3dx_effect->SetMatrix( + dx_element, + reinterpret_cast<D3DXMATRIX*>(¶m_matrix[0][0]))); +} + // A class for setting the the appropriate d3d sampler states from a // o3d Sampler object. class EffectParamHandlerForSamplersD3D9 : public EffectParamHandlerD3D9 { @@ -150,10 +471,7 @@ static const ObjectBase::Class* D3DXPDescToParamType( pdesc.Class == D3DXPC_OBJECT) { return ParamTexture::GetApparentClass(); // Sampler param - } else if (pdesc.Class == D3DXPC_OBJECT && - (pdesc.Type == D3DXPT_SAMPLER || - pdesc.Type == D3DXPT_SAMPLER2D || - pdesc.Type == D3DXPT_SAMPLERCUBE)) { + } else if (pdesc.Class == D3DXPC_OBJECT && IsSamplerType(pdesc.Type)) { return ParamSampler::GetApparentClass(); } return NULL; @@ -356,12 +674,69 @@ bool EffectD3D9::AddParameterMapping( D3DXHANDLE phandle, EffectParamHandlerCacheD3D9* effect_param_cache) { // Array param - if (param->IsA(ParamParamArray::GetApparentClass()) && - pdesc.Elements > 1) { - if (pdesc.Class == D3DXPC_SCALAR && pdesc.Type == D3DXPT_FLOAT) { + if (param->IsA(ParamParamArray::GetApparentClass()) && pdesc.Elements > 0) { + ParamParamArray* param_param_array = down_cast<ParamParamArray*>(param); + if (pdesc.Class == D3DXPC_SCALAR && + pdesc.Type == D3DXPT_FLOAT) { + effect_param_cache->AddElement( + new EffectParamArrayHandlerD3D9<ParamFloat>( + param_param_array, phandle, pdesc.Elements)); + } else if (pdesc.Class == D3DXPC_VECTOR && + pdesc.Type == D3DXPT_FLOAT && + pdesc.Columns == 2) { + effect_param_cache->AddElement( + new EffectParamArrayHandlerD3D9<ParamFloat2>( + param_param_array, phandle, pdesc.Elements)); + } else if (pdesc.Class == D3DXPC_VECTOR && + pdesc.Type == D3DXPT_FLOAT && + pdesc.Columns == 3) { + effect_param_cache->AddElement( + new EffectParamArrayHandlerD3D9<ParamFloat3>( + param_param_array, phandle, pdesc.Elements)); + } else if (pdesc.Class == D3DXPC_VECTOR && + pdesc.Type == D3DXPT_FLOAT && + pdesc.Columns == 4) { + effect_param_cache->AddElement( + new EffectParamArrayHandlerD3D9<ParamFloat4>( + param_param_array, phandle, pdesc.Elements)); + } else if (pdesc.Class == D3DXPC_SCALAR && + pdesc.Type == D3DXPT_INT && + pdesc.Columns == 1) { effect_param_cache->AddElement( - new EffectParamFloatArrayHandlerD3D9( - down_cast<ParamParamArray*>(param), phandle)); + new EffectParamArrayHandlerD3D9<ParamInteger>( + param_param_array, phandle, pdesc.Elements)); + } else if (pdesc.Class == D3DXPC_SCALAR && + pdesc.Type == D3DXPT_BOOL && + pdesc.Columns == 1) { + effect_param_cache->AddElement( + new EffectParamArrayHandlerD3D9<ParamBoolean>( + param_param_array, phandle, pdesc.Elements)); + } else if (pdesc.Class == D3DXPC_MATRIX_COLUMNS) { + effect_param_cache->AddElement( + new EffectParamMatrix4ArrayHandlerD3D9<true>( + param_param_array, phandle, pdesc.Elements)); + } else if (pdesc.Class == D3DXPC_MATRIX_ROWS) { + if (matrix_load_order() == COLUMN_MAJOR) { + // D3D has already created a uniform of type MATRIX_ROWS, but the + // effect wants column major matrices, so we create a handler + // for MATRIX_COLUMNS. This will cause the matrix to be transposed + // on load. + effect_param_cache->AddElement( + new EffectParamMatrix4ArrayHandlerD3D9<true>( + param_param_array, phandle, pdesc.Elements)); + } else { + effect_param_cache->AddElement( + new EffectParamMatrix4ArrayHandlerD3D9<false>( + param_param_array, phandle, pdesc.Elements)); + } + } else if (pdesc.Class == D3DXPC_OBJECT && IsSamplerType(pdesc.Type)) { + effect_param_cache->AddElement( + new EffectParamSamplerArrayHandlerD3D9( + param_param_array, + phandle, + pdesc, + fs_constant_table_, + d3d_device_)); } // Matrix4 Param } else if (param->IsA(ParamMatrix4::GetApparentClass()) && @@ -375,7 +750,7 @@ bool EffectD3D9::AddParameterMapping( if (matrix_load_order() == COLUMN_MAJOR) { // D3D has already created a uniform of type MATRIX_ROWS, but the // effect wants column major matrices, so we create a handler - // for MATRIX_COLUMNS. This will cause the matrix to be tranposed + // for MATRIX_COLUMNS. This will cause the matrix to be transposed // on load. effect_param_cache->AddElement( new TypedEffectParamHandlerD3D9<ParamMatrix4, @@ -453,10 +828,7 @@ bool EffectD3D9::AddParameterMapping( down_cast<ParamTexture*>(param), phandle)); // Sampler param } else if (param->IsA(ParamSampler::GetApparentClass()) && - pdesc.Class == D3DXPC_OBJECT && - (pdesc.Type == D3DXPT_SAMPLER || - pdesc.Type == D3DXPT_SAMPLER2D || - pdesc.Type == D3DXPT_SAMPLERCUBE)) { + pdesc.Class == D3DXPC_OBJECT && IsSamplerType(pdesc.Type)) { effect_param_cache->AddElement( new EffectParamHandlerForSamplersD3D9(down_cast<ParamSampler*>(param), pdesc, @@ -693,24 +1065,6 @@ void TypedEffectParamHandlerD3D9<ParamTexture, } } -void EffectParamFloatArrayHandlerD3D9::SetEffectParam( - RendererD3D9* renderer, - ID3DXEffect* d3dx_effect) { - ParamArray* param = param_->value(); - if (param) { - int size = param->size(); - for (int i = 0; i < size; ++i) { - ParamFloat* element = param->GetParam<ParamFloat>(i); - D3DXHANDLE dx_element = d3dx_effect->GetParameterElement(phandle_, i); - if (element) { - d3dx_effect->SetFloat(dx_element, element->value()); - } else { - d3dx_effect->SetFloat(dx_element, 0.0); - } - } - } -} - void EffectParamHandlerForSamplersD3D9::SetEffectParam( RendererD3D9* renderer, ID3DXEffect* d3dx_effect) { @@ -734,11 +1088,13 @@ void EffectParamHandlerForSamplersD3D9::ResetEffectParam( RendererD3D9* renderer, ID3DXEffect* d3dx_effect) { Sampler* sampler = sampler_param_->value(); - if (sampler) { - SamplerD3D9* d3d_sampler = down_cast<SamplerD3D9*>(sampler); - for (int stage = 0; stage < number_sampler_units_; stage++) { - d3d_sampler->ResetTexture(sampler_unit_index_array_[stage]); - } + if (!sampler) { + sampler = renderer->error_sampler(); + } + + SamplerD3D9* d3d_sampler = down_cast<SamplerD3D9*>(sampler); + for (int stage = 0; stage < number_sampler_units_; stage++) { + d3d_sampler->ResetTexture(sampler_unit_index_array_[stage]); } } @@ -781,9 +1137,7 @@ EffectParamHandlerForSamplersD3D9::EffectParamHandlerForSamplersD3D9( for (UINT desc_index = 0; desc_index < num_desc; desc_index++) { D3DXCONSTANT_DESC constant_desc = desc_array[desc_index]; if (constant_desc.Class == D3DXPC_OBJECT && - (constant_desc.Type == D3DXPT_SAMPLER || - constant_desc.Type == D3DXPT_SAMPLER2D || - constant_desc.Type == D3DXPT_SAMPLERCUBE)) { + IsSamplerType(constant_desc.Type)) { sampler_unit_index_array_[number_sampler_units_++] = constant_desc.RegisterIndex; } diff --git a/o3d/documentation/jsdoc-toolkit-templates/publish.js b/o3d/documentation/jsdoc-toolkit-templates/publish.js index 1890434..d4e102a 100644 --- a/o3d/documentation/jsdoc-toolkit-templates/publish.js +++ b/o3d/documentation/jsdoc-toolkit-templates/publish.js @@ -543,38 +543,35 @@ function linkifySingleType(type) { } } } else if (type.indexOf(':') >= 0) { // check for records. - var elements = type.split(/\s*,\s*/); - var output = '{'; - for (var ii = 0; ii < elements.length; ++ii) { - if (ii > 0) { - output += ', '; - } - var element = elements[ii]; - var colon = element.indexOf(': '); - if (colon < 0) { - print ("WARNING: Malformed record specification. Format must be " + - "{id1: type1, id2: type2, ...}."); - output += element; - } else { - var name = element.substring(0, colon); - var subType = element.substring(colon + 2); - output += name + ': ' + linkifyTypeSpec(subType) + if (type.indexOf('::') >= 0) { // check for CPP scope + print ('WARNING: CPP "::" scope operator found for type "' + type + + '" must be Javascript "." scope operator.'); + } else { + var elements = type.split(/\s*,\s*/); + var output = '{'; + for (var ii = 0; ii < elements.length; ++ii) { + if (ii > 0) { + output += ', '; + } + var element = elements[ii]; + var colon = element.indexOf(': '); + if (colon < 0) { + print ("WARNING: Malformed record specification. Format must be " + + "{id1: type1, id2: type2, ...}."); + output += element; + } else { + var name = element.substring(0, colon); + var subType = element.substring(colon + 2); + output += name + ': ' + linkifyTypeSpec(subType) + } } + link = output + '}'; } - link = output + '}'; } else { var symbol = getSymbol(type); if (symbol) { link = '<a class="el" href="' + getLinkToSymbol(symbol) + '">' + type + '</a>'; - } else if (startsWith(type, 'o3d.')) { - // TODO: remove this hack, make nixysa generate JSDOC js - // files instead of C++ headers and pass those into - // jsdoctoolkit. - reportUnknownType(type); - link = '<a class="el" href="../classo3d_1_1_' + - camelCaseToUnderscore(type.substring(4)) + '.html">' + - type + '</a>'; } else { // See if the symbol is a property or field. var period = type.lastIndexOf('.'); @@ -586,11 +583,21 @@ function linkifySingleType(type) { link = '<a class="el" href="' + getLinkToSymbol(symbol) + '#' + field + '">' + type + '</a>'; } else { - if (subType[0] == '?') { - subType = subType.substring(1); - } - if (!g_validJSDOCTypes[subType]) { + if (startsWith(type, 'o3d.')) { + // TODO(gman): remove this hack, make nixysa generate JSDOC js + // files instead of C++ headers and pass those into + // jsdoctoolkit. reportUnknownType(type); + link = '<a class="el" href="../classo3d_1_1_' + + camelCaseToUnderscore(type.substring(4)) + '.html">' + + type + '</a>'; + } else { + if (subType[0] == '?') { + subType = subType.substring(1); + } + if (!g_validJSDOCTypes[subType]) { + reportUnknownType(type); + } } } } diff --git a/o3d/plugin/idl/client.idl b/o3d/plugin/idl/client.idl index 439f63b..fc92311 100644 --- a/o3d/plugin/idl/client.idl +++ b/o3d/plugin/idl/client.idl @@ -138,7 +138,7 @@ class Client { \param id The id of the object to look for. \return The object or null if a object with the given id is not found. %] - [const] ObjectBase? GetObjectById(Id id); + [const, noreturndocs] ObjectBase? GetObjectById(Id id); %[ Searches the Client for objects of a particular name and type. @@ -146,14 +146,14 @@ class Client { \param class_name name of class to look for. \return Array of objects found. %] - [const] ObjectArray GetObjects(String name, String class_name); + [const, noretundocs] ObjectArray GetObjects(String name, String class_name); %[ Searches the Client for objects of a particular type. \param class_name name of class to look for. \return Array of objects found. %] - [const] ObjectArray GetObjectsByClassName(String class_name); + [const, noreturndocs] ObjectArray GetObjectsByClassName(String class_name); %[ \var RenderMode, diff --git a/o3d/plugin/idl/pack.idl b/o3d/plugin/idl/pack.idl index 460d2c6..4e1e6d5 100644 --- a/o3d/plugin/idl/pack.idl +++ b/o3d/plugin/idl/pack.idl @@ -165,7 +165,7 @@ typedef ObjectBase[] ObjectArray; \li o3d.TRSToMatrix4 \return The created object. %] - ObjectBase? CreateObject(String type_name); + [noreturndocs] ObjectBase? CreateObject(String type_name); %[ Creates a new Texture2D object of the specified size and format and @@ -234,7 +234,8 @@ typedef ObjectBase[] ObjectArray; DrawPasses, etc... \returns Array of Objects. %] - [const] ObjectArray GetObjects(String name, String class_type_name); + [const, noreturndocs] + ObjectArray GetObjects(String name, String class_type_name); %[ Search the pack for all objects of a certain class @@ -248,7 +249,8 @@ typedef ObjectBase[] ObjectArray; DrawPasses, etc... \returns Array of Objects. %] - [const] ObjectArray GetObjectsByClassName(String class_type_name); + [const, noreturndocs] + ObjectArray GetObjectsByClassName(String class_type_name); %[ All the objects managed by this pack. diff --git a/o3d/plugin/mac/main_mac.mm b/o3d/plugin/mac/main_mac.mm index 17f1039..c9dcec0 100644 --- a/o3d/plugin/mac/main_mac.mm +++ b/o3d/plugin/mac/main_mac.mm @@ -903,7 +903,7 @@ extern "C" { if (obj->drawing_model_ == NPDrawingModelOpenGL) { CGLSetCurrentContext(obj->mac_cgl_context_); - } else if (obj->mac_agl_context_ == NULL) { // setup AGL context + } else if (!had_a_window && obj->mac_agl_context_ == NULL) { // setup AGL context AGLPixelFormat myAGLPixelFormat = NULL; // We need to spec out a few similar but different sets of renderer @@ -1075,8 +1075,10 @@ extern "C" { // Renderer is already initialized from a previous call to this function, // just update size and position and return. if (had_a_window) { - obj->renderer()->SetClientOriginOffset(gl_x_origin, gl_y_origin); - obj->Resize(window->width, window->height); + if (obj->renderer()) { + obj->renderer()->SetClientOriginOffset(gl_x_origin, gl_y_origin); + obj->Resize(window->width, window->height); + } return NPERR_NO_ERROR; } @@ -1094,22 +1096,22 @@ extern "C" { ::aglDestroyContext(obj->mac_agl_context_); obj->mac_agl_context_ = NULL; } - return NPERR_NO_ERROR; } obj->client()->Init(); obj->client()->SetRenderOnDemandCallback( new RenderOnDemandCallbackHandler(obj)); - obj->renderer()->SetClientOriginOffset(gl_x_origin, gl_y_origin); - obj->Resize(window->width, window->height); - + if (obj->renderer()) { + obj->renderer()->SetClientOriginOffset(gl_x_origin, gl_y_origin); + obj->Resize(window->width, window->height); #ifdef CFTIMER - // now that the grahics context is setup, add this instance to the timer - // list so it gets drawn repeatedly - gRenderTimer.AddInstance(instance); + // now that the grahics context is setup, add this instance to the timer + // list so it gets drawn repeatedly + gRenderTimer.AddInstance(instance); #endif // CFTIMER + } return NPERR_NO_ERROR; } diff --git a/o3d/plugin/o3d_binding.py b/o3d/plugin/o3d_binding.py index 7d7490c..c0ae572 100644 --- a/o3d/plugin/o3d_binding.py +++ b/o3d/plugin/o3d_binding.py @@ -28,7 +28,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - """o3d binding model module. This module implements the glue functions for the o3d binding model, binding @@ -300,6 +299,21 @@ def CppGetStatic(scope, type_defn, field): cpp_utils.GetGetterName(field)) +def JSDocTypeString(type_defn): + """Gets the representation of a type in JSDoc notation. + + Args: + type_defn: a Definition for the type. + + Returns: + a string that is the JSDoc notation of type_defn. + """ + type_defn = type_defn.GetFinalType() + type_stack = type_defn.GetParentScopeStack() + name = type_defn.name + return '!' + '.'.join([s.name for s in type_stack[1:]] + [name]) + + _binding_glue_header_template = string.Template('') diff --git a/o3d/samples/o3djs/base.js b/o3d/samples/o3djs/base.js index a1cd85f..a68214c 100644 --- a/o3d/samples/o3djs/base.js +++ b/o3d/samples/o3djs/base.js @@ -641,6 +641,17 @@ o3djs.base.maybeDeobfuscateFunctionName_ = function(name) { }; /** + * Makes one class inherit from another. + * @param {!Object} subClass Class that wants to inherit. + * @param {!Object} superClass Class to inherit from. + */ +o3djs.base.inherit = function(subClass, superClass) { + var tmpClass = function() { }; + tmpClass.prototype = superClass.prototype; + subClass.prototype = new tmpClass(); +}; + +/** * Parses an error stack from an exception * @param {!Exception} excp The exception to get a stack trace from. * @return {!Array.<string>} An array of strings of the stack trace. diff --git a/o3d/samples/o3djs/effect.js b/o3d/samples/o3djs/effect.js index d9d22c4..3031cee 100644 --- a/o3d/samples/o3djs/effect.js +++ b/o3d/samples/o3djs/effect.js @@ -737,3 +737,36 @@ o3djs.effect.attachStandardShader = function(pack, } }; +/** + * Creates the uniform parameters needed for an Effect on the given ParamObject. + * @param {!o3d.Pack} pack Pack to create extra objects in like Samplers and + * ParamArrays. + * @param {!o3d.Effect} effect Effect. + * @param {!o3d.ParamObject} paramObject ParamObject on which to create Params. + */ +o3djs.effect.createUniformParameters = function(pack, effect, paramObject) { + effect.createUniformParameters(paramObject); + var infos = effect.getParameterInfo(); + for (var ii = 0; ii < infos.length; ++ii) { + var info = infos[ii]; + if (info.sasClassName.length == 0) { + if (info.numElements > 0) { + var paramArray = pack.createObject('ParamArray'); + var param = paramObject.getParam(info.name); + param.value = paramArray; + paramArray.resize(info.numElements, info.className); + if (info.className == 'o3d.ParamSampler') { + for (var jj = 0; jj < info.numElements; ++jj) { + var sampler = pack.createObject('Sampler'); + paramArray.getParam(jj).value = sampler; + } + } + } else if (info.className == 'o3d.ParamSampler') { + var sampler = pack.createObject('Sampler'); + var param = paramObject.getParam(info.name); + param.value = sampler; + } + } + } +}; + diff --git a/o3d/samples/o3djs/particles.js b/o3d/samples/o3djs/particles.js index 075c363..2b95eda 100644 --- a/o3d/samples/o3djs/particles.js +++ b/o3d/samples/o3djs/particles.js @@ -127,6 +127,7 @@ o3djs.particles.FX_STRINGS = [ ' output.colorMult = input.colorMult;\n' + '\n' + ' float size = lerp(startSize, endSize, percentLife);\n' + + ' size = (percentLife < 0 || percentLife > 1) ? 0 : size;\n' + ' float s = sin(spinStart + spinSpeed * localTime);\n' + ' float c = cos(spinStart + spinSpeed * localTime);\n' + '\n' + @@ -239,6 +240,7 @@ o3djs.particles.FX_STRINGS = [ ' float3 basisZ = viewInverse[1].xyz;\n' + '\n' + ' float size = lerp(startSize, endSize, percentLife);\n' + + ' size = (percentLife < 0 || percentLife > 1) ? 0 : size;\n' + ' float s = sin(spinStart + spinSpeed * localTime);\n' + ' float c = cos(spinStart + spinSpeed * localTime);\n' + '\n' + @@ -269,6 +271,18 @@ o3djs.particles.FX_STRINGS = [ '// #o3d MatrixLoadOrder RowMajor\n'}]; /** + * Corner values. + * @private + * @type {!Array.<!Array.<number>>} + */ +o3djs.particles.CORNERS_ = [ + [-0.5, -0.5], + [+0.5, -0.5], + [+0.5, +0.5], + [-0.5, +0.5]]; + + +/** * Creates a particle system. * You only need one of these to run multiple emitters of different types * of particles. @@ -676,6 +690,42 @@ o3djs.particles.ParticleSystem.prototype.createParticleEmitter = }; /** + * Creates a Trail particle emitter. + * You can use this for jet exhaust, etc... + * @param {!o3d.Transform} parent Transform to put emitter on. + * @param {number} maxParticles Maximum number of particles to appear at once. + * @param {!o3djs.particles.ParticleSpec} parameters The parameters used to + * generate particles. + * @param {!o3d.Texture} opt_texture The texture to use for the particles. + * If you don't supply a texture a default is provided. + * @param {!function(number, !o3djs.particles.ParticleSpec): void} + * opt_perParticleParamSetter A function that is called for each particle to + * allow it's parameters to be adjusted per particle. The number is the + * index of the particle being created, in other words, if numParticles is + * 20 this value will be 0 to 19. The ParticleSpec is a spec for this + * particular particle. You can set any per particle value before returning. + * @param {!o3d.ParamFloat} opt_clockParam A ParamFloat to be the clock for + * the emitter. + * @return {!o3djs.particles.Trail} A Trail object. + */ +o3djs.particles.ParticleSystem.prototype.createTrail = function( + parent, + maxParticles, + parameters, + opt_texture, + opt_perParticleParamSetter, + opt_clockParam) { + return new o3djs.particles.Trail( + this, + parent, + maxParticles, + parameters, + opt_texture, + opt_perParticleParamSetter, + opt_clockParam); +}; + +/** * A ParticleEmitter * @constructor * @param {!o3djs.particles.ParticleSystem} particleSystem The particle system @@ -688,7 +738,6 @@ o3djs.particles.ParticleSystem.prototype.createParticleEmitter = o3djs.particles.ParticleEmitter = function(particleSystem, opt_texture, opt_clockParam) { - opt_clockParam = opt_clockParam || particleSystem.clockParam; var o3d = o3djs.base.o3d; @@ -842,23 +891,29 @@ o3djs.particles.ParticleEmitter.prototype.setColorRamp = function(colorRamp) { }; /** - * Sets the parameters of the particle emitter. - * - * Each of these parameters are in pairs. The used to create a table - * of particle parameters. For each particle a specfic value is - * set like this - * - * particle.field = value + Math.random() - 0.5 * valueRange * 2; - * - * or in English - * - * particle.field = value plus or minus valueRange. - * - * So for example, if you wanted a value from 10 to 20 you'd pass 15 for value - * and 5 for valueRange because - * - * 15 + or - 5 = (10 to 20) - * + * Validates and adds missing particle parameters. + * @param {!o3djs.particles.ParticleSpec} parameters The parameters to validate. + */ +o3djs.particles.ParticleEmitter.prototype.validateParameters = function( + parameters) { + var defaults = new o3djs.particles.ParticleSpec(); + for (var key in parameters) { + if (typeof defaults[key] === 'undefined') { + throw 'unknown particle parameter "' + key + '"'; + } + } + for (var key in defaults) { + if (typeof parameters[key] === 'undefined') { + parameters[key] = defaults[key]; + } + } +}; + +/** + * Creates particles. + * @private + * @param {number} firstParticleIndex Index of first particle to create. + * @param {number} numParticles The number of particles to create. * @param {!o3djs.particles.ParticleSpec} parameters The parameters for the * emitters. * @param {!function(number, !o3djs.particles.ParticleSpec): void} @@ -868,42 +923,28 @@ o3djs.particles.ParticleEmitter.prototype.setColorRamp = function(colorRamp) { * 20 this value will be 0 to 19. The ParticleSpec is a spec for this * particular particle. You can set any per particle value before returning. */ -o3djs.particles.ParticleEmitter.prototype.setParameters = function( +o3djs.particles.ParticleEmitter.prototype.createParticles_ = function( + firstParticleIndex, + numParticles, parameters, opt_perParticleParamSetter) { - var defaults = new o3djs.particles.ParticleSpec(); - for (var key in parameters) { - if (typeof defaults[key] === 'undefined') { - throw 'unknown particle parameter "' + key + '"'; - } - defaults[key] = parameters[key]; - } - - var numParticles = defaults.numParticles; - - var uvLifeTimeFrameStart = []; - var positionStartTime = []; - var velocityStartSize = []; - var accelerationEndSize = []; - var spinStartSpinSpeed = []; - var orientation = []; - var colorMults = []; + var uvLifeTimeFrameStart = this.uvLifeTimeFrameStart_; + var positionStartTime = this.positionStartTime_; + var velocityStartSize = this.velocityStartSize_; + var accelerationEndSize = this.accelerationEndSize_; + var spinStartSpinSpeed = this.spinStartSpinSpeed_; + var orientation = this.orientation_; + var colorMults = this.colorMults_; // Set the globals. this.material.effect = - this.particleSystem.effects[defaults.billboard ? 1 : 0]; - this.material.getParam('timeRange').value = defaults.timeRange; - this.material.getParam('numFrames').value = defaults.numFrames; - this.material.getParam('frameDuration').value = defaults.frameDuration; - this.material.getParam('worldVelocity').value = defaults.worldVelocity; + this.particleSystem.effects[parameters.billboard ? 1 : 0]; + this.material.getParam('timeRange').value = parameters.timeRange; + this.material.getParam('numFrames').value = parameters.numFrames; + this.material.getParam('frameDuration').value = parameters.frameDuration; + this.material.getParam('worldVelocity').value = parameters.worldVelocity; this.material.getParam('worldAcceleration').value = - defaults.worldAcceleration; - - var corners = [ - [-0.5, -0.5], - [+0.5, -0.5], - [+0.5, +0.5], - [-0.5, +0.5]]; + parameters.worldAcceleration; var random = this.particleSystem.randomFunction_; @@ -911,6 +952,7 @@ o3djs.particles.ParticleEmitter.prototype.setParameters = function( return (random() - 0.5) * range * 2; }; + // TODO: change to not allocate. var plusMinusVector = function(range) { var v = []; for (var ii = 0; ii < range.length; ++ii) { @@ -921,44 +963,106 @@ o3djs.particles.ParticleEmitter.prototype.setParameters = function( for (var ii = 0; ii < numParticles; ++ii) { if (opt_perParticleParamSetter) { - opt_perParticleParamSetter(ii, defaults); + opt_perParticleParamSetter(ii, parameters); } - var pLifeTime = defaults.lifeTime; - var pStartTime = (defaults.startTime === null) ? - (ii * defaults.lifeTime / numParticles) : defaults.startTime; - var pFrameStart = defaults.frameStart + plusMinus(defaults.frameStartRange); + var pLifeTime = parameters.lifeTime; + var pStartTime = (parameters.startTime === null) ? + (ii * parameters.lifeTime / numParticles) : parameters.startTime; + var pFrameStart = + parameters.frameStart + plusMinus(parameters.frameStartRange); var pPosition = o3djs.math.addVector( - defaults.position, plusMinusVector(defaults.positionRange)); + parameters.position, plusMinusVector(parameters.positionRange)); var pVelocity = o3djs.math.addVector( - defaults.velocity, plusMinusVector(defaults.velocityRange)); + parameters.velocity, plusMinusVector(parameters.velocityRange)); var pAcceleration = o3djs.math.addVector( - defaults.acceleration, plusMinusVector(defaults.accelerationRange)); + parameters.acceleration, + plusMinusVector(parameters.accelerationRange)); var pColorMult = o3djs.math.addVector( - defaults.colorMult, plusMinusVector(defaults.colorMultRange)); - var pSpinStart = defaults.spinStart + plusMinus(defaults.spinStartRange); - var pSpinSpeed = defaults.spinSpeed + plusMinus(defaults.spinSpeedRange); - var pStartSize = defaults.startSize + plusMinus(defaults.startSizeRange); - var pEndSize = defaults.endSize + plusMinus(defaults.endSizeRange); - var pOrientation = defaults.orientation; + parameters.colorMult, plusMinusVector(parameters.colorMultRange)); + var pSpinStart = + parameters.spinStart + plusMinus(parameters.spinStartRange); + var pSpinSpeed = + parameters.spinSpeed + plusMinus(parameters.spinSpeedRange); + var pStartSize = + parameters.startSize + plusMinus(parameters.startSizeRange); + var pEndSize = parameters.endSize + plusMinus(parameters.endSizeRange); + var pOrientation = parameters.orientation; // make each corner of the particle. for (var jj = 0; jj < 4; ++jj) { - uvLifeTimeFrameStart.push(corners[jj][0], corners[jj][1], pLifeTime, - pFrameStart); - positionStartTime.push( - pPosition[0], pPosition[1], pPosition[2], pStartTime); - velocityStartSize.push( - pVelocity[0], pVelocity[1], pVelocity[2], pStartSize); - accelerationEndSize.push( - pAcceleration[0], pAcceleration[1], pAcceleration[2], pEndSize); - spinStartSpinSpeed.push(pSpinStart, pSpinSpeed, 0, 0); - orientation.push( - pOrientation[0], pOrientation[1], pOrientation[2], pOrientation[3]); - colorMults.push( - pColorMult[0], pColorMult[1], pColorMult[2], pColorMult[3]); + var offset0 = (ii * 4 + jj) * 4; + var offset1 = offset0 + 1; + var offset2 = offset0 + 2; + var offset3 = offset0 + 3; + + uvLifeTimeFrameStart[offset0] = o3djs.particles.CORNERS_[jj][0]; + uvLifeTimeFrameStart[offset1] = o3djs.particles.CORNERS_[jj][1]; + uvLifeTimeFrameStart[offset2] = pLifeTime; + uvLifeTimeFrameStart[offset3] = pFrameStart; + + positionStartTime[offset0] = pPosition[0]; + positionStartTime[offset1] = pPosition[1]; + positionStartTime[offset2] = pPosition[2]; + positionStartTime[offset3] = pStartTime; + + velocityStartSize[offset0] = pVelocity[0]; + velocityStartSize[offset1] = pVelocity[1]; + velocityStartSize[offset2] = pVelocity[2]; + velocityStartSize[offset3] = pStartSize; + + accelerationEndSize[offset0] = pAcceleration[0]; + accelerationEndSize[offset1] = pAcceleration[1]; + accelerationEndSize[offset2] = pAcceleration[2]; + accelerationEndSize[offset3] = pEndSize; + + spinStartSpinSpeed[offset0] = pSpinStart; + spinStartSpinSpeed[offset1] = pSpinSpeed; + spinStartSpinSpeed[offset2] = 0; + spinStartSpinSpeed[offset3] = 0; + + orientation[offset0] = pOrientation[0]; + orientation[offset1] = pOrientation[1]; + orientation[offset2] = pOrientation[2]; + orientation[offset3] = pOrientation[3]; + + colorMults[offset0] = pColorMult[0]; + colorMults[offset1] = pColorMult[1]; + colorMults[offset2] = pColorMult[2]; + colorMults[offset3] = pColorMult[3]; } } + firstParticleIndex *= 4; + this.uvLifeTimeFrameStartField_.setAt( + firstParticleIndex, + uvLifeTimeFrameStart); + this.positionStartTimeField_.setAt( + firstParticleIndex, + positionStartTime); + this.velocityStartSizeField_.setAt( + firstParticleIndex, + velocityStartSize); + this.accelerationEndSizeField_.setAt( + firstParticleIndex, + accelerationEndSize); + this.spinStartSpinSpeedField_.setAt( + firstParticleIndex, + spinStartSpinSpeed); + this.orientationField_.setAt( + firstParticleIndex, + orientation); + this.colorMultField_.setAt( + firstParticleIndex, + colorMults); +}; + +/** + * Allocates particles. + * @private + * @param {number} numParticles Number of particles to allocate. + */ +o3djs.particles.ParticleEmitter.prototype.allocateParticles_ = function( + numParticles) { if (this.vertexBuffer_.numElements != numParticles * 4) { this.vertexBuffer_.allocateElements(numParticles * 4); @@ -970,21 +1074,65 @@ o3djs.particles.ParticleEmitter.prototype.setParameters = function( indices.push(startIndex + 0, startIndex + 2, startIndex + 3); } this.indexBuffer_.set(indices); - } - this.uvLifeTimeFrameStartField_.setAt(0, uvLifeTimeFrameStart); - this.positionStartTimeField_.setAt(0, positionStartTime); - this.velocityStartSizeField_.setAt(0, velocityStartSize); - this.accelerationEndSizeField_.setAt(0, accelerationEndSize); - this.spinStartSpinSpeedField_.setAt(0, spinStartSpinSpeed); - this.orientationField_.setAt(0, orientation); - this.colorMultField_.setAt(0, colorMults); + // We keep these around to avoid memory allocations for trails. + this.uvLifeTimeFrameStart_ = []; + this.positionStartTime_ = []; + this.velocityStartSize_ = []; + this.accelerationEndSize_ = []; + this.spinStartSpinSpeed_ = []; + this.orientation_ = []; + this.colorMults_ = []; + } this.primitive_.numberPrimitives = numParticles * 2; this.primitive_.numberVertices = numParticles * 4; }; /** + * Sets the parameters of the particle emitter. + * + * Each of these parameters are in pairs. The used to create a table + * of particle parameters. For each particle a specfic value is + * set like this + * + * particle.field = value + Math.random() - 0.5 * valueRange * 2; + * + * or in English + * + * particle.field = value plus or minus valueRange. + * + * So for example, if you wanted a value from 10 to 20 you'd pass 15 for value + * and 5 for valueRange because + * + * 15 + or - 5 = (10 to 20) + * + * @param {!o3djs.particles.ParticleSpec} parameters The parameters for the + * emitters. + * @param {!function(number, !o3djs.particles.ParticleSpec): void} + * opt_perParticleParamSetter A function that is called for each particle to + * allow it's parameters to be adjusted per particle. The number is the + * index of the particle being created, in other words, if numParticles is + * 20 this value will be 0 to 19. The ParticleSpec is a spec for this + * particular particle. You can set any per particle value before returning. + */ +o3djs.particles.ParticleEmitter.prototype.setParameters = function( + parameters, + opt_perParticleParamSetter) { + this.validateParameters(parameters); + + var numParticles = parameters.numParticles; + + this.allocateParticles_(numParticles); + + this.createParticles_( + 0, + numParticles, + parameters, + opt_perParticleParamSetter); +}; + +/** * Creates a OneShot particle emitter instance. * You can use this for dust puffs, explosions, fireworks, etc... * @param {!o3d.Transform} opt_parent The parent for the oneshot. @@ -1049,3 +1197,81 @@ o3djs.particles.OneShot.prototype.trigger = function(opt_position, opt_parent) { this.transform.visible = true; this.timeOffsetParam_.value = this.emitter_.clockParam.value; }; + +/** + * A type of emitter to use for particle effects that leave trails like exhaust. + * @constructor + * @param {!o3djs.particles.ParticleSystem} particleSystem The particle system + * to manage this emitter. + * @param {!o3d.Transform} parent Transform to put emitter on. + * @param {number} maxParticles Maximum number of particles to appear at once. + * @param {!o3djs.particles.ParticleSpec} parameters The parameters used to + * generate particles. + * @param {!o3d.Texture} opt_texture The texture to use for the particles. + * If you don't supply a texture a default is provided. + * @param {!function(number, !o3djs.particles.ParticleSpec): void} + * opt_perParticleParamSetter A function that is called for each particle to + * allow it's parameters to be adjusted per particle. The number is the + * index of the particle being created, in other words, if numParticles is + * 20 this value will be 0 to 19. The ParticleSpec is a spec for this + * particular particle. You can set any per particle value before returning. + * @param {!o3d.ParamFloat} opt_clockParam A ParamFloat to be the clock for + * the emitter. + */ +o3djs.particles.Trail = function( + particleSystem, + parent, + maxParticles, + parameters, + opt_texture, + opt_perParticleParamSetter, + opt_clockParam) { + o3djs.particles.ParticleEmitter.call( + this, particleSystem, opt_texture, opt_clockParam); + + var pack = particleSystem.pack; + + this.allocateParticles_(maxParticles); + this.validateParameters(parameters); + + this.parameters = parameters; + this.perParticleParamSetter = opt_perParticleParamSetter; + this.birthIndex_ = 0; + this.maxParticles_ = maxParticles; + + /** + * Transform for OneShot. + * @type {!o3d.Transform} + */ + this.transform = pack.createObject('Transform'); + this.transform.addShape(this.shape); + + this.transform.parent = parent; +}; + +o3djs.base.inherit(o3djs.particles.Trail, o3djs.particles.ParticleEmitter); + +/** + * Births particles from this Trail. + * @param {!o3djs.math.Vector3} position Position to birth particles at. + */ +o3djs.particles.Trail.prototype.birthParticles = function(position) { + var numParticles = this.parameters.numParticles; + this.parameters.startTime = this.clockParam.value; + this.parameters.position = position; + while (this.birthIndex_ + numParticles >= this.maxParticles_) { + var numParticlesToEnd = this.maxParticles_ - this.birthIndex_; + this.createParticles_(this.birthIndex_, + numParticlesToEnd, + this.parameters, + this.perParticleParamSetter); + numParticles -= numParticlesToEnd; + this.birthIndex_ = 0; + } + this.createParticles_(this.birthIndex_, + numParticles, + this.parameters, + this.perParticleParamSetter); + this.birthIndex_ += numParticles; +}; + diff --git a/o3d/samples/o3djs/serialization.js b/o3d/samples/o3djs/serialization.js index a8b4ea5..4e00f84 100644 --- a/o3d/samples/o3djs/serialization.js +++ b/o3d/samples/o3djs/serialization.js @@ -65,13 +65,39 @@ o3djs.serialization.supportedVersion = 5; */ o3djs.serialization.Options = goog.typedef; +o3djs.serialization.SceneInfo = function() { + /** + * Extra information from json file. + * type {!Object} + */ + // TODO: It's probably better to just put extra info in a separate file + // in the archive. Though, maybe the code in this file should look it up + // like look for 'extra.json' and attach it here, saving the user from + // having to do it manually. + this.extra = { }; + + /** + * The json that represents the parts the need to be created to make an + * instance of the scene. + * type {!Object} + */ + this.sceneJson = { }; + + /** + * Objects by Id that can be reused for instancing. + * type {!Array.<!Object>} + */ + this.objectsById_ = []; +}; + /** * A Deserializer incrementally deserializes a transform graph. * @constructor + * @param {!o3djs.io.archiveInfo} archiveInfo Archive to load from. * @param {!o3d.Pack} pack The pack to deserialize into. * @param {!Object} json An object tree conforming to the JSON rules. */ -o3djs.serialization.Deserializer = function(pack, json) { +o3djs.serialization.Deserializer = function(archiveInfo, pack, json) { /** * The pack to deserialize into. * @type {!o3d.Pack} @@ -86,9 +112,16 @@ o3djs.serialization.Deserializer = function(pack, json) { /** * The archive from which assets referenced from JSON are retreived. - * @type {o3djs.io.ArchiveInfo} + * @type {!o3djs.io.ArchiveInfo} */ - this.archiveInfo = null; + this.archiveInfo = archiveInfo; + + /** + * Array of objects by id that have already been created during a previous + * deserialization. + * @type {!Array.<!Object>} + */ + this.preLoadedObjectsById = []; /** * A map from classname to a function that will create @@ -140,13 +173,12 @@ o3djs.serialization.Deserializer = function(pack, json) { } return object; }, - 'o3d.Texture2D': function(deserializer, json) { if ('o3d.uri' in json.params) { var uri = json.params['o3d.uri'].value; var rawData = deserializer.archiveInfo.getFileByURI(uri); if (!rawData) { - throw 'Could not find texture ' + uri + ' in the archive'; + throw 'Could not find texture "' + uri + '" in the archive'; } return deserializer.pack.createTextureFromRawData( rawData, @@ -168,9 +200,7 @@ o3djs.serialization.Deserializer = function(pack, json) { if (!rawData) { throw 'Could not find texture ' + uri + ' in the archive'; } - return deserializer.pack.createTextureFromRawData( - rawData, - true); + return deserializer.pack.createTextureFromRawData(rawData, true); } else { return deserializer.pack.createTextureCUBE( json.custom.edgeLength, @@ -223,13 +253,13 @@ o3djs.serialization.Deserializer = function(pack, json) { if ('custom' in json) { for (var i = 0; i < json.custom.vertexStreams.length; ++i) { var streamJson = json.custom.vertexStreams[i]; - var field = deserializer.getObjectById(streamJson.stream.field); + var field = deserializer.getO3DObjectById(streamJson.stream.field); object.setVertexStream(streamJson.stream.semantic, streamJson.stream.semanticIndex, field, streamJson.stream.startIndex); if ('bind' in streamJson) { - var source = deserializer.getObjectById(streamJson.bind); + var source = deserializer.getO3DObjectById(streamJson.bind); object.bindStream(source, streamJson.stream.semantic, streamJson.stream.semanticIndex); @@ -242,13 +272,13 @@ o3djs.serialization.Deserializer = function(pack, json) { if ('custom' in json) { for (var i = 0; i < json.custom.vertexStreams.length; ++i) { var streamJson = json.custom.vertexStreams[i]; - var field = deserializer.getObjectById(streamJson.stream.field); + var field = deserializer.getO3DObjectById(streamJson.stream.field); object.setVertexStream(streamJson.stream.semantic, streamJson.stream.semanticIndex, field, streamJson.stream.startIndex); if ('bind' in streamJson) { - var source = deserializer.getObjectById(streamJson.bind); + var source = deserializer.getO3DObjectById(streamJson.bind); object.bindStream(source, streamJson.stream.semantic, streamJson.stream.semanticIndex); @@ -273,19 +303,27 @@ o3djs.serialization.Deserializer = function(pack, json) { } /** - * An array of all objects deserialized so far, indexed by object id. Id zero - * means null. + * An array of all O3D objects deserialized so far, indexed by object id. Id + * zero means null. * @type {!Array.<(Object|undefined)>} * @private */ - this.objectsById_ = [null]; + this.o3dObjectsById_ = [null]; + + /** + * An array of O3D objects deserialized so far, indexed by position in the + * JSON. + * @type {!Array.<Object>} + * @private + */ + this.o3dObjectsByIndex_ = []; /** - * An array of objects deserialized so far, indexed by position in the JSON. + * An array of all json objects by id. * @type {!Array.<Object>} * @private */ - this.objectsByIndex_ = []; + this.jsonObjectsById_ = []; /** * Array of all classes present in the JSON. @@ -293,8 +331,15 @@ o3djs.serialization.Deserializer = function(pack, json) { * @private */ this.classNames_ = []; + + // TODO: This may be too slow and need to be moved to a phase. for (var className in json.objects) { this.classNames_.push(className); + var jsonObjects = json.objects[className]; + for (var jj = 0; jj < jsonObjects.length; ++jj) { + var jsonObject = jsonObjects[jj]; + this.jsonObjectsById_[jsonObject.id] = jsonObject; + } } /** @@ -333,8 +378,8 @@ o3djs.serialization.Deserializer = function(pack, json) { * @param {number} id The id to lookup. * @return {(Object|undefined)} The object with the given id. */ -o3djs.serialization.Deserializer.prototype.getObjectById = function(id) { - return this.objectsById_[id]; +o3djs.serialization.Deserializer.prototype.getO3DObjectById = function(id) { + return this.o3dObjectsById_[id]; }; /** @@ -346,7 +391,7 @@ o3djs.serialization.Deserializer.prototype.getObjectById = function(id) { */ o3djs.serialization.Deserializer.prototype.addObject = function( id, object) { - this.objectsById_[id] = object; + this.o3dObjectsById_[id] = object; }; /** @@ -373,7 +418,7 @@ o3djs.serialization.Deserializer.prototype.deserializeValue = function( var refId = valueAsObject['ref']; if (refId !== undefined) { - var referenced = this.objectsById_[refId]; + var referenced = this.getO3DObjectById(refId); if (referenced === undefined) { throw 'Could not find object with id ' + refId + '.'; } @@ -404,7 +449,7 @@ o3djs.serialization.Deserializer.prototype.setParamValue_ = function( var bindId = propertyJson['bind']; if (bindId !== undefined) { - var referenced = this.objectsById_[bindId]; + var referenced = this.getO3DObjectById(bindId); if (referenced === undefined) { throw 'Could not find output param with id ' + bindId + '.'; } @@ -432,7 +477,7 @@ o3djs.serialization.Deserializer.prototype.createAndIdentifyParam_ = var paramId = propertyJson['id']; if (paramId !== undefined && param !== null) { - this.objectsById_[paramId] = param; + this.o3dObjectsById_[paramId] = param; } }; @@ -458,7 +503,7 @@ o3djs.serialization.Deserializer.prototype.createObjectsPhase_ = var objectJson = classJson[this.nextObjectIndex_]; var object = undefined; if ('id' in objectJson) { - object = this.objectsById_[objectJson.id]; + object = this.getO3DObjectById(objectJson.id); } if (object === undefined) { if (className in this.createCallbacks) { @@ -467,9 +512,9 @@ o3djs.serialization.Deserializer.prototype.createObjectsPhase_ = object = this.pack.createObject(className); } } - this.objectsByIndex_[this.globalObjectIndex_++] = object; + this.o3dObjectsByIndex_[this.globalObjectIndex_++] = object; if ('id' in objectJson) { - this.objectsById_[objectJson.id] = object; + this.o3dObjectsById_[objectJson.id] = object; } if ('params' in objectJson) { if ('length' in objectJson.params) { @@ -516,7 +561,7 @@ o3djs.serialization.Deserializer.prototype.setPropertiesPhase_ = function( return; var objectJson = classJson[this.nextObjectIndex_]; - var object = this.objectsByIndex_[this.globalObjectIndex_++]; + var object = this.o3dObjectsByIndex_[this.globalObjectIndex_++]; if ('properties' in objectJson) { for (var propertyName in objectJson.properties) { if (propertyName in object) { @@ -646,23 +691,26 @@ o3djs.serialization.Deserializer.prototype.runBackground = function( * called run that does a fixed amount of work and returns. * It returns true until the transform graph is fully deserialized. * It returns false from then on. + * @param {!o3djs.io.archiveInfo} archiveInfo Archive to load from. * @param {!o3d.Pack} pack The pack to create the deserialized * objects in. * @param {!Object} json An object tree conforming to the JSON rules. * @return {!o3djs.serialization.Deserializer} A deserializer object. */ -o3djs.serialization.createDeserializer = function(pack, json) { - return new o3djs.serialization.Deserializer(pack, json); +o3djs.serialization.createDeserializer = function(archiveInfo, pack, json) { + return new o3djs.serialization.Deserializer(archiveInfo, pack, json); }; /** * Deserializes a transform graph. + * @param {!o3djs.io.archiveInfo} archiveInfo Archive to load from. * @param {!o3d.Pack} pack The pack to create the deserialized * objects in. * @param {!Object} json An object tree conforming to the JSON rules. */ -o3djs.serialization.deserialize = function(pack, json) { - var deserializer = o3djs.serialization.createDeserializer(pack, json); +o3djs.serialization.deserialize = function(archiveInfo, pack, json) { + var deserializer = o3djs.serialization.createDeserializer( + archiveInfo, pack, json); deserializer.run(); }; @@ -675,6 +723,87 @@ o3djs.serialization.deserialize = function(pack, json) { * @param {!o3d.Client} client An O3D client object. * @param {!o3d.Pack} pack The pack to create the deserialized objects * in. + * @param {!function(!o3djs.serialization.SceneInfo, *): void} callback A + * function that will be called when deserialization is finished. It will be + * passed an o3djs.serialization.SceneInfo, and an exception which will be + * null on success. + * @param {!o3djs.serialization.Options} opt_options Options. + */ +o3djs.serialization.deserializeArchiveForInstaning = function(archiveInfo, + sceneJsonUri, + client, + pack, + callback, + opt_options) { + opt_options = opt_options || { }; + var jsonFile = archiveInfo.getFileByURI(sceneJsonUri); + if (!jsonFile) { + throw 'Could not find ' + sceneJsonUri + ' in archive'; + } + var parsed = eval('(' + jsonFile.stringValue + ')'); + var deserializer = o3djs.serialization.createDeserializer( + archiveInfo, pack, parsed); + + var names = { + 'o3d.VertexBuffer': true, + 'o3d.SourceBuffer': true, + 'o3d.IndexBuffer': true, + 'o3d.Skin': true, + 'o3d.Curve': true, + 'o3d.Effect': true, + 'o3d.Material': true, + }; + + var finishCallback = function(pack, exception) { + if (!exception) { + var objects = pack.getObjects('o3d.animSourceOwner', 'o3d.ParamObject'); + if (objects.length > 0) { + // Rebind the output connections of the animSource to the user's param. + if (opt_options.opt_animSource) { + var animSource = objects[0].getParam('animSource'); + var outputConnections = animSource.outputConnections; + for (var ii = 0; ii < outputConnections.length; ++ii) { + outputConnections[ii].bind(opt_options.opt_animSource); + } + } + // Remove special object from pack. + for (var ii = 0; ii < objects.length; ++ii) { + pack.removeObject(objects[ii]); + } + } + } + callback(pack, parent, exception); + }; + + if (opt_options.opt_async) { + // TODO: Remove the 5. See deserializer.runBackground comments. + deserializer.runBackground(client, pack, 5, finishCallback); + } else { + var exception = null; + var errorCollector = o3djs.error.createErrorCollector(client); + try { + deserializer.run(); + } catch (e) { + exception = e; + } + if (errorCollector.errors.length > 0) { + exception = errorCollector.errors.join('\n') + + (exception ? ('\n' + exception.toString()) : ''); + } + errorCollector.finish(); + finishCallback(pack, exception); + } +}; + +/** + * Deserializes a single json object named 'scene.json' from a loaded + * o3djs.io.ArchiveInfo. + * @param {!o3djs.io.archiveInfo} archiveInfo Archive to load from. + * @param {string} sceneJsonUri The relative URI of the scene JSON file within + * the archive. + * @param {!o3d.Client} client An O3D client object. + * @param {!o3d.Pack} pack The pack to create the deserialized objects + * in. * @param {!o3d.Transform} parent Transform to parent loaded stuff from. * @param {!function(!o3d.Pack, !o3d.Transform, *): void} callback A function * that will be called when deserialization is finished. It will be passed @@ -695,10 +824,10 @@ o3djs.serialization.deserializeArchive = function(archiveInfo, throw 'Could not find ' + sceneJsonUri + ' in archive'; } var parsed = eval('(' + jsonFile.stringValue + ')'); - var deserializer = o3djs.serialization.createDeserializer(pack, parsed); + var deserializer = o3djs.serialization.createDeserializer( + archiveInfo, pack, parsed); deserializer.addObject(parsed.o3d_rootObject_root, parent); - deserializer.archiveInfo = archiveInfo; var finishCallback = function(pack, exception) { if (!exception) { diff --git a/o3d/samples/o3djs/simple.js b/o3d/samples/o3djs/simple.js index 8bb729b..9aa0157 100644 --- a/o3d/samples/o3djs/simple.js +++ b/o3d/samples/o3djs/simple.js @@ -29,7 +29,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - /** * @fileoverview This file contains functions to make it extremely simple * to get something on the screen in o3d. The disadvantage is it @@ -87,6 +86,8 @@ o3djs.require('o3djs.rendergraph'); o3djs.require('o3djs.pack'); o3djs.require('o3djs.primitives'); o3djs.require('o3djs.io'); +o3djs.require('o3djs.scene'); +o3djs.require('o3djs.camera'); /** * A Module for using o3d in a very simple way. @@ -140,16 +141,52 @@ o3djs.simple.create = function(clientObject) { * @param {!Element} clientObject O3D.Plugin Object. */ o3djs.simple.SimpleInfo = function(clientObject) { + /** + * The O3D Element. + * @type {!Element} + */ this.clientObject = clientObject; + + /** + * The O3D namespace object. + * @type {!o3d} + */ this.o3d = clientObject.o3d; - this.math = o3djs.math; + + /** + * The client object used by the SimpleInfo + * @type {!o3d.Client} + */ this.client = clientObject.client; + + /** + * The main pack for this SimpleInfo. + * @type {!o3d.Pack} + */ this.pack = this.client.createPack(); + + /** + * The root transform for this SimpleInfo + * @type {!o3d.Transform} + */ + this.root = this.pack.createObject('Transform'); + + /** + * The ViewInfo created by this SimpleInfo. + * @type {!o3d.ViewInfo} + */ this.viewInfo = o3djs.rendergraph.createBasicView( this.pack, - this.client.root, + this.root, this.client.renderGraphRoot); - this.id = 0; + + + /** + * The list of objects that need to have an update function called. + * @private + * @type {!Array.<!o3djs.simple.SimpleObject>} + */ + this.updateObjects_ = { }; // Create 1 non-textured material and 1 textured material. // @@ -171,7 +208,7 @@ o3djs.simple.SimpleInfo = function(clientObject) { [0, 0, 0], 'phong'); - this.nonTexturedEffect = material.effect; + this.nonTexturedEffect_ = material.effect; this.pack.removeObject(material); var material = this.pack.createObject('Material'); @@ -181,7 +218,7 @@ o3djs.simple.SimpleInfo = function(clientObject) { [0, 0, 0], 'phong'); - this.texturedEffect = material.effect; + this.texturedEffect_ = material.effect; this.pack.removeObject(material); this.globalParamObject = this.pack.createObject('ParamObject'); @@ -195,7 +232,7 @@ o3djs.simple.SimpleInfo = function(clientObject) { // Attempt to setup a resonable default perspective matrix. this.zNear = 0.1; this.zFar = 1000; - this.fieldOfView = this.math.degToRad(45); + this.fieldOfView = o3djs.math.degToRad(45); this.setPerspectiveMatrix_(); // Attempt to setup a resonable default view. @@ -203,22 +240,50 @@ o3djs.simple.SimpleInfo = function(clientObject) { this.cameraTarget = [0, 0, 0]; this.cameraUp = [0, 1, 0]; this.setViewMatrix_(); + + var that = this; + + this.client.setRenderCallback(function(renderEvent) { + that.onRender(renderEvent.elapsedTime); + }); }; /** * Creates a SimpleShape. A SimpleShape manages a transform with 1 shape that * holds 1 primitive and 1 unique material. * @param {!o3d.Shape} shape that holds 1 primitive and 1 unique material. - * @param {!o3d.Material} material assigned to shape. * @return {!o3djs.simple.SimpleShape} the created SimpleShape. */ -o3djs.simple.SimpleInfo.prototype.createSimpleShape = function(shape, - material) { +o3djs.simple.SimpleInfo.prototype.createSimpleShape = function(shape) { shape.createDrawElements(this.pack, null); var transform = this.pack.createObject('Transform'); - transform.parent = this.client.root; + transform.parent = this.root; transform.addShape(shape); - return new o3djs.simple.SimpleShape(this, transform, material); + return new o3djs.simple.SimpleShape(this, transform); +}; + +o3djs.simple.SimpleInfo.prototype.onRender = function(elapsedTime) { + for (var simpleObject in this.updateObjects_) { + simpleObject.onUpdate(elapsedTime); + } +}; + +/** + * Register an object for updating. You should not call this directly. + * @param {!o3djs.simple.SimpleObject} simpleObject SimpleObject to register. + */ +o3djs.simple.SimpleInfo.prototype.registerObjectForUpdate = + function (simpleObject) { + this.updateObjects_[simpleObject] = true; +}; + +/** + * Unregister an object for updating. You should not call this directly. + * @param {!o3djs.simple.SimpleObject} simpleObject SimpleObject to register. + */ +o3djs.simple.SimpleInfo.prototype.unregisterObjectForUpdate = + function (simpleObject) { + delete this.updateObjects_[simpleObject]; }; /** @@ -226,7 +291,7 @@ o3djs.simple.SimpleInfo.prototype.createSimpleShape = function(shape, * @private */ o3djs.simple.SimpleInfo.prototype.setPerspectiveMatrix_ = function() { - this.viewInfo.drawContext.projection = this.math.matrix4.perspective( + this.viewInfo.drawContext.projection = o3djs.math.matrix4.perspective( this.fieldOfView, this.client.width / this.client.height, this.zNear, @@ -238,7 +303,7 @@ o3djs.simple.SimpleInfo.prototype.setPerspectiveMatrix_ = function() { * @private */ o3djs.simple.SimpleInfo.prototype.setViewMatrix_ = function() { - this.viewInfo.drawContext.view = this.math.matrix4.lookAt( + this.viewInfo.drawContext.view = o3djs.math.matrix4.lookAt( this.cameraPosition, this.cameraTarget, this.cameraUp); @@ -344,7 +409,7 @@ o3djs.simple.SimpleInfo.prototype.createMaterialFromEffect = */ o3djs.simple.SimpleInfo.prototype.createNonTexturedMaterial = function(type) { - var material = this.createMaterialFromEffect(this.nonTexturedEffect); + var material = this.createMaterialFromEffect(this.nonTexturedEffect_); material.getParam('diffuse').set(1, 1, 1, 1); material.getParam('emissive').set(0, 0, 0, 1); material.getParam('ambient').set(0, 0, 0, 1); @@ -359,7 +424,7 @@ o3djs.simple.SimpleInfo.prototype.createNonTexturedMaterial = */ o3djs.simple.SimpleInfo.prototype.createTexturedMaterial = function(type) { - var material = this.createMaterialFromEffect(this.texturedEffect); + var material = this.createMaterialFromEffect(this.texturedEffect_); var samplerParam = material.getParam('diffuseSampler'); var sampler = this.pack.createObject('Sampler'); samplerParam.value = sampler; @@ -375,7 +440,7 @@ o3djs.simple.SimpleInfo.prototype.createTexturedMaterial = o3djs.simple.SimpleInfo.prototype.createCube = function(size) { var material = this.createNonTexturedMaterial('phong'); var shape = o3djs.primitives.createCube(this.pack, material, size); - return this.createSimpleShape(shape, material); + return this.createSimpleShape(shape); }; /** @@ -395,7 +460,7 @@ o3djs.simple.SimpleInfo.prototype.createBox = function(width, width, height, depth); - return this.createSimpleShape(shape, material); + return this.createSimpleShape(shape); }; /** @@ -414,35 +479,57 @@ o3djs.simple.SimpleInfo.prototype.createSphere = function(radius, radius, smoothness * 2, smoothness); - return this.createSimpleShape(shape, material); + return this.createSimpleShape(shape); }; /** * Loads a scene from a URL. - * TODO: Implement * @param {string} url Url of scene to load. - * @return {!o3djs.simple.Scene} A Javascript object to manage the scene. + * @param {!function(o3djs.simple.SimpleScene, *): void} a callback to + * call when the scene is loaded. The first argument will be null if the + * scene failed to load and last object will be an exception. + * @return {!o3djs.io.loadInfo} */ -o3djs.simple.SimpleInfo.prototype.loadScene = function(url) { - if (true) { - throw('not implemented'); - } - return null; +o3djs.simple.SimpleInfo.prototype.loadScene = function(url, callback) { + var pack = this.client.createPack(); + var root = pack.createObject('Transform'); + var paramObject = pack.createObject('ParamObject'); + var animTimeParam = paramObject.createParam('animTime', 'ParamFloat'); + var that = this; + + var prepScene = function(pack, root, exception) { + var simpleScene = null; + if (exception) { + pack.destroy(); + } else { + simpleScene = new o3djs.simple.SimpleScene( + that, url, pack, root, paramObject); + } + callback(simpleScene, exception); + }; + + return o3djs.scene.loadScene( + this.client, + pack, + root, + url, + prepScene, + {opt_animSource: animTimeParam}); }; /** * Moves the camera so everything in the current scene is visible. */ o3djs.simple.SimpleInfo.prototype.viewAll = function() { - var bbox = o3djs.util.getBoundingBoxOfTree(this.client.root); - var target = this.math.lerpVector(bbox.minExtent, bbox.maxExtent, 0.5); + var bbox = o3djs.util.getBoundingBoxOfTree(this.root); + var target = o3djs.math.lerpVector(bbox.minExtent, bbox.maxExtent, 0.5); this.setCameraTarget(target[0], target[1], target[2]); // TODO: Refactor this so it takes a vector from the current camera // position to the center of the scene and moves the camera along that // vector away from the center of the scene until for the given fieldOfView // everything is visible. - var diag = this.math.distance(bbox.minExtent, bbox.maxExtent); - var eye = this.math.addVector(target, [ + var diag = o3djs.math.distance(bbox.minExtent, bbox.maxExtent); + var eye = o3djs.math.addVector(target, [ bbox.maxExtent[0], bbox.minExtent[1] + 0.5 * diag, bbox.maxExtent[2]]); @@ -451,32 +538,100 @@ o3djs.simple.SimpleInfo.prototype.viewAll = function() { }; /** - * A SimpleShape manages a transform with 1 shape that holds 1 primitive - * and 1 unique material. + * An object for managing things simply. * @constructor - * @param {!o3djs.simple.SimpleInfo} simpleInfo SimpleInfo to manage this shape. - * @param {!o3d.Transform} transform Transform with 1 shape that holds 1 - * primitive and 1 unique material. - * @param {!o3d.Material} material assigned to shape. */ -o3djs.simple.SimpleShape = function(simpleInfo, transform, material) { +o3djs.simple.SimpleObject = function() { +}; + +/** + * @param {!o3djs.simple.SimpleInfo} simpleInfo The SimpleInfo to manage this + * object. + * @param {!o3d.Transform} transform Transform that orients this object. + */ +o3djs.simple.SimpleObject.prototype.init = function(simpleInfo, transform) { /** - * The SimpleInfo managing this SimpleShape. + * The SimpleInfo managing this object. * @type {!o3djs.simple.SimpleInfo} */ this.simpleInfo = simpleInfo; /** - * The transform for this SimpleShape. + * The Transform that orients this object. * @type {!o3d.Transform} */ this.transform = transform; /** - * The material for this SimpleShape. - * @type {!o3d.Material} + * The update callback for this object. + * @private + * @type {function(number): void} */ - this.material = material; + this.updateCallback_ = null; + + /** + * The pick callback for this object. + * @private + * @type {function(number): void} + */ + this.pickCallback_ = null; +}; + +o3djs.simple.SimpleObject.prototype.onPicked = function(onPickedCallback) { +}; + +/** + * Used to call the update callback on this object. You should not call this + * directly. Use o3djs.simple.SimpleObject.setOnUpdate to add your own update + * callback. + * @param {number} elapsedTime ElapsedTime in seconds for this frame. + * @see o3djs.simple.SimpleObject.setOnUpdate + */ +o3djs.simple.SimpleObject.prototype.onUpdate = function(elapsedTime) { + if (this.updateCallback_) { + this.updateCallback_(elapsedTime); + } +}; + +/** + * Sets a function to be called every frame for this object. + * @param {function(number): void} onUpdateCallback A function that is passed + * the elapsed time in seconds. Pass in null to clear the callback function. + * @return {function(number): void} The previous callback function. + */ +o3djs.simple.SimpleObject.prototype.setOnUpdate = function(onUpdateCallback) { + if (onUpdateCallback) { + this.simpleInfo.registerObjectForUpdate(this); + } else { + this.simpleInfo.unregisterObjectForUpdate(this); + } + var oldCallback = this.updateCallback_; + this.updateCallback_ = onUpdateCallback; + return oldCallback; +}; + +/** + * A SimpleShape manages a transform with 1 shape that holds 1 primitive + * and 1 unique material. + * @constructor + * @extends o3djs.simple.SimpleObject + * @param {!o3djs.simple.SimpleInfo} simpleInfo The SimpleInfo to manage this + * shape. + * @param {!o3d.Transform} transform Transform with 1 shape that holds 1 + * primitive and 1 unique material. + */ +o3djs.simple.SimpleShape = function(simpleInfo, transform) { + this.init(simpleInfo, transform); +}; + +o3djs.simple.SimpleShape.prototype = new o3djs.simple.SimpleObject(); + +/** + * Gets the current material for this shape. + * @return {!o3d.Material} the material for this SimpleShape. + */ +o3djs.simple.SimpleShape.prototype.getMaterial = function() { + return this.transform.shapes[0].elements[0].material; }; /** @@ -484,10 +639,11 @@ o3djs.simple.SimpleShape = function(simpleInfo, transform, material) { * @param {!o3d.Material} material new material. */ o3djs.simple.SimpleShape.prototype.setMaterial = function(material) { - var old_material = this.material; - this.simpleInfo.pack.removeObject(old_material); + var old_material = this.getMaterial(); + if (old_material != null) { + this.simpleInfo.pack.removeObject(old_material); + } this.transform.shapes[0].elements[0].material = material; - this.material = material; }; /** @@ -499,7 +655,7 @@ o3djs.simple.SimpleShape.prototype.setMaterial = function(material) { */ o3djs.simple.SimpleShape.prototype.setDiffuseColor = function(r, g, b, a) { - var material = this.material; + var material = this.getMaterial(); material.getParam('diffuse').set(r, g, b, a); if (a < 1) { material.drawList = this.simpleInfo.viewInfo.zOrderedDrawList; @@ -513,7 +669,7 @@ o3djs.simple.SimpleShape.prototype.setDiffuseColor = * @return {o3d.Texture} The texture on this shape. May be null. */ o3djs.simple.SimpleShape.prototype.getTexture = function() { - var material = this.material; + var material = this.getMaterial(); var samplerParam = material.getParam('diffuseSampler'); if (samplerParam.className == 'o3d.ParamSampler') { return samplerParam.texture; @@ -537,14 +693,14 @@ o3djs.simple.SimpleShape.prototype.loadTexture = function(url) { function(texture, exception) { if (!exception) { // See if this is a textured material. - var material = that.material; - if (material.effect != that.simpleInfo.texturedEffect) { + var material = that.getMaterial(); + if (material.effect != that.simpleInfo.texturedEffect_) { // replace the material with a textured one. var new_material = that.simpleInfo.createTexturedMaterial('phong'); new_material.copyParams(material); // Reset the effect since copy Params just copied the non-textured // one. - new_material.effect = that.simpleInfo.texturedEffect; + new_material.effect = that.simpleInfo.texturedEffect_; that.setMaterial(new_material); material = new_material; } @@ -556,3 +712,83 @@ o3djs.simple.SimpleShape.prototype.loadTexture = function(url) { }); }; +/** + * An object to simply manage a scene. + * @constructor + * @extends o3djs.simple.SimpleObject + * @param {!o3djs.simple.SimpleInfo} simpleInfo The SimpleInfo to manage this + * scene. + * @param {string} url Url scene was loaded from. + * @param {!o3d.Pack} pack Pack that is managing scene. + * @param {!o3d.Transform} root Root transform of scene. + * @param {!o3d.ParamObject} paramObject the holds global parameters. + */ +o3djs.simple.SimpleScene = function( + simpleInfo, url, pack, root, paramObject) { + this.init(simpleInfo, root); + /** + * The url this scene was loaded from. + * @type {string} + */ + this.url = url; + + /** + * The pack managing this scene. + * @type {!o3d.Pack} + */ + this.pack = pack; + + /** + * The param object holding global parameters for this scene. + * @type {!o3d.Pack} + */ + this.paramObject = paramObject; + + /** + * The animation parameter for this scene. + * @type {!o3d.ParamFloat} + */ + this.animTimeParam = paramObject.getParam('animTime'); + + o3djs.pack.preparePack(pack, simpleInfo.viewInfo); + + this.cameraInfos_ = o3djs.camera.getCameraInfos( + root, + simpleInfo.client.width, + simpleInfo.client.height); + + + /** + * Binds a param if it exists. + * @param {!o3d.ParamObject} paramObject The object that has the param. + * @param {string} paramName name of param. + * @param {!o3d.Param} sourceParam The param to bind to. + */ + var bindParam = function(paramObject, paramName, sourceParam) { + var param = paramObject.getParam(paramName); + if (param) { + param.bind(sourceParam); + } + } + + var materials = pack.getObjectsByClassName('o3d.Material'); + for (var m = 0; m < materials.length; ++m) { + var material = materials[m]; + bindParam(material, 'lightWorldPos', simpleInfo.lightWorldPosParam); + bindParam(material, 'lightColor', simpleInfo.lightColorParam); + } + + this.transform.parent = this.simpleInfo.root; +}; + +o3djs.simple.SimpleScene.prototype = new o3djs.simple.SimpleObject(); + +/** + * Sets the animation time for the scene. + * @param {number} time Animation time in seconds. + */ +o3djs.simple.SimpleScene.prototype.setAnimTime = function(time) { + this.animTimeParam.value = time; +}; + + diff --git a/o3d/samples/particles.html b/o3d/samples/particles.html index e3670db..15a7bb9 100644 --- a/o3d/samples/particles.html +++ b/o3d/samples/particles.html @@ -64,6 +64,13 @@ var g_particleSystem; var g_clockParam; var g_textures = []; var g_emitters = []; // so we can find in the debugger to edit in real time. +var g_poofs = []; +var g_keyDown = []; +var g_poofIndex = 0; +var g_trail; +var g_trailParameters; + +var MAX_POOFS = 3; /** * Loads a texture. @@ -141,8 +148,6 @@ function initStep2(clientElements) { [0, 200, 0], // target [0, 1, 0]); // up - - // Load textures. This happens asynchronously. var loader = o3djs.loader.createLoader(initStep3); loadTexture(loader, 'assets/particle-anim.png', 0); @@ -174,6 +179,12 @@ function initStep3() { setupAnim(); setupBall(); setupCube(); + setupPoof(); + setupTrail(); + + window.addEventListener('keypress', onKeyPress, true); + window.addEventListener('keydown', onKeyDown, true); + window.addEventListener('keyup', onKeyUp, true); // Setup an onrender callback for animation. g_client.setRenderCallback(onrender); @@ -181,6 +192,30 @@ function initStep3() { window.g_finished = true; // for selenium testing. } +function onKeyPress(event) { + event = event || window.event; + + var keyChar = String.fromCharCode(o3djs.event.getEventKeyChar(event)); + // Just in case they have capslock on. + keyChar = keyChar.toLowerCase(); + + switch (keyChar) { + case 'p': + triggerPoof(); + break; + } +} + +function onKeyDown(event) { + event = event || window.event; + g_keyDown[event.keyCode] = true; +} + +function onKeyUp(event) { + event = event || window.event; + g_keyDown[event.keyCode] = false; +} + function setupFlame() { var transform = g_pack.createObject('Transform'); transform.parent = g_client.root; @@ -460,6 +495,67 @@ function setupCube() { transform.addShape(emitter.shape); } +function setupPoof() { + var emitter = g_particleSystem.createParticleEmitter(); + emitter.setState(o3djs.particles.ParticleStateIds.ADD); + emitter.setColorRamp( + [1, 1, 1, 0.3, + 1, 1, 1, 0]); + emitter.setParameters({ + numParticles: 30, + lifeTime: 1.5, + startTime: 0, + startSize: 50, + endSize: 200, + spinSpeedRange: 10}, + function(index, parameters) { + var angle = Math.random() * 2 * Math.PI; + parameters.velocity = g_math.matrix4.transformPoint( + g_math.matrix4.rotationY(angle), [300, 0, 0]); + parameters.acceleration = g_math.mulVectorVector( + parameters.velocity, [-0.3, 0, -0.3]); + }); + // make 3 poofs one shots + for (var ii = 0; ii < MAX_POOFS; ++ii) { + g_poofs[ii] = emitter.createOneShot(g_client.root); + } +} + +function triggerPoof() { + // We have multiple poofs because if you only have one and it is still going + // when you trigger it a second time it will immediately start over. + g_poofs[g_poofIndex].trigger([100 + 100 * g_poofIndex, 0, 300]); + g_poofIndex++; + if (g_poofIndex == MAX_POOFS) { + g_poofIndex = 0; + } +} + +function setupTrail() { + g_trailParameters = { + numParticles: 2, + lifeTime: 2, + startSize: 10, + endSize: 90, + velocityRange: [20, 20, 20], + spinSpeedRange: 4}; + g_trail = g_particleSystem.createTrail( + g_client.root, + 1000, + g_trailParameters); + g_trail.setState(o3djs.particles.ParticleStateIds.ADD); + g_trail.setColorRamp( + [1, 0, 0, 1, + 1, 1, 0, 1, + 1, 1, 1, 0]); +} + +function leaveTrail() { + var trailClock = window.g_clock * -0.8; + g_trail.birthParticles( + [Math.sin(trailClock) * 400, 200, Math.cos(trailClock) * 400]); +} + /** * Called every frame. * @param {!o3d.RenderEvent} renderEvent Rendering Information. @@ -468,6 +564,10 @@ function onrender(renderEvent) { var elapsedTime = renderEvent.elapsedTime; window.g_clock += elapsedTime * window.g_timeMult; + if (g_keyDown[84]) { // 'T' key. + leaveTrail(); + } + var cameraClock = window.g_clock * 0.3; g_viewInfo.drawContext.view = g_math.matrix4.lookAt( [Math.sin(cameraClock) * 1500, 500, Math.cos(cameraClock) * 1500], // eye @@ -493,5 +593,7 @@ function unload() { <!-- Start of O3D plugin --> <div id="o3d" style="width: 800px; height: 600px;"></div> <!-- End of O3D plugin --> +Press 'P' to make a poof.<br/> +Press 'T' to make a trail. </body> </html> diff --git a/o3d/samples/shader-test.html b/o3d/samples/shader-test.html index a437370..812d067 100644 --- a/o3d/samples/shader-test.html +++ b/o3d/samples/shader-test.html @@ -85,21 +85,24 @@ var g_shaderSelection = 0; var g_rotateOn = true; var g_o3dWidth; // width of our client area var g_o3dHeight; // height of our client area -var g_shaders = ['diffuse', - 'checker', - 'bump', - 'bump', - 'texture-only', - 'texture-colormult', - 'tangent', - 'binormal', - 'normal', - 'solid-color', - 'vertex-color', - 'phong-with-colormult']; +var g_shaders = [ + {file: 'diffuse', name: 'Diffuse'}, + {file: 'checker', name: 'Checker'}, + {file: 'bump', name: 'Bump'}, + {file: 'bump', name: 'Bump With Texture'}, + {file: 'texture-only', name: 'Texture Only'}, + {file: 'texture-colormult', name: 'Texture with Color Multiplier'}, + {file: 'tangent', name: 'Tangent'}, + {file: 'binormal', name: 'Binormal'}, + {file: 'normal', name: 'Normal'}, + {file: 'solid-color', name: 'Solid Color'}, + {file: 'vertex-color', name: 'Vertex Color'}, + {file: 'phong-with-colormult', name: 'Blinn-Phong with Color Multiplier'}, + {file: 'toon', name: 'Toon'}]; var g_effects = []; var g_bumpTextureSampler; var g_bumpBumpsSampler; +var g_colorRampSampler; // Our view and projection matrices // The view matrix transforms objects from world space to view space. @@ -263,6 +266,7 @@ function applyShader(pack, shaderNumber) { setParam(material, 'AmbientSampler', g_bumpTextureSampler); setParam(material, 'DiffuseSampler', g_bumpTextureSampler); setParam(material, 'texSampler0', g_bumpTextureSampler); + setParam(material, 'colorRamp', g_colorRampSampler); var timeParam = material.getParam('inputTime'); if (timeParam) { @@ -312,12 +316,29 @@ function initStep2(clientElements) { var paramObject = g_pack.createObject('ParamObject'); g_currentTimeParam = paramObject.createParam('timeParam','ParamFloat'); - // Load effects + // Load effects and fill out options. + options = '' for(var s = 0; s < g_shaders.length; s++) { g_effects[s] = g_pack.createObject('Effect'); - var shaderString = 'shaders/' + g_shaders[s] + '.shader'; + var shaderString = 'shaders/' + g_shaders[s].file + '.shader'; o3djs.effect.loadEffect(g_effects[s], shaderString); + options += '<option value="' + s + '"' + (s == 0 ? ' selected' : '') + + '>' + g_shaders[s].name + '</option>'; } + document.getElementById('shaderSelect').innerHTML = options; + + var rampWidth = 64; + var texture = g_pack.createTexture2D( + rampWidth, 1, g_o3d.Texture.XRGB8, 1, false); + var pixels = []; + for (var ii = 0; ii < rampWidth; ++ii) { + var level = ii > rampWidth * 0.5 ? 1 : 0.3; + pixels.push(level, level, level); + } + texture.set(0, pixels); + g_colorRampSampler = g_pack.createObject('Sampler'); + g_colorRampSampler.texture = texture; + g_colorRampSampler.addressModeU = g_o3d.Sampler.CLAMP; var loader = o3djs.loader.createLoader(initStep3); loader.loadTexture(g_pack, 'assets/normalmap.dds', @@ -386,18 +407,6 @@ This example is useful for testing a shader or checking a scene. Clicking on the <!-- End of O3D plugin --> <p> <select id='shaderSelect' name='shaderSelect' onChange='changeShader()'> -<option value='0' selected>Diffuse</option> -<option value='1'>Checker</option> -<option value='2'>Bump</option> -<option value='3'>Bump With Texture</option> -<option value='4'>Texture Only</option> -<option value='5'>Texture with Color Multiplier</option> -<option value='6'>Tangent</option> -<option value='7'>Binormal</option> -<option value='8'>Normal</option> -<option value='9'>Solid Color</option> -<option value='10'>Vertex Color</option> -<option value='11'>Blinn-Phong with Color Multiplier</option> </select> </body> </html> diff --git a/o3d/samples/shaders/toon.shader b/o3d/samples/shaders/toon.shader new file mode 100755 index 0000000..8f2caec --- /dev/null +++ b/o3d/samples/shaders/toon.shader @@ -0,0 +1,98 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// The 4x4 world view projection matrix. +float4x4 worldViewProjection : WorldViewProjection; +float4x4 worldInverseTranspose : WorldInverseTranspose; +float4x4 world : World; + +float4 ambientIntensity; +float4 lightIntensity; +float4 ambient; +float4 diffuse; +float3 lightWorldPos; + +sampler colorRamp; + +// input parameters for our vertex shader +struct VertexShaderInput { + float4 position : POSITION; // Position vector of vertex + float4 normal : NORMAL; +}; + +// input parameters for our pixel shader +struct PixelShaderInput { + float4 position : POSITION; + float3 normal : TEXCOORD0; + float3 worldPosition : TEXCOORD1; +}; + +/** + * Our vertex shader. + */ +PixelShaderInput vertexShaderFunction(VertexShaderInput input) { + PixelShaderInput output; + + // Transform position into clip space. + output.position = mul(input.position, worldViewProjection); + + // Transform normal into world space, where we can do lighting + // calculations even if the world transform contains scaling. + output.normal = mul(input.normal, worldInverseTranspose).xyz; + + // Calculate surface position in world space. + output.worldPosition = mul(input.position, world).xyz; + + return output; +} + +/** + * Our pixel shader. + */ +float4 pixelShaderFunction(PixelShaderInput input): COLOR { + float3 surfaceToLight = normalize(lightWorldPos - input.worldPosition); + + float3 worldNormal = normalize(input.normal); + + // Apply diffuse lighting in world space in case the world transform + // contains scaling. + float4 directionalIntensity = lightIntensity * + tex2D(colorRamp, float2(saturate(dot(worldNormal, surfaceToLight)), 0.5)); + float4 outColor = ambientIntensity * ambient + directionalIntensity * diffuse; + return float4(outColor.rgb, diffuse.a); +} + +// Here we tell our effect file *which* functions are +// our vertex and pixel shaders. + +// #o3d VertexShaderEntryPoint vertexShaderFunction +// #o3d PixelShaderEntryPoint pixelShaderFunction +// #o3d MatrixLoadOrder RowMajor diff --git a/o3d/tests/selenium/javascript_unit_test_list.txt b/o3d/tests/selenium/javascript_unit_test_list.txt index 090ffe2..f73c951 100644 --- a/o3d/tests/selenium/javascript_unit_test_list.txt +++ b/o3d/tests/selenium/javascript_unit_test_list.txt @@ -70,8 +70,8 @@ small base-test small util-test small pixel-perfection screenshot pdiff_threshold(2500) pdiff_threshold_mac(3000) except(*iexplore) medium offscreen-test -# TODO Temporarily removing until its fixed on mac -#medium texture-set-test screenshot +medium texture-set-test screenshot +#medium param-array-test screenshot small no-rendergraph screenshot small non-cachable-params screenshot pdiff_threshold(1700) small type-test diff --git a/o3d/tests/selenium/tests/param-array-test.html b/o3d/tests/selenium/tests/param-array-test.html new file mode 100644 index 0000000..aca7d0f --- /dev/null +++ b/o3d/tests/selenium/tests/param-array-test.html @@ -0,0 +1,307 @@ +<!-- +Copyright 2009, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- +Param Array Test +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Param Array Test. +</title> +<script type="text/javascript" src="../../../samples/o3djs/base.js"></script> +<script type="text/javascript"> +o3djs.require('o3djs.util'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.primitives'); +o3djs.require('o3djs.effect'); + +// global variables +var g_o3d; +var g_math; +var g_client; +var g_pack; +var g_viewInfo; + +/** + * Creates the client area. + */ +function init() { + // Comment out the line below to run the sample in the browser + // JavaScript engine. This may be helpful for debugging. + o3djs.util.setMainEngine(o3djs.util.Engine.V8); + o3djs.util.makeClients(initStep2, 'FloatingPointTextures,NotAntiAliased'); +} + +/** + * Initializes O3D, loads an effect, creates some textures + * and quads to display them. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initializes global variables and libraries. + var o3dElement = clientElements[0]; + g_o3d = o3dElement.o3d; + g_math = o3djs.math; + + // Set window.g_client as well. Otherwise when the sample runs in + // V8, selenium won't be able to find this variable (it can only see + // the browser environment). + window.g_client = g_client = o3dElement.client; + + // Create a pack to manage our resources/assets + g_pack = g_client.createPack(); + + // Create the render graph for a view. + g_viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot); + + var clientWidth = g_client.width; + var clientHeight = g_client.height; + + // The + 0.5 makes this pixel aligned. + g_viewInfo.drawContext.projection = g_math.matrix4.orthographic( + -clientWidth * 0.5 + 0.5, + clientWidth * 0.5 + 0.5, + -clientHeight * 0.5 + 0.5, + clientHeight * 0.5 + 0.5, + 0.001, + 1000); + g_viewInfo.drawContext.view = g_math.matrix4.lookAt( + [0, 500, 0], // eye + [0, 0, 0], // target + [0, 0, -1]); // up + + var textures = []; + for (var ii = 0; ii < 2; ++ii) { + var texture = g_pack.createTexture2D(1, 1, g_o3d.Texture.ARGB8, 1, false); + texture.set(0, [ii, 0.7, 0.9, 1]); + textures[ii] = texture; + } + + for (var ii = 0; ii < 2; ++ii) { + var effect = g_pack.createObject('Effect'); + effect.loadFromFXString(o3djs.util.getElementContentById('fx' + (ii + 1))); + + // Create a Material for the effect. + var material = g_pack.createObject('Material'); + + // Set the material's drawList for transparent objects. + material.drawList = g_viewInfo.zOrderedDrawList; + + // Apply the effect to this material. + material.effect = effect; + + // Create the params that effect requires on the material. + o3djs.effect.createUniformParameters(g_pack, effect, material); + + // Create a quad. + var shape = o3djs.primitives.createPlane(g_pack, + material, + 1, + 1, + 1, + 1); + + if (ii == 0) { + var paramArray = material.getParam('colors1').value; + paramArray.getParam(0).value = 0.3; + paramArray.getParam(1).value = 0.7; + var paramArray = material.getParam('colors2').value; + paramArray.getParam(0).value = [1, 0.5]; + paramArray.getParam(1).value = [0.5, 1]; + var paramArray = material.getParam('colors3').value; + paramArray.getParam(0).value = [1, 1, 0]; + paramArray.getParam(1).value = [1, 0, 1]; + var paramArray = material.getParam('colors4').value; + paramArray.getParam(0).value = [1, 0, 0, 1]; + paramArray.getParam(1).value = [0, 0, 1, 1]; + } else { + var paramArray = material.getParam('colorsb').value; + paramArray.getParam(0).value = true; + paramArray.getParam(1).value = false; + var paramArray = material.getParam('colorsi').value; + paramArray.getParam(0).value = 254; + paramArray.getParam(1).value = 255; + var paramArray = material.getParam('colors4x4').value; + paramArray.getParam(0).value = [[0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 1, 1, 1]]; + paramArray.getParam(1).value = [[0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0.5, 0.3, 0.3, 1]]; + var paramArray = material.getParam('texSamplers').value; + paramArray.getParam(0).value.texture = textures[0]; + paramArray.getParam(1).value.texture = textures[1]; + } + + var transform = g_pack.createObject('Transform'); + transform.translate(-100 + ii * 200, 0, 0); + transform.scale(180, 1, 360); + transform.parent = g_client.root; + transform.addShape(shape); + } + + window.g_testResult = true; // for selenium testing. +} + +</script> +</head> +<body onload="init()"> +<h1>Param Array Test</h1> +<br/> + +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 400px; height: 400px;"></div> +<!-- End of O3D plugin --> +<script type="test/o3deffect" id="fx1"> +float colors1[2]; +float2 colors2[2]; +float3 colors3[2]; +float4 colors4[2]; +float4x4 worldViewProjection : WORLDVIEWPROJECTION; + +// input parameters for our vertex shader +struct PixelShaderInput { + float4 position : POSITION; + float2 texcoord : TEXCOORD0; // Texture coordinates +}; + +// input parameters for our pixel shader +struct VertexShaderInput { + float4 position : POSITION; + float2 texcoord : TEXCOORD0; // Texture coordinates +}; + +/** + * The vertex shader + */ +PixelShaderInput vertexShaderFunction(VertexShaderInput input) { + PixelShaderInput output; + output.position = mul(input.position, worldViewProjection); + output.texcoord = input.texcoord; + return output; +} + +bool segment(float id, float position) { + return position * 4 >= id && position * 4 < (id + 1); +} + +/** + * The pixel shader + */ +float4 pixelShaderFunction(PixelShaderInput input): COLOR { + if (segment(0, input.texcoord.y)) { + return float4(input.texcoord.x > 0.5 ? colors1[1].xxx : colors1[0].xxx, 1); + } + if (segment(1, input.texcoord.y)) { + return float4(input.texcoord.x > 0.5 ? colors2[1] : colors2[0], 0, 1); + } + if (segment(2, input.texcoord.y)) { + return float4(input.texcoord.x > 0.5 ? colors3[1] : colors3[0], 1); + } + return input.texcoord.x > 0.5 ? colors4[1] : colors4[0]; +} + +// Here we tell our effect file *which* functions are +// our vertex and pixel shaders. +// #o3d VertexShaderEntryPoint vertexShaderFunction +// #o3d PixelShaderEntryPoint pixelShaderFunction +// #o3d MatrixLoadOrder RowMajor +</script> +<script type="test/o3deffect" id="fx2"> +float4x4 colors4x4[2]; +int colorsi[2]; +bool colorsb[2]; +sampler texSamplers[2]; +float4x4 worldViewProjection : WORLDVIEWPROJECTION; + +// input parameters for our vertex shader +struct PixelShaderInput { + float4 position : POSITION; + float2 texcoord : TEXCOORD0; // Texture coordinates +}; + +// input parameters for our pixel shader +struct VertexShaderInput { + float4 position : POSITION; + float2 texcoord : TEXCOORD0; // Texture coordinates +}; + +/** + * The vertex shader + */ +PixelShaderInput vertexShaderFunction(VertexShaderInput input) { + PixelShaderInput output; + output.position = mul(input.position, worldViewProjection); + output.texcoord = input.texcoord; + return output; +} + +bool segment(float id, float position) { + return position * 4 >= id && position * 4 < (id + 1); +} + +/** + * The pixel shader + */ +float4 pixelShaderFunction(PixelShaderInput input): COLOR { + if (segment(0, input.texcoord.y)) { + return input.texcoord.x > 0.5 ? colors4x4[1][3] : colors4x4[0][3]; + } + if (segment(1, input.texcoord.y)) { + return float4(input.texcoord.x > 0.5 ? colorsb[1] : colorsb[0], 0, 0, 1); + } + if (segment(2, input.texcoord.y)) { + return float4((input.texcoord.x > 0.5 ? colorsi[1] : colorsi[0]) / 255, + 0, 0, 1); + } + float4 t0 = tex2D(texSamplers[0], input.texcoord); + float4 t1 = tex2D(texSamplers[1], input.texcoord); + return input.texcoord.x > 0.5 ? t1 : t0; +} + +// Here we tell our effect file *which* functions are +// our vertex and pixel shaders. +// #o3d VertexShaderEntryPoint vertexShaderFunction +// #o3d PixelShaderEntryPoint pixelShaderFunction +// #o3d MatrixLoadOrder RowMajor +</script> +</body> +</html> diff --git a/o3d/tests/selenium/tests/texture-set-test.html b/o3d/tests/selenium/tests/texture-set-test.html index a58d024..a421e5f 100644 --- a/o3d/tests/selenium/tests/texture-set-test.html +++ b/o3d/tests/selenium/tests/texture-set-test.html @@ -92,11 +92,12 @@ function initStep2(clientElements) { var clientWidth = g_client.width; var clientHeight = g_client.height; + // The + 0.5 makes this pixel aligned. g_viewInfo.drawContext.projection = g_math.matrix4.orthographic( - -clientWidth * 0.5, - clientWidth * 0.5, - -clientHeight * 0.5, - clientHeight * 0.5, + -clientWidth * 0.5 + 0.5, + clientWidth * 0.5 + 0.5, + -clientHeight * 0.5 + 0.5, + clientHeight * 0.5 + 0.5, 0.001, 1000); g_viewInfo.drawContext.view = g_math.matrix4.lookAt( |