summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-29 23:14:43 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-29 23:14:43 +0000
commit42ca9a490f404c33ab4462ed44afec22c3ecc82b (patch)
treeecaaeee0e76eba60846c3466eeadb4922e603cd5 /o3d
parent261baf9696bd0c28c6466de3d4921bef4ba937c5 (diff)
downloadchromium_src-42ca9a490f404c33ab4462ed44afec22c3ecc82b.zip
chromium_src-42ca9a490f404c33ab4462ed44afec22c3ecc82b.tar.gz
chromium_src-42ca9a490f404c33ab4462ed44afec22c3ecc82b.tar.bz2
Add support for Param Arrays for Effect parameters.
Arrays of floats, float2, float3, float4, Matrix4, int, bool and sampler are all supported. I'll enable the test for selenium and check in a screenshot in another build. Review URL: http://codereview.chromium.org/125188 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19548 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-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>