diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-08 23:41:11 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-08 23:41:11 +0000 |
commit | 760761bbccb2b6915a33551f4812b09e2ef9316c (patch) | |
tree | 6bd700729deab017aa008a7489bc09e4a6f65143 /o3d | |
parent | d1e110ee14a03f8774e57d275033d1d532a89134 (diff) | |
download | chromium_src-760761bbccb2b6915a33551f4812b09e2ef9316c.zip chromium_src-760761bbccb2b6915a33551f4812b09e2ef9316c.tar.gz chromium_src-760761bbccb2b6915a33551f4812b09e2ef9316c.tar.bz2 |
This change removes CG from O3D and uses GLSL
instead of HLSL. The current "hack" for shaders
is that the shader string you supply to
Effect::LoadFromFXString requires the lines
// #o3d SplitMarker \n"
Above which is the vertex shader and below which
is the fragment shader.
Since GLSL has no semantics the names are used
for semantics so to get an automatically supplied
worldViewProjection you must name the uniform
worldViewProjection as in
uniform mat4 worldViewProjection
Similarly for attributes (vertex streams) you must
name them to match O3D semantics as in
attribute vec4 texcoord1
attribute vec3 normal
etc.
Included in this is one working sample in
o3d/samples/hellocube-glsl.html
Other things: Added a glsl field to clientInfo
so that a program can check if it needs to supply
GLSL or HLSL. eg client.clientInfo.glsl == true
Updated the O3D libraries to store that info
in o3djs.base.glsl so that the libaries can be
modified to supply GLSL if we want.
Note: To run this on windows you must copy glew32.dll
and glut32.dll to <AppData>...\Mozilla\plugins
To get this to actually work in GLES2 will
require
(*) renaming a few functions
(*) telling O3D there is no NPOT support or if possible
no NPOT support unless the texture has only 1 level.
(*) removing LargeGeometry and FloatingPointTexture support.
(*) Making it link with the GLES2 code
Review URL: http://codereview.chromium.org/527028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35845 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
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*> ¶m_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*> ¶m_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', ], }, |