summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--o3d/converter/converter.gyp7
-rw-r--r--o3d/core/core.gyp2
-rw-r--r--o3d/core/cross/client_info.h9
-rw-r--r--o3d/core/cross/effect_test.cc68
-rw-r--r--o3d/core/cross/gles2/effect_gles2.cc660
-rw-r--r--o3d/core/cross/gles2/effect_gles2.h40
-rw-r--r--o3d/core/cross/gles2/gles2_headers.h2
-rw-r--r--o3d/core/cross/gles2/param_cache_gles2.cc646
-rw-r--r--o3d/core/cross/gles2/param_cache_gles2.h34
-rw-r--r--o3d/core/cross/gles2/primitive_gles2.cc26
-rw-r--r--o3d/core/cross/gles2/renderer_gles2.cc37
-rw-r--r--o3d/core/cross/gles2/renderer_gles2.h36
-rw-r--r--o3d/core/cross/gles2/sampler_gles2.cc98
-rw-r--r--o3d/core/cross/gles2/sampler_gles2.h15
-rw-r--r--o3d/core/cross/gles2/stream_bank_gles2.cc74
-rw-r--r--o3d/core/cross/gles2/stream_bank_gles2.h5
-rw-r--r--o3d/core/cross/gles2/utils_gles2-inl.h29
-rw-r--r--o3d/core/cross/gles2/utils_gles2.cc207
-rw-r--r--o3d/core/cross/gles2/utils_gles2.h5
-rw-r--r--o3d/core/cross/renderer_test.cc4
-rw-r--r--o3d/plugin/idl/client.idl11
-rw-r--r--o3d/plugin/plugin.gyp2
-rw-r--r--o3d/samples/hellocube-colors-glsl.html343
-rw-r--r--o3d/samples/hellocube-glsl.html304
-rw-r--r--o3d/samples/hellocube-textures-glsl.html433
-rw-r--r--o3d/samples/o3djs/base.js11
-rw-r--r--o3d/standalone/standalone.gyp1
-rw-r--r--o3d/tests/tests.gyp1
28 files changed, 1938 insertions, 1172 deletions
diff --git a/o3d/converter/converter.gyp b/o3d/converter/converter.gyp
index ddb5344..ffede11f 100644
--- a/o3d/converter/converter.gyp
+++ b/o3d/converter/converter.gyp
@@ -62,13 +62,6 @@
],
},
],
- ['renderer == "gles2"',
- {
- 'dependencies': [
- '../build/libs.gyp:cg_libs',
- ],
- },
- ],
['OS == "mac"',
{
'postbuilds': [
diff --git a/o3d/core/core.gyp b/o3d/core/core.gyp
index 323a4fe..46c5d4b 100644
--- a/o3d/core/core.gyp
+++ b/o3d/core/core.gyp
@@ -57,7 +57,6 @@
{
'include_dirs': [
'../../<(glewdir)/include',
- '../../<(cgdir)/include',
],
},
],
@@ -296,7 +295,6 @@
['renderer == "gles2"',
{
'dependencies': [
- '../build/libs.gyp:cg_libs',
'../build/libs.gyp:gles2_libs',
],
},
diff --git a/o3d/core/cross/client_info.h b/o3d/core/cross/client_info.h
index 2d2c9b7..552ce02 100644
--- a/o3d/core/cross/client_info.h
+++ b/o3d/core/cross/client_info.h
@@ -66,6 +66,15 @@ class ClientInfo {
return software_renderer_;
}
+ // Whether or not shaders are GLSL.
+ bool glsl() const {
+#if defined(RENDERER_GLES2)
+ return true;
+#else
+ return false;
+#endif
+ }
+
// Whether or not the underlying GPU supports non power of 2 textures.
// NOTE: O3D always supports non power of 2 textures from a public API
// point of view and massages the data underneath to make this work.
diff --git a/o3d/core/cross/effect_test.cc b/o3d/core/cross/effect_test.cc
index e240296..f301b61 100644
--- a/o3d/core/cross/effect_test.cc
+++ b/o3d/core/cross/effect_test.cc
@@ -74,6 +74,54 @@ void EffectTest::TearDown() {
namespace {
+#if defined(RENDERER_GLES2)
+
+char kLambertEffect[] =
+ "attribute vec4 position; // : POSITION; \n"
+ "attribute vec3 normal; // : NORMAL; \n"
+ "attribute vec2 texcoord1; // : TEXCOORD1; \n"
+ " \n"
+ "uniform mat4 worldViewProjection; // : WorldViewProjection; \n"
+ "uniform mat4 world; // : World; \n"
+ "uniform mat4 worldInverseTranspose; // : WorldInverseTranspose; \n"
+ "uniform vec3 lightWorldPos; \n"
+ " \n"
+ "varying vec3 v_n; // : TEXCOORD1; \n"
+ "varying vec3 v_l; // : TEXCOORD2; \n"
+ "varying vec2 v_diffuseUV; // : TEXCOORD0; \n"
+ " \n"
+ "void main() { \n"
+ " gl_Position = worldViewProjection * position; \n"
+ " v_n = (worldInverseTranspose * vec4(normal, 0)).xyz; \n"
+ " v_l = lightWorldPos - (world * position).xyz; \n"
+ " v_diffuseUV = texcoord1; \n"
+ "} \n"
+ " \n"
+ "// This hack is here for now since O3D only allows one string \n"
+ "// to be passed to Effect::loadFromFXString \n"
+ "// #o3d SplitMarker \n"
+ " \n"
+ "uniform vec4 lightColor; \n"
+ "uniform vec4 emissive; \n"
+ "uniform vec4 ambient; \n"
+ "uniform sampler2D diffuseSampler; \n"
+ " \n"
+ "varying vec3 v_n; // : TEXCOORD1; \n"
+ "varying vec3 v_l; // : TEXCOORD2; \n"
+ "varying vec2 v_diffuseUV; // : TEXCOORD0; \n"
+ " \n"
+ "void main() { \n"
+ " vec4 diffuse = texture2D(diffuseSampler, v_diffuseUV); \n"
+ " vec3 l = normalize(v_l); \n"
+ " vec3 n = normalize(v_n); \n"
+ " vec4 litR = vec4(dot(n,l),0,0,0); // fixme hack! \n"
+ " gl_FragColor = emissive+lightColor*(ambient+diffuse*litR.y); \n"
+ "} \n"
+ "// #o3d MatrixLoadOrder RowMajor \n"
+ "";
+
+#else
+
char kLambertEffect[] =
"struct a2v { \n"
"float4 pos : POSITION; \n"
@@ -118,6 +166,8 @@ char kLambertEffect[] =
"// #o3d MatrixLoadOrder RowMajor \n"
"";
+#endif
+
struct ParamInfo {
const char* name;
const ObjectBase::Class* type;
@@ -126,6 +176,23 @@ struct ParamInfo {
const ObjectBase::Class* sas_type;
};
+#if defined(RENDERER_GLES2)
+ParamInfo expected_params[] = {
+ { "lightWorldPos", ParamFloat3::GetApparentClass(), 0, "", NULL, },
+ { "lightColor", ParamFloat4::GetApparentClass(), 0, "", NULL, },
+ { "emissive", ParamFloat4::GetApparentClass(), 0, "", NULL, },
+ { "ambient", ParamFloat4::GetApparentClass(), 0, "", NULL, },
+ { "diffuseSampler", ParamSampler::GetApparentClass(), 0, "", NULL, },
+ { "worldViewProjection", ParamMatrix4::GetApparentClass(), 0,
+ "WORLDVIEWPROJECTION",
+ WorldViewProjectionParamMatrix4::GetApparentClass(), },
+ { "world", ParamMatrix4::GetApparentClass(), 0,
+ "WORLD", WorldParamMatrix4::GetApparentClass(), },
+ { "worldInverseTranspose", ParamMatrix4::GetApparentClass(), 0,
+ "WORLDINVERSETRANSPOSE",
+ WorldInverseTransposeParamMatrix4::GetApparentClass(), },
+};
+#else
ParamInfo expected_params[] = {
{ "lightWorldPos", ParamFloat3::GetApparentClass(), 0, "", NULL, },
{ "lightColor", ParamFloat4::GetApparentClass(), 0, "", NULL, },
@@ -141,6 +208,7 @@ ParamInfo expected_params[] = {
{ "worldIT", ParamMatrix4::GetApparentClass(), 0, "WORLDINVERSETRANSPOSE",
WorldInverseTransposeParamMatrix4::GetApparentClass(), },
};
+#endif
EffectStreamInfo expected_streams[] = {
EffectStreamInfo(Stream::POSITION, 0),
diff --git a/o3d/core/cross/gles2/effect_gles2.cc b/o3d/core/cross/gles2/effect_gles2.cc
index e0dfaca..f874334 100644
--- a/o3d/core/cross/gles2/effect_gles2.cc
+++ b/o3d/core/cross/gles2/effect_gles2.cc
@@ -33,7 +33,6 @@
// This file contains the definition of EffectGLES2, the OpenGLES2
// implementation of the abstract O3D class Effect.
-
// Disable pointer casting warning for OpenGLES2 calls that require a void* to
// be cast to a GLuint
#if defined(OS_WIN)
@@ -64,28 +63,46 @@ namespace o3d {
// draw polygons, etc.
const int kNumLoggedEvents = 5;
-// Convert a CGparameter data type into a Param type. Note that
-// Param::BOOLEAN is never generated by the Cg compiler.
-static const ObjectBase::Class* CgTypeToParamType(CGtype cg_type) {
- switch (cg_type) {
- case CG_FLOAT :
- case CG_FLOAT1 : return ParamFloat::GetApparentClass();
- 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 :
- case CG_BOOL1 : return ParamBoolean::GetApparentClass();
- case CG_SAMPLER :
- case CG_SAMPLER1D :
- case CG_SAMPLER2D :
- case CG_SAMPLER3D :
- case CG_SAMPLERCUBE : return ParamSampler::GetApparentClass();
+// Convert a GLunum data type into a Param type.
+static const ObjectBase::Class* GLTypeToParamType(GLenum gl_type) {
+ switch (gl_type) {
+ case GL_FLOAT:
+ return ParamFloat::GetApparentClass();
+ case GL_FLOAT_VEC2:
+ return ParamFloat2::GetApparentClass();
+ case GL_FLOAT_VEC3:
+ return ParamFloat3::GetApparentClass();
+ case GL_FLOAT_VEC4:
+ return ParamFloat4::GetApparentClass();
+ case GL_INT:
+ return ParamInteger::GetApparentClass();
+ case GL_INT_VEC2:
+ return NULL;
+ case GL_INT_VEC3:
+ return NULL;
+ case GL_INT_VEC4:
+ return NULL;
+ case GL_BOOL:
+ return ParamBoolean::GetApparentClass();
+ case GL_BOOL_VEC2:
+ return NULL;
+ case GL_BOOL_VEC3:
+ return NULL;
+ case GL_BOOL_VEC4:
+ return NULL;
+ case GL_FLOAT_MAT2:
+ return NULL;
+ case GL_FLOAT_MAT3:
+ return NULL;
+ case GL_FLOAT_MAT4:
+ return ParamMatrix4::GetApparentClass();
+ case GL_SAMPLER_2D:
+ return ParamSampler::GetApparentClass();
+ case GL_SAMPLER_CUBE:
+ return ParamSampler::GetApparentClass();
default : {
- DLOG(ERROR) << "Cannot convert CGtype "
- << cgGetTypeString(cg_type)
+ DLOG(ERROR) << "Cannot convert GLtype "
+ << gl_type
<< " to a Param type.";
return NULL;
}
@@ -94,14 +111,13 @@ static const ObjectBase::Class* CgTypeToParamType(CGtype cg_type) {
// -----------------------------------------------------------------------------
-EffectGLES2::EffectGLES2(ServiceLocator* service_locator, CGcontext cg_context)
+EffectGLES2::EffectGLES2(ServiceLocator* service_locator)
: Effect(service_locator),
semantic_manager_(service_locator->GetService<SemanticManager>()),
renderer_(static_cast<RendererGLES2*>(
service_locator->GetService<Renderer>())),
- cg_context_(cg_context),
- cg_vertex_(NULL),
- cg_fragment_(NULL) {
+ gl_program_(0),
+ compile_count_(-1) {
DLOG(INFO) << "EffectGLES2 Construct";
}
@@ -109,373 +125,205 @@ EffectGLES2::EffectGLES2(ServiceLocator* service_locator, CGcontext cg_context)
// constants tables.
EffectGLES2::~EffectGLES2() {
DLOG(INFO) << "EffectGLES2 Destruct \"" << name() << "\"";
- if (cg_vertex_) {
- cgDestroyProgram(cg_vertex_);
- }
- if (cg_fragment_) {
- cgDestroyProgram(cg_fragment_);
+ ClearProgram();
+}
+
+void EffectGLES2::ClearProgram() {
+ if (gl_program_) {
+ glDeleteProgram(gl_program_);
+ gl_program_ = 0;
}
+ set_source("");
}
-// Rewrites vertex program assembly code to match GLES2 semantics for clipping.
-// This parses the source, breaking it down into pieces:
-// - declaration ("!!ARBvp1.0")
-// - comments (that contain the parameter information)
-// - instructions
-// - "END" token.
-// Then it rewrites the instructions so that 'result.position' doesn't get
-// written directly, instead it is written to a temporary variable. Then a
-// transformation is done on that variable before outputing to
-// 'result.position':
-// - offset x and y by half a pixel (times w).
-// - remap z from [0..w] to [-w..w].
-// - invert y, if render targets are active.
-//
-// Note that for the 1/2 pixel offset, we need a parameter that depends on the
-// current viewport. This is done through 'program.env[0]' which is shared
-// across all programs (so we only have to update it once when we change the
-// viewport), because Cg won't use them currently (it uses 'program.local'
-// instead).
-static bool RewriteVertexProgramSource(String *source) {
- String::size_type pos = source->find('\n');
- if (pos == String::npos) {
- DLOG(ERROR) << "could not find program declaration";
- return false;
+GLuint EffectGLES2::LoadShader(GLenum type, const char* shader_src) {
+ GLuint shader = glCreateShader(type);
+ if (shader == 0) {
+ return 0;
}
- String decl(*source, 0, pos + 1);
- String::size_type start_comments = pos + 1;
- // skip the comments that contain the parameters etc.
- for (; pos < source->size(); pos = source->find('\n', pos)) {
- ++pos;
- if (pos >= source->size())
- break;
- if ((*source)[pos] != '#')
- break;
+
+ // Load the shader source
+ glShaderSource(shader, 1, &shader_src, NULL);
+ // Compile the shader
+ glCompileShader(shader);
+ // Check the compile status
+ GLint value;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
+ if (value == 0) {
+ GLint error_length;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &error_length);
+ scoped_array<char> buffer(new char[error_length + 1]);
+ GLsizei length;
+ glGetShaderInfoLog(shader, error_length + 1, &length, buffer.get());
+ O3D_ERROR(service_locator()) << "Effect Compile Error: " << buffer.get();
+ DLOG(ERROR) << "Error compiling shader:" << buffer.get();
+ glDeleteShader(shader);
+ return 0;
}
- if (pos >= source->size()) {
- // we only found comments.
- return false;
+ return shader;
+}
+
+namespace {
+
+String::size_type GetEndOfIdentifier(const String& original,
+ String::size_type start) {
+ if (start < original.size()) {
+ // check that first character is alpha or '_'
+ if (isalpha(original[start]) || original[start] == '_') {
+ String::size_type end = original.size();
+ String::size_type position = start;
+ while (position < end) {
+ char c = original[position];
+ if (!isalnum(c) && c != '_') {
+ break;
+ }
+ ++position;
+ }
+ return position;
+ }
}
- String comments(*source, start_comments, pos - start_comments);
+ return String::npos;
+}
- String::size_type end_token = source->find("\nEND", pos + 1);
- if (end_token == String::npos) {
- DLOG(ERROR) << "Compiled shader doesn't have an END token";
+bool GetIdentifierAfterString(const String& original,
+ const String& phrase,
+ String* word) {
+ String::size_type position = original.find(phrase);
+ if (position == String::npos) {
return false;
}
- String instructions(*source, pos, end_token + 1 - pos);
-
- // Replace accesses to 'result.position' by accesses to our temp variable
- // '$O3D_HPOS'.
- // '$' is a valid symbol for identifiers, but Cg doesn't seem to be using
- // it, so we can use it to ensure we don't have name conflicts.
- static const char kOutPositionRegister[] = "result.position";
- for (String::size_type i = instructions.find(kOutPositionRegister);
- i < String::npos; i = instructions.find(kOutPositionRegister, i)) {
- instructions.replace(i, strlen(kOutPositionRegister), "$O3D_HPOS");
- }
- *source = decl +
- comments +
- // .x = 1/viewport.width; .y = -1/viewport.height; .z = 2.0; w = +/-1.0;
- "PARAM $O3D_HELPER = program.env[0];\n"
- "TEMP $O3D_HPOS;\n" +
- instructions +
- // hpos.x <- hpos.x + hpos.w / viewport.width;
- // hpos.y <- hpos.y - hpos.w / viewport.height;
- "MAD $O3D_HPOS.xy, $O3D_HELPER.xyyy, $O3D_HPOS.w, $O3D_HPOS.xyyy;\n"
- // Invert y, based on the w component of the helper arg.
- "MUL $O3D_HPOS.y, $O3D_HELPER.w, $O3D_HPOS.y;\n"
- // hpos.z <- hpos.z * 2 - hpos.w
- "MAD $O3D_HPOS.z, $O3D_HPOS.z, $O3D_HELPER.z, -$O3D_HPOS.w;\n"
- "MOV result.position, $O3D_HPOS;\n"
- "END\n";
- return true;
+ // Find end of identifier
+ String::size_type start = position + phrase.size();
+ String::size_type end = GetEndOfIdentifier(original, start);
+ if (end != start && end != String::npos) {
+ *word = String(original, start, end - start);
+ return true;
+ }
+ return false;
}
+} // anonymous namespace
+
// Initializes the Effect object using the shaders found in an FX formatted
// string.
bool EffectGLES2::LoadFromFXString(const String& effect) {
DLOG(INFO) << "EffectGLES2 LoadFromFXString";
renderer_->MakeCurrentLazy();
- set_source("");
+ ++compile_count_;
+ ClearProgram();
- String vertex_shader_entry_point;
- String fragment_shader_entry_point;
- MatrixLoadOrder matrix_load_order;
- // TODO(gman): Check for failure once shader parser is in.
- if (!ValidateFX(effect,
- &vertex_shader_entry_point,
- &fragment_shader_entry_point,
- &matrix_load_order)) {
+ String matrix_load_order_str;
+ if (!GetIdentifierAfterString(effect,
+ kMatrixLoadOrderPrefix,
+ &matrix_load_order_str)) {
+ O3D_ERROR(service_locator()) << "Failed to find \""
+ << kMatrixLoadOrderPrefix
+ << "\" in Effect";
return false;
}
-
- set_matrix_load_order(matrix_load_order);
-
- // Compile the original vertex program once, to get the ARBVP1 assembly code.
- CGprogram original_vp = cgCreateProgram(cg_context_, CG_SOURCE,
- effect.c_str(), CG_PROFILE_ARBVP1,
- vertex_shader_entry_point.c_str(),
- NULL);
- const char* listing = cgGetLastListing(cg_context_);
- if (original_vp == NULL) {
- O3D_ERROR(service_locator()) << "Effect Compile Error: "
- << cgGetErrorString(cgGetError()) << " : "
- << listing;
+ bool column_major = matrix_load_order_str.c_str() == "ColumnMajor";
+ MatrixLoadOrder matrix_load_order = column_major ? COLUMN_MAJOR : ROW_MAJOR;
+
+ // Split the effect
+ const char* kSplitMarker = "// #o3d SplitMarker";
+ String::size_type split_pos = effect.find(kSplitMarker);
+ if (split_pos == String::npos) {
+ O3D_ERROR(service_locator()) << "Missing '" << kSplitMarker
+ << "' in shader: " << effect;
return false;
}
- if (listing && listing[0] != 0) {
- DLOG(WARNING) << "Effect Compile Warnings: " << listing;
- }
-
- String vp_assembly = cgGetProgramString(original_vp, CG_COMPILED_PROGRAM);
- cgDestroyProgram(original_vp);
- if (!RewriteVertexProgramSource(&vp_assembly)) {
- return false;
- }
- cg_vertex_ = cgCreateProgram(cg_context_, CG_OBJECT, vp_assembly.c_str(),
- CG_PROFILE_ARBVP1,
- vertex_shader_entry_point.c_str(), NULL);
- listing = cgGetLastListing(cg_context_);
- if (cg_vertex_ == NULL) {
- O3D_ERROR(service_locator()) << "Effect post-rewrite Compile Error: "
- << cgGetErrorString(cgGetError()) << " : "
- << listing;
- return false;
- }
+ String vertex_shader(effect.substr(0, split_pos));
+ String fragment_shader("// " + effect.substr(split_pos));
-#ifdef OS_WIN
- // Get metrics for length of the vertex shader
- const char* shader_data = cgGetProgramString(cg_vertex_, CG_COMPILED_PROGRAM);
- metric_vertex_shader_instruction_count.AddSample(strlen(shader_data));
-#endif
-
- if (listing && listing[0] != 0) {
- DLOG(WARNING) << "Effect post-rewrite compile warnings: " << listing;
- }
-
- CHECK_GL_ERROR();
+ set_matrix_load_order(matrix_load_order);
- // If the program rewrite introduced some syntax or semantic errors, we won't
- // know it until we load the program (through a GLES2 error).
- // So flush all GLES2 errors first...
- do {} while (glGetError() != GL_NO_ERROR);
-
- // ... Then load the program ...
- cgGLLoadProgram(cg_vertex_);
-
- // ... And check for GLES2 errors.
- if (glGetError() != GL_NO_ERROR) {
- O3D_ERROR(service_locator())
- << "Effect post-rewrite GLES2 Error: "
- << glGetString(GL_PROGRAM_ERROR_STRING_ARB)
- << "\nSource: \n"
- << vp_assembly;
+ GLuint gl_vertex_shader =
+ LoadShader(GL_VERTEX_SHADER, vertex_shader.c_str());
+ if (!gl_vertex_shader) {
return false;
}
-
- cg_fragment_ = cgCreateProgram(cg_context_, CG_SOURCE, effect.c_str(),
- CG_PROFILE_ARBFP1,
- fragment_shader_entry_point.c_str(), NULL);
- listing = cgGetLastListing(cg_context_);
- if (cg_fragment_ == NULL) {
- O3D_ERROR(service_locator()) << "Effect Compile Error: "
- << cgGetErrorString(cgGetError()) << " : "
- << listing;
+ GLuint gl_fragment_shader =
+ LoadShader(GL_FRAGMENT_SHADER, fragment_shader.c_str());
+ if (!gl_fragment_shader) {
+ glDeleteShader(gl_vertex_shader);
return false;
}
-
-#ifdef OS_WIN
- // Get metrics for length of the fragment shader
- shader_data = cgGetProgramString(cg_fragment_, CG_COMPILED_PROGRAM);
- metric_pixel_shader_instruction_count.AddSample(strlen(shader_data));
-#endif
-
- if (listing && listing[0] != 0) {
- DLOG(WARNING) << "Effect Compile Warnings: " << listing;
+ gl_program_ = glCreateProgram();
+ if (!gl_program_) {
+ glDeleteShader(gl_fragment_shader);
+ glDeleteShader(gl_vertex_shader);
+ return false;
}
-
- cgGLLoadProgram(cg_fragment_);
-
- // Also check for GLES2 errors, in case Cg managed to compile, but generated a
- // bad program.
- if (glGetError() != GL_NO_ERROR) {
- O3D_ERROR(service_locator())
- << "Effect GLES2 Error: "
- << glGetString(GL_PROGRAM_ERROR_STRING_ARB);
+ glAttachShader(gl_program_, gl_vertex_shader);
+ glAttachShader(gl_program_, gl_fragment_shader);
+ glLinkProgram(gl_program_);
+ glDeleteShader(gl_vertex_shader);
+ glDeleteShader(gl_fragment_shader);
+ // Check the compile status
+ GLint value;
+ glGetProgramiv(gl_program_, GL_LINK_STATUS, &value);
+ if (value == 0) {
+ GLint error_length;
+ glGetProgramiv(gl_program_, GL_INFO_LOG_LENGTH, &error_length);
+ scoped_array<char> buffer(new char[error_length + 1]);
+ GLsizei length;
+ glGetProgramInfoLog(gl_program_, error_length + 1, &length, buffer.get());
+ O3D_ERROR(service_locator()) << "Effect Link Error: " << buffer.get();
+ DLOG(ERROR) << "Error linking programr:" << buffer.get();
+ glDeleteProgram(gl_program_);
return false;
}
- // TODO(o3d): remove this (OLD path for textures).
- FillSamplerToTextureMap(effect);
-
CHECK_GL_ERROR();
set_source(effect);
return true;
}
-// Fills the sampler->texture map. This needs to compile the source as an
-// effect because the state assignments get lost when compiled as a
-// shader.
-// Note that we compile the raw effect, which shouldn't have any
-// technique/pass, so we don't actually create programs, just parse the
-// uniforms and state assignments.
-void EffectGLES2::FillSamplerToTextureMap(const String &effect) {
- CGeffect cg_effect = cgCreateEffect(cg_context_, effect.c_str(), NULL);
- if (!cg_effect) {
- DLOG(ERROR) << "Could not compile the effect to find "
- << "Sampler->Texture associations";
- return;
- }
- for (CGparameter param = cgGetFirstEffectParameter(cg_effect);
- param; param = cgGetNextLeafParameter(param)) {
- CGtype cg_type = cgGetParameterType(param);
- switch (cg_type) {
- case CG_SAMPLER:
- case CG_SAMPLER1D:
- case CG_SAMPLER2D:
- case CG_SAMPLER3D:
- case CG_SAMPLERCUBE:
- break;
- default:
- continue;
- }
- CGstateassignment state_assignment =
- cgGetNamedSamplerStateAssignment(param, "Texture");
- if (!state_assignment)
- continue;
- CGparameter texture_param =
- cgGetTextureStateAssignmentValue(state_assignment);
- if (!texture_param)
- continue;
- DCHECK((cgGetParameterType(texture_param) == CG_TEXTURE));
- sampler_to_texture_map_[cgGetParameterName(param)] =
- cgGetParameterName(texture_param);
- }
- cgDestroyEffect(cg_effect);
-}
-
-// TODO(o3d): remove this (OLD path for textures).
-String EffectGLES2::GetTextureNameFromSamplerParamName(
- const String &sampler_name) {
- std::map<String, String>::iterator it =
- sampler_to_texture_map_.find(sampler_name);
- if (it != sampler_to_texture_map_.end()) {
- return it->second;
- } else {
- return "";
- }
-}
-
-// Given a CG_SAMPLER parameter, find the corresponding CG_TEXTURE
-// parameter. From this CG_TEXTURE, find a matching Param by name.
-ParamTexture* EffectGLES2::GetTextureParamFromCgSampler(
- CGparameter cg_sampler,
- const std::vector<ParamObject*> &param_objects) {
- DLOG(INFO) << "EffectGLES2 GetTextureParamFromCgSampler";
- DLOG_ASSERT(cgGetParameterType(cg_sampler) != CG_SAMPLER);
- String sampler_name = cgGetParameterName(cg_sampler);
- String param_name = GetTextureNameFromSamplerParamName(sampler_name);
- if (param_name.size() == 0) {
- // Sampler has no texture associated with it.
- return NULL;
- }
- // Find a matching Param with the same name as the CG_TEXTURE.
- for (unsigned int i = 0; i < param_objects.size(); ++i) {
- Param* param = param_objects[i]->GetUntypedParam(param_name);
- if (param && param->IsA(ParamTexture::GetApparentClass())) {
- // Success.
- DLOG(INFO) << "EffectGLES2 Matched CG_SAMPLER \""
- << sampler_name
- << "\" To Param \""
- << param_name << "\"";
- return down_cast<ParamTexture*>(param);
- }
- }
- DLOG(INFO) << "No matching Param for CG_TEXTURE \""
- << param_name
- << "\" used by CG_SAMPLER \""
- << sampler_name << "\"";
- return NULL;
-}
-
void EffectGLES2::GetShaderParamInfo(
- CGprogram program,
- CGenum name_space,
+ GLuint program,
std::map<String, EffectParameterInfo>* info_map) {
DCHECK(info_map);
+ if (!program) {
+ return;
+ }
- // Loop over all parameters, visiting only CGparameters that have
- // had storage allocated to them.
- CGparameter cg_param = cgGetFirstParameter(program, name_space);
- for (; cg_param != NULL; cg_param = cgGetNextParameter(cg_param)) {
- CGenum variability = cgGetParameterVariability(cg_param);
- if (variability != CG_UNIFORM)
- continue;
- CGenum direction = cgGetParameterDirection(cg_param);
- if (direction != CG_IN)
- continue;
- String name = cgGetParameterName(cg_param);
- CGtype cg_type = cgGetParameterType(cg_param);
- // Texture parameters need special handling as the c3cImport system
- // records a handle to the CG_TEXTURE param, not the CG_SAMPLER
- // param. D3D sets textures by binding a bitmap to the Texture
- // param, Cg binds bitmaps to the Sampler parameter. We solve this
- // by keeping an internal collection of Texture-Sampler mappings
- // that is built here, so we can later to do the reverse lookup.
- //
- // 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(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 ||
- cg_type == CG_SAMPLERCUBE) {
- // rename the parameter to have the name of the texture.
- String texture_param_name = GetTextureNameFromSamplerParamName(name);
- if (texture_param_name.size() != 0) {
- (*info_map)[texture_param_name] = EffectParameterInfo(
- texture_param_name,
- ParamTexture::GetApparentClass(),
- 0,
- "",
- false);
- }
- } else if (cg_type == CG_TEXTURE) {
- continue;
- }
- int num_elements;
- if (cg_type == CG_ARRAY) {
- num_elements = cgGetArraySize(cg_param, 0);
- // Substitute the first element's type for our type.
- cg_type = cgGetParameterType(cgGetArrayParameter(cg_param, 0));
- } else {
- num_elements = 0;
+ GLint num_uniforms = 0;
+ GLint max_len = 0;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &num_uniforms);
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
+ // TODO(gman): Should we check for error?
+ scoped_array<char> name_buffer(new char[max_len + 1]);
+ // Loop over all parameters.
+ for (GLint ii = 0; ii < num_uniforms; ++ii) {
+ GLsizei length;
+ GLsizei size;
+ GLenum type;
+ glGetActiveUniform(
+ program, ii, max_len + 1, &length, &size, &type, name_buffer.get());
+ String name(name_buffer.get());
+ // TODO(gman): Should we check for error?
+ // TODO(gman): Should we skip uniforms that start with "gl_"?
+ GLint location = glGetUniformLocation(program, name_buffer.get());
+ int num_elements = 0;
+ if (size > 1) {
+ // It's an array.
+ num_elements = size;
}
- const ObjectBase::Class *param_class = CgTypeToParamType(cg_type);
+ const ObjectBase::Class *param_class = GLTypeToParamType(type);
if (!param_class)
continue;
- const char* cg_semantic = cgGetParameterSemantic(cg_param);
const ObjectBase::Class *sem_class = NULL;
- if (cg_semantic != NULL && cg_semantic[0] != '\0') {
- // NOTE: this semantic is not the regularised profile semantic output
- // from the CGC compiler but the actual user supplied semantic from
- // the shader source code, so this match is valid.
- sem_class = semantic_manager_->LookupSemantic(cg_semantic);
- }
+ // Since there is no SAS for GLSL let's just use reserved names.
+ sem_class = semantic_manager_->LookupSemantic(name);
(*info_map)[name] = EffectParameterInfo(
name,
param_class,
num_elements,
- (cg_semantic != NULL) ? cg_semantic : "",
+ sem_class != NULL ? name : "",
sem_class);
}
}
@@ -484,15 +332,8 @@ void EffectGLES2::GetParameterInfo(EffectParameterInfoArray* info_array) {
DCHECK(info_array);
std::map<String, EffectParameterInfo> info_map;
renderer_->MakeCurrentLazy();
- if (cg_vertex_) {
- GetShaderParamInfo(cg_vertex_, CG_PROGRAM, &info_map);
- GetShaderParamInfo(cg_vertex_, CG_GLOBAL, &info_map);
- }
- if (cg_fragment_) {
- // create Param objects based on the parameters found in the fragment
- // program.
- GetShaderParamInfo(cg_fragment_, CG_PROGRAM, &info_map);
- GetShaderParamInfo(cg_fragment_, CG_GLOBAL, &info_map);
+ if (gl_program_) {
+ GetShaderParamInfo(gl_program_, &info_map);
}
info_array->clear();
info_array->reserve(info_map.size());
@@ -504,34 +345,31 @@ void EffectGLES2::GetParameterInfo(EffectParameterInfoArray* info_array) {
}
void EffectGLES2::GetVaryingVertexShaderParamInfo(
- CGprogram program,
- CGenum name_space,
+ GLuint program,
std::vector<EffectStreamInfo>* info_array) {
- CGparameter cg_param = cgGetFirstLeafParameter(cg_vertex_, name_space);
- for (; cg_param != NULL; cg_param = cgGetNextLeafParameter(cg_param)) {
- CGenum variability = cgGetParameterVariability(cg_param);
- if (variability != CG_VARYING)
- continue;
- CGenum direction = cgGetParameterDirection(cg_param);
- if (direction != CG_IN)
- continue;
-
- const char* cg_semantic = cgGetParameterSemantic(cg_param);
- if (cg_semantic == NULL)
- continue;
-
- int attr = SemanticNameToGLVertexAttribute(cg_semantic);
- if (attr < 0)
- continue;
-
- int semantic_index = 0;
- Stream::Semantic semantic = GLVertexAttributeToStream(attr,
- &semantic_index);
- if (semantic == Stream::UNKNOWN_SEMANTIC)
+ GLint num_attribs = 0;
+ GLint max_len = 0;
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &num_attribs);
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
+ // TODO(gman): Should we check for error?
+ scoped_array<char> name_buffer(new char[max_len + 1]);
+ for (GLint ii = 0; ii < num_attribs; ++ii) {
+ GLsizei length;
+ GLsizei size;
+ GLenum type;
+ glGetActiveAttrib(
+ program, ii, max_len + 1, &length, &size, &type, name_buffer.get());
+ // TODO(gman): Should we check for error?
+ GLint location = glGetAttribLocation(program, name_buffer.get());
+ String name(name_buffer.get());
+ // Since GLSL has no semantics just go by name.
+ Stream::Semantic semantic;
+ int semantic_index;
+ if (!SemanticNameToSemantic(name, &semantic, &semantic_index)) {
continue;
+ }
- info_array->push_back(EffectStreamInfo(semantic,
- semantic_index));
+ info_array->push_back(EffectStreamInfo(semantic, semantic_index));
}
}
@@ -540,96 +378,66 @@ void EffectGLES2::GetStreamInfo(
DCHECK(info_array);
renderer_->MakeCurrentLazy();
info_array->clear();
- GetVaryingVertexShaderParamInfo(cg_vertex_, CG_PROGRAM, info_array);
- GetVaryingVertexShaderParamInfo(cg_vertex_, CG_GLOBAL, info_array);
+ GetVaryingVertexShaderParamInfo(gl_program_, info_array);
}
-
// private functions -----------------------------------------------------------
-// Loop over all the CG_SAMPLER objects and attach the GLuint handle for the
-// GLES2 texture object that we discovered earlier. Then execute the
-// CGstateassignments in the sampler_state to set up the texture unit.
-// TODO(o3d): remove this (OLD path for textures).
-void EffectGLES2::SetTexturesFromEffect(ParamCacheGLES2* param_cache_gl) {
- DLOG_FIRST_N(INFO, kNumLoggedEvents)
- << "EffectGLES2 EnableTexturesFromEffect";
- ParamCacheGLES2::SamplerParameterMap& map = param_cache_gl->sampler_map();
- ParamCacheGLES2::SamplerParameterMap::iterator i;
- for (i = map.begin(); i != map.end(); ++i) {
- CGparameter cg_param = i->first;
- ParamTexture *param = i->second;
- if (param != NULL) {
- Texture *t = param->value();
- if (t) {
- GLuint handle = static_cast<GLuint>(reinterpret_cast<intptr_t>(
- t->GetTextureHandle()));
- cgGLSetTextureParameter(cg_param, handle);
- cgGLEnableTextureParameter(cg_param);
- }
- }
- }
- CHECK_GL_ERROR();
-}
-
-// Loop through all the uniform CGparameters on the effect and set their
-// values from their corresponding Params on the various ParamObject (as stored
-// in the ParamCacheGLES2).
+// Loop through all the uniform parameters on the effect and set their values
+// from their corresponding Params on the various ParamObject (as stored in the
+// ParamCacheGLES2).
void EffectGLES2::UpdateShaderUniformsFromEffect(
ParamCacheGLES2* param_cache_gl) {
DLOG_FIRST_N(INFO, kNumLoggedEvents)
<< "EffectGLES2 UpdateShaderUniformsFromEffect";
+ renderer_->ResetTextureGroupSetCount();
ParamCacheGLES2::UniformParameterMap& map = param_cache_gl->uniform_map();
ParamCacheGLES2::UniformParameterMap::iterator i;
for (i = map.begin(); i != map.end(); ++i) {
- CGparameter cg_param = i->first;
- i->second->SetEffectParam(renderer_, cg_param);
+ GLES2Parameter gl_param = i->first;
+ i->second->SetEffectParam(renderer_, gl_param);
}
CHECK_GL_ERROR();
}
-// Loop through all the uniform CGparameters on the effect and reset their
-// values. For now, this unbinds textures contained in sampler parameters.
-void EffectGLES2::ResetShaderUniforms(ParamCacheGLES2* param_cache_gl) {
+// Loop through all the uniform parameters on the effect and reset their values.
+// For now, this unbinds textures contained in sampler parameters.
+void EffectGLES2::ResetShaderUniforms(ParamCacheGLES2* param_cache_gles2) {
DLOG_FIRST_N(INFO, kNumLoggedEvents) << "EffectGLES2 ResetShaderUniforms";
- ParamCacheGLES2::UniformParameterMap& map = param_cache_gl->uniform_map();
+ ParamCacheGLES2::UniformParameterMap& map = param_cache_gles2->uniform_map();
ParamCacheGLES2::UniformParameterMap::iterator i;
for (i = map.begin(); i != map.end(); ++i) {
- CGparameter cg_param = i->first;
- i->second->ResetEffectParam(renderer_, cg_param);
+ GLES2Parameter gl_param = i->first;
+ i->second->ResetEffectParam(renderer_, gl_param);
}
CHECK_GL_ERROR();
}
// Updates the values of the vertex and fragment shader parameters using the
-// current values in the param/cgparam caches.
-void EffectGLES2::PrepareForDraw(ParamCacheGLES2* param_cache_gl) {
+// current values in the param/glparam caches.
+void EffectGLES2::PrepareForDraw(ParamCacheGLES2* param_cache_gles2) {
DLOG_FIRST_N(INFO, kNumLoggedEvents) << "EffectGLES2 PrepareForDraw \""
<< name()
<< "\"";
DCHECK(renderer_->IsCurrent());
- if (cg_vertex_ && cg_fragment_) {
+ if (gl_program_) {
// Initialise the render states for this pass, this includes the shaders.
- cgGLBindProgram(cg_vertex_);
- cgGLBindProgram(cg_fragment_);
- UpdateShaderUniformsFromEffect(param_cache_gl);
-
- // TODO(o3d): remove this (OLD path for textures).
- SetTexturesFromEffect(param_cache_gl);
+ glUseProgram(gl_program_);
+ UpdateShaderUniformsFromEffect(param_cache_gles2);
} else {
DLOG_FIRST_N(ERROR, kNumLoggedEvents)
- << "No valid CGeffect found "
+ << "No valid GLES2effect found "
<< "in Effect \"" << name() << "\"";
}
CHECK_GL_ERROR();
}
// Resets the render states back to their default value.
-void EffectGLES2::PostDraw(ParamCacheGLES2* param_cache_gl) {
+void EffectGLES2::PostDraw(ParamCacheGLES2* param_cache_gles2) {
DLOG_FIRST_N(INFO, kNumLoggedEvents)
<< "EffectGLES2 PostDraw \"" << name() << "\"";
DCHECK(renderer_->IsCurrent());
- ResetShaderUniforms(param_cache_gl);
+ ResetShaderUniforms(param_cache_gles2);
CHECK_GL_ERROR();
}
diff --git a/o3d/core/cross/gles2/effect_gles2.h b/o3d/core/cross/gles2/effect_gles2.h
index a919fec..e9655ae 100644
--- a/o3d/core/cross/gles2/effect_gles2.h
+++ b/o3d/core/cross/gles2/effect_gles2.h
@@ -59,20 +59,23 @@ class ParamTexture;
class RendererGLES2;
class SemanticManager;
+// TODO(gman): Replace.
+typedef GLuint GLES2Parameter;
+
// A class to set an effect parameter from an O3D parameter.
class EffectParamHandlerGLES2 : public RefCounted {
public:
typedef SmartPointer<EffectParamHandlerGLES2> Ref;
virtual ~EffectParamHandlerGLES2() { }
- // Sets a GLES2/Cg Effect Parameter by an O3D Param.
+ // Sets a GLES2 Effect Parameter by an O3D Param.
virtual void SetEffectParam(
- RendererGLES2* renderer, CGparameter cg_param) = 0;
+ RendererGLES2* renderer, GLES2Parameter param) = 0;
- // Resets a GLES2/Cg Effect parameter to default (currently only
- // unbinds textures contained in Sampler params).
+ // Resets a GLES2 Effect parameter to default (currently only unbinds textures
+ // contained in Sampler params).
virtual void ResetEffectParam(
- RendererGLES2* renderer, CGparameter cg_param) {}
+ RendererGLES2* renderer, GLES2Parameter param) {}
};
// EffectGLES2 is an implementation of the Effect object for OpenGLES2. It
@@ -81,7 +84,7 @@ class EffectParamHandlerGLES2 : public RefCounted {
// provided separately as shader code or together in an FX file.
class EffectGLES2 : public Effect {
public:
- EffectGLES2(ServiceLocator* service_locator, CGcontext cg_context);
+ explicit EffectGLES2(ServiceLocator* service_locator);
virtual ~EffectGLES2();
// Reads the vertex and fragment shaders from string in the FX format.
@@ -104,16 +107,8 @@ class EffectGLES2 : public Effect {
virtual void GetStreamInfo(
EffectStreamInfoArray* info_array);
- // Given a CG_SAMPLER parameter, find the corresponding CG_TEXTURE
- // parameterand from this CG_TEXTURE, find a matching Param by name in a list
- // of ParamObject.
- // TODO(o3d): remove this (OLD path for textures).
- ParamTexture* GetTextureParamFromCgSampler(
- CGparameter cg_sampler,
- const std::vector<ParamObject*> &param_objects);
-
- CGprogram cg_vertex_program() { return cg_vertex_; }
- CGprogram cg_fragment_program() { return cg_fragment_; }
+ GLuint gl_program() { return gl_program_; }
+ int compile_count() { return compile_count_; }
private:
// Loops through all the parameters in the ShapeDataGLES2 and updates the
@@ -121,13 +116,13 @@ class EffectGLES2 : public Effect {
void UpdateShaderUniformsFromEffect(ParamCacheGLES2* param_cache_gl);
// Undoes the effect of the above. For now, this unbinds textures.
void ResetShaderUniforms(ParamCacheGLES2* param_cache_gl);
- void GetShaderParamInfo(CGprogram program,
- CGenum name_space,
+ void GetShaderParamInfo(GLuint program,
std::map<String, EffectParameterInfo>* info_map);
void GetVaryingVertexShaderParamInfo(
- CGprogram program,
- CGenum name_space,
+ GLuint program,
std::vector<EffectStreamInfo>* info_array);
+ void ClearProgram();
+ GLuint LoadShader(GLenum type, const char* shader_src);
// TODO(o3d): remove these (OLD path for textures).
void SetTexturesFromEffect(ParamCacheGLES2* param_cache_gl);
@@ -137,9 +132,8 @@ class EffectGLES2 : public Effect {
SemanticManager* semantic_manager_;
RendererGLES2* renderer_;
- CGcontext cg_context_;
- CGprogram cg_vertex_;
- CGprogram cg_fragment_;
+ GLuint gl_program_;
+ int compile_count_;
// TODO(o3d): remove this (OLD path for textures).
std::map<String, String> sampler_to_texture_map_;
diff --git a/o3d/core/cross/gles2/gles2_headers.h b/o3d/core/cross/gles2/gles2_headers.h
index 6fc9c9c..d00e2ef 100644
--- a/o3d/core/cross/gles2/gles2_headers.h
+++ b/o3d/core/cross/gles2/gles2_headers.h
@@ -36,8 +36,6 @@
#if defined(OS_WIN)
#include <GL/wglew.h>
#endif
-#include <Cg/cg.h>
-#include <Cg/cgGL.h>
#endif // O3D_CORE_CROSS_GLES2_GL_HEADERS_H_
diff --git a/o3d/core/cross/gles2/param_cache_gles2.cc b/o3d/core/cross/gles2/param_cache_gles2.cc
index 8d3371a..921813f 100644
--- a/o3d/core/cross/gles2/param_cache_gles2.cc
+++ b/o3d/core/cross/gles2/param_cache_gles2.cc
@@ -45,22 +45,28 @@
namespace o3d {
+namespace {
+
+String GetUniformSemantic(GLES2Parameter gl_param, const String& name) {
+ return name;
+}
+
+} // anonymous namespace
+
typedef std::vector<ParamObject *> ParamObjectList;
ParamCacheGLES2::ParamCacheGLES2(SemanticManager* semantic_manager,
Renderer* renderer)
: semantic_manager_(semantic_manager),
renderer_(renderer),
- last_vertex_program_(0),
- last_fragment_program_(0) {
+ last_compile_count_(0) {
}
bool ParamCacheGLES2::ValidateEffect(Effect* effect) {
DLOG_ASSERT(effect);
- EffectGLES2* effect_gl = down_cast<EffectGLES2*>(effect);
- return (effect_gl->cg_vertex_program() == last_vertex_program_ ||
- effect_gl->cg_fragment_program() == last_fragment_program_);
+ EffectGLES2* effect_gles2 = down_cast<EffectGLES2*>(effect);
+ return (effect_gles2->compile_count() == last_compile_count_);
}
void ParamCacheGLES2::UpdateCache(Effect* effect,
@@ -71,15 +77,13 @@ void ParamCacheGLES2::UpdateCache(Effect* effect,
DLOG_ASSERT(effect);
EffectGLES2* effect_gl = down_cast<EffectGLES2*>(effect);
- ScanCgEffectParameters(effect_gl->cg_vertex_program(),
- effect_gl->cg_fragment_program(),
+ ScanGLEffectParameters(effect_gl->gl_program(),
draw_element,
element,
material,
override);
- last_vertex_program_ = effect_gl->cg_vertex_program();
- last_fragment_program_ = effect_gl->cg_fragment_program();
+ last_compile_count_ = effect_gl->compile_count();
}
template <typename T>
@@ -88,7 +92,7 @@ class TypedEffectParamHandlerGLES2 : public EffectParamHandlerGLES2 {
explicit TypedEffectParamHandlerGLES2(T* param)
: param_(param) {
}
- virtual void SetEffectParam(RendererGLES2* renderer, CGparameter cg_param);
+ virtual void SetEffectParam(RendererGLES2* renderer, GLES2Parameter gl_param);
private:
T* param_;
};
@@ -98,10 +102,11 @@ class EffectParamHandlerGLMatrixRows : public EffectParamHandlerGLES2 {
explicit EffectParamHandlerGLMatrixRows(ParamMatrix4* param)
: param_(param) {
}
- virtual void SetEffectParam(RendererGLES2* renderer, CGparameter cg_param) {
+ virtual void SetEffectParam(RendererGLES2* renderer,
+ GLES2Parameter gl_param) {
// set the data as floats in row major order.
Matrix4 mat = param_->value();
- cgSetMatrixParameterfr(cg_param, &mat[0][0]);
+ glUniformMatrix4fv(gl_param, 1, GL_FALSE, &mat[0][0]);
}
private:
ParamMatrix4* param_;
@@ -112,10 +117,11 @@ class EffectParamHandlerGLMatrixColumns : public EffectParamHandlerGLES2 {
explicit EffectParamHandlerGLMatrixColumns(ParamMatrix4* param)
: param_(param) {
}
- virtual void SetEffectParam(RendererGLES2* renderer, CGparameter cg_param) {
+ virtual void SetEffectParam(
+ RendererGLES2* renderer, GLES2Parameter gl_param) {
// set the data as floats in column major order.
- Matrix4 mat = param_->value();
- cgSetMatrixParameterfc(cg_param, &mat[0][0]);
+ Matrix4 mat = transpose(param_->value());
+ glUniformMatrix4fv(gl_param, 1, GL_FALSE, &mat[0][0]);
}
private:
ParamMatrix4* param_;
@@ -124,49 +130,49 @@ class EffectParamHandlerGLMatrixColumns : public EffectParamHandlerGLES2 {
template <>
void TypedEffectParamHandlerGLES2<ParamFloat>::SetEffectParam(
RendererGLES2* renderer,
- CGparameter cg_param) {
+ GLES2Parameter gl_param) {
Float f = param_->value();
- cgSetParameter1f(cg_param, f);
+ glUniform1f(gl_param, f);
};
template <>
void TypedEffectParamHandlerGLES2<ParamFloat2>::SetEffectParam(
RendererGLES2* renderer,
- CGparameter cg_param) {
+ GLES2Parameter gl_param) {
Float2 f = param_->value();
- cgSetParameter2fv(cg_param, f.GetFloatArray());
+ glUniform2fv(gl_param, 1, f.GetFloatArray());
};
template <>
void TypedEffectParamHandlerGLES2<ParamFloat3>::SetEffectParam(
RendererGLES2* renderer,
- CGparameter cg_param) {
+ GLES2Parameter gl_param) {
Float3 f = param_->value();
- cgSetParameter3fv(cg_param, f.GetFloatArray());
+ glUniform3fv(gl_param, 1, f.GetFloatArray());
};
template <>
void TypedEffectParamHandlerGLES2<ParamFloat4>::SetEffectParam(
RendererGLES2* renderer,
- CGparameter cg_param) {
+ GLES2Parameter gl_param) {
Float4 f = param_->value();
- cgSetParameter4fv(cg_param, f.GetFloatArray());
+ glUniform4fv(gl_param, 1, f.GetFloatArray());
};
template <>
void TypedEffectParamHandlerGLES2<ParamInteger>::SetEffectParam(
RendererGLES2* renderer,
- CGparameter cg_param) {
+ GLES2Parameter gl_param) {
int i = param_->value();
- cgSetParameter1i(cg_param, i);
+ glUniform1i(gl_param, i);
};
template <>
void TypedEffectParamHandlerGLES2<ParamBoolean>::SetEffectParam(
RendererGLES2* renderer,
- CGparameter cg_param) {
+ GLES2Parameter gl_param) {
int i = param_->value();
- cgSetParameter1i(cg_param, i);
+ glUniform1i(gl_param, i);
};
class EffectParamHandlerForSamplersGLES2 : public EffectParamHandlerGLES2 {
@@ -174,7 +180,8 @@ class EffectParamHandlerForSamplersGLES2 : public EffectParamHandlerGLES2 {
explicit EffectParamHandlerForSamplersGLES2(ParamSampler* param)
: param_(param) {
}
- virtual void SetEffectParam(RendererGLES2* renderer, CGparameter cg_param) {
+ virtual void SetEffectParam(
+ RendererGLES2* renderer, GLES2Parameter gl_param) {
SamplerGLES2* sampler_gl = down_cast<SamplerGLES2*>(param_->value());
if (!sampler_gl) {
// Use the error sampler.
@@ -185,14 +192,16 @@ class EffectParamHandlerForSamplersGLES2 : public EffectParamHandlerGLES2 {
<< "Missing Sampler for ParamSampler " << param_->name();
}
}
- sampler_gl->SetTextureAndStates(cg_param);
+ GLint handle = sampler_gl->SetTextureAndStates(gl_param);
+ glUniform1iv(gl_param, 1, &handle);
}
- virtual void ResetEffectParam(RendererGLES2* renderer, CGparameter cg_param) {
+ virtual void ResetEffectParam(
+ RendererGLES2* renderer, GLES2Parameter gl_param) {
SamplerGLES2* sampler_gl = down_cast<SamplerGLES2*>(param_->value());
if (!sampler_gl) {
sampler_gl = down_cast<SamplerGLES2*>(renderer->error_sampler());
}
- sampler_gl->ResetTexture(cg_param);
+ sampler_gl->ResetTexture(gl_param);
}
private:
ParamSampler* param_;
@@ -201,100 +210,72 @@ class EffectParamHandlerForSamplersGLES2 : public EffectParamHandlerGLES2 {
template <typename T>
class EffectParamArrayHandlerGLES2 : public EffectParamHandlerGLES2 {
public:
- explicit EffectParamArrayHandlerGLES2(ParamParamArray* param)
- : param_(param) {
+ typedef typename T::DataType DataType;
+ EffectParamArrayHandlerGLES2(ParamParamArray* param, GLsizei size)
+ : param_(param),
+ size_(size) {
+ values_.reset(new DataType[size]);
}
- virtual void SetEffectParam(RendererGLES2* renderer, CGparameter cg_param) {
+ virtual void SetEffectParam(
+ RendererGLES2* renderer, GLES2Parameter gl_param) {
ParamArray* param = param_->value();
if (param) {
- int size = cgGetArraySize(cg_param, 0);
- if (size != static_cast<int>(param->size())) {
+ 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) {
+ 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));
+ SetElement(down_cast<T*>(untyped_element), &values_[i]);
} else {
O3D_ERROR(param->service_locator())
<< "Param in ParamArray at index " << i << " is not a "
<< T::GetApparentClassName();
}
}
+ SetElements(gl_param, size_, values_.get());
}
}
}
- void SetElement(CGparameter cg_element, T* param);
-
- private:
- ParamParamArray* param_;
-};
-
-template <bool column_major>
-class EffectParamArrayMatrix4HandlerGLES2 : public EffectParamHandlerGLES2 {
- public:
- explicit EffectParamArrayMatrix4HandlerGLES2(ParamParamArray* param)
- : param_(param) {
- }
- virtual void SetEffectParam(RendererGLES2* 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(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);
+ void SetElement(T* param, DataType* value);
+ void SetElements(GLES2Parameter gl_param, GLsizei size,
+ const DataType* values);
private:
ParamParamArray* param_;
+ scoped_array<DataType> values_;
+ GLsizei size_;
};
class EffectParamArraySamplerHandlerGLES2 : public EffectParamHandlerGLES2 {
public:
- explicit EffectParamArraySamplerHandlerGLES2(ParamParamArray* param)
- : param_(param) {
+ explicit EffectParamArraySamplerHandlerGLES2(ParamParamArray* param,
+ GLsizei size)
+ : param_(param),
+ size_(size) {
+ values_.reset(new GLint[size]);
}
- virtual void SetEffectParam(RendererGLES2* renderer, CGparameter cg_param) {
+ virtual void SetEffectParam(RendererGLES2* renderer,
+ GLES2Parameter gl_param) {
ParamArray* param = param_->value();
if (param) {
- int size = cgGetArraySize(cg_param, 0);
- if (size != static_cast<int>(param->size())) {
+ 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) {
+ for (int i = 0; i < size_; ++i) {
+ GLint handle = 0;
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);
SamplerGLES2* sampler_gl =
down_cast<SamplerGLES2*>(element->value());
@@ -308,32 +289,33 @@ class EffectParamArraySamplerHandlerGLES2 : public EffectParamHandlerGLES2 {
<< "' index " << i;
}
}
- sampler_gl->SetTextureAndStates(cg_element);
+ handle = sampler_gl->SetTextureAndStates(gl_param);
} else {
O3D_ERROR(param->service_locator())
<< "Param in ParamArray at index " << i
<< " is not a ParamSampler";
}
+ values_[i] = handle;
}
+ glUniform1iv(gl_param, size_, values_.get());
}
}
}
- virtual void ResetEffectParam(RendererGLES2* renderer, CGparameter cg_param) {
+ virtual void ResetEffectParam(RendererGLES2* renderer,
+ GLES2Parameter gl_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) {
+ 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);
SamplerGLES2* sampler_gl =
down_cast<SamplerGLES2*>(element->value());
if (!sampler_gl) {
sampler_gl = down_cast<SamplerGLES2*>(renderer->error_sampler());
}
- sampler_gl->ResetTexture(cg_element);
+ sampler_gl->ResetTexture(gl_param);
}
}
}
@@ -342,129 +324,206 @@ class EffectParamArraySamplerHandlerGLES2 : public EffectParamHandlerGLES2 {
private:
ParamParamArray* param_;
+ scoped_array<GLint> values_;
+ GLsizei size_;
};
template<>
void EffectParamArrayHandlerGLES2<ParamFloat>::SetElement(
- CGparameter cg_element,
- ParamFloat* param) {
- cgSetParameter1f(cg_element, param->value());
+ ParamFloat* param,
+ float* value) {
+ *value = param->value();
+}
+
+template<>
+void EffectParamArrayHandlerGLES2<ParamFloat>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const float* values) {
+ glUniform1fv(gl_param, count, values);
}
template<>
void EffectParamArrayHandlerGLES2<ParamFloat2>::SetElement(
- CGparameter cg_element,
- ParamFloat2* param) {
- Float2 f = param->value();
- cgSetParameter2fv(cg_element, f.GetFloatArray());
+ ParamFloat2* param,
+ Float2* value) {
+ *value = param->value();
+}
+
+template<>
+void EffectParamArrayHandlerGLES2<ParamFloat2>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const Float2* values) {
+ glUniform2fv(gl_param, count, values[0].GetFloatArray());
}
template<>
void EffectParamArrayHandlerGLES2<ParamFloat3>::SetElement(
- CGparameter cg_element,
- ParamFloat3* param) {
- Float3 f = param->value();
- cgSetParameter3fv(cg_element, f.GetFloatArray());
+ ParamFloat3* param,
+ Float3* value) {
+ *value = param->value();
+}
+
+template<>
+void EffectParamArrayHandlerGLES2<ParamFloat3>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const Float3* values) {
+ glUniform3fv(gl_param, count, values[0].GetFloatArray());
}
template<>
void EffectParamArrayHandlerGLES2<ParamFloat4>::SetElement(
- CGparameter cg_element,
- ParamFloat4* param) {
- Float4 f = param->value();
- cgSetParameter4fv(cg_element, f.GetFloatArray());
+ ParamFloat4* param,
+ Float4* value) {
+ *value = param->value();
+}
+
+template<>
+void EffectParamArrayHandlerGLES2<ParamFloat4>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const Float4* values) {
+ glUniform4fv(gl_param, count, values[0].GetFloatArray());
+}
+
+class ColumnMajorParamMatrix4 : public ParamMatrix4 {
+};
+
+class RowMajorParamMatrix4 : public ParamMatrix4 {
+};
+
+template<>
+void EffectParamArrayHandlerGLES2<RowMajorParamMatrix4>::SetElement(
+ RowMajorParamMatrix4* param,
+ Matrix4* value) {
+ // set the data as floats in row major order.
+ *value = param->value();
+}
+
+template<>
+void EffectParamArrayHandlerGLES2<RowMajorParamMatrix4>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const Matrix4* values) {
+ glUniformMatrix4fv(gl_param, count, GL_FALSE,
+ reinterpret_cast<const GLfloat*>(values_.get()));
}
template<>
-void EffectParamArrayMatrix4HandlerGLES2<false>::SetElement(
- CGparameter cg_element,
- ParamMatrix4* param) {
+void EffectParamArrayHandlerGLES2<ColumnMajorParamMatrix4>::SetElement(
+ ColumnMajorParamMatrix4* param,
+ Matrix4* value) {
// set the data as floats in row major order.
- Matrix4 mat = param->value();
- cgSetMatrixParameterfr(cg_element, &mat[0][0]);
+ *value = transpose(param->value());
}
template<>
-void EffectParamArrayMatrix4HandlerGLES2<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]);
+void EffectParamArrayHandlerGLES2<ColumnMajorParamMatrix4>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const Matrix4* values) {
+ // NOTE: The transpose happens in the function above because GLES2 requires
+ // the transpose argument to this function to be GL_FALSE.
+ glUniformMatrix4fv(gl_param, count, GL_FALSE,
+ reinterpret_cast<const GLfloat*>(values_.get()));
+}
+
+template<>
+void EffectParamArrayHandlerGLES2<ParamBoolean>::SetElement(
+ ParamBoolean* param,
+ bool* value) {
+ *value = param->value();
+}
+
+template<>
+void EffectParamArrayHandlerGLES2<ParamBoolean>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const bool* values) {
+ scoped_array<GLint> local(new GLint[count]);
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ local[ii] = values[ii];
+ }
+ glUniform1iv(gl_param, count, local.get());
}
template<>
void EffectParamArrayHandlerGLES2<ParamInteger>::SetElement(
- CGparameter cg_element,
- ParamInteger* param) {
- cgSetParameter1i(cg_element, param->value());
+ ParamInteger* param,
+ int* value) {
+ *value = param->value();
}
template<>
-void EffectParamArrayHandlerGLES2<ParamBoolean>::SetElement(
- CGparameter cg_element,
- ParamBoolean* param) {
- cgSetParameter1i(cg_element, param->value());
+void EffectParamArrayHandlerGLES2<ParamInteger>::SetElements(
+ GLES2Parameter gl_param,
+ GLsizei count,
+ const int* values) {
+ glUniform1iv(gl_param, count, values);
}
-static EffectParamHandlerGLES2::Ref GetHandlerFromParamAndCgType(
+static EffectParamHandlerGLES2::Ref GetHandlerFromParamAndGLType(
EffectGLES2* effect_gl,
Param *param,
- CGtype cg_type) {
+ GLenum gl_type,
+ GLsizei size) {
EffectParamHandlerGLES2::Ref handler;
if (param->IsA(ParamParamArray::GetApparentClass())) {
ParamParamArray* param_param_array = down_cast<ParamParamArray*>(param);
- switch (cg_type) {
- case CG_FLOAT:
- case CG_FLOAT1:
+ switch (gl_type) {
+ case GL_FLOAT:
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayHandlerGLES2<ParamFloat>(param_param_array));
+ new EffectParamArrayHandlerGLES2<ParamFloat>(param_param_array,
+ size));
break;
- case CG_FLOAT2:
+ case GL_FLOAT_VEC2:
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayHandlerGLES2<ParamFloat2>(param_param_array));
+ new EffectParamArrayHandlerGLES2<ParamFloat2>(param_param_array,
+ size));
break;
- case CG_FLOAT3:
+ case GL_FLOAT_VEC3:
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayHandlerGLES2<ParamFloat3>(param_param_array));
+ new EffectParamArrayHandlerGLES2<ParamFloat3>(param_param_array,
+ size));
break;
- case CG_FLOAT4:
+ case GL_FLOAT_VEC4:
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayHandlerGLES2<ParamFloat4>(param_param_array));
+ new EffectParamArrayHandlerGLES2<ParamFloat4>(param_param_array,
+ size));
break;
- case CG_FLOAT4x4:
+ case GL_FLOAT_MAT4:
if (effect_gl->matrix_load_order() == Effect::COLUMN_MAJOR) {
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayMatrix4HandlerGLES2<true>(param_param_array));
+ new EffectParamArrayHandlerGLES2<ColumnMajorParamMatrix4>(
+ param_param_array, size));
} else {
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayMatrix4HandlerGLES2<false>(
- param_param_array));
+ new EffectParamArrayHandlerGLES2<RowMajorParamMatrix4>(
+ param_param_array, size));
}
break;
- case CG_INT:
- case CG_INT1:
+ case GL_INT:
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayHandlerGLES2<ParamInteger>(param_param_array));
+ new EffectParamArrayHandlerGLES2<ParamInteger>(param_param_array,
+ size));
break;
- case CG_BOOL:
- case CG_BOOL1:
+ case GL_BOOL:
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArrayHandlerGLES2<ParamBoolean>(param_param_array));
+ new EffectParamArrayHandlerGLES2<ParamBoolean>(param_param_array,
+ size));
break;
- case CG_SAMPLER:
- case CG_SAMPLER1D:
- case CG_SAMPLER2D:
- case CG_SAMPLER3D:
- case CG_SAMPLERCUBE:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
handler = EffectParamHandlerGLES2::Ref(
- new EffectParamArraySamplerHandlerGLES2(param_param_array));
+ new EffectParamArraySamplerHandlerGLES2(param_param_array, size));
break;
default:
break;
}
} else if (param->IsA(ParamMatrix4::GetApparentClass())) {
- if (cg_type == CG_FLOAT4x4) {
+ if (gl_type == GL_FLOAT_MAT4) {
if (effect_gl->matrix_load_order() == Effect::COLUMN_MAJOR) {
// set the data as floats in column major order.
handler = EffectParamHandlerGLES2::Ref(
@@ -478,48 +537,44 @@ static EffectParamHandlerGLES2::Ref GetHandlerFromParamAndCgType(
}
}
} else if (param->IsA(ParamFloat::GetApparentClass())) {
- if (cg_type == CG_FLOAT ||
- cg_type == CG_FLOAT1) {
+ if (gl_type == GL_FLOAT) {
handler = EffectParamHandlerGLES2::Ref(
new TypedEffectParamHandlerGLES2<ParamFloat>(
down_cast<ParamFloat*>(param)));
}
} else if (param->IsA(ParamFloat2::GetApparentClass())) {
- if (cg_type == CG_FLOAT2) {
+ if (gl_type == GL_FLOAT_VEC2) {
handler = EffectParamHandlerGLES2::Ref(
new TypedEffectParamHandlerGLES2<ParamFloat2>(
down_cast<ParamFloat2*>(param)));
}
} else if (param->IsA(ParamFloat3::GetApparentClass())) {
- if (cg_type == CG_FLOAT3) {
+ if (gl_type == GL_FLOAT_VEC3) {
handler = EffectParamHandlerGLES2::Ref(
new TypedEffectParamHandlerGLES2<ParamFloat3>(
down_cast<ParamFloat3*>(param)));
}
} else if (param->IsA(ParamFloat4::GetApparentClass())) {
- if (cg_type == CG_FLOAT4) {
+ if (gl_type == GL_FLOAT_VEC4) {
handler = EffectParamHandlerGLES2::Ref(
new TypedEffectParamHandlerGLES2<ParamFloat4>(
down_cast<ParamFloat4*>(param)));
}
} else if (param->IsA(ParamInteger::GetApparentClass())) {
- if (cg_type == CG_INT || cg_type == CG_INT1) {
+ if (gl_type == GL_INT) {
handler = EffectParamHandlerGLES2::Ref(
new TypedEffectParamHandlerGLES2<ParamInteger>(
down_cast<ParamInteger*>(param)));
}
} else if (param->IsA(ParamBoolean::GetApparentClass())) {
- if (cg_type == CG_BOOL || cg_type == CG_BOOL1) {
+ if (gl_type == GL_BOOL) {
handler = EffectParamHandlerGLES2::Ref(
new TypedEffectParamHandlerGLES2<ParamBoolean>(
down_cast<ParamBoolean*>(param)));
}
} else if (param->IsA(ParamSampler::GetApparentClass())) {
- if (cg_type == CG_SAMPLER ||
- cg_type == CG_SAMPLER1D ||
- cg_type == CG_SAMPLER2D ||
- cg_type == CG_SAMPLER3D ||
- cg_type == CG_SAMPLERCUBE) {
+ if (gl_type == GL_SAMPLER_2D ||
+ gl_type == GL_SAMPLER_CUBE) {
handler = EffectParamHandlerGLES2::Ref(
new EffectParamHandlerForSamplersGLES2(
down_cast<ParamSampler*>(param)));
@@ -530,28 +585,23 @@ static EffectParamHandlerGLES2::Ref GetHandlerFromParamAndCgType(
// Local helper function for scanning varying Cg parameters of a
// program or effect and recording their entries into the varying map.
-static void ScanVaryingParameters(CGprogram program,
- CGenum name_space,
+static void ScanVaryingParameters(GLuint gl_program,
ParamCacheGLES2* param_cache_gl) {
- CGparameter cg_param = cgGetFirstLeafParameter(program, name_space);
- for (; cg_param; cg_param = cgGetNextLeafParameter(cg_param)) {
- if (!cgIsParameterReferenced(cg_param))
- continue;
- CGenum variability = cgGetParameterVariability(cg_param);
- CGenum direction = cgGetParameterDirection(cg_param);
- if (variability == CG_VARYING && direction == CG_IN) {
- // Add a link between the parameter and no stream (index -1)
- // NOTE: Stream indexes will be set later in
- // InsertMissingVertexStreams().
- if (param_cache_gl->varying_map().find(cg_param) ==
- param_cache_gl->varying_map().end()) {
- const char* cg_name = cgGetParameterName(cg_param);
- param_cache_gl->varying_map().insert(std::make_pair(cg_param, -1));
- DLOG(INFO) << "ElementGLES2 Found CG_VARYING \""
- << cg_name << " : "
- << cgGetParameterSemantic(cg_param) << "\"";
- }
- }
+ GLint num_attribs = 0;
+ GLint max_len = 0;
+ glGetProgramiv(gl_program, GL_ACTIVE_ATTRIBUTES, &num_attribs);
+ glGetProgramiv(gl_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
+ // TODO(gman): Should we check for error?
+ scoped_array<char> name_buffer(new char[max_len + 1]);
+ for (GLint ii = 0; ii < num_attribs; ++ii) {
+ GLsizei length;
+ GLsizei size;
+ GLenum type;
+ glGetActiveAttrib(
+ gl_program, ii, max_len + 1, &length, &size, &type, name_buffer.get());
+ // TODO(gman): Should we check for error?
+ GLint location = glGetAttribLocation(gl_program, name_buffer.get());
+ param_cache_gl->varying_map().insert(std::make_pair(ii, location));
}
}
@@ -559,160 +609,94 @@ static void ScanVaryingParameters(CGprogram program,
// program or effect and recording their entries into the parameter maps.
static void ScanUniformParameters(SemanticManager* semantic_manager,
Renderer* renderer,
- CGprogram program,
- CGenum name_space,
+ GLuint gl_program,
ParamCacheGLES2* param_cache_gl,
const ParamObjectList& param_objects,
EffectGLES2* effect_gl) {
- CGparameter cg_param = cgGetFirstParameter(program, name_space);
- for (; cg_param; cg_param = cgGetNextParameter(cg_param)) {
- if (!cgIsParameterReferenced(cg_param))
- continue;
- CGenum direction = cgGetParameterDirection(cg_param);
- if (direction != CG_IN)
- continue;
- CGtype cg_type = cgGetParameterType(cg_param);
- CGenum variability = cgGetParameterVariability(cg_param);
- const char* cg_name = cgGetParameterName(cg_param);
-
- if (variability == CG_UNIFORM) {
- // We have a CGparameter to add, find a Param that matches it by name.
- if (cg_type == CG_TEXTURE) {
- // CG_TEXTURE objects are handled by CG_SAMPLER objects.
- continue;
- }
-
- // 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 ||
- cg_type == CG_SAMPLER3D ||
- cg_type == CG_SAMPLERCUBE) {
- // Uniform is a Sampler object. Find the CG_TEXTURE object
- // assigned to the CG_SAMPLER, then find a Param object with the
- // same name as the CG_TEXTURE. This is the tricky bit!
- if (param_cache_gl->sampler_map().find(cg_param) ==
- param_cache_gl->sampler_map().end()) {
- ParamTexture* param =
- effect_gl->GetTextureParamFromCgSampler(cg_param,
- param_objects);
- if (param) {
- param_cache_gl->sampler_map().insert(std::make_pair(cg_param,
- param));
- }
- }
+ GLint num_uniforms = 0;
+ GLint max_len = 0;
+ glGetProgramiv(gl_program, GL_ACTIVE_UNIFORMS, &num_uniforms);
+ glGetProgramiv(gl_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
+ // TODO(gman): Should we check for error?
+ scoped_array<char> name_buffer(new char[max_len + 1]);
+ for (GLint ii = 0; ii < num_uniforms; ++ii) {
+ GLsizei length;
+ GLsizei size;
+ GLenum gl_type;
+ glGetActiveUniform(
+ gl_program, ii,
+ max_len + 1, &length, &size, &gl_type, name_buffer.get());
+ // TODO(gman): Should we check for error?
+ GLint location = glGetUniformLocation(gl_program, name_buffer.get());
+ String name(name_buffer.get(), length);
+
+ // Find a Param of the same name, and record the link.
+ if (param_cache_gl->uniform_map().find(ii) ==
+ param_cache_gl->uniform_map().end()) {
+ const ObjectBase::Class *sem_class = NULL;
+ // Try looking by SAS class name.
+ String semantic = GetUniformSemantic(ii, name);
+ if (!semantic.empty()) {
+ sem_class = semantic_manager->LookupSemantic(semantic);
}
-
- // Find a Param of the same name, and record the link.
- if (param_cache_gl->uniform_map().find(cg_param) ==
- param_cache_gl->uniform_map().end()) {
- const ObjectBase::Class *sem_class = NULL;
- // Try looking by SAS class name.
- const char* cg_semantic = cgGetParameterSemantic(cg_param);
- if (cg_semantic != NULL && cg_semantic[0] != '\0') {
- // NOTE: this semantic is not the regularised profile semantic
- // output from the CGC compiler but the actual user supplied
- // semantic from the shader source code, so this match is valid.
- sem_class = semantic_manager->LookupSemantic(cg_semantic);
+ EffectParamHandlerGLES2::Ref handler;
+ // Look through all the param objects to find a matching param.
+ unsigned last = param_objects.size() - 1;
+ for (unsigned int i = 0; i < param_objects.size(); ++i) {
+ ParamObject *param_object = param_objects[i];
+ Param *param = param_object->GetUntypedParam(name);
+ if (!param && sem_class) {
+ param = param_object->GetUntypedParam(sem_class->name());
}
- EffectParamHandlerGLES2::Ref handler;
- // Look through all the param objects to find a matching param.
- unsigned last = param_objects.size() - 1;
- for (unsigned int i = 0; i < param_objects.size(); ++i) {
- ParamObject *param_object = param_objects[i];
- Param *param = param_object->GetUntypedParam(cg_name);
- if (!param && sem_class) {
- param = param_object->GetUntypedParam(sem_class->name());
- }
- if (!param) {
- // If this is the last param object and we didn't find a matching
- // param then if it's a sampler use the error sampler
- if (i == last) {
- if (cg_type == CG_SAMPLER ||
- cg_type == CG_SAMPLER1D ||
- cg_type == CG_SAMPLER2D ||
- cg_type == CG_SAMPLER3D ||
- cg_type == CG_SAMPLERCUBE) {
- param =
- renderer->error_param_sampler();
- }
- }
- if (!param) {
- continue;
+ if (!param) {
+ // If this is the last param object and we didn't find a matching
+ // param then if it's a sampler use the error sampler
+ if (i == last) {
+ if (gl_type == GL_SAMPLER_2D || gl_type == GL_SAMPLER_CUBE) {
+ param = renderer->error_param_sampler();
}
}
- if (cg_type == CG_ARRAY) {
- // Substitute the first element's type for our type.
- cg_type = cgGetParameterType(cgGetArrayParameter(cg_param, 0));
- }
- handler = GetHandlerFromParamAndCgType(effect_gl, param, cg_type);
- if (!handler.IsNull()) {
- param_cache_gl->uniform_map().insert(
- std::make_pair(cg_param, handler));
- DLOG(INFO) << "ElementGLES2 Matched CG_PARAMETER \""
- << cg_name << "\" to Param \""
- << param->name() << "\" from \""
- << param_object->name() << "\"";
- break;
- } else {
- // We found a param, but it didn't match the type. keep looking.
- DLOG(ERROR) << "ElementGLES2 Param \""
- << param->name() << "\" type \""
- << param->GetClassName() << "\" from \""
- << param_object->name()
- << "\" does not match CG_PARAMETER \""
- << cg_name << "\"";
+ if (!param) {
+ continue;
}
}
- if (handler.IsNull()) {
- DLOG(ERROR) << "No matching Param for CG_PARAMETER \""
- << cg_name << "\"";
+ handler = GetHandlerFromParamAndGLType(effect_gl, param, gl_type, size);
+ if (!handler.IsNull()) {
+ param_cache_gl->uniform_map().insert(
+ std::make_pair(location, handler));
+ DLOG(INFO) << "ElementGLES2 Matched gl_paramETER \""
+ << name << "\" to Param \""
+ << param->name() << "\" from \""
+ << param_object->name() << "\"";
+ break;
+ } else {
+ // We found a param, but it didn't match the type. keep looking.
+ DLOG(ERROR) << "ElementGLES2 Param \""
+ << param->name() << "\" type \""
+ << param->GetClassName() << "\" from \""
+ << param_object->name()
+ << "\" does not match gl_paramETER \""
+ << name << "\"";
}
}
+ if (handler.IsNull()) {
+ DLOG(ERROR) << "No matching Param for gl_paramETER \""
+ << name << "\"";
+ }
}
}
}
-static void DoScanCgEffectParameters(SemanticManager* semantic_manager,
+static void DoScanGLEffectParameters(SemanticManager* semantic_manager,
Renderer* renderer,
ParamCacheGLES2* param_cache_gl,
- CGprogram cg_vertex,
- CGprogram cg_fragment,
+ GLuint gl_program,
EffectGLES2* effect_gl,
const ParamObjectList& param_objects) {
- ScanVaryingParameters(cg_vertex, CG_PROGRAM, param_cache_gl);
- ScanVaryingParameters(cg_vertex, CG_GLOBAL, param_cache_gl);
+ ScanVaryingParameters(gl_program, param_cache_gl);
ScanUniformParameters(semantic_manager,
renderer,
- cg_vertex,
- CG_PROGRAM,
- param_cache_gl,
- param_objects,
- effect_gl);
- ScanUniformParameters(semantic_manager,
- renderer,
- cg_vertex,
- CG_GLOBAL,
- param_cache_gl,
- param_objects,
- effect_gl);
- // Do not record varying inputs for a fragment program
- ScanUniformParameters(semantic_manager,
- renderer,
- cg_fragment,
- CG_PROGRAM,
- param_cache_gl,
- param_objects,
- effect_gl);
- ScanUniformParameters(semantic_manager,
- renderer,
- cg_fragment,
- CG_GLOBAL,
+ gl_program,
param_cache_gl,
param_objects,
effect_gl);
@@ -720,32 +704,25 @@ static void DoScanCgEffectParameters(SemanticManager* semantic_manager,
// Search the leaf parameters of a CGeffect and it's shaders for parameters
// using cgGetFirstEffectParameter() / cgGetFirstLeafParameter() /
-// cgGetNextLeafParameter(). Add the CGparameters found to the parameter
+// cgGetNextLeafParameter(). Add the GLES2Parameters found to the parameter
// maps on the DrawElement.
-void ParamCacheGLES2::ScanCgEffectParameters(CGprogram cg_vertex,
- CGprogram cg_fragment,
+void ParamCacheGLES2::ScanGLEffectParameters(GLuint gl_program,
ParamObject* draw_element,
ParamObject* element,
Material* material,
ParamObject* override) {
- DLOG(INFO) << "DrawElementGLES2 ScanCgEffectParameters";
+ DLOG(INFO) << "DrawElementGLES2 ScanGLEffectParameters";
DLOG_ASSERT(material);
DLOG_ASSERT(draw_element);
DLOG_ASSERT(element);
EffectGLES2* effect_gl = static_cast<EffectGLES2*>(material->effect());
DLOG_ASSERT(effect_gl);
- if (cg_vertex == NULL) {
- DLOG(ERROR) << "Can't scan an empty Vertex Program for Cg Parameters.";
+ if (gl_program == 0) {
+ DLOG(ERROR) << "Can't scan an empty Program for Parameters.";
return;
}
- if (cg_fragment == NULL) {
- DLOG(ERROR) << "Can't scan an empty Fragment Program for Cg Parameters.";
- return;
- }
-
uniform_map_.clear();
varying_map_.clear();
- sampler_map_.clear();
ParamObjectList param_object_list;
param_object_list.push_back(override);
param_object_list.push_back(draw_element);
@@ -753,11 +730,10 @@ void ParamCacheGLES2::ScanCgEffectParameters(CGprogram cg_vertex,
param_object_list.push_back(material);
param_object_list.push_back(effect_gl);
param_object_list.push_back(semantic_manager_->sas_param_object());
- DoScanCgEffectParameters(semantic_manager_,
+ DoScanGLEffectParameters(semantic_manager_,
renderer_,
this,
- cg_vertex,
- cg_fragment,
+ gl_program,
effect_gl,
param_object_list);
}
diff --git a/o3d/core/cross/gles2/param_cache_gles2.h b/o3d/core/cross/gles2/param_cache_gles2.h
index 2d1d771..f3c193e 100644
--- a/o3d/core/cross/gles2/param_cache_gles2.h
+++ b/o3d/core/cross/gles2/param_cache_gles2.h
@@ -49,9 +49,10 @@ class ParamCacheGLES2 : public ParamCache {
public:
ParamCacheGLES2(SemanticManager* semantic_manager, Renderer* renderer);
- typedef std::map<CGparameter, int> VaryingParameterMap;
- typedef std::map<CGparameter, EffectParamHandlerGLES2::Ref> UniformParameterMap;
- typedef std::map<CGparameter, ParamTexture*> SamplerParameterMap;
+ typedef std::map<GLES2Parameter, int> VaryingParameterMap;
+ typedef std::map<GLES2Parameter,
+ EffectParamHandlerGLES2::Ref> UniformParameterMap;
+ typedef std::map<GLES2Parameter, ParamTexture*> SamplerParameterMap;
// Overridden from ParamCache.
virtual void UpdateCache(Effect* effect,
@@ -62,7 +63,6 @@ class ParamCacheGLES2 : public ParamCache {
VaryingParameterMap& varying_map() { return varying_map_; }
UniformParameterMap& uniform_map() { return uniform_map_; }
- SamplerParameterMap& sampler_map() { return sampler_map_; }
protected:
// Overridden from ParamCache
@@ -70,33 +70,25 @@ class ParamCacheGLES2 : public ParamCache {
virtual bool ValidateEffect(Effect* effect);
private:
-
SemanticManager* semantic_manager_;
Renderer* renderer_;
- // Records the last two shaders used on this cache, allowing us to rescan the
- // shader parameters if the user changes the shader on an active cache.
- CGprogram last_vertex_program_;
- CGprogram last_fragment_program_;
-
- // Search the leaf parameters of a CGeffect and it's shaders for
- // parameters using cgGetFirstEffectParameter() /
- // cgGetFirstLeafParameter() / cgGetNextLeafParameter(). Add the
- // CGparameters found to the parameter maps on the DrawElement.
- void ScanCgEffectParameters(CGprogram cg_vertex,
- CGprogram fragment,
+ // Used to track if the shader on the Effect has changed and
+ // therefore we need to rebuild our cache.
+ int last_compile_count_;
+
+ // Search the leaf parameters of a GLSL program for parameters and add the
+ // parameters found to the parameter maps on the DrawElement.
+ void ScanGLEffectParameters(GLuint gl_program,
ParamObject* draw_element,
ParamObject* element,
Material* material,
ParamObject* override);
- // A map of varying CGparameter to Stream index.
+ // A map of varying GLES2Parameter to Stream index.
VaryingParameterMap varying_map_;
- // A map of uniform CGparameter to Param objects.
+ // A map of uniform GLES2Parameter to Param objects.
UniformParameterMap uniform_map_;
- // A map of uniform CG_SAMPLER CGparameters to ParamTexture objects.
- // TODO(o3d): remove this (OLD path for textures).
- SamplerParameterMap sampler_map_;
};
} // o3d
diff --git a/o3d/core/cross/gles2/primitive_gles2.cc b/o3d/core/cross/gles2/primitive_gles2.cc
index ec63fdb..e229833 100644
--- a/o3d/core/cross/gles2/primitive_gles2.cc
+++ b/o3d/core/cross/gles2/primitive_gles2.cc
@@ -43,7 +43,6 @@
#include "core/cross/gles2/draw_element_gles2.h"
#include "core/cross/gles2/stream_bank_gles2.h"
#include "core/cross/gles2/utils_gles2-inl.h"
-#include "Cg/cgGL.h"
// Someone defines min, conflicting with std::min
#ifdef min
@@ -94,7 +93,7 @@ void PrimitiveGLES2::PlatformSpecificRender(Renderer* renderer,
// If this PrimitiveGLES2 has an effect we haven't seen before (or it's the
// first time through), initalize the parameter lists before drawing with it.
- if (effect_gl->cg_vertex_program() && effect_gl->cg_fragment_program()) {
+ if (effect_gl->gl_program()) {
// Set up the current CGeffect.
if (!param_cache_gl->ValidateAndCacheParams(effect_gl,
draw_element_gl,
@@ -102,17 +101,15 @@ void PrimitiveGLES2::PlatformSpecificRender(Renderer* renderer,
stream_bank_gl,
material,
override)) {
- Stream::Semantic missing_semantic;
- int missing_semnatic_index;
+ String missing_stream;
if (!stream_bank_gl->CheckForMissingVertexStreams(
varying_map,
- &missing_semantic,
- &missing_semnatic_index)) {
+ effect_gl->gl_program(),
+ &missing_stream)) {
param_cache_gl->ClearParamCache();
O3D_ERROR(service_locator())
<< "Required Stream "
- << Stream::GetSemanticDescription(missing_semantic) << ":"
- << missing_semnatic_index << " missing on Primitive '" << name()
+ << missing_stream << " missing on Primitive '" << name()
<< "' using Material '" << material->name()
<< "' with Effect '" << effect_gl->name() << "'";
return;
@@ -131,7 +128,9 @@ void PrimitiveGLES2::PlatformSpecificRender(Renderer* renderer,
stream_bank_gl->UpdateStreams();
unsigned int max_vertices;
- if (!stream_bank_gl->BindStreamsForRendering(varying_map, &max_vertices)) {
+ if (!stream_bank_gl->BindStreamsForRendering(varying_map,
+ effect_gl->gl_program(),
+ &max_vertices)) {
return;
}
@@ -235,13 +234,14 @@ void PrimitiveGLES2::PlatformSpecificRender(Renderer* renderer,
if (draw) {
DCHECK_NE(gl_primitive_type, static_cast<unsigned int>(GL_NONE));
renderer->AddPrimitivesRendered(number_primitives_);
- if (indexed())
+ if (indexed()) {
glDrawElements(gl_primitive_type,
index_count,
GL_UNSIGNED_INT,
- BUFFER_OFFSET(start_index() * sizeof(uint32))); // NOLINT
- else
+ BufferOffset(start_index() * sizeof(uint32))); // NOLINT
+ } else {
glDrawArrays(gl_primitive_type, start_index(), index_count);
+ }
}
// Clean up the shaders.
@@ -251,7 +251,7 @@ void PrimitiveGLES2::PlatformSpecificRender(Renderer* renderer,
for (ParamCacheGLES2::VaryingParameterMap::iterator i = varying_map.begin();
i != varying_map.end();
++i) {
- cgGLDisableClientState(i->first);
+ glDisableVertexAttribArray(i->first);
}
CHECK_GL_ERROR();
}
diff --git a/o3d/core/cross/gles2/renderer_gles2.cc b/o3d/core/cross/gles2/renderer_gles2.cc
index da5f5e7..6d012e2 100644
--- a/o3d/core/cross/gles2/renderer_gles2.cc
+++ b/o3d/core/cross/gles2/renderer_gles2.cc
@@ -31,8 +31,7 @@
// This file contains the definition of the RendererGLES2 class that
-// implements the abstract Renderer API using OpenGLES2 and the Cg
-// Runtime.
+// implements the abstract Renderer API using OpenGLES2.
#include "core/cross/gles2/renderer_gles2.h"
@@ -546,7 +545,6 @@ RendererGLES2::RendererGLES2(ServiceLocator* service_locator)
mac_cgl_context_(0),
#endif
render_surface_framebuffer_(0),
- cg_context_(NULL),
alpha_function_ref_changed_(true),
alpha_function_(GL_ALWAYS),
alpha_ref_(0.f),
@@ -714,33 +712,9 @@ Renderer::InitStatus RendererGLES2::InitCommonGLES2() {
if (!GLEW_VERSION_2_0 && !GLEW_EXT_blend_equation_separate) {
DLOG(ERROR) << "Separate blend function extension missing.";
}
- // create a Cg Runtime.
- cg_context_ = cgCreateContext();
- DLOG_CG_ERROR("Creating Cg context");
- // NOTE: the first CGerror number after the recreation of a
- // CGcontext (the second time through) seems to be trashed. Please
- // ignore any "CG ERROR: Invalid context handle." message on this
- // function - Invalid context handle isn't one of therror states of
- // cgCreateContext().
DLOG(INFO) << "OpenGLES2 Vendor: " << ::glGetString(GL_VENDOR);
DLOG(INFO) << "OpenGLES2 Renderer: " << ::glGetString(GL_RENDERER);
DLOG(INFO) << "OpenGLES2 Version: " << ::glGetString(GL_VERSION);
- DLOG(INFO) << "Cg Version: " << cgGetString(CG_VERSION);
- cg_vertex_profile_ = cgGLGetLatestProfile(CG_GL_VERTEX);
- cgGLSetOptimalOptions(cg_vertex_profile_);
- DLOG(INFO) << "Best Cg vertex profile = "
- << cgGetProfileString(cg_vertex_profile_);
- cg_fragment_profile_ = cgGLGetLatestProfile(CG_GL_FRAGMENT);
- cgGLSetOptimalOptions(cg_fragment_profile_);
- DLOG(INFO) << "Best Cg fragment profile = "
- << cgGetProfileString(cg_fragment_profile_);
- // Set up all Cg State Assignments for OpenGLES2.
- cgGLRegisterStates(cg_context_);
- DLOG_CG_ERROR("Registering GLES2 StateAssignments");
- cgGLSetDebugMode(CG_FALSE);
- // Enable the profiles we use.
- cgGLEnableProfile(CG_PROFILE_ARBVP1);
- cgGLEnableProfile(CG_PROFILE_ARBFP1);
// get some limits for this profile.
GLint max_vertex_attribs = 0;
::glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);
@@ -770,11 +744,6 @@ void RendererGLES2::DestroyCommonGLES2() {
if (render_surface_framebuffer_) {
::glDeleteFramebuffersEXT(1, &render_surface_framebuffer_);
}
-
- if (cg_context_) {
- cgDestroyContext(cg_context_);
- cg_context_ = NULL;
- }
}
#ifdef OS_WIN
@@ -1000,7 +969,7 @@ Renderer::InitStatus RendererGLES2::InitPlatformSpecific(
return SUCCESS;
}
-// Releases the Cg Context and deletes the GLES2 device.
+// Deletes the GLES2 device.
void RendererGLES2::Destroy() {
DLOG(INFO) << "Destroy RendererGLES2";
DestroyCommonGLES2();
@@ -1497,7 +1466,7 @@ IndexBuffer::Ref RendererGLES2::CreateIndexBuffer() {
Effect::Ref RendererGLES2::CreateEffect() {
DLOG(INFO) << "RendererGLES2 CreateEffect";
MakeCurrentLazy();
- return Effect::Ref(new EffectGLES2(service_locator(), cg_context_));
+ return Effect::Ref(new EffectGLES2(service_locator()));
}
Sampler::Ref RendererGLES2::CreateSampler() {
diff --git a/o3d/core/cross/gles2/renderer_gles2.h b/o3d/core/cross/gles2/renderer_gles2.h
index dcf04fa..eeb7260 100644
--- a/o3d/core/cross/gles2/renderer_gles2.h
+++ b/o3d/core/cross/gles2/renderer_gles2.h
@@ -31,8 +31,7 @@
// This file contains the definition of the RendererGLES2 class that provides
-// low-level access for O3D to graphics hardware using the OpenGLES2 API
-// and Cg Runtime.
+// low-level access for O3D to graphics hardware using the OpenGLES2 API.
#ifndef O3D_CORE_CROSS_GLES2_RENDERER_GLES2_H_
#define O3D_CORE_CROSS_GLES2_RENDERER_GLES2_H_
@@ -51,8 +50,7 @@ class Effect;
class DrawEffect;
class SemanticManager;
-// Implements the genereric Renderer interface using OpenGLES2 and the Cg
-// Runtime.
+// Implements the genereric Renderer interface using OpenGLES2.
class RendererGLES2 : public Renderer {
public:
// Creates a default Renderer.
@@ -158,9 +156,20 @@ class RendererGLES2 : public Renderer {
// Makes this renderer active on the current thread.
bool MakeCurrent();
- inline CGcontext cg_context() const { return cg_context_; }
- inline CGprofile cg_vertex_profile() const { return cg_vertex_profile_; }
- inline CGprofile cg_fragment_profile() const { return cg_fragment_profile_; }
+ // Called by EffectGLES2::PrepareForDraw before setting any parameters.
+ void ResetTextureGroupSetCount() {
+ ++texture_unit_group_set_count_;
+ next_texture_unit_ = 0;
+ }
+
+ int GetTextureGroupSetCount() {
+ return texture_unit_group_set_count_;
+ }
+
+ // Samplers call this if their texture group set count is out of date.
+ GLenum GetNextTextureUnit() {
+ return next_texture_unit_++;
+ }
protected:
// Keep the constructor protected so only factory methods can create
@@ -243,7 +252,6 @@ class RendererGLES2 : public Renderer {
// Indicates we're rendering fullscreen rather than in the plugin region.
bool fullscreen_;
-
#ifdef OS_WIN
// Handle to the GLES2 device.
HWND window_;
@@ -266,11 +274,6 @@ class RendererGLES2 : public Renderer {
// targets.
GLuint render_surface_framebuffer_;
- // Cg Runtime variables.
- CGcontext cg_context_;
- CGprofile cg_vertex_profile_;
- CGprofile cg_fragment_profile_;
-
friend class AlphaReferenceHandler;
bool alpha_function_ref_changed_;
GLenum alpha_function_;
@@ -330,6 +333,13 @@ class RendererGLES2 : public Renderer {
// Sets the stencils states for either front, back or both facing polys.
void SetStencilStates(GLenum face, const StencilStates& stencil_states);
+
+ // Sampler test against this to see if their cached texture unit is valid.
+ int texture_unit_group_set_count_;
+
+ // The next texture unit to use. This is reset with ResetTextureUnit
+ // and retrieved with GetNextTextureUnit.
+ GLenum next_texture_unit_;
};
} // namespace o3d
diff --git a/o3d/core/cross/gles2/sampler_gles2.cc b/o3d/core/cross/gles2/sampler_gles2.cc
index 502389c..a52affa 100644
--- a/o3d/core/cross/gles2/sampler_gles2.cc
+++ b/o3d/core/cross/gles2/sampler_gles2.cc
@@ -42,7 +42,9 @@ namespace o3d {
SamplerGLES2::SamplerGLES2(ServiceLocator* service_locator)
: Sampler(service_locator),
renderer_(static_cast<RendererGLES2*>(
- service_locator->GetService<Renderer>())) {
+ service_locator->GetService<Renderer>())),
+ texture_unit_group_set_count_(renderer_->GetTextureGroupSetCount() - 1),
+ texture_unit_(0) {
}
SamplerGLES2::~SamplerGLES2() {
@@ -131,7 +133,7 @@ GLenum GLTextureTarget(Texture* texture) {
} // namespace
-void SamplerGLES2::SetTextureAndStates(CGparameter cg_param) {
+GLint SamplerGLES2::SetTextureAndStates(GLES2Parameter gl_param) {
// Get the texture object associated with this sampler.
Texture* texture_object = texture();
@@ -151,65 +153,65 @@ void SamplerGLES2::SetTextureAndStates(CGparameter cg_param) {
texture_object = renderer_->error_texture();
}
- GLuint handle = static_cast<GLuint>(reinterpret_cast<intptr_t>(
+ GLint handle = static_cast<GLint>(reinterpret_cast<intptr_t>(
texture_object->GetTextureHandle()));
if (handle) {
- cgGLSetTextureParameter(cg_param, handle);
- cgGLEnableTextureParameter(cg_param);
- } else {
- cgGLSetTextureParameter(cg_param, 0);
- cgGLDisableTextureParameter(cg_param);
- return;
- }
-
- // TODO(o3d): this is a slow check and needs to be moved to initialization
- // time.
- GLenum target = GLTextureTarget(texture_object);
-
- if (target) {
- GLenum texture_unit = cgGLGetTextureEnum(cg_param);
- ::glActiveTextureARB(texture_unit);
- glBindTexture(target, handle);
- glTexParameteri(target,
- GL_TEXTURE_WRAP_S,
- GLAddressMode(address_mode_u(), GL_REPEAT));
- glTexParameteri(target,
- GL_TEXTURE_WRAP_T,
- GLAddressMode(address_mode_v(), GL_REPEAT));
- if (texture_object->IsA(TextureCUBE::GetApparentClass())) {
+ // TODO(o3d): this is a slow check and needs to be moved to initialization
+ // time.
+ GLenum target = GLTextureTarget(texture_object);
+ if (target) {
+ int renderer_texture_unit_group_set_count =
+ renderer_->GetTextureGroupSetCount();
+ if (renderer_texture_unit_group_set_count !=
+ texture_unit_group_set_count_) {
+ texture_unit_group_set_count_ = renderer_texture_unit_group_set_count;
+ texture_unit_ = renderer_->GetNextTextureUnit();
+ }
+ ::glActiveTextureARB(GL_TEXTURE0 + texture_unit_);
+ glBindTexture(target, handle);
glTexParameteri(target,
- GL_TEXTURE_WRAP_R,
- GLAddressMode(address_mode_w(), GL_REPEAT));
- }
- glTexParameteri(target,
- GL_TEXTURE_MIN_FILTER,
- GLMinFilter(min_filter(), mip_filter()));
- glTexParameteri(target,
- GL_TEXTURE_MAG_FILTER,
- GLMagFilter(mag_filter()));
-
- Float4 color = border_color();
- GLfloat gl_color[4] = {color[0], color[1], color[2], color[3]};
- glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, gl_color);
-
- // Check for anisotropic texture filtering.
- if (GLEW_EXT_texture_filter_anisotropic) {
- int gl_max_anisotropy =
- (min_filter() == ANISOTROPIC) ? max_anisotropy() : 1;
- glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy);
+ GL_TEXTURE_WRAP_S,
+ GLAddressMode(address_mode_u(), GL_REPEAT));
+ glTexParameteri(target,
+ GL_TEXTURE_WRAP_T,
+ GLAddressMode(address_mode_v(), GL_REPEAT));
+ if (texture_object->IsA(TextureCUBE::GetApparentClass())) {
+ glTexParameteri(target,
+ GL_TEXTURE_WRAP_R,
+ GLAddressMode(address_mode_w(), GL_REPEAT));
+ }
+ glTexParameteri(target,
+ GL_TEXTURE_MIN_FILTER,
+ GLMinFilter(min_filter(), mip_filter()));
+ glTexParameteri(target,
+ GL_TEXTURE_MAG_FILTER,
+ GLMagFilter(mag_filter()));
+
+ Float4 color = border_color();
+ GLfloat gl_color[4] = {color[0], color[1], color[2], color[3]};
+ glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, gl_color);
+
+ // Check for anisotropic texture filtering.
+ if (GLEW_EXT_texture_filter_anisotropic) {
+ int gl_max_anisotropy =
+ (min_filter() == ANISOTROPIC) ? max_anisotropy() : 1;
+ glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+ gl_max_anisotropy);
+ }
}
}
+
+ return texture_unit_;
}
-void SamplerGLES2::ResetTexture(CGparameter cg_param) {
+void SamplerGLES2::ResetTexture(GLES2Parameter gl_param) {
Texture* the_texture = texture();
if (the_texture) {
// TODO(o3d): this is a slow check and needs to be moved to initialization
// time.
GLenum target = GLTextureTarget(the_texture);
if (target) {
- GLenum texture_unit = cgGLGetTextureEnum(cg_param);
- glActiveTextureARB(texture_unit);
+ glActiveTextureARB(GL_TEXTURE0 + texture_unit_);
glBindTexture(target, 0);
}
}
diff --git a/o3d/core/cross/gles2/sampler_gles2.h b/o3d/core/cross/gles2/sampler_gles2.h
index d388473..1562c8c 100644
--- a/o3d/core/cross/gles2/sampler_gles2.h
+++ b/o3d/core/cross/gles2/sampler_gles2.h
@@ -41,6 +41,9 @@ namespace o3d {
class RendererGLES2;
+// TODO(gman): Replace.
+typedef GLuint GLES2Parameter;
+
// SamplerGLES2 is an implementation of the Sampler object for GLES2.
class SamplerGLES2 : public Sampler {
public:
@@ -48,15 +51,21 @@ class SamplerGLES2 : public Sampler {
virtual ~SamplerGLES2();
// Sets the gl texture and sampler states.
- void SetTextureAndStates(CGparameter cg_param);
+ // Returns the handle to the texture.
+ GLint SetTextureAndStates(GLES2Parameter gl_param);
// Unbinds the GLES2 texture.
- void ResetTexture(CGparameter cg_param);
+ void ResetTexture(GLES2Parameter gl_param);
private:
-
RendererGLES2* renderer_;
+ // We compare this to RendererGLES2::GetTextureGroupSetCount to see
+ // if we need to update our texture unit
+ int texture_unit_group_set_count_;
+
+ GLenum texture_unit_;
+
DISALLOW_COPY_AND_ASSIGN(SamplerGLES2);
};
} // namespace o3d
diff --git a/o3d/core/cross/gles2/stream_bank_gles2.cc b/o3d/core/cross/gles2/stream_bank_gles2.cc
index 8808c6b..1501f35 100644
--- a/o3d/core/cross/gles2/stream_bank_gles2.cc
+++ b/o3d/core/cross/gles2/stream_bank_gles2.cc
@@ -42,7 +42,6 @@
#include "core/cross/gles2/renderer_gles2.h"
#include "core/cross/gles2/draw_element_gles2.h"
#include "core/cross/gles2/utils_gles2-inl.h"
-#include "Cg/cgGL.h"
// Someone defines min, conflicting with std::min
#ifdef min
@@ -67,6 +66,29 @@ GLenum GLDataType(const Field& field) {
return GL_INVALID_ENUM;
}
+String GetAttribName(GLuint gl_program, GLES2Parameter gl_param) {
+ GLchar buffer[1024];
+ GLsizei name_len;
+ GLint size;
+ GLenum type;
+ glGetActiveAttrib(gl_program,
+ gl_param,
+ sizeof(buffer),
+ &name_len,
+ &size,
+ &type,
+ &buffer[0]);
+ if (name_len == 0) {
+ return String("**NO INFO FOR ATTRIB**");
+ }
+ return String(&buffer[0], name_len);
+}
+
+String GetAttribSemantic(GLuint gl_program, GLES2Parameter gl_param) {
+ // GLES doesn't have semantics so for now we just return the names.
+ return GetAttribName(gl_program, gl_param);
+}
+
} // anonymous namespace
// Number of times to log a repeated event before giving up.
@@ -85,27 +107,28 @@ StreamBankGLES2::~StreamBankGLES2() {
bool StreamBankGLES2::CheckForMissingVertexStreams(
ParamCacheGLES2::VaryingParameterMap& varying_map,
- Stream::Semantic* missing_semantic,
- int* missing_semantic_index) {
- DCHECK(missing_semantic);
- DCHECK(missing_semantic_index);
+ GLuint gl_program,
+ String* missing_stream) {
+ DCHECK(missing_stream);
DLOG(INFO) << "StreamBankGLES2 InsertMissingVertexStreams";
- // Match CG_VARYING parameters to Buffers with the matching semantics.
+ // Match VARYING parameters to Buffers with the matching semantics.
ParamCacheGLES2::VaryingParameterMap::iterator i;
for (i = varying_map.begin(); i != varying_map.end(); ++i) {
- CGparameter cg_param = i->first;
- const char* semantic_string = cgGetParameterSemantic(cg_param);
- int attr = SemanticNameToGLVertexAttribute(semantic_string);
- int index = 0;
- Stream::Semantic semantic = GLVertexAttributeToStream(attr, &index);
- int stream_index = FindVertexStream(semantic, index);
+ GLES2Parameter gl_param = i->first;
+ String semantic_string(GetAttribSemantic(gl_program, gl_param));
+ Stream::Semantic semantic;
+ int semantic_index;
+ if (!SemanticNameToSemantic(semantic_string, &semantic, &semantic_index)) {
+ *missing_stream = semantic_string;
+ }
+ int stream_index = FindVertexStream(semantic, semantic_index);
if (stream_index >= 0) {
// record the matched stream into the varying parameter map for later
// use by StreamBankGLES2::Draw().
i->second = stream_index;
DLOG(INFO)
- << "StreamBankGLES2 Matched CG_PARAMETER \""
- << cgGetParameterName(cg_param) << " : "
+ << "StreamBankGLES2 Matched PARAMETER \""
+ << GetAttribName(gl_program, gl_param) << " : "
<< semantic_string << "\" to stream "
<< stream_index << " \""
<< vertex_stream_params_.at(
@@ -113,8 +136,7 @@ bool StreamBankGLES2::CheckForMissingVertexStreams(
<< "\"";
} else {
// no matching stream was found.
- *missing_semantic = semantic;
- *missing_semantic_index = index;
+ *missing_stream = semantic_string;
return false;
}
}
@@ -124,6 +146,7 @@ bool StreamBankGLES2::CheckForMissingVertexStreams(
bool StreamBankGLES2::BindStreamsForRendering(
const ParamCacheGLES2::VaryingParameterMap& varying_map,
+ GLuint gl_program,
unsigned int* max_vertices) {
*max_vertices = UINT_MAX;
// Loop over varying params setting up the streams.
@@ -152,8 +175,8 @@ bool StreamBankGLES2::BindStreamsForRendering(
if (element_count > 4) {
element_count = 0;
DLOG_FIRST_N(ERROR, kNumLoggedEvents)
- << "Unable to find stream for CGparameter: "
- << cgGetParameterName(i->first);
+ << "Unable to find stream for attrib: "
+ << GetAttribName(gl_program, i->first);
}
// In the num_elements = 1 case we want to do the D3D stride = 0 thing.
@@ -169,15 +192,16 @@ bool StreamBankGLES2::BindStreamsForRendering(
// stride at the API level, and instead maybe provide a way to pss a
// constant value - but the DX version relies on being able to pass a 0
// stride, so the whole thing needs a bit of rewrite.
- cgGLDisableClientState(i->first);
+ glDisableVertexAttribArray(i->first);
} else {
glBindBufferARB(GL_ARRAY_BUFFER, vbuffer->gl_buffer());
- cgGLSetParameterPointer(i->first,
- element_count,
- GLDataType(field),
- vbuffer->stride(),
- BUFFER_OFFSET(field.offset()));
- cgGLEnableClientState(i->first);
+ glVertexAttribPointer(i->first,
+ element_count,
+ GLDataType(field),
+ false,
+ vbuffer->stride(),
+ BufferOffset(field.offset()));
+ glEnableVertexAttribArray(i->first);
*max_vertices = std::min(*max_vertices, stream.GetMaxVertices());
}
}
diff --git a/o3d/core/cross/gles2/stream_bank_gles2.h b/o3d/core/cross/gles2/stream_bank_gles2.h
index 1e81dc5..3582069 100644
--- a/o3d/core/cross/gles2/stream_bank_gles2.h
+++ b/o3d/core/cross/gles2/stream_bank_gles2.h
@@ -56,13 +56,14 @@ class StreamBankGLES2 : public StreamBank {
// true if all streams were bound.
bool BindStreamsForRendering(
const ParamCacheGLES2::VaryingParameterMap& varying_map,
+ GLuint gl_program,
unsigned int* max_vertices);
// Checks for all required streams before rendering.
bool CheckForMissingVertexStreams(
ParamCacheGLES2::VaryingParameterMap& varying_map,
- Stream::Semantic* missing_semantic,
- int* missing_semantic_index);
+ GLuint gl_program,
+ String* missing_stream);
private:
int FindVertexStream(Stream::Semantic semantic, int index);
diff --git a/o3d/core/cross/gles2/utils_gles2-inl.h b/o3d/core/cross/gles2/utils_gles2-inl.h
index e69b552..2e15e4c 100644
--- a/o3d/core/cross/gles2/utils_gles2-inl.h
+++ b/o3d/core/cross/gles2/utils_gles2-inl.h
@@ -37,40 +37,17 @@
namespace o3d {
-// Define this to debug GLES2 errors. This has a significant performance hit.
-// #define GL_ERROR_DEBUGGING
-
// convert a byte offset into a Vertex Buffer Object into a GLvoid* for
// use with glVertexPointer(), glNormalPointer(), glVertexAttribPointer(),
// etc. after having used a glBindBuffer().
-#define BUFFER_OFFSET(i) (reinterpret_cast<char *>(NULL)+(i))
-
-// Writes any Cg errors to the log with a descriptive message.
-// NOTE: macros used to make sure the LOG calls note the correct
-// line number and source file.
-#define DLOG_CG_ERROR(message) { \
- CGerror error = cgGetError(); \
- DLOG_IF(INFO, error != CG_NO_ERROR) \
- << message << " : " \
- << cgGetErrorString(error); \
-}
-
-// Writes any Cg errors to the log with a descriptive message, along with
-// the error messages from the CGC compiler.
-#define DLOG_CG_COMPILER_ERROR(message, cg_context) { \
- CGerror error = cgGetError(); \
- DLOG_IF(ERROR, error == CG_NO_ERROR) \
- << message << " : " << cgGetErrorString(error); \
- if (error == CG_COMPILER_ERROR) { \
- DLOG(ERROR) << "CGC compiler output :\n" \
- << cgGetLastListing(cg_context); \
- } \
+inline GLvoid* BufferOffset(unsigned i) {
+ return static_cast<int8 *>(NULL)+(i);
}
#ifdef GL_ERROR_DEBUGGING
#define CHECK_GL_ERROR() do { \
GLenum gl_error = glGetError(); \
- LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GLES2 Error :" << gl_error; \
+ LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
} while(0)
#else // GL_ERROR_DEBUGGING
#define CHECK_GL_ERROR() void(0)
diff --git a/o3d/core/cross/gles2/utils_gles2.cc b/o3d/core/cross/gles2/utils_gles2.cc
index 696a067..1d48958 100644
--- a/o3d/core/cross/gles2/utils_gles2.cc
+++ b/o3d/core/cross/gles2/utils_gles2.cc
@@ -43,187 +43,38 @@
namespace o3d {
-typedef std::pair<String, int> SemanticMapElement;
-typedef std::map<String, int> SemanticMap;
-
-// The map batween the semantics on vertex program varying parameters names
-// and vertex attribute indices under the VP_30 profile.
-SemanticMapElement semantic_map_vp_30[] = {
- SemanticMapElement("POSITION", 0),
- SemanticMapElement("ATTR0", 0),
- SemanticMapElement("BLENDWEIGHT", 1),
- SemanticMapElement("ATTR1", 1),
- SemanticMapElement("NORMAL", 2),
- SemanticMapElement("ATTR2", 2),
- SemanticMapElement("COLOR0", 3),
- SemanticMapElement("DIFFUSE", 3),
- SemanticMapElement("ATTR3", 3),
- SemanticMapElement("COLOR1", 4),
- SemanticMapElement("SPECULAR", 4),
- SemanticMapElement("ATTR4", 4),
- SemanticMapElement("TESSFACTOR", 5),
- SemanticMapElement("FOGCOORD", 5),
- SemanticMapElement("ATTR5", 5),
- SemanticMapElement("PSIZE", 6),
- SemanticMapElement("ATTR6", 6),
- SemanticMapElement("BLENDINDICES", 7),
- SemanticMapElement("ATTR7", 7),
- SemanticMapElement("TEXCOORD0", 8),
- SemanticMapElement("ATTR8", 8),
- SemanticMapElement("TEXCOORD1", 9),
- SemanticMapElement("ATTR9", 9),
- SemanticMapElement("TEXCOORD2", 10),
- SemanticMapElement("ATTR10", 10),
- SemanticMapElement("TEXCOORD3", 11),
- SemanticMapElement("ATTR11", 11),
- SemanticMapElement("TEXCOORD4", 12),
- SemanticMapElement("ATTR12", 12),
- SemanticMapElement("TEXCOORD5", 13),
- SemanticMapElement("ATTR13", 13),
- SemanticMapElement("TEXCOORD6", 14),
- SemanticMapElement("TANGENT", 14),
- SemanticMapElement("ATTR14", 14),
- SemanticMapElement("TEXCOORD7", 15),
- SemanticMapElement("BINORMAL", 15),
- SemanticMapElement("ATTR15", 15),
-};
-
-// The map batween the semantics on vertex program varying parameters names
-// and vertex attribute indices under the VP_40 profile.
-SemanticMapElement semantic_map_vp_40[] = {
- SemanticMapElement("POSITION", 0),
- SemanticMapElement("POSITION0", 0),
- SemanticMapElement("ATTR0", 0),
- SemanticMapElement("BLENDWEIGHT", 1),
- SemanticMapElement("BLENDWEIGHT0", 1),
- SemanticMapElement("ATTR1", 1),
- SemanticMapElement("NORMAL", 2),
- SemanticMapElement("NORMAL0", 2),
- SemanticMapElement("ATTR2", 2),
- SemanticMapElement("COLOR", 3),
- SemanticMapElement("COLOR0", 3),
- SemanticMapElement("DIFFUSE", 3),
- SemanticMapElement("ATTR3", 3),
- SemanticMapElement("COLOR1", 4),
- SemanticMapElement("SPECULAR", 4),
- SemanticMapElement("ATTR4", 4),
- SemanticMapElement("TESSFACTOR", 5),
- SemanticMapElement("FOGCOORD", 5),
- SemanticMapElement("TESSFACTOR0", 5),
- SemanticMapElement("FOGCOORD0", 5),
- SemanticMapElement("ATTR5", 5),
- SemanticMapElement("PSIZE", 6),
- SemanticMapElement("PSIZE0", 6),
- SemanticMapElement("ATTR6", 6),
- SemanticMapElement("BLENDINDICES", 7),
- SemanticMapElement("BLENDINDICES0", 7),
- SemanticMapElement("ATTR7", 7),
- SemanticMapElement("TEXCOORD", 8),
- SemanticMapElement("TEXCOORD0", 8),
- SemanticMapElement("ATTR8", 8),
- SemanticMapElement("TEXCOORD1", 9),
- SemanticMapElement("ATTR9", 9),
- SemanticMapElement("TEXCOORD2", 10),
- SemanticMapElement("ATTR10", 10),
- SemanticMapElement("TEXCOORD3", 11),
- SemanticMapElement("ATTR11", 11),
- SemanticMapElement("TEXCOORD4", 12),
- SemanticMapElement("ATTR12", 12),
- SemanticMapElement("TEXCOORD5", 13),
- SemanticMapElement("ATTR13", 13),
- SemanticMapElement("TANGENT", 14),
- SemanticMapElement("TANGENT0", 14),
- SemanticMapElement("TEXCOORD6", 14),
- SemanticMapElement("ATTR14", 14),
- SemanticMapElement("BINORMAL", 15),
- SemanticMapElement("BINORMAL0", 15),
- SemanticMapElement("TEXCOORD7", 15),
- SemanticMapElement("ATTR15", 15),
-};
-
-// The map batween OpenGLES2 Vertex Attribute indexes under the VP_40 profile
-// to Stream::Semantic identifiers (with index offsets).
-struct AttrMapElement {
- AttrMapElement(Stream::Semantic s, int i) : semantic(s), index(i) {}
- Stream::Semantic semantic;
- int index;
-};
-AttrMapElement attr_map_vp_40[] = {
- AttrMapElement(Stream::POSITION, 0),
- AttrMapElement(Stream::UNKNOWN_SEMANTIC, 0),
- AttrMapElement(Stream::NORMAL, 0),
- AttrMapElement(Stream::COLOR, 0),
- AttrMapElement(Stream::COLOR, 1),
- AttrMapElement(Stream::UNKNOWN_SEMANTIC, 0),
- AttrMapElement(Stream::UNKNOWN_SEMANTIC, 0),
- AttrMapElement(Stream::UNKNOWN_SEMANTIC, 0),
- AttrMapElement(Stream::TEXCOORD, 0),
- AttrMapElement(Stream::TEXCOORD, 1),
- AttrMapElement(Stream::TEXCOORD, 2),
- AttrMapElement(Stream::TEXCOORD, 3),
- AttrMapElement(Stream::TEXCOORD, 4),
- AttrMapElement(Stream::TEXCOORD, 5),
- AttrMapElement(Stream::TANGENT, 0),
- AttrMapElement(Stream::BINORMAL, 0),
-};
-
-// TODO(o3d): make this choice a runtime decision in RendererGLES2
-// initialisation.
-static SemanticMap semantic_map(semantic_map_vp_40,
- semantic_map_vp_40 +
- sizeof(semantic_map_vp_40) /
- sizeof(SemanticMapElement) );
-
-// Converts a semantic string to an OpenGLES2 vertex attribute number using the
-// standard VP_40 shader semantic mappings. If the semantic is not
-// recognised, it returns an index of -1.
-int SemanticNameToGLVertexAttribute(const char* semantic) {
- SemanticMap::const_iterator i = semantic_map.find(semantic);
- if (i == semantic_map.end()) {
- return -1;
- }
- return i->second;
-}
-
-// Given a vertex attribute stream, convert it to a Stream::Semantic number
-// and index. This is an imprecise operation.
-Stream::Semantic GLVertexAttributeToStream(const unsigned int attr,
- int *index) {
- // kMaxAttrIndex is available from:
- // glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);
- //
- // TODO(o3d): make this a runtime provided value discovered during
- // Renderer creation.
- const unsigned int kMaxAttrIndex = 15u;
- if (attr > kMaxAttrIndex) {
- //TODO(o3d): Figure out how to get errors out of here to the client.
- DLOG(ERROR) << "Invalid vertex attribute index.";
- *index = 0;
- return Stream::UNKNOWN_SEMANTIC;
- }
- *index = attr_map_vp_40[attr].index;
- return attr_map_vp_40[attr].semantic;
-}
-
-#ifdef OS_WIN
-
-// Given a CGcontext object, check to see if any errors have occurred since
-// the last Cg API call, and report the message and any compiler errors (if
-// necessary).
-inline void CheckForCgError(const String& logmessage, CGcontext cg_context) {
- CGerror error = CG_NO_ERROR;
- const char *error_string = cgGetLastErrorString(&error);
- if (error == CG_NO_ERROR) {
- return;
- } else {
- DLOG(ERROR) << logmessage << ": " << error_string;
- if (error == CG_COMPILER_ERROR) {
- DLOG(ERROR) << "Compiler message:\n" << cgGetLastListing(cg_context);
+bool SemanticNameToSemantic(
+ const String& name, Stream::Semantic* semantic, int* semantic_index) {
+ struct NameToSemantic {
+ const char* const name;
+ size_t length;
+ const Stream::Semantic semantic;
+ };
+ static const char kPosition[] = "POSITION";
+ static const char kNormal[] = "NORMAL";
+ static const char kTangent[] = "TANGENT";
+ static const char kBinormal[] = "BINORMAL";
+ static const char kColor[] = "COLOR";
+ static const char kTexcoord[] = "TEXCOORD";
+
+ static const NameToSemantic lookup[] = {
+ { kPosition, sizeof(kPosition) - 1, Stream::POSITION, },
+ { kNormal, sizeof(kNormal) - 1, Stream::NORMAL, },
+ { kTangent, sizeof(kTangent) - 1, Stream::TANGENT, },
+ { kBinormal, sizeof(kBinormal) - 1, Stream::BINORMAL, },
+ { kColor, sizeof(kColor) - 1, Stream::COLOR, },
+ { kTexcoord, sizeof(kTexcoord) - 1, Stream::TEXCOORD, },
+ };
+ for (unsigned ii = 0; ii < arraysize(lookup); ++ii) {
+ const NameToSemantic& info = lookup[ii];
+ if (!_strnicmp(info.name, name.c_str(), info.length)) {
+ *semantic = info.semantic;
+ *semantic_index = atoi(name.c_str() + info.length);
+ return true;
}
}
+ return false;
}
-#endif
-
} // namespace o3d
diff --git a/o3d/core/cross/gles2/utils_gles2.h b/o3d/core/cross/gles2/utils_gles2.h
index 4eb71c0..113b857 100644
--- a/o3d/core/cross/gles2/utils_gles2.h
+++ b/o3d/core/cross/gles2/utils_gles2.h
@@ -38,9 +38,8 @@
namespace o3d {
-bool GetGLProcedures();
-int SemanticNameToGLVertexAttribute(const char* semantic);
-Stream::Semantic GLVertexAttributeToStream(const unsigned int attr, int *index);
+bool SemanticNameToSemantic(
+ const String& name, Stream::Semantic* semantic, int* semantic_index);
} // namespace o3d
diff --git a/o3d/core/cross/renderer_test.cc b/o3d/core/cross/renderer_test.cc
index 057e624..427777f 100644
--- a/o3d/core/cross/renderer_test.cc
+++ b/o3d/core/cross/renderer_test.cc
@@ -93,9 +93,7 @@ TEST_F(RendererTest, InitAndDestroyRenderer) {
RendererGL* gl_renderer = down_cast<RendererGL*>(renderer.get());
EXPECT_TRUE(gl_renderer->cg_context() != NULL);
#elif defined(RENDERER_GLES2)
- // test that the Cg Context was correctly created
RendererGLES2* gles2_renderer = down_cast<RendererGLES2*>(renderer.get());
- EXPECT_TRUE(gles2_renderer->cg_context() != NULL);
#endif
// destroy the renderer
renderer->Destroy();
@@ -107,8 +105,6 @@ TEST_F(RendererTest, InitAndDestroyRenderer) {
// check that the renderer no longer has a Cg Context.
EXPECT_FALSE(gl_renderer->cg_context() != NULL);
#elif defined(RENDERER_GLES2)
- // check that the renderer no longer has a Cg Context.
- EXPECT_FALSE(gles2_renderer->cg_context() != NULL);
#endif
}
diff --git a/o3d/plugin/idl/client.idl b/o3d/plugin/idl/client.idl
index f8810e7..5b1634f 100644
--- a/o3d/plugin/idl/client.idl
+++ b/o3d/plugin/idl/client.idl
@@ -119,7 +119,7 @@ class ClientInfo {
For testing purposes you can force O3D to use the software renderer
by setting the environment variable O3D_FORCE_SOFTWARE_RENDERER to
- anything.
+ anything.
\code
set O3D_FORCE_SOFTWARE_RENDERER=foo
@@ -130,9 +130,9 @@ class ClientInfo {
\endcode
You can set it at a system level if you want to set it for all
- browser instances or set it from a command line and start your
+ browser instances or set it from a command line and start your
browser from that same command line if you want to effect just
- that instance of the browser.
+ that instance of the browser.
Note that many browers require special command line options to
run in a separate process, otherwise they default to finding
@@ -151,6 +151,11 @@ class ClientInfo {
a non power of 2 texture.
%]
[getter] bool non_power_of_two_textures;
+
+ %[
+ True if shaders need to be GLSL instead of Cg/HLSL.
+ %]
+ [getter] bool glsl;
};
%[
diff --git a/o3d/plugin/plugin.gyp b/o3d/plugin/plugin.gyp
index 1104157..48b9498 100644
--- a/o3d/plugin/plugin.gyp
+++ b/o3d/plugin/plugin.gyp
@@ -112,7 +112,6 @@
{
'dependencies': [
'../build/libs.gyp:gles2_libs',
- '../build/libs.gyp:cg_libs',
],
},
],
@@ -325,7 +324,6 @@
{
'dependencies': [
'../build/libs.gyp:gles2_libs',
- '../build/libs.gyp:cg_libs',
],
},
],
diff --git a/o3d/samples/hellocube-colors-glsl.html b/o3d/samples/hellocube-colors-glsl.html
new file mode 100644
index 0000000..10cf735
--- /dev/null
+++ b/o3d/samples/hellocube-colors-glsl.html
@@ -0,0 +1,343 @@
+<!--
+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.
+-->
+
+<!--
+This sample creates an O3D area with a spinning cube. The user
+can change the color of the cube by clicking on one of the buttons that appear
+at the bottom of the page. This sample demonstrates how to use O3D Params
+to change the values of uniform parameters used by shaders.
+-->
+<!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>
+Hello Square Colors: Getting started with O3D, take 2.
+</title>
+<script type="text/javascript" src="o3djs/base.js"></script>
+<script type="text/javascript" id="o3dscript">
+o3djs.require('o3djs.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.rendergraph');
+
+// Events
+// Run the init() function once the page has finished loading.
+// Run the uninit() function when the page has is unloaded.
+window.onload = init;
+window.onunload = uninit;
+
+// global variables
+var g_o3d;
+var g_math;
+var g_pack;
+var g_client;
+var g_clock = 0;
+var g_timeMult = 1;
+var g_finished = false; // for selenium testing
+
+var g_cubeTransform;
+var g_cubeColorParam;
+
+/**
+ * Changes the color of the cube.
+ * @param red red component of the color
+ * @param green green component of the color
+ * @param blue blue component of the color
+ */
+function changeColor(red, green, blue) {
+ // Set the rgb color values and alpha = 1
+ g_cubeColorParam.value = [red, green, blue, 1];
+}
+
+/**
+ * Creates an O3D shape representing a cube. The shape consists of
+ * a single primitive with eight vertices and 12 triangles (two for each face
+ * of the cube).
+ * @param {o3d.Material} material the material used by the primitive.
+ * @return {o3d.Shape} The Shape object created.
+ */
+function createCube(material) {
+ // Create a Shape object for the mesh.
+ var cubeShape = g_pack.createObject('Shape');
+
+ // Create the Primitive that will contain the geometry data for
+ // the cube.
+ var cubePrimitive = g_pack.createObject('Primitive');
+
+ // Create a StreamBank to hold the streams of vertex data.
+ var streamBank = g_pack.createObject('StreamBank');
+
+ // Assign the material that was passed in to the primitive.
+ cubePrimitive.material = material;
+
+ // Assign the Primitive to the Shape.
+ cubePrimitive.owner = cubeShape;
+
+ // Assign the StreamBank to the Primitive.
+ cubePrimitive.streamBank = streamBank;
+
+ // The cube is made of 12 triangles. There's eight vertices in total which
+ // are shared between the face triangles.
+ cubePrimitive.primitiveType = g_o3d.Primitive.TRIANGLELIST;
+ cubePrimitive.numberPrimitives = 12; // 12 triangles
+ cubePrimitive.numberVertices = 8; // 8 vertices in total
+
+ // Generate the draw element for the cube primitive.
+ cubePrimitive.createDrawElement(g_pack, null);
+
+ // Create a javascript array that stores the X, Y and Z coordinates of each
+ // of the 8 corners of the cube.
+ var positionArray = [
+ -0.5, -0.5, 0.5, // vertex 0
+ 0.5, -0.5, 0.5, // vertex 1
+ -0.5, 0.5, 0.5, // vertex 2
+ 0.5, 0.5, 0.5, // vertex 3
+ -0.5, 0.5, -0.5, // vertex 4
+ 0.5, 0.5, -0.5, // vertex 5
+ -0.5, -0.5, -0.5, // vertex 6
+ 0.5, -0.5, -0.5 // vertex 7
+ ];
+
+ // The following array defines how vertices are to be put together to form
+ // the triangles that make up the cube's faces. In the index array, every
+ // three elements define a triangle. So for example vertices 0, 1 and 2
+ // make up the first triangle, vertices 2, 1 and 3 the second one, etc.
+ var indicesArray = [
+ 0, 1, 2, // face 1
+ 2, 1, 3,
+ 2, 3, 4, // face 2
+ 4, 3, 5,
+ 4, 5, 6, // face 3
+ 6, 5, 7,
+ 6, 7, 0, // face 4
+ 0, 7, 1,
+ 1, 7, 3, // face 5
+ 3, 7, 5,
+ 6, 0, 4, // face 6
+ 4, 0, 2
+ ];
+
+ // Create buffers containing the vertex data.
+ var positionsBuffer = g_pack.createObject('VertexBuffer');
+ var positionsField = positionsBuffer.createField('FloatField', 3);
+ positionsBuffer.set(positionArray);
+
+ var indexBuffer = g_pack.createObject('IndexBuffer');
+ indexBuffer.set(indicesArray);
+
+ // Associate the positions Buffer with the StreamBank.
+ streamBank.setVertexStream(
+ g_o3d.Stream.POSITION, // semantic: This stream stores vertex positions
+ 0, // semantic index: First (and only) position stream
+ positionsField, // field: the field this stream uses.
+ 0); // start_index: How many elements to skip in the
+ // field.
+
+ // Associate the triangle indices Buffer with the primitive.
+ cubePrimitive.indexBuffer = indexBuffer;
+
+ return cubeShape;
+}
+
+/**
+ * This method gets called every time O3D renders a frame. Here's where
+ * we update the cube's transform to make it spin.
+ * @param {o3d.RenderEvent} renderEvent The render event object that gives
+ * us the elapsed time since the last time a frame was rendered.
+ */
+function renderCallback(renderEvent) {
+ g_clock += renderEvent.elapsedTime * g_timeMult;
+ // Rotate the cube around the Y axis.
+ g_cubeTransform.identity();
+ g_cubeTransform.rotateY(2.0 * g_clock);
+}
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.util.makeClients(initStep2);
+}
+
+/**
+ * Initializes O3D, creates the cube and sets up the transform and
+ * render graphs.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Initializes global variables and libraries.
+ var o3dElement = clientElements[0];
+ g_client = o3dElement.client;
+ g_o3d = o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ var viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+
+ // Set up a perspective projection.
+ viewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree fov.
+ g_client.width / g_client.height,
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // cube is located.
+ viewInfo.drawContext.view = g_math.matrix4.lookAt(
+ [0, 1, 5], // eye
+ [0, 0, 0], // target
+ [0, 1, 0]); // up
+
+ // Create an Effect object and initialize it using the shaders from the
+ // text area.
+ var cubeEffect = g_pack.createObject('Effect');
+ var shaderString = document.getElementById('effect').value;
+ cubeEffect.loadFromFXString(shaderString);
+
+ // Create a Material for the mesh.
+ var cubeMaterial = g_pack.createObject('Material');
+
+ // Set the material's drawList.
+ cubeMaterial.drawList = viewInfo.performanceDrawList;
+
+ // Apply our effect to this material. The effect tells the 3D hardware
+ // which shaders to use.
+ cubeMaterial.effect = cubeEffect;
+
+ // Create an O3D Param on the material for every uniform used by the
+ // shader.
+ cubeEffect.createUniformParameters(cubeMaterial);
+
+ // Get the color parameter from the material and set its value to red.
+ g_cubeColorParam = cubeMaterial.getParam('color');
+ g_cubeColorParam.value = [1, 0, 0, 1];
+
+ // Create the Shape for the cube mesh and assign its material.
+ var cubeShape = createCube(cubeMaterial);
+
+ // Create a new transform and parent the Shape under it.
+ g_cubeTransform = g_pack.createObject('Transform');
+ g_cubeTransform.addShape(cubeShape);
+
+ // Parent the cube's transform to the client root.
+ g_cubeTransform.parent = g_client.root;
+
+ // Set our render callback for animation.
+ // This sets a function to be executed every time a frame is rendered.
+ g_client.setRenderCallback(renderCallback);
+
+ g_finished = true; // for selenium testing.
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function uninit() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+
+</script>
+</head>
+<body>
+<h1>Hello Square: Colors</h1>
+This example shows how to use parameters to the color output of a shader.
+<br/>
+
+
+<!-- Start of O3D plugin -->
+<div id="o3d" style="width: 600px; height: 600px;"></div>
+<!-- End of O3D plugin -->
+
+<form name="default_form" action="#" method="get">
+ <p>
+ Change color:
+ <input type="button" value="Red" onclick="changeColor(1,0,0);" />
+ <input type="button" value="Green" onclick="changeColor(0,1,0);" />
+ <input type="button" value="Blue" onclick="changeColor(0,0,1);" />
+ <input type="button" value="Yellow" onclick="changeColor(1,1,0);" />
+ <input type="button" value="Cyan" onclick="changeColor(0,1,1);" />
+ <input type="button" value="Purple" onclick="changeColor(1,0,1);" />
+ <input type="button" value="White" onclick="changeColor(1,1,1);" />
+ </p>
+</form>
+
+<!-- Don't render the textarea -->
+<div style="display:none">
+<!-- Start of effect -->
+<textarea id="effect">
+ // World View Projection matrix that will transform the input vertices
+ // to screen space.
+ uniform mat4 worldViewProjection;
+
+ // input parameters for our vertex shader
+ attribute vec4 position;
+
+ /**
+ * The vertex shader simply transforms the input vertices to screen space.
+ */
+ void main() {
+ // Multiply the vertex positions by the worldViewProjection matrix to
+ // transform them to screen space.
+ gl_Position = worldViewProjection * position;
+ }
+
+// This hack his here for now since O3D only allows one string
+// to be passed to Effect::loadFromFXString
+// #o3d SplitMarker
+// #o3d MatrixLoadOrder RowMajor
+
+ // Color to draw with.
+ uniform vec4 color;
+
+ /**
+ * This pixel shader just returns the color red.
+ */
+ void main() {
+ gl_FragColor = color;
+ }
+
+ // Here we tell our effect file *which* functions are
+ // our vertex and pixel shaders.
+
+</textarea>
+<!-- End of effect -->
+</div>
+</body>
+</html>
diff --git a/o3d/samples/hellocube-glsl.html b/o3d/samples/hellocube-glsl.html
new file mode 100644
index 0000000..ac89206
--- /dev/null
+++ b/o3d/samples/hellocube-glsl.html
@@ -0,0 +1,304 @@
+<!--
+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.
+-->
+
+<!--
+This sample shows how to place an O3D area in a page and draw simple
+3D shape in it.
+-->
+<!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>
+Hello Cube: Getting started with O3D
+</title>
+<script type="text/javascript" src="o3djs/base.js"></script>
+<script type="text/javascript" id="o3dscript">
+o3djs.require('o3djs.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.rendergraph');
+
+// Events
+// Run the init() function once the page has finished loading.
+// Run the uninit() function when the page has is unloaded.
+window.onload = init;
+window.onunload = uninit;
+
+// global variables
+var g_o3d;
+var g_math;
+var g_client;
+var g_pack;
+var g_clock = 0;
+var g_timeMult = 1;
+var g_cubeTransform;
+var g_finished = false; // for selenium testing
+
+/**
+ * Creates an O3D shape representing a cube. The shape consists of
+ * a single primitive with eight vertices and 12 triangles (two for each face
+ * of the cube).
+ * @param {o3d.Material} material the material used by the primitive.
+ * @return {o3d.Shape} The Shape object created.
+ */
+function createCube(material) {
+ // Create a Shape object for the mesh.
+ var cubeShape = g_pack.createObject('Shape');
+
+ // Create the Primitive that will contain the geometry data for
+ // the cube.
+ var cubePrimitive = g_pack.createObject('Primitive');
+
+ // Create a StreamBank to hold the streams of vertex data.
+ var streamBank = g_pack.createObject('StreamBank');
+
+ // Assign the material that was passed in to the primitive.
+ cubePrimitive.material = material;
+
+ // Assign the Primitive to the Shape.
+ cubePrimitive.owner = cubeShape;
+
+ // Assign the StreamBank to the Primitive.
+ cubePrimitive.streamBank = streamBank;
+
+ // The cube is made of 12 triangles. There's eight vertices in total which
+ // are shared between the face triangles.
+ cubePrimitive.primitiveType = g_o3d.Primitive.TRIANGLELIST;
+ cubePrimitive.numberPrimitives = 12; // 12 triangles
+ cubePrimitive.numberVertices = 8; // 8 vertices in total
+
+ // Generate the draw element for the cube primitive.
+ cubePrimitive.createDrawElement(g_pack, null);
+
+ // Create a javascript array that stores the X, Y and Z coordinates of each
+ // of the 8 corners of the cube.
+ var positionArray = [
+ -0.5, -0.5, 0.5, // vertex 0
+ 0.5, -0.5, 0.5, // vertex 1
+ -0.5, 0.5, 0.5, // vertex 2
+ 0.5, 0.5, 0.5, // vertex 3
+ -0.5, 0.5, -0.5, // vertex 4
+ 0.5, 0.5, -0.5, // vertex 5
+ -0.5, -0.5, -0.5, // vertex 6
+ 0.5, -0.5, -0.5 // vertex 7
+ ];
+
+ // The following array defines how vertices are to be put together to form
+ // the triangles that make up the cube's faces. In the index array, every
+ // three elements define a triangle. So for example vertices 0, 1 and 2
+ // make up the first triangle, vertices 2, 1 and 3 the second one, etc.
+ var indicesArray = [
+ 0, 1, 2, // face 1
+ 2, 1, 3,
+ 2, 3, 4, // face 2
+ 4, 3, 5,
+ 4, 5, 6, // face 3
+ 6, 5, 7,
+ 6, 7, 0, // face 4
+ 0, 7, 1,
+ 1, 7, 3, // face 5
+ 3, 7, 5,
+ 6, 0, 4, // face 6
+ 4, 0, 2
+ ];
+
+ // Create buffers containing the vertex data.
+ var positionsBuffer = g_pack.createObject('VertexBuffer');
+ var positionsField = positionsBuffer.createField('FloatField', 3);
+ positionsBuffer.set(positionArray);
+
+ var indexBuffer = g_pack.createObject('IndexBuffer');
+ indexBuffer.set(indicesArray);
+
+ // Associate the positions Buffer with the StreamBank.
+ streamBank.setVertexStream(
+ g_o3d.Stream.POSITION, // semantic: This stream stores vertex positions
+ 0, // semantic index: First (and only) position stream
+ positionsField, // field: the field this stream uses.
+ 0); // start_index: How many elements to skip in the
+ // field.
+
+ // Associate the triangle indices Buffer with the primitive.
+ cubePrimitive.indexBuffer = indexBuffer;
+
+ return cubeShape;
+}
+
+/**
+ * This method gets called every time O3D renders a frame. Here's where
+ * we update the cube's transform to make it spin.
+ * @param {o3d.RenderEvent} renderEvent The render event object that gives
+ * us the elapsed time since the last time a frame was rendered.
+ */
+function renderCallback(renderEvent) {
+ g_clock += renderEvent.elapsedTime * g_timeMult;
+ // Rotate the cube around the Y axis.
+ g_cubeTransform.identity();
+ g_cubeTransform.rotateY(2.0 * g_clock);
+}
+
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.util.makeClients(initStep2);
+}
+
+/**
+ * Initializes O3D, creates the cube and sets up the transform and
+ * render graphs.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Initializes global variables and libraries.
+ var o3dElement = clientElements[0];
+ g_client = o3dElement.client;
+ g_o3d = o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ var viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+
+ // Set up a perspective projection.
+ viewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree fov.
+ g_client.width / g_client.height,
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // cube is located.
+ viewInfo.drawContext.view = g_math.matrix4.lookAt([0, 1, 5], // eye
+ [0, 0, 0], // target
+ [0, 1, 0]); // up
+
+ // Create an Effect object and initialize it using the shaders from the
+ // text area.
+ var redEffect = g_pack.createObject('Effect');
+ var shaderString = document.getElementById('effect').value;
+ redEffect.loadFromFXString(shaderString);
+
+ // Create a Material for the mesh.
+ var redMaterial = g_pack.createObject('Material');
+
+ // Set the material's drawList.
+ redMaterial.drawList = viewInfo.performanceDrawList;
+
+ // Apply our effect to this material. The effect tells the 3D hardware
+ // which shaders to use.
+ redMaterial.effect = redEffect;
+
+ // Create the Shape for the cube mesh and assign its material.
+ var cubeShape = createCube(redMaterial);
+
+ // Create a new transform and parent the Shape under it.
+ g_cubeTransform = g_pack.createObject('Transform');
+ g_cubeTransform.addShape(cubeShape);
+
+ // Parent the cube's transform to the client root.
+ g_cubeTransform.parent = g_client.root;
+
+ // Set our render callback for animation.
+ // This sets a function to be executed every time a frame is rendered.
+ g_client.setRenderCallback(renderCallback);
+
+ g_finished = true; // for selenium testing.
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function uninit() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+
+</script>
+</head>
+<body>
+<h1>Hello Cube</h1>
+This example shows how to display a spinning red cube in O3D.
+<br/>
+
+
+<!-- Start of O3D plugin -->
+<div id="o3d" style="width: 600px; height: 600px;"></div>
+<!-- End of O3D plugin -->
+
+<!-- Don't render the textarea -->
+<div style="display:none">
+<!-- Start of effect -->
+<textarea id="effect">
+ // World View Projection matrix that will transform the input vertices
+ // to screen space.
+ uniform mat4 worldViewProjection;
+
+ // input parameters for our vertex shader
+ attribute vec4 position;
+
+ /**
+ * The vertex shader simply transforms the input vertices to screen space.
+ */
+ void main() {
+ // Multiply the vertex positions by the worldViewProjection matrix to
+ // transform them to screen space.
+ gl_Position = worldViewProjection * position;
+ }
+
+// This hack his here for now since O3D only allows one string
+// to be passed to Effect::loadFromFXString
+// #o3d SplitMarker
+// #o3d MatrixLoadOrder RowMajor
+
+ /**
+ * This pixel shader just returns the color red.
+ */
+ void main() {
+ gl_FragColor = vec4(1, 0, 0, 1); // Red.
+ }
+
+ // Here we tell our effect file *which* functions are
+ // our vertex and pixel shaders.
+
+</textarea>
+<!-- End of effect -->
+</div>
+</body>
+</html>
diff --git a/o3d/samples/hellocube-textures-glsl.html b/o3d/samples/hellocube-textures-glsl.html
new file mode 100644
index 0000000..86b8857
--- /dev/null
+++ b/o3d/samples/hellocube-textures-glsl.html
@@ -0,0 +1,433 @@
+<!--
+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.
+-->
+
+<!--
+This sample creates an O3D area with a textured cube in the middle. The
+user can specify the URL where the texture image will be picked from.
+This sample is a simple demonstration of texture usage in O3D.
+-->
+<!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>
+Hello Square Textures: Getting started with O3D, take 3.
+</title>
+<script type="text/javascript" src="o3djs/base.js"></script>
+<script type="text/javascript" id="o3dscript">
+o3djs.require('o3djs.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.io');
+
+// Events
+// Run the init() function once the page has finished loading.
+// Run the uninit() function when the page is unloaded.
+window.onload = init;
+window.onunload = uninit;
+
+// global variables
+var g_o3d;
+var g_math;
+var g_pack;
+var g_client;
+var g_cubeTransform;
+var g_sampler;
+var g_clock = 0;
+var g_timeMult = 1;
+var g_finished = false; // for selenium testing
+var g_textureLoadDenied = false; // also for selenium testing
+
+/**
+ * Creates an O3D shape representing a cube.
+ * @param {o3d.Material} material the material used by the primitive.
+ * @return {o3d.Shape} The Shape object created.
+ */
+function createCube(material) {
+ // Create a Shape object for the mesh.
+ var cubeShape = g_pack.createObject('Shape');
+
+ // Create the Primitive that will contain the geometry data for
+ // the cube.
+ var cubePrimitive = g_pack.createObject('Primitive');
+
+ // Create a StreamBank to hold the streams of vertex data.
+ var streamBank = g_pack.createObject('StreamBank');
+
+ // Assign the material that was passed in to the primitive.
+ cubePrimitive.material = material;
+
+ // Assign the Primitive to the Shape.
+ cubePrimitive.owner = cubeShape;
+
+ // Assign the StreamBank to the Primitive.
+ cubePrimitive.streamBank = streamBank;
+
+ // The cube is made of 12 triangles (6 faces x 2 triangles per face)
+ cubePrimitive.primitiveType = g_o3d.Primitive.TRIANGLELIST;
+ cubePrimitive.numberPrimitives = 12; // 12 triangles
+
+ // Vertices used by each triangle must specify both a position and texture
+ // coordinates. We cannot share vertices between adjacent cube faces since
+ // while their positions are the same, their texture coordinates are
+ // different. We therefore create 24 vertices, 4 for each of the cube's
+ // six faces.
+ cubePrimitive.numberVertices = 24;
+
+ // Generate the draw element for the cube primitive.
+ cubePrimitive.createDrawElement(g_pack, null);
+
+ // Create a javascript array that stores the X, Y and Z coordinates of each
+ // of the 24 vertices used by the cube.
+ var positionArray = [
+ -0.5, -0.5, 0.5,
+ 0.5, -0.5, 0.5,
+ 0.5, 0.5, 0.5,
+ -0.5, 0.5, 0.5,
+ -0.5, 0.5, 0.5,
+ 0.5, 0.5, 0.5,
+ 0.5, 0.5, -0.5,
+ -0.5, 0.5, -0.5,
+ -0.5, 0.5, -0.5,
+ 0.5, 0.5, -0.5,
+ 0.5, -0.5, -0.5,
+ -0.5, -0.5, -0.5,
+ -0.5, -0.5, -0.5,
+ 0.5, -0.5, -0.5,
+ 0.5, -0.5, 0.5,
+ -0.5, -0.5, 0.5,
+ 0.5, -0.5, 0.5,
+ 0.5, -0.5, -0.5,
+ 0.5, 0.5, -0.5,
+ 0.5, 0.5, 0.5,
+ -0.5, -0.5, -0.5,
+ -0.5, -0.5, 0.5,
+ -0.5, 0.5, 0.5,
+ -0.5, 0.5, -0.5
+ ];
+
+ // The following array stores the texture coordinates (u, v) for each vertex.
+ // These coordinates are used by the shader when displaying the texture image
+ // on the mesh triangles.
+ var texCoordsArray = [
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1
+ ];
+
+ // The following array defines how vertices are to be put together to form
+ // the triangles that make up the cube's faces. In the index array, every
+ // three elements define a triangle. So for example vertices 0, 1 and 2
+ // make up the first triangle, vertices 0, 2 and 3 the second one, etc.
+ var indicesArray = [
+ 0, 1, 2,
+ 0, 2, 3,
+ 4, 5, 6,
+ 4, 6, 7,
+ 8, 9, 10,
+ 8, 10, 11,
+ 12, 13, 14,
+ 12, 14, 15,
+ 16, 17, 18,
+ 16, 18, 19,
+ 20, 21, 22,
+ 20, 22, 23
+ ];
+
+ // Create buffers containing the vertex data.
+ var positionsBuffer = g_pack.createObject('VertexBuffer');
+ var positionsField = positionsBuffer.createField('FloatField', 3);
+ positionsBuffer.set(positionArray);
+
+ var texCoordsBuffer = g_pack.createObject('VertexBuffer');
+ var texCoordsField = texCoordsBuffer.createField('FloatField', 2);
+ texCoordsBuffer.set(texCoordsArray);
+
+ var indexBuffer = g_pack.createObject('IndexBuffer');
+ indexBuffer.set(indicesArray);
+
+ // Associate the positions buffer with the StreamBank.
+ streamBank.setVertexStream(
+ g_o3d.Stream.POSITION, // semantic: This stream stores vertex positions
+ 0, // semantic index: First (and only) position stream
+ positionsField, // field: the field this stream uses.
+ 0); // start_index: How many elements to skip in the
+ // field.
+
+ // Associate the texture coordinates buffer with the primitive.
+ streamBank.setVertexStream(
+ g_o3d.Stream.TEXCOORD, // semantic
+ 0, // semantic index
+ texCoordsField, // field
+ 0); // start_index
+
+ // Associate the triangle indices Buffer with the primitive.
+ cubePrimitive.indexBuffer = indexBuffer;
+
+ return cubeShape;
+}
+
+/**
+ * This method gets called every time O3D renders a frame. Here's where
+ * we update the cube's transform to make it spin.
+ * @param {o3d.RenderEvent} renderEvent The render event object that gives
+ * us the elapsed time since the last time a frame was rendered.
+ */
+function renderCallback(renderEvent) {
+ g_clock += renderEvent.elapsedTime * g_timeMult;
+ // Rotate the cube around the Y axis.
+ g_cubeTransform.identity();
+ g_cubeTransform.rotateY(2.0 * g_clock);
+}
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.util.makeClients(initStep2);
+}
+
+/**
+ * Initializes O3D, creates the quad and sets up the transform and
+ * render graphs.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Set the texture URL.
+ var path = window.location.href;
+ var index = path.lastIndexOf('/');
+ path = path.substring(0, index+1) + 'assets/texture_b3.jpg';
+ var url = document.getElementById("url").value = path;
+
+ // Initialize global variables and libraries.
+ var o3dElement = clientElements[0];
+ g_client = o3dElement.client;
+ g_o3d = o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ var viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+
+ // Set up a perspective projection.
+ viewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree fov.
+ g_client.width / g_client.height,
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // cube is located.
+ viewInfo.drawContext.view = g_math.matrix4.lookAt(
+ [0, 1, 5], // eye
+ [0, 0, 0], // target
+ [0, 1, 0]); // up
+
+ // Create an Effect object and initialize it using the shaders from the
+ // text area.
+ var cubeEffect = g_pack.createObject('Effect');
+ var shaderString = document.getElementById('effect').value;
+ cubeEffect.loadFromFXString(shaderString);
+
+ // Create a Material for the mesh.
+ var cubeMaterial = g_pack.createObject('Material');
+
+ // Set the material's drawList.
+ cubeMaterial.drawList = viewInfo.performanceDrawList;
+
+ // Apply our effect to this material. The effect tells the 3D hardware
+ // which shaders to use.
+ cubeMaterial.effect = cubeEffect;
+
+ // Create an O3D Param on the material for every uniform used by the
+ // shader.
+ cubeEffect.createUniformParameters(cubeMaterial);
+
+ // Get the material's sampler parameter so that we can set the texture value
+ // to it.
+ var samplerParam = cubeMaterial.getParam('texSampler0');
+
+ // Create a Sampler object and set the min filtering to ANISOTROPIC. This
+ // will improve the quality of the rendered texture when viewed at an angle.
+ g_sampler = g_pack.createObject('Sampler');
+ g_sampler.minFilter = g_o3d.Sampler.ANISOTROPIC;
+ g_sampler.maxAnisotropy = 4;
+ samplerParam.value = g_sampler;
+
+ // Create the Shape for the cube mesh and assign its material.
+ var cubeShape = createCube(cubeMaterial);
+
+ // Create a new transform and parent the Shape under it.
+ g_cubeTransform = g_pack.createObject('Transform');
+ g_cubeTransform.addShape(cubeShape);
+
+ // Note that we don't parent the transform until the texture is
+ // succesfully loaded because we don't want the system
+ // to try the draw the shape without its required texture.
+
+ // Set our render callback for animation.
+ // This sets a function to be executed every time a frame is rendered.
+ g_client.setRenderCallback(renderCallback);
+
+ // Set the initial texture.
+ changeTexture();
+}
+
+/**
+ * Fetches the bitmap pointed to by the URL supplied by the user, creates
+ * an O3D Texture object with it updates the Sampler used by the material
+ * to point to the newly created texture.
+ */
+function changeTexture() {
+ var textureUrl = document.getElementById('url').value;
+ o3djs.io.loadTexture(g_pack, textureUrl, function(texture, exception) {
+ // Remove the currently used texture from the pack so that when it's not
+ // referenced anymore, it can get destroyed.
+ if (g_sampler.texture)
+ g_pack.removeObject(g_sampler.texture);
+
+ // Because the loading is asynchronous an exception is not thrown but is
+ // instead passed on failure.
+ if (exception) {
+ g_sampler.texture = null;
+
+ g_textureLoadDenied = true; // for selenium testing.
+ } else {
+ // Set the texture on the sampler object to the newly created texture
+ // object returned by the request.
+ g_sampler.texture = texture;
+
+ // We can now safely add the cube transform to the root of the
+ // scenegraph since it now has a valid texture. If the transform
+ // is already parented under the root, the call will have no effect.
+ g_cubeTransform.parent = g_client.root;
+
+ g_finished = true; // for selenium testing.
+ }
+ });
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function uninit() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+
+</script>
+</head>
+<body>
+<h1>Hello Cube: Textures</h1>
+This example shows how texture map a cube using an image fetched from a URL.
+<br/>
+
+
+<!-- Start of O3D plugin -->
+<div id="o3d" style="width: 600px; height: 600px;"></div>
+<!-- End of O3D plugin -->
+<br />
+Image URL: <input type="text" id="url" size="100">
+<input type="button" id="updateButton" onclick="changeTexture();" value="Update Texture"><BR>
+
+<!-- Don't render the textarea -->
+<div style="display:none">
+<!-- Start of effect -->
+<textarea id="effect">
+ // World View Projection matrix that will transform the input vertices
+ // to screen space.
+ uniform mat4 worldViewProjection;
+
+ // input parameters for our vertex shader
+ attribute vec4 position;
+ attribute vec2 texcoords0;
+
+ varying vec2 uvs;
+
+ /**
+ * The vertex shader simply transforms the input vertices to screen space.
+ */
+ void main() {
+ // Multiply the vertex positions by the worldViewProjection matrix to
+ // transform them to screen space.
+ gl_Position = worldViewProjection * position;
+ uvs = texcoords0;
+ }
+
+// This hack his here for now since O3D only allows one string
+// to be passed to Effect::loadFromFXString
+// #o3d SplitMarker
+// #o3d MatrixLoadOrder RowMajor
+
+ // Color to draw with.
+ uniform sampler2D texSampler0;
+
+ varying vec2 uvs;
+
+ /**
+ * This pixel shader just returns the color red.
+ */
+ void main() {
+ gl_FragColor = texture2D(texSampler0, uvs);
+ }
+</textarea>
+<!-- End of effect -->
+</div>
+</body>
+</html>
diff --git a/o3d/samples/o3djs/base.js b/o3d/samples/o3djs/base.js
index e7765c4..281f5bc 100644
--- a/o3d/samples/o3djs/base.js
+++ b/o3d/samples/o3djs/base.js
@@ -533,6 +533,12 @@ o3djs.base = o3djs.base || {};
o3djs.base.o3d = null;
/**
+ * Whether or not we need to use GLSL instead of HLSL.
+ * @type {boolean}
+ */
+o3djs.base.glsl = false;
+
+/**
* Snapshots the current state of all provided namespaces. This state will be
* used to initialize future V8 instances. It is automatically
* called by o3djs.util.makeClients.
@@ -577,6 +583,9 @@ o3djs.base.initV8 = function(clientObject) {
// Make sure this points to the o3d namespace for this particular
// instance of the plugin.
o3djs.base.o3d = plugin.o3d;
+
+ // Save off if we need GLSL.
+ o3djs.base.glsl = plugin.client.clientInfo.glsl;
};
clientObject.eval(v8Init.toString())(o3djs.v8Initializer_,
@@ -616,6 +625,8 @@ o3djs.base.init = function(clientObject) {
// the properties of an NPObject.
// Chrome bug: http://code.google.com/p/chromium/issues/detail?id=5743
o3djs.base.o3d = o3djs.base.o3d || clientObject.o3d;
+ // Save off if we need GLSL.
+ o3djs.base.glsl = clientObject.client.clientInfo.glsl;
};
/**
diff --git a/o3d/standalone/standalone.gyp b/o3d/standalone/standalone.gyp
index 535debf..c5a5d5b 100644
--- a/o3d/standalone/standalone.gyp
+++ b/o3d/standalone/standalone.gyp
@@ -58,7 +58,6 @@
['renderer == "gles2"',
{
'dependencies': [
- '../build/libs.gyp:cg_libs',
'../build/libs.gyp:gles2_libs',
],
},
diff --git a/o3d/tests/tests.gyp b/o3d/tests/tests.gyp
index 6593ec1..67118a2 100644
--- a/o3d/tests/tests.gyp
+++ b/o3d/tests/tests.gyp
@@ -105,7 +105,6 @@
['renderer == "gles2"',
{
'dependencies': [
- '../build/libs.gyp:cg_libs',
'../build/libs.gyp:gles2_libs',
],
},