summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--o3d/core/cross/effect.cc9
-rw-r--r--o3d/core/cross/effect_test.cc77
-rw-r--r--o3d/core/cross/gl/effect_gl.cc21
-rw-r--r--o3d/core/cross/gl/param_cache_gl.cc284
-rw-r--r--o3d/core/win/d3d9/effect_d3d9.cc456
-rw-r--r--o3d/samples/o3djs/effect.js33
-rw-r--r--o3d/tests/selenium/tests/param-array-test.html307
7 files changed, 1086 insertions, 101 deletions
diff --git a/o3d/core/cross/effect.cc b/o3d/core/cross/effect.cc
index 9c271fb..5aba914 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") +
@@ -188,7 +187,7 @@ bool GetIdentifierAfterString(const String& original,
} // anonymous namespace
-// TODO: Replace this with the runtime shader parser.
+// TODO(gman): Replace this with the runtime shader parser.
// For now it's very stupid. It requires the word "techinque" not appear
// anywhere inside the file. Then it searches for
//
diff --git a/o3d/core/cross/effect_test.cc b/o3d/core/cross/effect_test.cc
index af028e6..b3a245c 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) {
@@ -187,7 +188,7 @@ bool IsExpectedStream(const EffectStreamInfo& info) {
} // anonymous namespace.
TEST_F(EffectTest, LogOpenGLCalls) {
- // TODO: Find a way to implement a Mocklog object under
+ // TODO(o3d): Find a way to implement a Mocklog object under
// Googleclient. The code would be of the usual form:
//
// ScopedMockLog log;
@@ -215,7 +216,7 @@ TEST_F(EffectTest, LogOpenGLCalls) {
material->set_effect(fx);
primitive->set_material(material);
- // TODO: Test the log file.
+ // TODO(o3d): Test the log file.
// Clean up.
object_manager()->DestroyPack(pack);
@@ -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..f20d704 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 "
@@ -204,7 +206,7 @@ bool EffectGL::LoadFromFXString(const String& effect) {
String vertex_shader_entry_point;
String fragment_shader_entry_point;
MatrixLoadOrder matrix_load_order;
- // TODO: Check for failure once shader parser is in.
+ // TODO(gman): Check for failure once shader parser is in.
if (!ValidateFX(effect,
&vertex_shader_entry_point,
&fragment_shader_entry_point,
@@ -309,7 +311,7 @@ bool EffectGL::LoadFromFXString(const String& effect) {
return false;
}
- // TODO: remove this (OLD path for textures).
+ // TODO(o3d): remove this (OLD path for textures).
FillSamplerToTextureMap(effect);
CHECK_GL_ERROR();
@@ -359,7 +361,7 @@ void EffectGL::FillSamplerToTextureMap(const String &effect) {
cgDestroyEffect(cg_effect);
}
-// TODO: remove this (OLD path for textures).
+// TODO(o3d): remove this (OLD path for textures).
String EffectGL::GetTextureNameFromSamplerParamName(
const String &sampler_name) {
std::map<String, String>::iterator it =
@@ -428,12 +430,13 @@ void EffectGL::GetShaderParamInfo(
// by keeping an internal collection of Texture-Sampler mappings
// that is built here, so we can later to do the reverse lookup.
//
- // TODO: This will not solve the one-to-many problem of one
+ // TODO(o3d): This will not solve the one-to-many problem of one
// Texture being used by many Sampler params, but it's enough to get
// us up and running.
- // TODO: Once we start using samplers exclusively, this special
- // treatment of textures should go away. For the time being though, we
- // do end up creating a texture param on the param_object.
+ //
+ // TODO(o3d): Once we start using samplers exclusively, this special
+ // treatment of textures should go away. For the time being though, we do
+ // end up creating a texture param on the param_object.
if (cg_type == CG_SAMPLER1D ||
cg_type == CG_SAMPLER2D ||
cg_type == CG_SAMPLER3D ||
@@ -549,7 +552,7 @@ void EffectGL::GetStreamInfo(
// Loop over all the CG_SAMPLER objects and attach the GLuint handle for the
// GL texture object that we discovered earlier. Then execute the
// CGstateassignments in the sampler_state to set up the texture unit.
-// TODO: remove this (OLD path for textures).
+// TODO(o3d): remove this (OLD path for textures).
void EffectGL::SetTexturesFromEffect(ParamCacheGL* param_cache_gl) {
DLOG_FIRST_N(INFO, kNumLoggedEvents) << "EffectGL EnableTexturesFromEffect";
ParamCacheGL::SamplerParameterMap& map = param_cache_gl->sampler_map();
@@ -610,7 +613,7 @@ void EffectGL::PrepareForDraw(ParamCacheGL* param_cache_gl) {
cgGLBindProgram(cg_fragment_);
UpdateShaderUniformsFromEffect(param_cache_gl);
- // TODO: remove this (OLD path for textures).
+ // TODO(o3d): remove this (OLD path for textures).
SetTexturesFromEffect(param_cache_gl);
} else {
DLOG_FIRST_N(ERROR, kNumLoggedEvents)
diff --git a/o3d/core/cross/gl/param_cache_gl.cc b/o3d/core/cross/gl/param_cache_gl.cc
index b91245e..c950f3f 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(gman): 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(gman): 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(gman): 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)));
@@ -358,12 +578,12 @@ static void ScanUniformParameters(SemanticManager* semantic_manager,
continue;
}
- // TODO: The following code block should be removed once we
- // start creating sampler params for all effects coming in via the
- // importer. For the time being, we keep an extra ParamTexture
- // that does the job it used to do. If we are using a ParamSampler
- // on the object then the ParamTexture will have no value and
- // therefore its handler will have no side-effects.
+ // TODO(o3d): The following code block should be removed once we start
+ // creating sampler params for all effects coming in via the importer. For
+ // the time being, we keep an extra ParamTexture that does the job it used
+ // to do. If we are using a ParamSampler on the object then the
+ // ParamTexture will have no value and therefore its handler will have no
+ // side-effects.
if (cg_type == CG_SAMPLER ||
cg_type == CG_SAMPLER1D ||
cg_type == CG_SAMPLER2D ||
diff --git a/o3d/core/win/d3d9/effect_d3d9.cc b/o3d/core/win/d3d9/effect_d3d9.cc
index 216e6b9..2bac2d9 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(gman): 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(gman): 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(gman): 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(gman): 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(gman): 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 {
@@ -144,16 +465,13 @@ static const ObjectBase::Class* D3DXPDescToParamType(
pdesc.Columns == 1) {
return ParamBoolean::GetApparentClass();
// Texture param
- // TODO Texture params should be removed once we switch over to
+ // TODO(o3d): Texture params should be removed once we switch over to
// using samplers only.
} else if (pdesc.Type == D3DXPT_TEXTURE &&
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;
@@ -178,13 +496,13 @@ bool EffectD3D9::PrepareFX(const String& effect,
String fragment_shader_entry_point;
MatrixLoadOrder matrix_load_order;
- // TODO: Temporary fix to make GL and D3D match until the shader parser
+ // TODO(o3d): Temporary fix to make GL and D3D match until the shader parser
// is written.
if (!ValidateFX(effect,
&vertex_shader_entry_point,
&fragment_shader_entry_point,
&matrix_load_order)) {
- // TODO: Remove this but for now just let bad ones pass so collada
+ // TODO(o3d): Remove this but for now just let bad ones pass so collada
// importer works.
*prepared_effect = effect;
return false;
@@ -219,7 +537,7 @@ bool EffectD3D9::LoadFromFXString(const String& effect) {
LPD3DXBUFFER error_buffer;
String prepared_effect;
- // TODO: Check for failure once shader parser is in.
+ // TODO(o3d): Check for failure once shader parser is in.
PrepareFX(effect, &prepared_effect);
if (!HR(o3d::D3DXCreateEffect(d3d_device_,
@@ -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,
@@ -441,7 +816,7 @@ bool EffectD3D9::AddParameterMapping(
D3DXPC_SCALAR>(
down_cast<ParamBoolean*>(param), phandle));
// Texture param
- // TODO The texture param block should be removed once we start
+ // TODO(o3d): The texture param block should be removed once we start
// using samplers only. In the meantime, we need to create a texture param
// to be able to handle collada files referencing external fx .
} else if (param->IsA(ParamTexture::GetApparentClass()) &&
@@ -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,
@@ -663,7 +1035,7 @@ void TypedEffectParamHandlerD3D9<ParamBoolean,
HR(d3dx_effect->SetBool(phandle_, param_->value()));
}
-// TODO: The following handler should be removed once we switch to
+// TODO(o3d): The following handler should be removed once we switch to
// using Samplers exclusively.
template<>
void TypedEffectParamHandlerD3D9<ParamTexture,
@@ -671,7 +1043,7 @@ void TypedEffectParamHandlerD3D9<ParamTexture,
RendererD3D9* renderer,
ID3DXEffect* d3dx_effect) {
Texture* texture = param_->value();
- // TODO: If texture is NULL then we don't set the texture on the
+ // TODO(o3d): If texture is NULL then we don't set the texture on the
// effect to avoid clobbering texture set by the corresponding sampler in
// the cases where we use samplers. The side-effect of this is that if
// the texture is not set, we could end up using whatever texture was used
@@ -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/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/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>