summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-17 06:26:52 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-17 06:26:52 +0000
commit1dc3ba84c3da4edfeaf22cedf65750533a20de00 (patch)
tree936325e6f2dd07667fc4161ac524f1ab076aa5bf
parent3d476cf047d6a463d5706f70bfdf5e3787f863ee (diff)
downloadchromium_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.cc7
-rw-r--r--o3d/core/cross/effect_test.cc73
-rw-r--r--o3d/core/cross/gl/effect_gl.cc2
-rw-r--r--o3d/core/cross/gl/param_cache_gl.cc272
-rw-r--r--o3d/core/win/d3d9/effect_d3d9.cc442
-rw-r--r--o3d/documentation/jsdoc-toolkit-templates/publish.js65
-rw-r--r--o3d/plugin/idl/client.idl6
-rw-r--r--o3d/plugin/idl/pack.idl8
-rw-r--r--o3d/plugin/mac/main_mac.mm22
-rw-r--r--o3d/plugin/o3d_binding.py16
-rw-r--r--o3d/samples/o3djs/base.js11
-rw-r--r--o3d/samples/o3djs/effect.js33
-rw-r--r--o3d/samples/o3djs/particles.js392
-rw-r--r--o3d/samples/o3djs/serialization.js195
-rw-r--r--o3d/samples/o3djs/simple.js336
-rw-r--r--o3d/samples/particles.html106
-rw-r--r--o3d/samples/shader-test.html61
-rwxr-xr-xo3d/samples/shaders/toon.shader98
-rw-r--r--o3d/tests/selenium/javascript_unit_test_list.txt4
-rw-r--r--o3d/tests/selenium/tests/param-array-test.html307
-rw-r--r--o3d/tests/selenium/tests/texture-set-test.html9
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*>(&param_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*>(&param_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 + ':&nbsp;' + 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 + ':&nbsp;' + 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(