summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-16 20:50:58 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-16 20:50:58 +0000
commit3762aeb6b417e032ff7d97acaf02670fd2b83248 (patch)
tree036429340f2ee065c8e3b320d9bfe56947178f29 /o3d
parent3b18461e5a1e8e35b7e1a8d5c2e5b3bf08f2d63f (diff)
downloadchromium_src-3762aeb6b417e032ff7d97acaf02670fd2b83248.zip
chromium_src-3762aeb6b417e032ff7d97acaf02670fd2b83248.tar.gz
chromium_src-3762aeb6b417e032ff7d97acaf02670fd2b83248.tar.bz2
Step 1 in Adding GLES2 renderer to O3D.
This step does only copies the GL files to a GLES2 folder. It's still actually the GL renderer at this point but it's the smallest step for getting something that builds and a place to start working. The next step will be to rename all the classes from xxxGL to xxxGLES2 At some point CG will be removed as well One other thing slipped in there. A standalone build path to help generate a C++ only example of using O3D. It's currently only a placeholder. Review URL: http://codereview.chromium.org/500070 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34744 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/build/common.gypi21
-rw-r--r--o3d/build/libs.gyp55
-rw-r--r--o3d/build/o3d_all.gyp1
-rw-r--r--o3d/converter/converter.gyp7
-rw-r--r--o3d/core/core.gyp49
-rw-r--r--o3d/core/cross/gles2/buffer_gles2.cc253
-rw-r--r--o3d/core/cross/gles2/buffer_gles2.h120
-rw-r--r--o3d/core/cross/gles2/draw_element_gles2.cc46
-rw-r--r--o3d/core/cross/gles2/draw_element_gles2.h57
-rw-r--r--o3d/core/cross/gles2/effect_gles2.cc634
-rw-r--r--o3d/core/cross/gles2/effect_gles2.h147
-rw-r--r--o3d/core/cross/gles2/gles2_headers.h43
-rw-r--r--o3d/core/cross/gles2/install_check.cc41
-rw-r--r--o3d/core/cross/gles2/param_cache_gles2.cc762
-rw-r--r--o3d/core/cross/gles2/param_cache_gles2.h103
-rw-r--r--o3d/core/cross/gles2/primitive_gles2.cc258
-rw-r--r--o3d/core/cross/gles2/primitive_gles2.h63
-rw-r--r--o3d/core/cross/gles2/render_surface_gles2.cc125
-rw-r--r--o3d/core/cross/gles2/render_surface_gles2.h109
-rw-r--r--o3d/core/cross/gles2/renderer_gles2.cc1561
-rw-r--r--o3d/core/cross/gles2/renderer_gles2.h335
-rw-r--r--o3d/core/cross/gles2/sampler_gles2.cc217
-rw-r--r--o3d/core/cross/gles2/sampler_gles2.h65
-rw-r--r--o3d/core/cross/gles2/stream_bank_gles2.cc201
-rw-r--r--o3d/core/cross/gles2/stream_bank_gles2.h72
-rw-r--r--o3d/core/cross/gles2/texture_gles2.cc875
-rw-r--r--o3d/core/cross/gles2/texture_gles2.h243
-rw-r--r--o3d/core/cross/gles2/utils_gles2-inl.h81
-rw-r--r--o3d/core/cross/gles2/utils_gles2.cc228
-rw-r--r--o3d/core/cross/gles2/utils_gles2.h47
-rw-r--r--o3d/core/cross/renderer_platform.h5
-rw-r--r--o3d/core/cross/renderer_test.cc7
-rw-r--r--o3d/import/cross/precompile.h7
-rw-r--r--o3d/plugin/plugin.gyp16
-rw-r--r--o3d/samples/o3djs/js_list.manifest1
-rw-r--r--o3d/standalone/standalone.cc5
-rw-r--r--o3d/standalone/standalone.gyp150
-rw-r--r--o3d/tests/tests.gyp15
38 files changed, 7025 insertions, 0 deletions
diff --git a/o3d/build/common.gypi b/o3d/build/common.gypi
index e03653d..765f7d2 100644
--- a/o3d/build/common.gypi
+++ b/o3d/build/common.gypi
@@ -113,6 +113,13 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'defines': [
+ 'RENDERER_GLES2',
+ ],
+ },
+ ],
],
},
},
@@ -152,6 +159,13 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'defines': [
+ 'RENDERER_GLES2',
+ ],
+ },
+ ],
],
},
},
@@ -180,6 +194,13 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'defines': [
+ 'RENDERER_GLES2',
+ ],
+ },
+ ],
],
},
},
diff --git a/o3d/build/libs.gyp b/o3d/build/libs.gyp
index 32e5f42..315ce7c 100644
--- a/o3d/build/libs.gyp
+++ b/o3d/build/libs.gyp
@@ -73,6 +73,61 @@
],
},
{
+ 'target_name': 'gles2_libs',
+ 'type': 'none',
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '../../<(glewdir)/include',
+ ],
+ },
+ 'conditions': [
+ [ 'OS=="linux"',
+ {
+ 'all_dependent_settings': {
+ 'defines': [
+ 'GL_GLEXT_PROTOTYPES',
+ ],
+ 'ldflags': [
+ '-L<(PRODUCT_DIR)',
+ ],
+ 'libraries': [
+ '-lGL',
+ '-lGLEW',
+ '-lX11',
+ ],
+ },
+ },
+ ],
+ [ 'OS=="mac"',
+ {
+ 'direct_dependent_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
+ ],
+ },
+ },
+ ],
+ [ 'OS=="win"',
+ {
+ 'all_dependent_settings': {
+ 'libraries': [
+ '-lOpenGL32.lib',
+ '../../<(glewdir)/lib/glew32.lib',
+ ],
+ },
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ "../../<(glewdir)/bin/glew32.dll",
+ ]
+ },
+ ],
+ },
+ ],
+ ],
+ },
+ {
'target_name': 'cg_libs',
'type': 'none',
'hard_dependency': 1,
diff --git a/o3d/build/o3d_all.gyp b/o3d/build/o3d_all.gyp
index 9901e71..e172ed2 100644
--- a/o3d/build/o3d_all.gyp
+++ b/o3d/build/o3d_all.gyp
@@ -28,6 +28,7 @@
'../plugin/idl/idl.gyp:o3dNpnApi',
'../plugin/plugin.gyp:npo3dautoplugin',
'../samples/samples.gyp:*',
+ '../standalone/standalone.gyp:*',
'../tests/selenium/selenium.gyp:*',
'../tests/tests.gyp:unit_tests',
'../utils/utils.gyp:o3dUtils',
diff --git a/o3d/converter/converter.gyp b/o3d/converter/converter.gyp
index ffede11f..ddb5344 100644
--- a/o3d/converter/converter.gyp
+++ b/o3d/converter/converter.gyp
@@ -62,6 +62,13 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:cg_libs',
+ ],
+ },
+ ],
['OS == "mac"',
{
'postbuilds': [
diff --git a/o3d/core/core.gyp b/o3d/core/core.gyp
index f2773ec..323a4fe 100644
--- a/o3d/core/core.gyp
+++ b/o3d/core/core.gyp
@@ -53,6 +53,14 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'include_dirs': [
+ '../../<(glewdir)/include',
+ '../../<(cgdir)/include',
+ ],
+ },
+ ],
],
},
'includes': [
@@ -285,6 +293,14 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:cg_libs',
+ '../build/libs.gyp:gles2_libs',
+ ],
+ },
+ ],
['OS == "linux"',
{
'sources': [
@@ -365,6 +381,39 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'sources': [
+ 'cross/gles2/buffer_gles2.cc',
+ 'cross/gles2/buffer_gles2.h',
+ 'cross/gles2/draw_element_gles2.cc',
+ 'cross/gles2/draw_element_gles2.h',
+ 'cross/gles2/effect_gles2.cc',
+ 'cross/gles2/effect_gles2.h',
+ 'cross/gles2/install_check.cc',
+ 'cross/gles2/param_cache_gles2.cc',
+ 'cross/gles2/param_cache_gles2.h',
+ 'cross/gles2/primitive_gles2.cc',
+ 'cross/gles2/primitive_gles2.h',
+ 'cross/gles2/render_surface_gles2.cc',
+ 'cross/gles2/render_surface_gles2.h',
+ 'cross/gles2/renderer_gles2.cc',
+ 'cross/gles2/renderer_gles2.h',
+ 'cross/gles2/sampler_gles2.cc',
+ 'cross/gles2/sampler_gles2.h',
+ 'cross/gles2/stream_bank_gles2.cc',
+ 'cross/gles2/stream_bank_gles2.h',
+ 'cross/gles2/texture_gles2.cc',
+ 'cross/gles2/texture_gles2.h',
+ 'cross/gles2/utils_gles2-inl.h',
+ 'cross/gles2/utils_gles2.cc',
+ 'cross/gles2/utils_gles2.h',
+ ],
+ 'dependencies': [
+ '../build/libs.gyp:gles2_libs',
+ ],
+ },
+ ],
['renderer == "d3d9" and OS == "win"',
{
'sources': [
diff --git a/o3d/core/cross/gles2/buffer_gles2.cc b/o3d/core/cross/gles2/buffer_gles2.cc
new file mode 100644
index 0000000..05b1276
--- /dev/null
+++ b/o3d/core/cross/gles2/buffer_gles2.cc
@@ -0,0 +1,253 @@
+/*
+ * 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 file contains the implementatinos of VertexBufferGL and
+// IndexBufferGL, used to implement O3D using OpenGL.
+//
+// To force the vertex and index buffers to be created by Cg Runtime
+// control, define the compile flag "USE_CG_BUFFERS". This option is off by
+// default and buffers are created, locked and managed using the OpenGL
+// "ARB_vertex_buffer_object" extension.
+
+#include "core/cross/error.h"
+#include "core/cross/gles2/buffer_gles2.h"
+#include "core/cross/gles2/renderer_gles2.h"
+#include "core/cross/gles2/utils_gles2.h"
+#include "core/cross/gles2/utils_gles2-inl.h"
+
+namespace o3d {
+
+namespace {
+
+GLenum BufferAccessModeToGLenum(Buffer::AccessMode access_mode) {
+ switch (access_mode) {
+ case Buffer::READ_ONLY:
+ return GL_READ_ONLY_ARB;
+ case Buffer::WRITE_ONLY:
+ return GL_WRITE_ONLY_ARB;
+ case Buffer::READ_WRITE:
+ return GL_READ_WRITE_ARB;
+ case Buffer::NONE:
+ break;
+ }
+ DCHECK(false);
+ return GL_READ_WRITE_ARB;
+}
+
+} // anonymous namespace
+
+// Vertex Buffers --------------------------------------------------------------
+
+// Initializes the O3D VertexBuffer object but does not allocate an
+// OpenGL vertex buffer object yet.
+VertexBufferGL::VertexBufferGL(ServiceLocator* service_locator)
+ : VertexBuffer(service_locator),
+ renderer_(static_cast<RendererGL*>(
+ service_locator->GetService<Renderer>())),
+ gl_buffer_(0) {
+ DLOG(INFO) << "VertexBufferGL Construct";
+}
+
+// Destructor releases the OpenGL VBO.
+VertexBufferGL::~VertexBufferGL() {
+ DLOG(INFO) << "VertexBufferGL Destruct \"" << name() << "\"";
+ ConcreteFree();
+}
+
+// Creates a OpenGL vertex buffer of the requested size.
+bool VertexBufferGL::ConcreteAllocate(size_t size_in_bytes) {
+ DLOG(INFO) << "VertexBufferGL Allocate \"" << name() << "\"";
+ renderer_->MakeCurrentLazy();
+ ConcreteFree();
+ // Create a new VBO.
+ glGenBuffersARB(1, &gl_buffer_);
+
+ if (!gl_buffer_) return false;
+
+ // Give the VBO a size, but no data, and set the hint to "STATIC_DRAW"
+ // to mark the buffer as set up once then used often.
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, gl_buffer_);
+ glBufferDataARB(GL_ARRAY_BUFFER_ARB,
+ size_in_bytes,
+ NULL,
+ GL_STATIC_DRAW_ARB);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+void VertexBufferGL::ConcreteFree() {
+ if (gl_buffer_) {
+ renderer_->MakeCurrentLazy();
+ glDeleteBuffersARB(1, &gl_buffer_);
+ gl_buffer_ = 0;
+ CHECK_GL_ERROR();
+ }
+}
+
+// Calls Lock on the OpenGL buffer to get the address in memory of where the
+// buffer data is currently stored.
+bool VertexBufferGL::ConcreteLock(Buffer::AccessMode access_mode,
+ void **buffer_data) {
+ DLOG(INFO) << "VertexBufferGL Lock \"" << name() << "\"";
+ renderer_->MakeCurrentLazy();
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, gl_buffer_);
+ *buffer_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB,
+ BufferAccessModeToGLenum(access_mode));
+ if (*buffer_data == NULL) {
+ GLenum error = glGetError();
+ if (error == GL_OUT_OF_MEMORY) {
+ O3D_ERROR(service_locator()) << "Out of memory for buffer lock.";
+ } else {
+ O3D_ERROR(service_locator()) << "Unable to lock a GL Array Buffer";
+ }
+ return false;
+ }
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Calls Unlock on the OpenGL buffer to notify that the contents of the buffer
+// are now ready for use.
+bool VertexBufferGL::ConcreteUnlock() {
+ DLOG(INFO) << "VertexBufferGL Unlock \"" << name() << "\"";
+ renderer_->MakeCurrentLazy();
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, gl_buffer_);
+ if (!glUnmapBufferARB(GL_ARRAY_BUFFER)) {
+ GLenum error = glGetError();
+ if (error == GL_INVALID_OPERATION) {
+ O3D_ERROR(service_locator()) <<
+ "Buffer was unlocked without first being locked.";
+ } else {
+ O3D_ERROR(
+ service_locator()) << "Unable to unlock a GL Element Array Buffer";
+ }
+ return false;
+ }
+ CHECK_GL_ERROR();
+ return true;
+}
+
+
+// Index Buffers ---------------------------------------------------------------
+
+// Initializes the O3D IndexBuffer object but does not create a OpenGL
+// buffer yet.
+
+IndexBufferGL::IndexBufferGL(ServiceLocator* service_locator)
+ : IndexBuffer(service_locator),
+ renderer_(static_cast<RendererGL*>(
+ service_locator->GetService<Renderer>())),
+ gl_buffer_(0) {
+ DLOG(INFO) << "IndexBufferGL Construct";
+}
+
+// Destructor releases the OpenGL index buffer.
+IndexBufferGL::~IndexBufferGL() {
+ DLOG(INFO) << "IndexBufferGL Destruct \"" << name() << "\"";
+ ConcreteFree();
+}
+
+// Creates a OpenGL index buffer of the requested size.
+bool IndexBufferGL::ConcreteAllocate(size_t size_in_bytes) {
+ DLOG(INFO) << "IndexBufferGL Allocate \"" << name() << "\"";
+ renderer_->MakeCurrentLazy();
+ ConcreteFree();
+ // Create a new VBO.
+ glGenBuffersARB(1, &gl_buffer_);
+ if (!gl_buffer_) return false;
+ // Give the VBO a size, but no data, and set the hint to "STATIC_DRAW"
+ // to mark the buffer as set up once then used often.
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, gl_buffer_);
+ glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+ size_in_bytes,
+ NULL,
+ GL_STATIC_DRAW_ARB);
+ CHECK_GL_ERROR();
+ return true;
+}
+
+void IndexBufferGL::ConcreteFree() {
+ if (gl_buffer_) {
+ renderer_->MakeCurrentLazy();
+ glDeleteBuffersARB(1, &gl_buffer_);
+ gl_buffer_ = 0;
+ CHECK_GL_ERROR();
+ }
+}
+
+// Maps the OpenGL buffer to get the address in memory of the buffer data.
+bool IndexBufferGL::ConcreteLock(Buffer::AccessMode access_mode,
+ void **buffer_data) {
+ DLOG(INFO) << "IndexBufferGL Lock \"" << name() << "\"";
+ renderer_->MakeCurrentLazy();
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, gl_buffer_);
+ if (!num_elements())
+ return true;
+ *buffer_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+ BufferAccessModeToGLenum(access_mode));
+ if (*buffer_data == NULL) {
+ GLenum error = glGetError();
+ if (error == GL_OUT_OF_MEMORY) {
+ O3D_ERROR(service_locator()) << "Out of memory for buffer lock.";
+ } else {
+ O3D_ERROR(
+ service_locator()) << "Unable to lock a GL Element Array Buffer";
+ }
+ return false;
+ }
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Calls Unlock on the OpenGL buffer to notify that the contents of the buffer
+// are now ready for use.
+bool IndexBufferGL::ConcreteUnlock() {
+ DLOG(INFO) << "IndexBufferGL Unlock \"" << name() << "\"";
+ renderer_->MakeCurrentLazy();
+ if (!num_elements())
+ return true;
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, gl_buffer_);
+ if (!glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER)) {
+ GLenum error = glGetError();
+ if (error == GL_INVALID_OPERATION) {
+ O3D_ERROR(service_locator()) <<
+ "Buffer was unlocked without first being locked.";
+ } else {
+ O3D_ERROR(
+ service_locator()) << "Unable to unlock a GL Element Array Buffer";
+ }
+ return false;
+ }
+ CHECK_GL_ERROR();
+ return true;
+}
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/buffer_gles2.h b/o3d/core/cross/gles2/buffer_gles2.h
new file mode 100644
index 0000000..90a8327
--- /dev/null
+++ b/o3d/core/cross/gles2/buffer_gles2.h
@@ -0,0 +1,120 @@
+/*
+ * 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 file contains the declaration of the platform specific
+// VertexBufferGL and IndexBufferGL objects used by O3D
+
+#ifndef O3D_CORE_CROSS_GLES2_BUFFER_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_BUFFER_GLES2_H_
+
+#include "core/cross/buffer.h"
+#include "core/cross/gles2/gles2_headers.h"
+
+namespace o3d {
+
+class RendererGL;
+
+// VertexBufferGL is a wrapper around an OpenGL Vertex Buffer Object (VBO).
+// The buffer starts out empty. Calling Allocate() will reserve video memory
+// for the buffer. Buffer contents are are updated by calling Lock() to get a
+// pointer to the memory allocated for the buffer, updating that data in place
+// and calling Unlock() to notify OpenGL that the edits are done.
+//
+// To force the vertex and index buffers to be created by Cg Runtime
+// control, define the compile flag "USE_CG_BUFFERS". This option is off by
+// default and buffers are created, locked and managed using the OpenGL
+// "ARB_vertex_buffer_object" extension.
+
+class VertexBufferGL : public VertexBuffer {
+ public:
+ explicit VertexBufferGL(ServiceLocator* service_locator);
+ ~VertexBufferGL();
+
+ // Returns the OpenGL vertex buffer Object handle.
+ GLuint gl_buffer() const { return gl_buffer_; }
+
+ protected:
+ // Creates a OpenGL vertex buffer object of the specified size.
+ virtual bool ConcreteAllocate(size_t size_in_bytes);
+
+ // Frees the OpenGL vertex buffer object.
+ virtual void ConcreteFree();
+
+ // Returns a pointer to the current contents of the buffer. A matching
+ // call to Unlock is necessary to update the contents of the buffer.
+ virtual bool ConcreteLock(AccessMode access_mode, void** buffer_data);
+
+ // Notifies OpenGL that the buffer data has been updated. Unlock is only
+ // valid if it follows a Lock operation.
+ virtual bool ConcreteUnlock();
+
+ private:
+ RendererGL* renderer_;
+ GLuint gl_buffer_;
+};
+
+// IndexBufferGL is a wrapper around an OpenGL Index Buffer Object (VBO).
+// The buffer starts out empty. A call to Allocate() will create an OpenGL
+// index buffer of the requested size. Updates the to the contents of the
+// buffer are done via the Lock/Unlock calls.
+class IndexBufferGL : public IndexBuffer {
+ public:
+ explicit IndexBufferGL(ServiceLocator* service_locator);
+ ~IndexBufferGL();
+
+ // Returns the OpenGL vertex buffer Object handle.
+ GLuint gl_buffer() const { return gl_buffer_; }
+
+ protected:
+ // Creates a OpenGL index buffer of the specified size.
+ virtual bool ConcreteAllocate(size_t size_in_bytes);
+
+ // Frees the OpenGL vertex buffer object.
+ virtual void ConcreteFree();
+
+ // Returns a pointer to the current contents of the buffer. After calling
+ // Lock, the contents of the buffer can be updated in place.
+ virtual bool ConcreteLock(AccessMode access_mode, void** buffer_data);
+
+ // Notifies OpenGL that the buffer data has been updated. Unlock is only
+ // valid if it follows a Lock operation.
+ virtual bool ConcreteUnlock();
+
+ private:
+ RendererGL* renderer_;
+ GLuint gl_buffer_;
+};
+
+} // namespace o3d
+
+
+#endif // O3D_CORE_CROSS_GLES2_BUFFER_GLES2_H_
diff --git a/o3d/core/cross/gles2/draw_element_gles2.cc b/o3d/core/cross/gles2/draw_element_gles2.cc
new file mode 100644
index 0000000..efe3aca
--- /dev/null
+++ b/o3d/core/cross/gles2/draw_element_gles2.cc
@@ -0,0 +1,46 @@
+/*
+ * 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 file contains the definition of the DrawElementGL class.
+
+#include "core/cross/gles2/draw_element_gles2.h"
+
+namespace o3d {
+
+DrawElementGL::DrawElementGL(ServiceLocator* service_locator)
+ : DrawElement(service_locator) {
+}
+
+DrawElementGL::~DrawElementGL() {
+}
+} // namespace o3d
+
diff --git a/o3d/core/cross/gles2/draw_element_gles2.h b/o3d/core/cross/gles2/draw_element_gles2.h
new file mode 100644
index 0000000..a6c769e
--- /dev/null
+++ b/o3d/core/cross/gles2/draw_element_gles2.h
@@ -0,0 +1,57 @@
+/*
+ * 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 file contains the declaration of the DrawElementGL class.
+
+#ifndef O3D_CORE_CROSS_GLES2_DRAW_ELEMENT_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_DRAW_ELEMENT_GLES2_H_
+
+#include <map>
+#include "core/cross/draw_element.h"
+
+namespace o3d {
+
+class Element;
+
+// DrawElementGL is the OpenGL implementation of the DrawElement. It
+// provides a place for the renderer to store platform specific cache
+// information.
+class DrawElementGL : public DrawElement {
+ public:
+ explicit DrawElementGL(ServiceLocator* service_locator);
+ ~DrawElementGL();
+
+ private:
+};
+} // o3d
+
+#endif // O3D_CORE_CROSS_GLES2_DRAW_ELEMENT_GLES2_H_
diff --git a/o3d/core/cross/gles2/effect_gles2.cc b/o3d/core/cross/gles2/effect_gles2.cc
new file mode 100644
index 0000000..efff57e
--- /dev/null
+++ b/o3d/core/cross/gles2/effect_gles2.cc
@@ -0,0 +1,634 @@
+/*
+ * 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 file contains the definition of EffectGL, the OpenGL implementation
+// of the abstract O3D class Effect.
+
+
+// Disable pointer casting warning for openGL calls that require a void* to
+// be cast to a GLuint
+#if defined(OS_WIN)
+#pragma warning(disable : 4312)
+#pragma warning(disable : 4311)
+#endif
+
+#include <sstream>
+#include "base/cross/std_functional.h"
+#include "core/cross/semantic_manager.h"
+#include "core/cross/error.h"
+#include "core/cross/standard_param.h"
+#include "core/cross/gles2/effect_gles2.h"
+#include "core/cross/gles2/renderer_gles2.h"
+#include "core/cross/gles2/primitive_gles2.h"
+#include "core/cross/gles2/draw_element_gles2.h"
+#include "core/cross/gles2/texture_gles2.h"
+#include "core/cross/gles2/utils_gles2.h"
+#include "core/cross/gles2/utils_gles2-inl.h"
+
+#if defined(OS_WIN)
+#include "core/cross/core_metrics.h"
+#endif
+
+namespace o3d {
+
+// Number of repeating events to log before giving up, e.g. setup frame,
+// 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();
+ default : {
+ DLOG(ERROR) << "Cannot convert CGtype "
+ << cgGetTypeString(cg_type)
+ << " to a Param type.";
+ return NULL;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+EffectGL::EffectGL(ServiceLocator* service_locator, CGcontext cg_context)
+ : Effect(service_locator),
+ semantic_manager_(service_locator->GetService<SemanticManager>()),
+ renderer_(static_cast<RendererGL*>(
+ service_locator->GetService<Renderer>())),
+ cg_context_(cg_context),
+ cg_vertex_(NULL),
+ cg_fragment_(NULL) {
+ DLOG(INFO) << "EffectGL Construct";
+}
+
+// Destructor releases vertex and fragment shaders and their correspoding
+// constants tables.
+EffectGL::~EffectGL() {
+ DLOG(INFO) << "EffectGL Destruct \"" << name() << "\"";
+ if (cg_vertex_) {
+ cgDestroyProgram(cg_vertex_);
+ }
+ if (cg_fragment_) {
+ cgDestroyProgram(cg_fragment_);
+ }
+}
+
+// Rewrites vertex program assembly code to match GL 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;
+ }
+ 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;
+ }
+ if (pos >= source->size()) {
+ // we only found comments.
+ return false;
+ }
+ String comments(*source, start_comments, pos - start_comments);
+
+ 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";
+ 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;
+}
+
+// Initializes the Effect object using the shaders found in an FX formatted
+// string.
+bool EffectGL::LoadFromFXString(const String& effect) {
+ DLOG(INFO) << "EffectGL LoadFromFXString";
+ renderer_->MakeCurrentLazy();
+
+ set_source("");
+
+ 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)) {
+ 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;
+ 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;
+ }
+
+#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();
+
+ // If the program rewrite introduced some syntax or semantic errors, we won't
+ // know it until we load the program (through a GL error).
+ // So flush all GL errors first...
+ do {} while (glGetError() != GL_NO_ERROR);
+
+ // ... Then load the program ...
+ cgGLLoadProgram(cg_vertex_);
+
+ // ... And check for GL errors.
+ if (glGetError() != GL_NO_ERROR) {
+ O3D_ERROR(service_locator())
+ << "Effect post-rewrite GL Error: "
+ << glGetString(GL_PROGRAM_ERROR_STRING_ARB)
+ << "\nSource: \n"
+ << vp_assembly;
+ 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;
+ 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;
+ }
+
+ cgGLLoadProgram(cg_fragment_);
+
+ // Also check for GL errors, in case Cg managed to compile, but generated a
+ // bad program.
+ if (glGetError() != GL_NO_ERROR) {
+ O3D_ERROR(service_locator())
+ << "Effect GL Error: "
+ << glGetString(GL_PROGRAM_ERROR_STRING_ARB);
+ 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 EffectGL::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 EffectGL::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* EffectGL::GetTextureParamFromCgSampler(
+ CGparameter cg_sampler,
+ const std::vector<ParamObject*> &param_objects) {
+ DLOG(INFO) << "EffectGL 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) << "EffectGL 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 EffectGL::GetShaderParamInfo(
+ CGprogram program,
+ CGenum name_space,
+ std::map<String, EffectParameterInfo>* info_map) {
+ DCHECK(info_map);
+
+ // 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;
+ }
+ const ObjectBase::Class *param_class = CgTypeToParamType(cg_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);
+ }
+ (*info_map)[name] = EffectParameterInfo(
+ name,
+ param_class,
+ num_elements,
+ (cg_semantic != NULL) ? cg_semantic : "",
+ sem_class);
+ }
+}
+
+void EffectGL::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);
+ }
+ info_array->clear();
+ info_array->reserve(info_map.size());
+ std::transform(
+ info_map.begin(),
+ info_map.end(),
+ std::back_inserter(*info_array),
+ base::select2nd<std::map<String, EffectParameterInfo>::value_type>());
+}
+
+void EffectGL::GetVaryingVertexShaderParamInfo(
+ CGprogram program,
+ CGenum name_space,
+ 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)
+ continue;
+
+ info_array->push_back(EffectStreamInfo(semantic,
+ semantic_index));
+ }
+}
+
+void EffectGL::GetStreamInfo(
+ EffectStreamInfoArray* info_array) {
+ DCHECK(info_array);
+ renderer_->MakeCurrentLazy();
+ info_array->clear();
+ GetVaryingVertexShaderParamInfo(cg_vertex_, CG_PROGRAM, info_array);
+ GetVaryingVertexShaderParamInfo(cg_vertex_, CG_GLOBAL, info_array);
+}
+
+
+// private functions -----------------------------------------------------------
+
+// Loop over all the CG_SAMPLER objects and attach the GLuint handle for the
+// GL texture object that we discovered earlier. Then execute the
+// CGstateassignments in the sampler_state to set up the texture unit.
+// TODO(o3d): remove this (OLD path for textures).
+void EffectGL::SetTexturesFromEffect(ParamCacheGL* param_cache_gl) {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents) << "EffectGL EnableTexturesFromEffect";
+ ParamCacheGL::SamplerParameterMap& map = param_cache_gl->sampler_map();
+ ParamCacheGL::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 ParamCacheGL).
+void EffectGL::UpdateShaderUniformsFromEffect(ParamCacheGL* param_cache_gl) {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents)
+ << "EffectGL UpdateShaderUniformsFromEffect";
+ ParamCacheGL::UniformParameterMap& map = param_cache_gl->uniform_map();
+ ParamCacheGL::UniformParameterMap::iterator i;
+ for (i = map.begin(); i != map.end(); ++i) {
+ CGparameter cg_param = i->first;
+ i->second->SetEffectParam(renderer_, cg_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 EffectGL::ResetShaderUniforms(ParamCacheGL* param_cache_gl) {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents) << "EffectGL ResetShaderUniforms";
+ ParamCacheGL::UniformParameterMap& map = param_cache_gl->uniform_map();
+ ParamCacheGL::UniformParameterMap::iterator i;
+ for (i = map.begin(); i != map.end(); ++i) {
+ CGparameter cg_param = i->first;
+ i->second->ResetEffectParam(renderer_, cg_param);
+ }
+ CHECK_GL_ERROR();
+}
+
+// Updates the values of the vertex and fragment shader parameters using the
+// current values in the param/cgparam caches.
+void EffectGL::PrepareForDraw(ParamCacheGL* param_cache_gl) {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents) << "EffectGL PrepareForDraw \""
+ << name()
+ << "\"";
+ DCHECK(renderer_->IsCurrent());
+ if (cg_vertex_ && cg_fragment_) {
+ // 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);
+ } else {
+ DLOG_FIRST_N(ERROR, kNumLoggedEvents)
+ << "No valid CGeffect found "
+ << "in Effect \"" << name() << "\"";
+ }
+ CHECK_GL_ERROR();
+}
+
+// Resets the render states back to their default value.
+void EffectGL::PostDraw(ParamCacheGL* param_cache_gl) {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents)
+ << "EffectGL PostDraw \"" << name() << "\"";
+ DCHECK(renderer_->IsCurrent());
+ ResetShaderUniforms(param_cache_gl);
+ CHECK_GL_ERROR();
+}
+
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/effect_gles2.h b/o3d/core/cross/gles2/effect_gles2.h
new file mode 100644
index 0000000..93bc857
--- /dev/null
+++ b/o3d/core/cross/gles2/effect_gles2.h
@@ -0,0 +1,147 @@
+/*
+ * 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 file contains the declaration of the EffectGL class.
+
+#ifndef O3D_CORE_CROSS_GLES2_EFFECT_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_EFFECT_GLES2_H_
+
+// Disable compiler warning for openGL calls that require a void* to
+// be cast to a GLuint
+#if defined(OS_WIN)
+#pragma warning(disable : 4312)
+#pragma warning(disable : 4311)
+#endif
+
+#include <utility>
+#include <vector>
+#include <map>
+#include "core/cross/gles2/gles2_headers.h"
+#include "core/cross/effect.h"
+#include "core/cross/gles2/utils_gles2.h"
+
+namespace o3d {
+
+class DrawElementGL;
+class ParamCacheGL;
+class ParamObject;
+class Param;
+class ParamTexture;
+class RendererGL;
+class SemanticManager;
+
+// A class to set an effect parameter from an O3D parameter.
+class EffectParamHandlerGL : public RefCounted {
+ public:
+ typedef SmartPointer<EffectParamHandlerGL> Ref;
+ virtual ~EffectParamHandlerGL() { }
+
+ // Sets a GL/Cg Effect Parameter by an O3D Param.
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) = 0;
+
+ // Resets a GL/Cg Effect parameter to default (currently only
+ // unbinds textures contained in Sampler params).
+ virtual void ResetEffectParam(RendererGL* renderer, CGparameter cg_param) {}
+};
+
+// EffectGL is an implementation of the Effect object for OpenGL. It
+// provides the API for setting the vertex and framgent shaders for the
+// Effect using the Cg Runtime. Currently the two shaders can either be
+// provided separately as shader code or together in an FX file.
+class EffectGL : public Effect {
+ public:
+ EffectGL(ServiceLocator* service_locator, CGcontext cg_context);
+ virtual ~EffectGL();
+
+ // Reads the vertex and fragment shaders from string in the FX format.
+ // It returns true if the shaders were successfully compiled.
+ virtual bool LoadFromFXString(const String& effect);
+
+ // Binds the shaders to the device and sets up all the shader parameters using
+ // the values from the matching Param's of the param_object.
+ void PrepareForDraw(ParamCacheGL* param_cache_gl);
+
+ // Removes any pipeline state-changes installed during a draw.
+ void PostDraw(ParamCacheGL* param_cache_gl);
+
+ // Gets info about the parameters this effect needs.
+ // Overriden from Effect.
+ virtual void GetParameterInfo(EffectParameterInfoArray* info_array);
+
+ // Gets info about the streams this effect needs.
+ // Overriden from 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: remove this (OLD path for textures).
+ ParamTexture* GetTextureParamFromCgSampler(
+ CGparameter cg_sampler,
+ const std::vector<ParamObject*> &param_objects);
+
+ CGprogram cg_vertex_program() { return cg_vertex_; }
+ CGprogram cg_fragment_program() { return cg_fragment_; }
+
+ private:
+ // Loops through all the parameters in the ShapeDataGL and updates the
+ // corresponding parameter EffectGL object
+ void UpdateShaderUniformsFromEffect(ParamCacheGL* param_cache_gl);
+ // Undoes the effect of the above. For now, this unbinds textures.
+ void ResetShaderUniforms(ParamCacheGL* param_cache_gl);
+ void GetShaderParamInfo(CGprogram program,
+ CGenum name_space,
+ std::map<String, EffectParameterInfo>* info_map);
+ void GetVaryingVertexShaderParamInfo(
+ CGprogram program,
+ CGenum name_space,
+ std::vector<EffectStreamInfo>* info_array);
+
+ // TODO: remove these (OLD path for textures).
+ void SetTexturesFromEffect(ParamCacheGL* param_cache_gl);
+ void FillSamplerToTextureMap(const String &effect);
+ String GetTextureNameFromSamplerParamName(const String &sampler_name);
+
+ SemanticManager* semantic_manager_;
+ RendererGL* renderer_;
+
+ CGcontext cg_context_;
+ CGprogram cg_vertex_;
+ CGprogram cg_fragment_;
+
+ // TODO: remove this (OLD path for textures).
+ std::map<String, String> sampler_to_texture_map_;
+};
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_GLES2_EFFECT_GLES2_H_
diff --git a/o3d/core/cross/gles2/gles2_headers.h b/o3d/core/cross/gles2/gles2_headers.h
new file mode 100644
index 0000000..6fc9c9c
--- /dev/null
+++ b/o3d/core/cross/gles2/gles2_headers.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef O3D_CORE_CROSS_GLES2_GL_HEADERS_H_
+#define O3D_CORE_CROSS_GLES2_GL_HEADERS_H_
+
+#include <GL/glew.h>
+#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/install_check.cc b/o3d/core/cross/gles2/install_check.cc
new file mode 100644
index 0000000..9ae59dd
--- /dev/null
+++ b/o3d/core/cross/gles2/install_check.cc
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+
+#include "core/cross/install_check.h"
+
+namespace o3d {
+
+bool RendererInstallCheck(std::string *error) {
+ return true;
+}
+
+} // o3d
diff --git a/o3d/core/cross/gles2/param_cache_gles2.cc b/o3d/core/cross/gles2/param_cache_gles2.cc
new file mode 100644
index 0000000..dc42a45
--- /dev/null
+++ b/o3d/core/cross/gles2/param_cache_gles2.cc
@@ -0,0 +1,762 @@
+/*
+ * 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 file contains the definition of the ParamCacheGL class.
+
+#include "core/cross/error.h"
+#include "core/cross/param_array.h"
+#include "core/cross/renderer.h"
+#include "core/cross/semantic_manager.h"
+#include "core/cross/gles2/param_cache_gles2.h"
+#include "core/cross/gles2/effect_gles2.h"
+#include "core/cross/gles2/sampler_gles2.h"
+#include "core/cross/gles2/renderer_gles2.h"
+#include "core/cross/element.h"
+#include "core/cross/draw_element.h"
+
+namespace o3d {
+
+typedef std::vector<ParamObject *> ParamObjectList;
+
+ParamCacheGL::ParamCacheGL(SemanticManager* semantic_manager,
+ Renderer* renderer)
+ : semantic_manager_(semantic_manager),
+ renderer_(renderer),
+ last_vertex_program_(0),
+ last_fragment_program_(0) {
+}
+
+bool ParamCacheGL::ValidateEffect(Effect* effect) {
+ DLOG_ASSERT(effect);
+
+ EffectGL* effect_gl = down_cast<EffectGL*>(effect);
+ return (effect_gl->cg_vertex_program() == last_vertex_program_ ||
+ effect_gl->cg_fragment_program() == last_fragment_program_);
+}
+
+void ParamCacheGL::UpdateCache(Effect* effect,
+ DrawElement* draw_element,
+ Element* element,
+ Material* material,
+ ParamObject* override) {
+ DLOG_ASSERT(effect);
+ EffectGL* effect_gl = down_cast<EffectGL*>(effect);
+
+ ScanCgEffectParameters(effect_gl->cg_vertex_program(),
+ effect_gl->cg_fragment_program(),
+ draw_element,
+ element,
+ material,
+ override);
+
+ last_vertex_program_ = effect_gl->cg_vertex_program();
+ last_fragment_program_ = effect_gl->cg_fragment_program();
+}
+
+template <typename T>
+class TypedEffectParamHandlerGL : public EffectParamHandlerGL {
+ public:
+ explicit TypedEffectParamHandlerGL(T* param)
+ : param_(param) {
+ }
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param);
+ private:
+ T* param_;
+};
+
+class EffectParamHandlerGLMatrixRows : public EffectParamHandlerGL {
+ public:
+ explicit EffectParamHandlerGLMatrixRows(ParamMatrix4* param)
+ : param_(param) {
+ }
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ // set the data as floats in row major order.
+ Matrix4 mat = param_->value();
+ cgSetMatrixParameterfr(cg_param, &mat[0][0]);
+ }
+ private:
+ ParamMatrix4* param_;
+};
+
+class EffectParamHandlerGLMatrixColumns : public EffectParamHandlerGL {
+ public:
+ explicit EffectParamHandlerGLMatrixColumns(ParamMatrix4* param)
+ : param_(param) {
+ }
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ // set the data as floats in column major order.
+ Matrix4 mat = param_->value();
+ cgSetMatrixParameterfc(cg_param, &mat[0][0]);
+ }
+ private:
+ ParamMatrix4* param_;
+};
+
+template <>
+void TypedEffectParamHandlerGL<ParamFloat>::SetEffectParam(
+ RendererGL* renderer,
+ CGparameter cg_param) {
+ Float f = param_->value();
+ cgSetParameter1f(cg_param, f);
+};
+
+template <>
+void TypedEffectParamHandlerGL<ParamFloat2>::SetEffectParam(
+ RendererGL* renderer,
+ CGparameter cg_param) {
+ Float2 f = param_->value();
+ cgSetParameter2fv(cg_param, f.GetFloatArray());
+};
+
+template <>
+void TypedEffectParamHandlerGL<ParamFloat3>::SetEffectParam(
+ RendererGL* renderer,
+ CGparameter cg_param) {
+ Float3 f = param_->value();
+ cgSetParameter3fv(cg_param, f.GetFloatArray());
+};
+
+template <>
+void TypedEffectParamHandlerGL<ParamFloat4>::SetEffectParam(
+ RendererGL* renderer,
+ CGparameter cg_param) {
+ Float4 f = param_->value();
+ cgSetParameter4fv(cg_param, f.GetFloatArray());
+};
+
+template <>
+void TypedEffectParamHandlerGL<ParamInteger>::SetEffectParam(
+ RendererGL* renderer,
+ CGparameter cg_param) {
+ int i = param_->value();
+ cgSetParameter1i(cg_param, i);
+};
+
+template <>
+void TypedEffectParamHandlerGL<ParamBoolean>::SetEffectParam(
+ RendererGL* renderer,
+ CGparameter cg_param) {
+ int i = param_->value();
+ cgSetParameter1i(cg_param, i);
+};
+
+class EffectParamHandlerForSamplersGL : public EffectParamHandlerGL {
+ public:
+ explicit EffectParamHandlerForSamplersGL(ParamSampler* param)
+ : param_(param) {
+ }
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ SamplerGL* sampler_gl = down_cast<SamplerGL*>(param_->value());
+ if (!sampler_gl) {
+ // Use the error sampler.
+ sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler());
+ // If no error texture is set then generate an error.
+ if (!renderer->error_texture()) {
+ O3D_ERROR(param_->service_locator())
+ << "Missing Sampler for ParamSampler " << param_->name();
+ }
+ }
+ sampler_gl->SetTextureAndStates(cg_param);
+ }
+ virtual void ResetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ SamplerGL* sampler_gl = down_cast<SamplerGL*>(param_->value());
+ if (!sampler_gl) {
+ sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler());
+ }
+ sampler_gl->ResetTexture(cg_param);
+ }
+ private:
+ ParamSampler* param_;
+};
+
+template <typename T>
+class EffectParamArrayHandlerGL : public EffectParamHandlerGL {
+ public:
+ explicit EffectParamArrayHandlerGL(ParamParamArray* param)
+ : param_(param) {
+ }
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ ParamArray* param = param_->value();
+ if (param) {
+ int size = cgGetArraySize(cg_param, 0);
+ if (size != static_cast<int>(param->size())) {
+ O3D_ERROR(param->service_locator())
+ << "number of params in ParamArray does not match number of params "
+ << "needed by shader array";
+ } else {
+ for (int i = 0; i < size; ++i) {
+ Param* untyped_element = param->GetUntypedParam(i);
+ // TODO(gman): Make this check happen when building the param cache.
+ // To do that would require that ParamParamArray mark it's owner
+ // as changed if a Param in it's ParamArray changes.
+ if (untyped_element->IsA(T::GetApparentClass())) {
+ CGparameter cg_element = cgGetArrayParameter(cg_param, i);
+ SetElement(cg_element, down_cast<T*>(untyped_element));
+ } else {
+ O3D_ERROR(param->service_locator())
+ << "Param in ParamArray at index " << i << " is not a "
+ << T::GetApparentClassName();
+ }
+ }
+ }
+ }
+ }
+ void SetElement(CGparameter cg_element, T* param);
+
+ private:
+ ParamParamArray* param_;
+};
+
+template <bool column_major>
+class EffectParamArrayMatrix4HandlerGL : public EffectParamHandlerGL {
+ public:
+ explicit EffectParamArrayMatrix4HandlerGL(ParamParamArray* param)
+ : param_(param) {
+ }
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ ParamArray* param = param_->value();
+ if (param) {
+ int size = cgGetArraySize(cg_param, 0);
+ if (size != static_cast<int>(param->size())) {
+ O3D_ERROR(param->service_locator())
+ << "number of params in ParamArray does not match number of params "
+ << "needed by shader array";
+ } else {
+ for (int i = 0; i < size; ++i) {
+ Param* untyped_element = param->GetUntypedParam(i);
+ // TODO(gman): Make this check happen when building the param cache.
+ // To do that would require that ParamParamArray mark it's owner
+ // as changed if a Param in it's ParamArray changes.
+ if (untyped_element->IsA(ParamMatrix4::GetApparentClass())) {
+ CGparameter cg_element = cgGetArrayParameter(cg_param, i);
+ SetElement(cg_element, down_cast<ParamMatrix4*>(untyped_element));
+ } else {
+ O3D_ERROR(param->service_locator())
+ << "Param in ParamArray at index " << i
+ << " is not a ParamMatrix4";
+ }
+ }
+ }
+ }
+ }
+ void SetElement(CGparameter cg_element, ParamMatrix4* param);
+
+ private:
+ ParamParamArray* param_;
+};
+
+class EffectParamArraySamplerHandlerGL : public EffectParamHandlerGL {
+ public:
+ explicit EffectParamArraySamplerHandlerGL(ParamParamArray* param)
+ : param_(param) {
+ }
+ virtual void SetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ ParamArray* param = param_->value();
+ if (param) {
+ int size = cgGetArraySize(cg_param, 0);
+ if (size != static_cast<int>(param->size())) {
+ O3D_ERROR(param->service_locator())
+ << "number of params in ParamArray does not match number of params "
+ << "needed by shader array";
+ } else {
+ for (int i = 0; i < size; ++i) {
+ Param* untyped_element = param->GetUntypedParam(i);
+ // TODO(gman): Make this check happen when building the param cache.
+ // To do that would require that ParamParamArray mark it's owner
+ // as changed if a Param in it's ParamArray changes.
+ if (untyped_element->IsA(ParamSampler::GetApparentClass())) {
+ CGparameter cg_element = cgGetArrayParameter(cg_param, i);
+ ParamSampler* element = down_cast<ParamSampler*>(untyped_element);
+ SamplerGL* sampler_gl = down_cast<SamplerGL*>(element->value());
+ if (!sampler_gl) {
+ // Use the error sampler.
+ sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler());
+ // If no error texture is set then generate an error.
+ if (!renderer->error_texture()) {
+ O3D_ERROR(param_->service_locator())
+ << "Missing Sampler for ParamSampler '" << param_->name()
+ << "' index " << i;
+ }
+ }
+ sampler_gl->SetTextureAndStates(cg_element);
+ } else {
+ O3D_ERROR(param->service_locator())
+ << "Param in ParamArray at index " << i
+ << " is not a ParamSampler";
+ }
+ }
+ }
+ }
+ }
+ virtual void ResetEffectParam(RendererGL* renderer, CGparameter cg_param) {
+ ParamArray* param = param_->value();
+ if (param) {
+ int size = cgGetArraySize(cg_param, 0);
+ if (size == static_cast<int>(param->size())) {
+ for (int i = 0; i < size; ++i) {
+ Param* untyped_element = param->GetUntypedParam(i);
+ if (untyped_element->IsA(ParamSampler::GetApparentClass())) {
+ CGparameter cg_element = cgGetArrayParameter(cg_param, i);
+ ParamSampler* element = down_cast<ParamSampler*>(untyped_element);
+ SamplerGL* sampler_gl = down_cast<SamplerGL*>(element->value());
+ if (!sampler_gl) {
+ sampler_gl = down_cast<SamplerGL*>(renderer->error_sampler());
+ }
+ sampler_gl->ResetTexture(cg_element);
+ }
+ }
+ }
+ }
+ }
+
+ private:
+ ParamParamArray* param_;
+};
+
+template<>
+void EffectParamArrayHandlerGL<ParamFloat>::SetElement(
+ CGparameter cg_element,
+ ParamFloat* param) {
+ cgSetParameter1f(cg_element, param->value());
+}
+
+template<>
+void EffectParamArrayHandlerGL<ParamFloat2>::SetElement(
+ CGparameter cg_element,
+ ParamFloat2* param) {
+ Float2 f = param->value();
+ cgSetParameter2fv(cg_element, f.GetFloatArray());
+}
+
+template<>
+void EffectParamArrayHandlerGL<ParamFloat3>::SetElement(
+ CGparameter cg_element,
+ ParamFloat3* param) {
+ Float3 f = param->value();
+ cgSetParameter3fv(cg_element, f.GetFloatArray());
+}
+
+template<>
+void EffectParamArrayHandlerGL<ParamFloat4>::SetElement(
+ CGparameter cg_element,
+ ParamFloat4* param) {
+ Float4 f = param->value();
+ cgSetParameter4fv(cg_element, f.GetFloatArray());
+}
+
+template<>
+void EffectParamArrayMatrix4HandlerGL<false>::SetElement(
+ CGparameter cg_element,
+ ParamMatrix4* param) {
+ // set the data as floats in row major order.
+ Matrix4 mat = param->value();
+ cgSetMatrixParameterfr(cg_element, &mat[0][0]);
+}
+
+template<>
+void EffectParamArrayMatrix4HandlerGL<true>::SetElement(
+ CGparameter cg_element,
+ ParamMatrix4* param) {
+ // set the data as floats in column major order.
+ Matrix4 mat = param->value();
+ cgSetMatrixParameterfc(cg_element, &mat[0][0]);
+}
+
+template<>
+void EffectParamArrayHandlerGL<ParamInteger>::SetElement(
+ CGparameter cg_element,
+ ParamInteger* param) {
+ cgSetParameter1i(cg_element, param->value());
+}
+
+template<>
+void EffectParamArrayHandlerGL<ParamBoolean>::SetElement(
+ CGparameter cg_element,
+ ParamBoolean* param) {
+ cgSetParameter1i(cg_element, param->value());
+}
+
+static EffectParamHandlerGL::Ref GetHandlerFromParamAndCgType(
+ EffectGL* effect_gl,
+ Param *param,
+ CGtype cg_type) {
+ EffectParamHandlerGL::Ref handler;
+ if (param->IsA(ParamParamArray::GetApparentClass())) {
+ ParamParamArray* param_param_array = down_cast<ParamParamArray*>(param);
+ switch (cg_type) {
+ case CG_FLOAT:
+ case CG_FLOAT1:
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayHandlerGL<ParamFloat>(param_param_array));
+ break;
+ case CG_FLOAT2:
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayHandlerGL<ParamFloat2>(param_param_array));
+ break;
+ case CG_FLOAT3:
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayHandlerGL<ParamFloat3>(param_param_array));
+ break;
+ case CG_FLOAT4:
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayHandlerGL<ParamFloat4>(param_param_array));
+ break;
+ case CG_FLOAT4x4:
+ if (effect_gl->matrix_load_order() == Effect::COLUMN_MAJOR) {
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayMatrix4HandlerGL<true>(param_param_array));
+ } else {
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayMatrix4HandlerGL<false>(param_param_array));
+ }
+ break;
+ case CG_INT:
+ case CG_INT1:
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayHandlerGL<ParamInteger>(param_param_array));
+ break;
+ case CG_BOOL:
+ case CG_BOOL1:
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArrayHandlerGL<ParamBoolean>(param_param_array));
+ break;
+ case CG_SAMPLER:
+ case CG_SAMPLER1D:
+ case CG_SAMPLER2D:
+ case CG_SAMPLER3D:
+ case CG_SAMPLERCUBE:
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamArraySamplerHandlerGL(param_param_array));
+ break;
+ default:
+ break;
+ }
+ } else if (param->IsA(ParamMatrix4::GetApparentClass())) {
+ if (cg_type == CG_FLOAT4x4) {
+ if (effect_gl->matrix_load_order() == Effect::COLUMN_MAJOR) {
+ // set the data as floats in column major order.
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamHandlerGLMatrixColumns(
+ down_cast<ParamMatrix4*>(param)));
+ } else {
+ // set the data as floats in row major order.
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamHandlerGLMatrixRows(
+ down_cast<ParamMatrix4*>(param)));
+ }
+ }
+ } else if (param->IsA(ParamFloat::GetApparentClass())) {
+ if (cg_type == CG_FLOAT ||
+ cg_type == CG_FLOAT1) {
+ handler = EffectParamHandlerGL::Ref(
+ new TypedEffectParamHandlerGL<ParamFloat>(
+ down_cast<ParamFloat*>(param)));
+ }
+ } else if (param->IsA(ParamFloat2::GetApparentClass())) {
+ if (cg_type == CG_FLOAT2) {
+ handler = EffectParamHandlerGL::Ref(
+ new TypedEffectParamHandlerGL<ParamFloat2>(
+ down_cast<ParamFloat2*>(param)));
+ }
+ } else if (param->IsA(ParamFloat3::GetApparentClass())) {
+ if (cg_type == CG_FLOAT3) {
+ handler = EffectParamHandlerGL::Ref(
+ new TypedEffectParamHandlerGL<ParamFloat3>(
+ down_cast<ParamFloat3*>(param)));
+ }
+ } else if (param->IsA(ParamFloat4::GetApparentClass())) {
+ if (cg_type == CG_FLOAT4) {
+ handler = EffectParamHandlerGL::Ref(
+ new TypedEffectParamHandlerGL<ParamFloat4>(
+ down_cast<ParamFloat4*>(param)));
+ }
+ } else if (param->IsA(ParamInteger::GetApparentClass())) {
+ if (cg_type == CG_INT || cg_type == CG_INT1) {
+ handler = EffectParamHandlerGL::Ref(
+ new TypedEffectParamHandlerGL<ParamInteger>(
+ down_cast<ParamInteger*>(param)));
+ }
+ } else if (param->IsA(ParamBoolean::GetApparentClass())) {
+ if (cg_type == CG_BOOL || cg_type == CG_BOOL1) {
+ handler = EffectParamHandlerGL::Ref(
+ new TypedEffectParamHandlerGL<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) {
+ handler = EffectParamHandlerGL::Ref(
+ new EffectParamHandlerForSamplersGL(
+ down_cast<ParamSampler*>(param)));
+ }
+ }
+ return handler;
+}
+
+// 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,
+ ParamCacheGL* 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) << "ElementGL Found CG_VARYING \""
+ << cg_name << " : "
+ << cgGetParameterSemantic(cg_param) << "\"";
+ }
+ }
+ }
+}
+
+// Local helper function for scanning uniform Cg parameters of a
+// program or effect and recording their entries into the parameter maps.
+static void ScanUniformParameters(SemanticManager* semantic_manager,
+ Renderer* renderer,
+ CGprogram program,
+ CGenum name_space,
+ ParamCacheGL* param_cache_gl,
+ const ParamObjectList& param_objects,
+ EffectGL* 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));
+ }
+ }
+ }
+
+ // 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);
+ }
+ EffectParamHandlerGL::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 (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) << "ElementGL 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) << "ElementGL Param \""
+ << param->name() << "\" type \""
+ << param->GetClassName() << "\" from \""
+ << param_object->name()
+ << "\" does not match CG_PARAMETER \""
+ << cg_name << "\"";
+ }
+ }
+ if (handler.IsNull()) {
+ DLOG(ERROR) << "No matching Param for CG_PARAMETER \""
+ << cg_name << "\"";
+ }
+ }
+ }
+ }
+}
+
+static void DoScanCgEffectParameters(SemanticManager* semantic_manager,
+ Renderer* renderer,
+ ParamCacheGL* param_cache_gl,
+ CGprogram cg_vertex,
+ CGprogram cg_fragment,
+ EffectGL* effect_gl,
+ const ParamObjectList& param_objects) {
+ ScanVaryingParameters(cg_vertex, CG_PROGRAM, param_cache_gl);
+ ScanVaryingParameters(cg_vertex, CG_GLOBAL, 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,
+ param_cache_gl,
+ param_objects,
+ effect_gl);
+}
+
+// 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 ParamCacheGL::ScanCgEffectParameters(CGprogram cg_vertex,
+ CGprogram cg_fragment,
+ ParamObject* draw_element,
+ ParamObject* element,
+ Material* material,
+ ParamObject* override) {
+ DLOG(INFO) << "DrawElementGL ScanCgEffectParameters";
+ DLOG_ASSERT(material);
+ DLOG_ASSERT(draw_element);
+ DLOG_ASSERT(element);
+ EffectGL* effect_gl = static_cast<EffectGL*>(material->effect());
+ DLOG_ASSERT(effect_gl);
+ if (cg_vertex == NULL) {
+ DLOG(ERROR) << "Can't scan an empty Vertex Program for Cg 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);
+ param_object_list.push_back(element);
+ 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_,
+ renderer_,
+ this,
+ cg_vertex,
+ cg_fragment,
+ effect_gl,
+ param_object_list);
+}
+
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/param_cache_gles2.h b/o3d/core/cross/gles2/param_cache_gles2.h
new file mode 100644
index 0000000..d8f14c9
--- /dev/null
+++ b/o3d/core/cross/gles2/param_cache_gles2.h
@@ -0,0 +1,103 @@
+/*
+ * 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 file contains the declaration of the ParamCacheGL class.
+
+#ifndef O3D_CORE_CROSS_GLES2_PARAM_CACHE_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_PARAM_CACHE_GLES2_H_
+
+#include <map>
+#include "core/cross/gles2/gles2_headers.h"
+#include "core/cross/param_cache.h"
+#include "core/cross/gles2/effect_gles2.h"
+
+namespace o3d {
+
+class ParamTexture;
+class SemanticManager;
+
+class ParamCacheGL : public ParamCache {
+ public:
+ ParamCacheGL(SemanticManager* semantic_manager, Renderer* renderer);
+
+ typedef std::map<CGparameter, int> VaryingParameterMap;
+ typedef std::map<CGparameter, EffectParamHandlerGL::Ref> UniformParameterMap;
+ typedef std::map<CGparameter, ParamTexture*> SamplerParameterMap;
+
+ // Overridden from ParamCache.
+ virtual void UpdateCache(Effect* effect,
+ DrawElement* draw_element,
+ Element* element,
+ Material* material,
+ ParamObject* override);
+
+ VaryingParameterMap& varying_map() { return varying_map_; }
+ UniformParameterMap& uniform_map() { return uniform_map_; }
+ SamplerParameterMap& sampler_map() { return sampler_map_; }
+
+ protected:
+ // Overridden from ParamCache
+ // Validates platform specific information about the effect.
+ 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,
+ ParamObject* draw_element,
+ ParamObject* element,
+ Material* material,
+ ParamObject* override);
+
+ // A map of varying CGparameter to Stream index.
+ VaryingParameterMap varying_map_;
+ // A map of uniform CGparameter to Param objects.
+ UniformParameterMap uniform_map_;
+ // A map of uniform CG_SAMPLER CGparameters to ParamTexture objects.
+ // TODO: remove this (OLD path for textures).
+ SamplerParameterMap sampler_map_;
+};
+} // o3d
+
+#endif // O3D_CORE_CROSS_GLES2_PARAM_CACHE_GLES2_H_
diff --git a/o3d/core/cross/gles2/primitive_gles2.cc b/o3d/core/cross/gles2/primitive_gles2.cc
new file mode 100644
index 0000000..3770ca2
--- /dev/null
+++ b/o3d/core/cross/gles2/primitive_gles2.cc
@@ -0,0 +1,258 @@
+/*
+ * 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 file contains the definition of PrimitiveGL.
+
+#include <algorithm>
+
+#include "core/cross/stream.h"
+#include "core/cross/error.h"
+#include "core/cross/gles2/buffer_gles2.h"
+#include "core/cross/gles2/effect_gles2.h"
+#include "core/cross/gles2/primitive_gles2.h"
+#include "core/cross/gles2/renderer_gles2.h"
+#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
+#undef min
+#endif
+
+namespace o3d {
+
+// Number of times to log a repeated event before giving up.
+const int kNumLoggedEvents = 5;
+
+// PrimitiveGL functions -------------------------------------------------------
+
+PrimitiveGL::PrimitiveGL(ServiceLocator* service_locator)
+ : Primitive(service_locator) {
+ DLOG(INFO) << "PrimitiveGL Construct";
+}
+
+PrimitiveGL::~PrimitiveGL() {
+ DLOG(INFO) << "PrimitiveGL Destruct";
+}
+
+// Binds the vertex and index streams required to draw the shape. If the
+// vertex or fragment programs have changed since the last time this method
+// was called (or it's the first time it's getting called) then it forces
+// an update of the mapping between the Shape Param's and the shader parameters
+// and also fills in for any missing streams.
+void PrimitiveGL::PlatformSpecificRender(Renderer* renderer,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache) {
+ DLOG_ASSERT(material);
+ DLOG_ASSERT(draw_element);
+ DLOG_ASSERT(param_cache);
+ DLOG_FIRST_N(INFO, kNumLoggedEvents) << "PrimitiveGL Draw \""
+ << draw_element->name() << "\"";
+ DrawElementGL* draw_element_gl = down_cast<DrawElementGL*>(draw_element);
+ EffectGL* effect_gl = down_cast<EffectGL*>(material->effect());
+ DLOG_ASSERT(effect_gl);
+ StreamBankGL* stream_bank_gl = down_cast<StreamBankGL*>(stream_bank());
+ DLOG_ASSERT(stream_bank_gl);
+
+ ParamCacheGL* param_cache_gl = down_cast<ParamCacheGL*>(param_cache);
+ ParamCacheGL::VaryingParameterMap& varying_map =
+ param_cache_gl->varying_map();
+
+ // If this PrimitiveGL 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()) {
+ // Set up the current CGeffect.
+ if (!param_cache_gl->ValidateAndCacheParams(effect_gl,
+ draw_element_gl,
+ this,
+ stream_bank_gl,
+ material,
+ override)) {
+ Stream::Semantic missing_semantic;
+ int missing_semnatic_index;
+ if (!stream_bank_gl->CheckForMissingVertexStreams(
+ varying_map,
+ &missing_semantic,
+ &missing_semnatic_index)) {
+ param_cache_gl->ClearParamCache();
+ O3D_ERROR(service_locator())
+ << "Required Stream "
+ << Stream::GetSemanticDescription(missing_semantic) << ":"
+ << missing_semnatic_index << " missing on Primitive '" << name()
+ << "' using Material '" << material->name()
+ << "' with Effect '" << effect_gl->name() << "'";
+ return;
+ }
+ }
+ } else {
+ O3D_ERROR(service_locator())
+ << "No CG effect provided in Effect \""
+ << effect_gl->name() << "\" used by Material \""
+ << material->name() << "\" in Shape \""
+ << draw_element_gl->name() << "\". Drawing nothing.";
+ return;
+ }
+
+ // Make sure our streams are up to date (skinned, etc..)
+ stream_bank_gl->UpdateStreams();
+
+ unsigned int max_vertices;
+ if (!stream_bank_gl->BindStreamsForRendering(varying_map, &max_vertices)) {
+ return;
+ }
+
+ // TODO: move these checks at 'set' time instead of draw time.
+
+ bool draw = true;
+ if (number_vertices_ > max_vertices) {
+ O3D_ERROR(service_locator())
+ << "Trying to draw with " << number_vertices_
+ << " vertices when there are only " << max_vertices
+ << " available in the buffers. Skipping primitive.";
+ draw = false;
+ }
+
+ unsigned int index_count;
+
+ if (!Primitive::GetIndexCount(primitive_type_,
+ number_primitives_,
+ &index_count)) {
+ O3D_ERROR(service_locator())
+ << "Unknown Primitive Type in GetIndexCount: "
+ << primitive_type_ << ". Skipping primitive "
+ << name();
+ draw = false;
+ }
+
+ if (indexed()) {
+ // Re-bind the index buffer for this shape
+ IndexBufferGL *ibuffer = down_cast<IndexBufferGL*>(index_buffer());
+
+ unsigned int max_indices = ibuffer->num_elements();
+
+ if (index_count > max_indices) {
+ O3D_ERROR(service_locator())
+ << "Trying to draw with " << index_count
+ << " indices when only " << max_indices
+ << " are available in the buffer. Skipping shape.";
+ draw = false;
+ }
+
+ // TODO: Also check that indices in the index buffer are less than
+ // max_vertices_. Needs support from the index buffer (scan indices on
+ // Unlock).
+
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, ibuffer->gl_buffer());
+ }
+
+ // Set up the shaders in this drawcall from the Effect.
+ effect_gl->PrepareForDraw(param_cache_gl);
+
+ // Do the drawcall.
+ GLenum gl_primitive_type = GL_NONE;
+ switch (primitive_type_) {
+ case Primitive::POINTLIST : {
+ if (indexed()) {
+ O3D_ERROR(service_locator())
+ << "POINTLIST unsupported for indexed primitives for primitive "
+ << name();
+ draw = false;
+ } else {
+ gl_primitive_type = GL_POINTS;
+ }
+ break;
+ }
+ case Primitive::LINELIST : {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents)
+ << "Draw " << number_primitives_ << " GL_LINES";
+ gl_primitive_type = GL_LINES;
+ break;
+ }
+ case Primitive::LINESTRIP : {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents)
+ << "Draw " << number_primitives_ << " GL_LINE_STRIP";
+ gl_primitive_type = GL_LINE_STRIP;
+ break;
+ }
+ case Primitive::TRIANGLELIST : {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents)
+ << "Draw " << number_primitives_ << " GL_TRIANGLES";
+ gl_primitive_type = GL_TRIANGLES;
+ break;
+ }
+ case Primitive::TRIANGLESTRIP : {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents)
+ << "Draw " << number_primitives_ << " GL_TRIANGLE_STRIP";
+ gl_primitive_type = GL_TRIANGLE_STRIP;
+ break;
+ }
+ case Primitive::TRIANGLEFAN : {
+ DLOG_FIRST_N(INFO, kNumLoggedEvents)
+ << "Draw " << number_primitives_ << " GL_TRIANGLE_FAN";
+ gl_primitive_type = GL_TRIANGLE_FAN;
+ break;
+ }
+ default : {
+ DLOG(ERROR) << "Unknown Primitive Type in Primitive: "
+ << primitive_type_;
+ draw = false;
+ }
+ }
+ if (draw) {
+ DCHECK_NE(gl_primitive_type, static_cast<unsigned int>(GL_NONE));
+ renderer->AddPrimitivesRendered(number_primitives_);
+ if (indexed())
+ glDrawElements(gl_primitive_type,
+ index_count,
+ GL_UNSIGNED_INT,
+ BUFFER_OFFSET(start_index() * sizeof(uint32))); // NOLINT
+ else
+ glDrawArrays(gl_primitive_type, start_index(), index_count);
+ }
+
+ // Clean up the shaders.
+ effect_gl->PostDraw(param_cache_gl);
+
+ // Disable the vertex attribute states set earlier.
+ for (ParamCacheGL::VaryingParameterMap::iterator i = varying_map.begin();
+ i != varying_map.end();
+ ++i) {
+ cgGLDisableClientState(i->first);
+ }
+ CHECK_GL_ERROR();
+}
+
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/primitive_gles2.h b/o3d/core/cross/gles2/primitive_gles2.h
new file mode 100644
index 0000000..7dd1c75
--- /dev/null
+++ b/o3d/core/cross/gles2/primitive_gles2.h
@@ -0,0 +1,63 @@
+/*
+ * 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 file contains the declaration of the PrimitiveGL class.
+
+#ifndef O3D_CORE_CROSS_GLES2_PRIMITIVE_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_PRIMITIVE_GLES2_H_
+
+#include <map>
+#include "core/cross/primitive.h"
+#include "core/cross/gles2/param_cache_gles2.h"
+
+namespace o3d {
+
+// PrimitiveGL is the OpenGL implementation of the Primitive. It provides the
+// necessary interfaces for setting the geometry streams on the Primitive.
+class PrimitiveGL : public Primitive {
+ public:
+ explicit PrimitiveGL(ServiceLocator* service_locator);
+ virtual ~PrimitiveGL();
+
+ protected:
+ // Overridden from Primitive.
+ virtual void PlatformSpecificRender(Renderer* renderer,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache);
+
+ private:
+};
+} // o3d
+
+#endif // O3D_CORE_CROSS_GLES2_PRIMITIVE_GLES2_H_
diff --git a/o3d/core/cross/gles2/render_surface_gles2.cc b/o3d/core/cross/gles2/render_surface_gles2.cc
new file mode 100644
index 0000000..b57403f
--- /dev/null
+++ b/o3d/core/cross/gles2/render_surface_gles2.cc
@@ -0,0 +1,125 @@
+/*
+ * 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 file contains the implementation of RenderSurfaceGL and
+// RenderDepthStencilSurfaceGL.
+
+#include "core/cross/gles2/render_surface_gles2.h"
+#include "core/cross/gles2/utils_gles2-inl.h"
+#include "core/cross/renderer.h"
+
+namespace o3d {
+
+RenderSurfaceGL::RenderSurfaceGL(ServiceLocator *service_locator,
+ int width,
+ int height,
+ GLenum cube_face,
+ int mip_level,
+ Texture *texture)
+ : RenderSurface(service_locator, width, height, texture),
+ cube_face_(cube_face),
+ mip_level_(mip_level) {
+ DCHECK(texture);
+}
+
+RenderSurfaceGL::~RenderSurfaceGL() {
+}
+
+Bitmap::Ref RenderSurfaceGL::PlatformSpecificGetBitmap() const {
+ Renderer* renderer = service_locator()->GetService<Renderer>();
+ DCHECK(renderer);
+
+ Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator()));
+ bitmap->Allocate(
+ Texture::ARGB8, clip_width(), clip_height(), 1, Bitmap::IMAGE);
+
+ const RenderSurface* old_render_surface;
+ const RenderDepthStencilSurface* old_depth_surface;
+ bool old_is_back_buffer;
+
+ renderer->GetRenderSurfaces(&old_render_surface, &old_depth_surface,
+ &old_is_back_buffer);
+ renderer->SetRenderSurfaces(this, NULL, false);
+
+ ::glReadPixels(0, 0, clip_width(), clip_height(), GL_BGRA, GL_UNSIGNED_BYTE,
+ bitmap->image_data());
+
+ renderer->SetRenderSurfaces(old_render_surface, old_depth_surface,
+ old_is_back_buffer);
+
+ return bitmap;
+}
+
+RenderDepthStencilSurfaceGL::RenderDepthStencilSurfaceGL(
+ ServiceLocator *service_locator,
+ int width,
+ int height)
+ : RenderDepthStencilSurface(service_locator, width, height) {
+
+ // If packed depth stencil is supported, create only one buffer for both
+ // depth and stencil.
+ if (GLEW_EXT_packed_depth_stencil) {
+ glGenRenderbuffersEXT(1, render_buffers_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[0]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_DEPTH24_STENCIL8_EXT,
+ width,
+ height);
+ CHECK_GL_ERROR();
+ render_buffers_[1] = render_buffers_[0];
+ } else {
+ glGenRenderbuffersEXT(2, render_buffers_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[0]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_DEPTH_COMPONENT24,
+ width,
+ height);
+ CHECK_GL_ERROR();
+
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[1]);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
+ GL_STENCIL_INDEX8_EXT,
+ width,
+ height);
+ CHECK_GL_ERROR();
+ }
+}
+
+RenderDepthStencilSurfaceGL::~RenderDepthStencilSurfaceGL() {
+ if (GLEW_EXT_packed_depth_stencil) {
+ glDeleteRenderbuffersEXT(1, render_buffers_);
+ } else {
+ glDeleteRenderbuffersEXT(2, render_buffers_);
+ }
+}
+
+} // end namespace o3d
diff --git a/o3d/core/cross/gles2/render_surface_gles2.h b/o3d/core/cross/gles2/render_surface_gles2.h
new file mode 100644
index 0000000..c75aa18
--- /dev/null
+++ b/o3d/core/cross/gles2/render_surface_gles2.h
@@ -0,0 +1,109 @@
+/*
+ * 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 file contains the declarations for RenderSurfaceGL and
+// RenderDepthStencilSurfaceGL.
+
+#ifndef O3D_CORE_CROSS_GLES2_RENDER_SURFACE_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_RENDER_SURFACE_GLES2_H_
+
+#include "core/cross/gles2/gles2_headers.h"
+#include "core/cross/render_surface.h"
+#include "core/cross/texture.h"
+
+namespace o3d {
+
+class RenderSurfaceGL : public RenderSurface {
+ public:
+ typedef SmartPointer<RenderSurfaceGL> Ref;
+
+ // Constructs a RenderSurfaceGL instance associated with the texture argument.
+ // Parameters:
+ // service_locator: Service locator for the instance.
+ // width: The width of the surface, in pixels.
+ // height: The height of the surface, in pixels.
+ // cube_face: The face of the cube texture to which the surface is to be
+ // associated. NOTE: If the texture is a 2d texture, then the value of
+ // this argument is irrelevent.
+ // mip_level: The mip-level of the texture to associate with the surface.
+ // texture: The texture to associate with the surface.
+ RenderSurfaceGL(ServiceLocator *service_locator,
+ int width,
+ int height,
+ GLenum cube_face,
+ int mip_level,
+ Texture *texture);
+ virtual ~RenderSurfaceGL();
+
+ GLenum cube_face() const {
+ return cube_face_;
+ }
+
+ int mip_level() const {
+ return mip_level_;
+ }
+
+ protected:
+ // The platform specific part of GetBitmap.
+ virtual Bitmap::Ref PlatformSpecificGetBitmap() const;
+
+ private:
+ GLenum cube_face_;
+ int mip_level_;
+ DISALLOW_COPY_AND_ASSIGN(RenderSurfaceGL);
+};
+
+class RenderDepthStencilSurfaceGL : public RenderDepthStencilSurface {
+ public:
+ typedef SmartPointer<RenderDepthStencilSurfaceGL> Ref;
+
+ RenderDepthStencilSurfaceGL(ServiceLocator *service_locator,
+ int width,
+ int height);
+ virtual ~RenderDepthStencilSurfaceGL();
+
+ GLuint depth_buffer() const {
+ return render_buffers_[0];
+ }
+
+ GLuint stencil_buffer() const {
+ return render_buffers_[1];
+ }
+ private:
+ // Handles to the depth and stencil render-buffers, respectively.
+ GLuint render_buffers_[2];
+ DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurfaceGL);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_GLES2_RENDER_SURFACE_GLES2_H_
diff --git a/o3d/core/cross/gles2/renderer_gles2.cc b/o3d/core/cross/gles2/renderer_gles2.cc
new file mode 100644
index 0000000..e2f4a04
--- /dev/null
+++ b/o3d/core/cross/gles2/renderer_gles2.cc
@@ -0,0 +1,1561 @@
+/*
+ * 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 file contains the definition of the RendererGL class that
+// implements the abstract Renderer API using OpenGL and the Cg
+// Runtime.
+
+
+#include "core/cross/gles2/renderer_gles2.h"
+
+#include "core/cross/error.h"
+#include "core/cross/gles2/buffer_gles2.h"
+#include "core/cross/gles2/draw_element_gles2.h"
+#include "core/cross/gles2/effect_gles2.h"
+#include "core/cross/gles2/param_cache_gles2.h"
+#include "core/cross/gles2/primitive_gles2.h"
+#include "core/cross/gles2/render_surface_gles2.h"
+#include "core/cross/gles2/sampler_gles2.h"
+#include "core/cross/gles2/stream_bank_gles2.h"
+#include "core/cross/gles2/texture_gles2.h"
+#include "core/cross/gles2/utils_gles2-inl.h"
+#include "core/cross/gles2/utils_gles2.h"
+#include "core/cross/material.h"
+#include "core/cross/semantic_manager.h"
+#include "core/cross/features.h"
+#include "core/cross/shape.h"
+#include "core/cross/types.h"
+
+namespace o3d {
+
+namespace {
+
+GLenum ConvertCmpFunc(State::Comparison cmp) {
+ switch (cmp) {
+ case State::CMP_ALWAYS:
+ return GL_ALWAYS;
+ case State::CMP_NEVER:
+ return GL_NEVER;
+ case State::CMP_LESS:
+ return GL_LESS;
+ case State::CMP_GREATER:
+ return GL_GREATER;
+ case State::CMP_LEQUAL:
+ return GL_LEQUAL;
+ case State::CMP_GEQUAL:
+ return GL_GEQUAL;
+ case State::CMP_EQUAL:
+ return GL_EQUAL;
+ case State::CMP_NOTEQUAL:
+ return GL_NOTEQUAL;
+ default:
+ break;
+ }
+ return GL_ALWAYS;
+}
+
+GLenum ConvertFillMode(State::Fill mode) {
+ switch (mode) {
+ case State::POINT:
+ return GL_POINT;
+ case State::WIREFRAME:
+ return GL_LINE;
+ case State::SOLID:
+ return GL_FILL;
+ default:
+ break;
+ }
+ return GL_FILL;
+}
+
+GLenum ConvertBlendFunc(State::BlendingFunction blend_func) {
+ switch (blend_func) {
+ case State::BLENDFUNC_ZERO:
+ return GL_ZERO;
+ case State::BLENDFUNC_ONE:
+ return GL_ONE;
+ case State::BLENDFUNC_SOURCE_COLOR:
+ return GL_SRC_COLOR;
+ case State::BLENDFUNC_INVERSE_SOURCE_COLOR:
+ return GL_ONE_MINUS_SRC_COLOR;
+ case State::BLENDFUNC_SOURCE_ALPHA:
+ return GL_SRC_ALPHA;
+ case State::BLENDFUNC_INVERSE_SOURCE_ALPHA:
+ return GL_ONE_MINUS_SRC_ALPHA;
+ case State::BLENDFUNC_DESTINATION_ALPHA:
+ return GL_DST_ALPHA;
+ case State::BLENDFUNC_INVERSE_DESTINATION_ALPHA:
+ return GL_ONE_MINUS_DST_ALPHA;
+ case State::BLENDFUNC_DESTINATION_COLOR:
+ return GL_DST_COLOR;
+ case State::BLENDFUNC_INVERSE_DESTINATION_COLOR:
+ return GL_ONE_MINUS_DST_COLOR;
+ case State::BLENDFUNC_SOURCE_ALPHA_SATUTRATE:
+ return GL_SRC_ALPHA_SATURATE;
+ default:
+ break;
+ }
+ return GL_ONE;
+}
+
+GLenum ConvertBlendEquation(State::BlendingEquation blend_equation) {
+ switch (blend_equation) {
+ case State::BLEND_ADD:
+ return GL_FUNC_ADD;
+ case State::BLEND_SUBTRACT:
+ return GL_FUNC_SUBTRACT;
+ case State::BLEND_REVERSE_SUBTRACT:
+ return GL_FUNC_REVERSE_SUBTRACT;
+ case State::BLEND_MIN:
+ return GL_MIN;
+ case State::BLEND_MAX:
+ return GL_MAX;
+ default:
+ break;
+ }
+ return GL_FUNC_ADD;
+}
+
+GLenum ConvertStencilOp(State::StencilOperation stencil_func) {
+ switch (stencil_func) {
+ case State::STENCIL_KEEP:
+ return GL_KEEP;
+ case State::STENCIL_ZERO:
+ return GL_ZERO;
+ case State::STENCIL_REPLACE:
+ return GL_REPLACE;
+ case State::STENCIL_INCREMENT_SATURATE:
+ return GL_INCR;
+ case State::STENCIL_DECREMENT_SATURATE:
+ return GL_DECR;
+ case State::STENCIL_INVERT:
+ return GL_INVERT;
+ case State::STENCIL_INCREMENT:
+ return GL_INCR_WRAP;
+ case State::STENCIL_DECREMENT:
+ return GL_DECR_WRAP;
+ default:
+ break;
+ }
+ return GL_KEEP;
+}
+
+// Helper routine that will bind the surfaces stored in the RenderSurface and
+// RenderDepthStencilSurface arguments to the current OpenGL context.
+// Returns true upon success.
+// Note: This routine assumes that a frambuffer object is presently bound
+// to the context.
+bool InstallFramebufferObjects(const RenderSurface* surface,
+ const RenderDepthStencilSurface* surface_depth) {
+#ifdef _DEBUG
+ GLint bound_framebuffer;
+ ::glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &bound_framebuffer);
+ DCHECK(bound_framebuffer != 0);
+#endif
+
+ // Reset the bound attachments to the current framebuffer object.
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ 0);
+
+ if (surface) {
+ const RenderSurfaceGL *gl_surface =
+ down_cast<const RenderSurfaceGL*>(surface);
+ Texture *texture = gl_surface->texture();
+ GLuint handle = static_cast<GLuint>(reinterpret_cast<intptr_t>(
+ texture->GetTextureHandle()));
+ if (texture->IsA(Texture2D::GetApparentClass())) {
+ ::glFramebufferTexture2DEXT(
+ GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D,
+ handle,
+ gl_surface->mip_level());
+ } else if (texture->IsA(TextureCUBE::GetApparentClass())) {
+ ::glFramebufferTexture2DEXT(
+ GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ gl_surface->cube_face(),
+ handle,
+ gl_surface->mip_level());
+ }
+ }
+
+ if (surface_depth) {
+ // Bind both the depth and stencil attachments.
+ const RenderDepthStencilSurfaceGL* gl_surface =
+ down_cast<const RenderDepthStencilSurfaceGL*>(surface_depth);
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ gl_surface->depth_buffer());
+ ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ gl_surface->stencil_buffer());
+ }
+ GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) {
+ return false;
+ }
+
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Helper routine that returns a pointer to the non-NULL entry in the renderer's
+// stack of bound surfaces.
+const RenderSurfaceBase* GetValidRenderSurface(
+ const std::pair<RenderSurface*, RenderDepthStencilSurface*> &stack_entry) {
+ if (stack_entry.first) {
+ return stack_entry.first;
+ } else {
+ return stack_entry.second;
+ }
+}
+
+} // unnamed namespace
+
+// This class wraps StateHandler to make it typesafe.
+template <typename T>
+class TypedStateHandler : public RendererGL::StateHandler {
+ public:
+ // Override this function to set a specific state.
+ // Parameters:
+ // renderer: The platform specific renderer.
+ // param: A concrete param with state data.
+ virtual void SetStateFromTypedParam(RendererGL* renderer, T* param) const = 0;
+
+ // Gets Class of State's Parameter
+ virtual const ObjectBase::Class* GetClass() const {
+ return T::GetApparentClass();
+ }
+
+ private:
+ // Calls SetStateFromTypedParam if the Param type is the correct type.
+ // Parameters:
+ // renderer: The platform specific renderer.
+ // param: A param with state data.
+ virtual void SetState(Renderer* renderer, Param* param) const {
+ RendererGL *renderer_gl = down_cast<RendererGL *>(renderer);
+ // This is safe because State guarntees Params match by type.
+ DCHECK(param->IsA(T::GetApparentClass()));
+ SetStateFromTypedParam(renderer_gl, down_cast<T*>(param));
+ }
+};
+
+// A template the generates a handler for enable/disable states.
+// Parameters:
+// state_constant: GLenum of state we want to enable/disable
+template <GLenum state_constant>
+class StateEnableHandler : public TypedStateHandler<ParamBoolean> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamBoolean* param) const {
+ if (param->value()) {
+ ::glEnable(state_constant);
+ } else {
+ ::glDisable(state_constant);
+ }
+ }
+};
+
+class BoolHandler : public TypedStateHandler<ParamBoolean> {
+ public:
+ explicit BoolHandler(bool* var, bool* changed_var)
+ : var_(*var),
+ changed_var_(*changed_var) {
+ }
+ virtual void SetStateFromTypedParam(RendererGL *renderer,
+ ParamBoolean *param) const {
+ var_ = param->value();
+ }
+ private:
+ bool& var_;
+ bool& changed_var_;
+};
+
+class ZWriteEnableHandler : public TypedStateHandler<ParamBoolean> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL *renderer,
+ ParamBoolean *param) const {
+ ::glDepthMask(param->value());
+ }
+};
+
+class AlphaReferenceHandler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamFloat* param) const {
+ float refFloat = param->value();
+
+ // cap the float to the required range
+ if (refFloat < 0.0f) {
+ refFloat = 0.0f;
+ } else if (refFloat > 1.0f) {
+ refFloat = 1.0f;
+ }
+
+ renderer->alpha_function_ref_changed_ = true;
+ renderer->alpha_ref_ = refFloat;
+ }
+};
+
+class CullModeHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ State::Cull cull = static_cast<State::Cull>(param->value());
+ switch (cull) {
+ case State::CULL_CW:
+ ::glEnable(GL_CULL_FACE);
+ ::glCullFace(GL_BACK);
+ break;
+ case State::CULL_CCW:
+ ::glEnable(GL_CULL_FACE);
+ ::glCullFace(GL_FRONT);
+ break;
+ default:
+ ::glDisable(GL_CULL_FACE);
+ break;
+ }
+ }
+};
+
+class PolygonOffset1Handler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamFloat* param) const {
+ renderer->polygon_offset_factor_ = param->value();
+ renderer->polygon_offset_changed_ = true;
+ }
+};
+
+class PolygonOffset2Handler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamFloat* param) const {
+ renderer->polygon_offset_bias_ = param->value();
+ renderer->polygon_offset_changed_ = true;
+ }
+};
+
+class FillModeHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ ::glPolygonMode(GL_FRONT_AND_BACK,
+ ConvertFillMode(static_cast<State::Fill>(param->value())));
+ }
+};
+
+class ZFunctionHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ ::glDepthFunc(
+ ConvertCmpFunc(static_cast<State::Comparison>(param->value())));
+ }
+};
+
+class BlendEquationHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ explicit BlendEquationHandler(GLenum* var)
+ : var_(*var) {
+ }
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ renderer->alpha_blend_settings_changed_ = true;
+ var_ = ConvertBlendEquation(
+ static_cast<State::BlendingEquation>(param->value()));
+ }
+ private:
+ GLenum& var_;
+};
+
+class BlendFunctionHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ explicit BlendFunctionHandler(GLenum* var)
+ : var_(*var) {
+ }
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ renderer->alpha_blend_settings_changed_ = true;
+ var_ = ConvertBlendFunc(
+ static_cast<State::BlendingFunction>(param->value()));
+ }
+ private:
+ GLenum& var_;
+};
+
+
+class StencilOperationHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ StencilOperationHandler(int face, int condition)
+ : face_(face) ,
+ condition_(condition) {
+ }
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ renderer->stencil_settings_changed_ = true;
+ renderer->stencil_settings_[face_].op_[condition_] = ConvertStencilOp(
+ static_cast<State::StencilOperation>(param->value()));
+ }
+ private:
+ int face_;
+ int condition_;
+};
+
+class ComparisonFunctionHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ ComparisonFunctionHandler(GLenum* var, bool* changed_var)
+ : var_(*var),
+ changed_var_(*changed_var) {
+ }
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ changed_var_ = true;
+ var_ = ConvertCmpFunc(static_cast<State::Comparison>(param->value()));
+ }
+ private:
+ GLenum& var_;
+ bool& changed_var_;
+};
+
+class StencilRefHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ renderer->stencil_settings_changed_ = true;
+ renderer->stencil_ref_ = param->value();
+ }
+};
+
+class StencilMaskHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ explicit StencilMaskHandler(int mask_index)
+ : mask_index_(mask_index) {
+ }
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ renderer->stencil_settings_changed_ = true;
+ renderer->stencil_mask_[mask_index_] = param->value();
+ }
+ private:
+ int mask_index_;
+};
+
+class ColorWriteEnableHandler : public TypedStateHandler<ParamInteger> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamInteger* param) const {
+ int mask = param->value();
+ ::glColorMask((mask & 0x1) != 0,
+ (mask & 0x2) != 0,
+ (mask & 0x4) != 0,
+ (mask & 0x8) != 0);
+ renderer->SetWriteMask(mask);
+ }
+};
+
+class PointSpriteEnableHandler : public TypedStateHandler<ParamBoolean> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamBoolean* param) const {
+ if (param->value()) {
+ ::glEnable(GL_POINT_SPRITE);
+ // TODO: It's not clear from D3D docs that point sprites affect
+ // TEXCOORD0, but that's my guess. Check that.
+ ::glActiveTextureARB(GL_TEXTURE0);
+ ::glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
+ } else {
+ ::glActiveTextureARB(GL_TEXTURE0);
+ ::glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_FALSE);
+ ::glDisable(GL_POINT_SPRITE);
+ }
+ }
+};
+
+class PointSizeHandler : public TypedStateHandler<ParamFloat> {
+ public:
+ virtual void SetStateFromTypedParam(RendererGL* renderer,
+ ParamFloat* param) const {
+ ::glPointSize(param->value());
+ }
+};
+
+RendererGL* RendererGL::CreateDefault(ServiceLocator* service_locator) {
+ return new RendererGL(service_locator);
+}
+
+RendererGL::RendererGL(ServiceLocator* service_locator)
+ : Renderer(service_locator),
+ semantic_manager_(service_locator),
+#ifdef OS_WIN
+ gl_context_(NULL),
+#endif
+ fullscreen_(0),
+#ifdef OS_LINUX
+ display_(NULL),
+ window_(0),
+ context_(0),
+#endif
+#ifdef OS_MACOSX
+ mac_agl_context_(0),
+ 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),
+ alpha_blend_settings_changed_(true),
+ separate_alpha_blend_enable_(false),
+ stencil_settings_changed_(true),
+ separate_stencil_settings_enable_(false),
+ stencil_ref_(0),
+ polygon_offset_changed_(true),
+ polygon_offset_factor_(0.f),
+ polygon_offset_bias_(0.f) {
+ DLOG(INFO) << "RendererGL Construct";
+
+ // Setup default state values.
+ for (int ii = 0; ii < 2; ++ii) {
+ stencil_settings_[ii].func_ = GL_ALWAYS;
+ stencil_settings_[ii].op_[StencilStates::FAIL_OP] = GL_KEEP;
+ stencil_settings_[ii].op_[StencilStates::ZFAIL_OP] = GL_KEEP;
+ stencil_settings_[ii].op_[StencilStates::PASS_OP] = GL_KEEP;
+ stencil_mask_[ii] = -1;
+ blend_function_[ii][FRONT] = GL_ONE;
+ blend_function_[ii][BACK] = GL_ZERO;
+ blend_equation_[ii] = GL_FUNC_ADD;
+ }
+
+ // Setup state handlers
+ AddStateHandler(State::kAlphaTestEnableParamName,
+ new StateEnableHandler<GL_ALPHA_TEST>);
+ AddStateHandler(State::kAlphaReferenceParamName,
+ new AlphaReferenceHandler);
+ AddStateHandler(State::kAlphaComparisonFunctionParamName,
+ new ComparisonFunctionHandler(&alpha_function_,
+ &alpha_function_ref_changed_));
+ AddStateHandler(State::kCullModeParamName,
+ new CullModeHandler);
+ AddStateHandler(State::kDitherEnableParamName,
+ new StateEnableHandler<GL_DITHER>);
+ AddStateHandler(State::kLineSmoothEnableParamName,
+ new StateEnableHandler<GL_LINE_SMOOTH>);
+ AddStateHandler(State::kPointSpriteEnableParamName,
+ new PointSpriteEnableHandler);
+ AddStateHandler(State::kPointSizeParamName,
+ new PointSizeHandler);
+ AddStateHandler(State::kPolygonOffset1ParamName,
+ new PolygonOffset1Handler);
+ AddStateHandler(State::kPolygonOffset2ParamName,
+ new PolygonOffset2Handler);
+ AddStateHandler(State::kFillModeParamName,
+ new FillModeHandler);
+ AddStateHandler(State::kZEnableParamName,
+ new StateEnableHandler<GL_DEPTH_TEST>);
+ AddStateHandler(State::kZWriteEnableParamName,
+ new ZWriteEnableHandler);
+ AddStateHandler(State::kZComparisonFunctionParamName,
+ new ZFunctionHandler);
+ AddStateHandler(State::kAlphaBlendEnableParamName,
+ new StateEnableHandler<GL_BLEND>);
+ AddStateHandler(State::kSourceBlendFunctionParamName,
+ new BlendFunctionHandler(&blend_function_[SRC][RGB]));
+ AddStateHandler(State::kDestinationBlendFunctionParamName,
+ new BlendFunctionHandler(&blend_function_[DST][RGB]));
+ AddStateHandler(State::kStencilEnableParamName,
+ new StateEnableHandler<GL_STENCIL_TEST>);
+ AddStateHandler(State::kStencilFailOperationParamName,
+ new StencilOperationHandler(FRONT, StencilStates::FAIL_OP));
+ AddStateHandler(State::kStencilZFailOperationParamName,
+ new StencilOperationHandler(FRONT, StencilStates::ZFAIL_OP));
+ AddStateHandler(State::kStencilPassOperationParamName,
+ new StencilOperationHandler(FRONT, StencilStates::PASS_OP));
+ AddStateHandler(State::kStencilComparisonFunctionParamName,
+ new ComparisonFunctionHandler(
+ &stencil_settings_[FRONT].func_,
+ &stencil_settings_changed_));
+ AddStateHandler(State::kStencilReferenceParamName,
+ new StencilRefHandler);
+ AddStateHandler(State::kStencilMaskParamName,
+ new StencilMaskHandler(READ_MASK));
+ AddStateHandler(State::kStencilWriteMaskParamName,
+ new StencilMaskHandler(WRITE_MASK));
+ AddStateHandler(State::kColorWriteEnableParamName,
+ new ColorWriteEnableHandler);
+ AddStateHandler(State::kBlendEquationParamName,
+ new BlendEquationHandler(&blend_equation_[RGB]));
+ AddStateHandler(State::kTwoSidedStencilEnableParamName,
+ new BoolHandler(&separate_stencil_settings_enable_,
+ &stencil_settings_changed_));
+ AddStateHandler(State::kCCWStencilFailOperationParamName,
+ new StencilOperationHandler(BACK, StencilStates::FAIL_OP));
+ AddStateHandler(State::kCCWStencilZFailOperationParamName,
+ new StencilOperationHandler(BACK, StencilStates::ZFAIL_OP));
+ AddStateHandler(State::kCCWStencilPassOperationParamName,
+ new StencilOperationHandler(BACK, StencilStates::PASS_OP));
+ AddStateHandler(State::kCCWStencilComparisonFunctionParamName,
+ new ComparisonFunctionHandler(
+ &stencil_settings_[BACK].func_,
+ &stencil_settings_changed_));
+ AddStateHandler(State::kSeparateAlphaBlendEnableParamName,
+ new BoolHandler(&separate_alpha_blend_enable_,
+ &alpha_blend_settings_changed_));
+ AddStateHandler(State::kSourceBlendAlphaFunctionParamName,
+ new BlendFunctionHandler(&blend_function_[SRC][ALPHA]));
+ AddStateHandler(State::kDestinationBlendAlphaFunctionParamName,
+ new BlendFunctionHandler(&blend_function_[DST][ALPHA]));
+ AddStateHandler(State::kBlendAlphaEquationParamName,
+ new BlendEquationHandler(&blend_equation_[ALPHA]));
+}
+
+RendererGL::~RendererGL() {
+ Destroy();
+}
+
+// platform neutral initialization code
+//
+Renderer::InitStatus RendererGL::InitCommonGL() {
+ GLenum glew_error = glewInit();
+ if (glew_error != GLEW_OK) {
+ DLOG(ERROR) << "Unable to initialise GLEW : "
+ << ::glewGetErrorString(glew_error);
+ return INITIALIZATION_ERROR;
+ }
+
+ // Check to see that we can use the OpenGL vertex attribute APIs
+ // TODO: We should return false if this check fails, but because some
+ // Intel hardware does not support OpenGL 2.0, yet does support all of the
+ // extensions we require, we only log an error. A future CL should change
+ // this check to ensure that all of the extension strings we require are
+ // present.
+ if (!GLEW_VERSION_2_0) {
+ DLOG(ERROR) << "GL drivers do not have OpenGL 2.0 functionality.";
+ }
+
+ if (!GLEW_ARB_vertex_buffer_object) {
+ // NOTE: Linux NVidia drivers claim to support OpenGL 2.0 when using
+ // indirect rendering (e.g. remote X), but it is actually lying. The
+ // ARB_vertex_buffer_object functions silently no-op (!) when using
+ // indirect rendering, leading to crashes. Fortunately, in that case, the
+ // driver claims to not support ARB_vertex_buffer_object, so fail in that
+ // case.
+ DLOG(ERROR) << "GL drivers do not support vertex buffer objects.";
+ return GPU_NOT_UP_TO_SPEC;
+ }
+
+ if (!GLEW_EXT_framebuffer_object) {
+ DLOG(ERROR) << "GL drivers do not support framebuffer objects.";
+ return GPU_NOT_UP_TO_SPEC;
+ }
+
+ SetSupportsNPOT(GLEW_ARB_texture_non_power_of_two != 0);
+
+#ifdef OS_MACOSX
+ // The Radeon X1600 says it supports NPOT, but in most situations it doesn't.
+ if (supports_npot() &&
+ !strcmp("ATI Radeon X1600 OpenGL Engine",
+ reinterpret_cast<const char*>(::glGetString(GL_RENDERER))))
+ SetSupportsNPOT(false);
+#endif
+
+ // Check for necessary extensions
+ if (!GLEW_VERSION_2_0 && !GLEW_EXT_stencil_two_side) {
+ DLOG(ERROR) << "Two sided stencil extension missing.";
+ }
+ if (!GLEW_VERSION_1_4 && !GLEW_EXT_blend_func_separate) {
+ DLOG(ERROR) << "Separate blend func extension missing.";
+ }
+ 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) << "OpenGL Vendor: " << ::glGetString(GL_VENDOR);
+ DLOG(INFO) << "OpenGL Renderer: " << ::glGetString(GL_RENDERER);
+ DLOG(INFO) << "OpenGL 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 OpenGL.
+ cgGLRegisterStates(cg_context_);
+ DLOG_CG_ERROR("Registering GL 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);
+ DLOG(INFO) << "Max Vertex Attribs = " << max_vertex_attribs;
+ // Initialize global GL settings.
+ // Tell GL that texture buffers can be single-byte aligned.
+ ::glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ ::glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+ ::glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+ CHECK_GL_ERROR();
+
+ GLint viewport[4];
+ ::glGetIntegerv(GL_VIEWPORT, &viewport[0]);
+ SetClientSize(viewport[2], viewport[3]);
+ CHECK_GL_ERROR();
+
+ ::glGenFramebuffersEXT(1, &render_surface_framebuffer_);
+ CHECK_GL_ERROR();
+
+ return SUCCESS;
+}
+
+// platform neutral destruction code
+void RendererGL::DestroyCommonGL() {
+ MakeCurrentLazy();
+ if (render_surface_framebuffer_) {
+ ::glDeleteFramebuffersEXT(1, &render_surface_framebuffer_);
+ }
+
+ if (cg_context_) {
+ cgDestroyContext(cg_context_);
+ cg_context_ = NULL;
+ }
+}
+
+#ifdef OS_WIN
+
+namespace {
+
+PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = {
+ sizeof(kPixelFormatDescriptor), // Size of structure.
+ 1, // Default version.
+ PFD_DRAW_TO_WINDOW | // Window drawing support.
+ PFD_SUPPORT_OPENGL | // OpenGL support.
+ PFD_DOUBLEBUFFER, // Double buffering support (not stereo).
+ PFD_TYPE_RGBA, // RGBA color mode (not indexed).
+ 24, // 24 bit color mode.
+ 0, 0, 0, 0, 0, 0, // Don't set RGB bits & shifts.
+ 8, 0, // 8 bit alpha
+ 0, // No accumulation buffer.
+ 0, 0, 0, 0, // Ignore accumulation bits.
+ 24, // 24 bit z-buffer size.
+ 8, // 8-bit stencil buffer.
+ 0, // No aux buffer.
+ PFD_MAIN_PLANE, // Main drawing plane (not overlay).
+ 0, // Reserved.
+ 0, 0, 0, // Layer masks ignored.
+};
+
+LRESULT CALLBACK IntermediateWindowProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return ::DefWindowProc(window, message, w_param, l_param);
+}
+
+// Helper routine that returns the highest quality pixel format supported on
+// the current platform. Returns true upon success.
+Renderer::InitStatus GetWindowsPixelFormat(HWND window,
+ Features* features,
+ int* pixel_format) {
+ // We must initialize a GL context before we can determine the multi-sampling
+ // supported on the current hardware, so we create an intermediate window
+ // and context here.
+ HINSTANCE module_handle;
+ if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ reinterpret_cast<wchar_t*>(IntermediateWindowProc),
+ &module_handle)) {
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ WNDCLASS intermediate_class;
+ intermediate_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ intermediate_class.lpfnWndProc = IntermediateWindowProc;
+ intermediate_class.cbClsExtra = 0;
+ intermediate_class.cbWndExtra = 0;
+ intermediate_class.hInstance = module_handle;
+ intermediate_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ intermediate_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ intermediate_class.hbrBackground = NULL;
+ intermediate_class.lpszMenuName = NULL;
+ intermediate_class.lpszClassName = L"Intermediate GL Window";
+
+ ATOM class_registration = ::RegisterClass(&intermediate_class);
+ if (!class_registration) {
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ HWND intermediate_window = ::CreateWindow(
+ reinterpret_cast<wchar_t*>(class_registration),
+ L"",
+ WS_OVERLAPPEDWINDOW,
+ 0, 0,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (!intermediate_window) {
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ HDC intermediate_dc = ::GetDC(intermediate_window);
+ int format_index = ::ChoosePixelFormat(intermediate_dc,
+ &kPixelFormatDescriptor);
+ if (format_index == 0) {
+ DLOG(ERROR) << "Unable to get the pixel format for GL context.";
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return Renderer::INITIALIZATION_ERROR;
+ }
+ if (!::SetPixelFormat(intermediate_dc, format_index,
+ &kPixelFormatDescriptor)) {
+ DLOG(ERROR) << "Unable to set the pixel format for GL context.";
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ // Store the pixel format without multisampling.
+ *pixel_format = format_index;
+ HGLRC gl_context = ::wglCreateContext(intermediate_dc);
+ if (::wglMakeCurrent(intermediate_dc, gl_context)) {
+ // GL context was successfully created and applied to the window's DC.
+ // Startup GLEW, the GL extensions wrangler.
+ GLenum glew_error = ::glewInit();
+ if (glew_error == GLEW_OK) {
+ DLOG(INFO) << "Initialized GLEW " << ::glewGetString(GLEW_VERSION);
+ } else {
+ DLOG(ERROR) << "Unable to initialise GLEW : "
+ << ::glewGetErrorString(glew_error);
+ ::wglMakeCurrent(intermediate_dc, NULL);
+ ::wglDeleteContext(gl_context);
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return Renderer::INITIALIZATION_ERROR;
+ }
+
+ // If the multi-sample extensions are present, query the api to determine
+ // the pixel format.
+ if (!features->not_anti_aliased() &&
+ WGLEW_ARB_pixel_format && WGLEW_ARB_multisample) {
+ int pixel_attributes[] = {
+ WGL_SAMPLES_ARB, 4,
+ WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
+ WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
+ WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
+ WGL_COLOR_BITS_ARB, 24,
+ WGL_ALPHA_BITS_ARB, 8,
+ WGL_DEPTH_BITS_ARB, 24,
+ WGL_STENCIL_BITS_ARB, 8,
+ WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
+ WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
+ 0, 0};
+
+ float pixel_attributes_f[] = {0, 0};
+ int msaa_pixel_format;
+ unsigned int num_formats;
+
+ // Query for the highest sampling rate supported, starting at 4x.
+ static const int kSampleCount[] = {4, 2};
+ static const int kNumSamples = 2;
+ for (int sample = 0; sample < kNumSamples; ++sample) {
+ pixel_attributes[1] = kSampleCount[sample];
+ if (GL_TRUE == ::wglChoosePixelFormatARB(intermediate_dc,
+ pixel_attributes,
+ pixel_attributes_f,
+ 1,
+ &msaa_pixel_format,
+ &num_formats)) {
+ *pixel_format = msaa_pixel_format;
+ break;
+ }
+ }
+ }
+ }
+
+ ::wglMakeCurrent(intermediate_dc, NULL);
+ ::wglDeleteContext(gl_context);
+ ::ReleaseDC(intermediate_window, intermediate_dc);
+ ::DestroyWindow(intermediate_window);
+ ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration),
+ module_handle);
+ return Renderer::SUCCESS;
+}
+
+} // unnamed namespace
+
+Renderer::InitStatus RendererGL::InitPlatformSpecific(
+ const DisplayWindow& display,
+ bool off_screen) {
+ const DisplayWindowWindows &display_platform =
+ static_cast<const DisplayWindowWindows&>(display);
+
+ DLOG(INFO) << "RendererGL Init";
+
+ // TODO: Add support for off-screen rendering using OpenGL.
+ if (off_screen) {
+ return INITIALIZATION_ERROR;
+ }
+
+ int pixel_format;
+ InitStatus init_status;
+
+ init_status = GetWindowsPixelFormat(display_platform.hwnd(),
+ features(),
+ &pixel_format);
+ if (init_status != SUCCESS) {
+ return init_status;
+ }
+
+ window_ = display_platform.hwnd();
+ device_context_ = ::GetDC(window_);
+ if (!::SetPixelFormat(device_context_, pixel_format,
+ &kPixelFormatDescriptor)) {
+ DLOG(ERROR) << "Unable to set the pixel format for GL context.";
+ return INITIALIZATION_ERROR;
+ }
+
+ gl_context_ = ::wglCreateContext(device_context_);
+ if (MakeCurrent()) {
+ // Ensure that glew has been initialized for the created rendering context.
+ init_status = InitCommonGL();
+ if (init_status != SUCCESS) {
+ DLOG(ERROR) << "Failed to initialize GL rendering context.";
+ return init_status;
+ }
+ if (WGLEW_ARB_multisample) {
+ ::glEnable(GL_MULTISAMPLE_ARB);
+ }
+ } else {
+ DLOG(ERROR) << "Failed to create the GL Context.";
+ return INITIALIZATION_ERROR;
+ }
+ CHECK_GL_ERROR();
+ return SUCCESS;
+}
+
+// Releases the Cg Context and deletes the GL device.
+void RendererGL::Destroy() {
+ DLOG(INFO) << "Destroy RendererGL";
+ DestroyCommonGL();
+ if (device_context_) {
+ CHECK_GL_ERROR();
+ // Release the OpenGL rendering context.
+ ::wglMakeCurrent(device_context_, NULL);
+ if (gl_context_) {
+ ::wglDeleteContext(gl_context_);
+ gl_context_ = NULL;
+ }
+ // release the hDC obtained through GetDC().
+ ::ReleaseDC(window_, device_context_);
+ device_context_ = NULL;
+ window_ = NULL;
+ }
+ DLOG(INFO) << "Renderer destroyed.";
+}
+
+#endif // OS_WIN
+
+#ifdef OS_MACOSX
+
+Renderer::InitStatus RendererGL::InitPlatformSpecific(
+ const DisplayWindow& display,
+ bool /*off_screen*/) {
+ const DisplayWindowMac &display_platform =
+ static_cast<const DisplayWindowMac&>(display);
+ // TODO: Add support for off screen rendering on the Mac.
+ mac_agl_context_ = display_platform.agl_context();
+ mac_cgl_context_ = display_platform.cgl_context();
+
+ return InitCommonGL();
+}
+
+void RendererGL::Destroy() {
+ DestroyCommonGL();
+ // We only have to destroy agl contexts,
+ // cgl contexts are not owned by us.
+ if (mac_agl_context_) {
+ ::aglDestroyContext(mac_agl_context_);
+ mac_agl_context_ = NULL;
+ }
+}
+
+#endif // OS_MACOSX
+
+#ifdef OS_LINUX
+Renderer::InitStatus RendererGL::InitPlatformSpecific(
+ const DisplayWindow& display_window,
+ bool off_screen) {
+ const DisplayWindowLinux &display_platform =
+ static_cast<const DisplayWindowLinux&>(display_window);
+ Display *display = display_platform.display();
+ Window window = display_platform.window();
+ XWindowAttributes attributes;
+ ::XGetWindowAttributes(display, window, &attributes);
+ XVisualInfo visual_info_template;
+ visual_info_template.visualid = ::XVisualIDFromVisual(attributes.visual);
+ int visual_info_count = 0;
+ XVisualInfo *visual_info_list = ::XGetVisualInfo(display, VisualIDMask,
+ &visual_info_template,
+ &visual_info_count);
+ DCHECK(visual_info_list);
+ DCHECK_GT(visual_info_count, 0);
+ context_ = 0;
+ for (int i = 0; i < visual_info_count; ++i) {
+ context_ = ::glXCreateContext(display, visual_info_list + i, 0,
+ True);
+ if (context_) break;
+ }
+ ::XFree(visual_info_list);
+ if (!context_) {
+ DLOG(ERROR) << "Couldn't create GL context.";
+ return INITIALIZATION_ERROR;
+ }
+ display_ = display;
+ window_ = window;
+ if (!MakeCurrent()) {
+ ::glXDestroyContext(display, context_);
+ context_ = 0;
+ display_ = NULL;
+ window_ = 0;
+ DLOG(ERROR) << "Couldn't create GL context.";
+ return INITIALIZATION_ERROR;
+ }
+
+ InitStatus init_status = InitCommonGL();
+ if (init_status != SUCCESS) {
+ ::glXDestroyContext(display, context_);
+ context_ = 0;
+ display_ = NULL;
+ window_ = 0;
+ }
+ return init_status;
+}
+
+void RendererGL::Destroy() {
+ DestroyCommonGL();
+ if (display_) {
+ ::glXMakeCurrent(display_, 0, 0);
+ if (context_) {
+ ::glXDestroyContext(display_, context_);
+ context_ = 0;
+ }
+ display_ = NULL;
+ window_ = 0;
+ }
+}
+
+#endif
+
+bool RendererGL::MakeCurrent() {
+#ifdef OS_WIN
+ if (!device_context_ || !gl_context_) return false;
+ bool result = ::wglMakeCurrent(device_context_, gl_context_) != 0;
+ return result;
+#endif
+#ifdef OS_MACOSX
+ if (mac_cgl_context_ != NULL) {
+ ::CGLSetCurrentContext(mac_cgl_context_);
+ return true;
+ } else if (mac_agl_context_ != NULL) {
+ ::aglSetCurrentContext(mac_agl_context_);
+ return true;
+ } else {
+ return false;
+ }
+#endif
+#ifdef OS_LINUX
+ if (context_ != NULL) {
+ bool result = ::glXMakeCurrent(display_, window_, context_) == True;
+ return result;
+ } else {
+ return false;
+ }
+#endif
+}
+
+void RendererGL::PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag) {
+ MakeCurrentLazy();
+ ::glClearColor(color[0], color[1], color[2], color[3]);
+ ::glClearDepth(depth);
+ ::glClearStencil(stencil);
+
+ ::glClear((color_flag ? GL_COLOR_BUFFER_BIT : 0) |
+ (depth_flag ? GL_DEPTH_BUFFER_BIT : 0) |
+ (stencil_flag ? GL_STENCIL_BUFFER_BIT : 0));
+ CHECK_GL_ERROR();
+}
+
+// Updates the helper constant used for the D3D -> GL remapping.
+// See effect_gles2.cc for details.
+void RendererGL::UpdateHelperConstant(float width, float height) {
+ MakeCurrentLazy();
+ // If render-targets are active, pass -1 to invert the Y axis. OpenGL uses
+ // a different viewport orientation than DX. Without the inversion, the
+ // output of render-target rendering will be upside down.
+ if (RenderSurfaceActive()) {
+ ::glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB,
+ 0,
+ 1.0f / width,
+ -1.0f / height,
+ 2.0f,
+ -1.0f);
+ } else {
+ // Only apply the origin offset when rendering to the client area.
+ ::glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB,
+ 0,
+ (1.0f + (2.0f * -dest_x_offset())) / width,
+ (-1.0f + (2.0f * dest_y_offset())) / height,
+ 2.0f,
+ 1.0f);
+ }
+ CHECK_GL_ERROR();
+}
+
+void RendererGL::SetViewportInPixels(int left,
+ int top,
+ int width,
+ int height,
+ float min_z,
+ float max_z) {
+ MakeCurrentLazy();
+ int vieport_top =
+ RenderSurfaceActive() ? top : display_height() - top - height;
+ ::glViewport(left, vieport_top, width, height);
+ UpdateHelperConstant(static_cast<float>(width), static_cast<float>(height));
+
+ // If it's the full client area turn off scissor test for speed.
+ if (left == 0 &&
+ top == 0 &&
+ width == display_width() &&
+ height == display_height()) {
+ ::glDisable(GL_SCISSOR_TEST);
+ } else {
+ ::glScissor(left, vieport_top, width, height);
+ ::glEnable(GL_SCISSOR_TEST);
+ }
+ ::glDepthRange(min_z, max_z);
+}
+
+// Resizes the viewport.
+void RendererGL::Resize(int width, int height) {
+ MakeCurrentLazy();
+ SetClientSize(width, height);
+ CHECK_GL_ERROR();
+}
+
+bool RendererGL::GoFullscreen(const DisplayWindow& display,
+ int mode_id) {
+#ifdef OS_LINUX
+ // This actually just switches the GLX context to the new window. The real
+ // work is in main_linux.cc.
+ const DisplayWindowLinux &display_platform =
+ static_cast<const DisplayWindowLinux&>(display);
+ display_ = display_platform.display();
+ window_ = display_platform.window();
+ if (!MakeCurrent()) {
+ return false;
+ }
+#endif
+ fullscreen_ = true;
+ return true;
+}
+
+bool RendererGL::CancelFullscreen(const DisplayWindow& display,
+ int width, int height) {
+#ifdef OS_LINUX
+ // This actually just switches the GLX context to the old window. The real
+ // work is in main_linux.cc.
+ const DisplayWindowLinux &display_platform =
+ static_cast<const DisplayWindowLinux&>(display);
+ display_ = display_platform.display();
+ window_ = display_platform.window();
+ if (!MakeCurrent()) {
+ return false;
+ }
+#endif
+ fullscreen_ = false;
+ return true;
+}
+
+void RendererGL::GetDisplayModes(std::vector<DisplayMode> *modes) {
+#ifdef OS_MACOSX
+ // Mac is supposed to call a different function in plugin_mac.mm instead.
+ DLOG(FATAL) << "Not supposed to be called";
+#endif
+ // On all other platforms this is unimplemented. Linux only supports
+ // DISPLAY_MODE_DEFAULT for now.
+ modes->clear();
+}
+
+bool RendererGL::GetDisplayMode(int id, DisplayMode *mode) {
+#ifdef OS_MACOSX
+ // Mac is supposed to call a different function in plugin_mac.mm instead.
+ DLOG(FATAL) << "Not supposed to be called";
+ return false;
+#elif defined(OS_LINUX)
+ if (id == DISPLAY_MODE_DEFAULT) {
+ // Don't need to know any of this on Linux.
+ mode->Set(0, 0, 0, id);
+ return true;
+ } else {
+ // There are no other valid ids until we implement GetDisplayModes() and
+ // mode switching.
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+bool RendererGL::PlatformSpecificStartRendering() {
+ DLOG_FIRST_N(INFO, 10) << "RendererGL StartRendering";
+ MakeCurrentLazy();
+
+ // Currently always returns true.
+ // Should be modified if current behavior changes.
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Clears the color, depth and stncil buffers and prepares GL for rendering
+// the frame.
+// Returns true on success.
+bool RendererGL::PlatformSpecificBeginDraw() {
+ DLOG_FIRST_N(INFO, 10) << "RendererGL BeginDraw";
+
+ MakeCurrentLazy();
+
+ // Currently always returns true.
+ // Should be modified if current behavior changes.
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Assign the surface arguments to the renderer, and update the stack
+// of pushed surfaces.
+void RendererGL::SetRenderSurfacesPlatformSpecific(
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* surface_depth) {
+ // TODO: This routine re-uses a single global framebuffer object for
+ // all RenderSurface rendering. Because of the validation checks performed
+ // at attachment-change time, it may be more performant to create a pool
+ // of framebuffer objects with different attachment characterists and
+ // switch between them here.
+ MakeCurrentLazy();
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER, render_surface_framebuffer_);
+ if (!InstallFramebufferObjects(surface, surface_depth)) {
+ O3D_ERROR(service_locator())
+ << "Failed to bind OpenGL render target objects:"
+ << surface->name() <<", "<< surface_depth->name();
+ }
+ // RenderSurface rendering is performed with an inverted Y, so the front
+ // face winding must be changed to clock-wise. See comments for
+ // UpdateHelperConstant.
+ glFrontFace(GL_CW);
+}
+
+void RendererGL::SetBackBufferPlatformSpecific() {
+ MakeCurrentLazy();
+ // Bind the default context, and restore the default front-face winding.
+ ::glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ glFrontFace(GL_CCW);
+}
+
+// Executes a post rendering step
+void RendererGL::PlatformSpecificEndDraw() {
+ DLOG_FIRST_N(INFO, 10) << "RendererGL EndDraw";
+ DCHECK(IsCurrent());
+}
+
+// Swaps the buffers.
+void RendererGL::PlatformSpecificFinishRendering() {
+ DLOG_FIRST_N(INFO, 10) << "RendererGL FinishRendering";
+ DCHECK(IsCurrent());
+ ::glFlush();
+ CHECK_GL_ERROR();
+}
+
+void RendererGL::PlatformSpecificPresent() {
+ DLOG_FIRST_N(INFO, 10) << "RendererGL Present";
+ DCHECK(IsCurrent());
+#ifdef OS_WIN
+ ::SwapBuffers(device_context_);
+#endif
+#ifdef OS_MACOSX
+#ifdef USE_AGL_DOUBLE_BUFFER
+ if (mac_agl_context_) {
+ ::aglSwapBuffers(mac_agl_context_);
+ }
+#endif
+#endif
+#ifdef OS_LINUX
+ ::glXSwapBuffers(display_, window_);
+#endif
+}
+
+StreamBank::Ref RendererGL::CreateStreamBank() {
+ return StreamBank::Ref(new StreamBankGL(service_locator()));
+}
+
+Primitive::Ref RendererGL::CreatePrimitive() {
+ return Primitive::Ref(new PrimitiveGL(service_locator()));
+}
+
+DrawElement::Ref RendererGL::CreateDrawElement() {
+ return DrawElement::Ref(new DrawElementGL(service_locator()));
+}
+
+void RendererGL::SetStencilStates(GLenum face,
+ const StencilStates& stencil_state) {
+ DCHECK(IsCurrent());
+ if (face == GL_FRONT_AND_BACK) {
+ ::glStencilFunc(stencil_state.func_,
+ stencil_ref_,
+ stencil_mask_[READ_MASK]);
+ ::glStencilOp(stencil_state.op_[StencilStates::FAIL_OP],
+ stencil_state.op_[StencilStates::ZFAIL_OP],
+ stencil_state.op_[StencilStates::PASS_OP]);
+ ::glStencilMask(stencil_mask_[WRITE_MASK]);
+ } else if (GLEW_VERSION_2_0) {
+ ::glStencilFuncSeparate(face,
+ stencil_state.func_,
+ stencil_ref_,
+ stencil_mask_[READ_MASK]);
+ ::glStencilOpSeparate(face,
+ stencil_state.op_[StencilStates::FAIL_OP],
+ stencil_state.op_[StencilStates::ZFAIL_OP],
+ stencil_state.op_[StencilStates::PASS_OP]);
+ ::glStencilMaskSeparate(face,
+ stencil_mask_[WRITE_MASK]);
+ } else if (GLEW_EXT_stencil_two_side) {
+ ::glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ ::glActiveStencilFaceEXT(face);
+ ::glStencilFunc(stencil_state.func_,
+ stencil_ref_,
+ stencil_mask_[READ_MASK]);
+ ::glStencilOp(stencil_state.op_[StencilStates::FAIL_OP],
+ stencil_state.op_[StencilStates::ZFAIL_OP],
+ stencil_state.op_[StencilStates::PASS_OP]);
+ ::glStencilMask(stencil_mask_[WRITE_MASK]);
+ ::glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+ }
+ CHECK_GL_ERROR();
+}
+
+void RendererGL::ApplyDirtyStates() {
+ MakeCurrentLazy();
+ DCHECK(IsCurrent());
+ // Set blend settings.
+ if (alpha_blend_settings_changed_) {
+ if (separate_alpha_blend_enable_) {
+ if (GLEW_VERSION_1_4) {
+ ::glBlendFuncSeparate(blend_function_[SRC][RGB],
+ blend_function_[DST][RGB],
+ blend_function_[SRC][ALPHA],
+ blend_function_[DST][ALPHA]);
+ } else if (GLEW_EXT_blend_func_separate) {
+ ::glBlendFuncSeparateEXT(blend_function_[SRC][RGB],
+ blend_function_[DST][RGB],
+ blend_function_[SRC][ALPHA],
+ blend_function_[DST][ALPHA]);
+ }
+ if (GLEW_VERSION_2_0) {
+ ::glBlendEquationSeparate(blend_equation_[RGB],
+ blend_equation_[ALPHA]);
+ } else if (GLEW_EXT_blend_equation_separate) {
+ ::glBlendEquationSeparateEXT(blend_equation_[RGB],
+ blend_equation_[ALPHA]);
+ }
+ } else {
+ ::glBlendFunc(blend_function_[SRC][RGB],
+ blend_function_[DST][RGB]);
+ if (::glBlendEquation != NULL)
+ ::glBlendEquation(blend_equation_[RGB]);
+ }
+ alpha_blend_settings_changed_ = false;
+ }
+
+ // Set alpha settings.
+ if (alpha_function_ref_changed_) {
+ ::glAlphaFunc(alpha_function_, alpha_ref_);
+ alpha_function_ref_changed_ = false;
+ }
+
+ // Set stencil settings.
+ if (stencil_settings_changed_) {
+ if (separate_stencil_settings_enable_) {
+ SetStencilStates(GL_FRONT, stencil_settings_[FRONT]);
+ SetStencilStates(GL_BACK, stencil_settings_[BACK]);
+ } else {
+ SetStencilStates(GL_FRONT_AND_BACK, stencil_settings_[FRONT]);
+ }
+ stencil_settings_changed_ = false;
+ }
+
+ if (polygon_offset_changed_) {
+ bool enable = (polygon_offset_factor_ != 0.f) ||
+ (polygon_offset_bias_ != 0.f);
+ if (enable) {
+ ::glEnable(GL_POLYGON_OFFSET_POINT);
+ ::glEnable(GL_POLYGON_OFFSET_LINE);
+ ::glEnable(GL_POLYGON_OFFSET_FILL);
+ ::glPolygonOffset(polygon_offset_factor_, polygon_offset_bias_);
+ } else {
+ ::glDisable(GL_POLYGON_OFFSET_POINT);
+ ::glDisable(GL_POLYGON_OFFSET_LINE);
+ ::glDisable(GL_POLYGON_OFFSET_FILL);
+ }
+ polygon_offset_changed_ = false;
+ }
+ CHECK_GL_ERROR();
+}
+
+VertexBuffer::Ref RendererGL::CreateVertexBuffer() {
+ DLOG(INFO) << "RendererGL CreateVertexBuffer";
+ MakeCurrentLazy();
+ return VertexBuffer::Ref(new VertexBufferGL(service_locator()));
+}
+
+IndexBuffer::Ref RendererGL::CreateIndexBuffer() {
+ DLOG(INFO) << "RendererGL CreateIndexBuffer";
+ MakeCurrentLazy();
+ return IndexBuffer::Ref(new IndexBufferGL(service_locator()));
+}
+
+Effect::Ref RendererGL::CreateEffect() {
+ DLOG(INFO) << "RendererGL CreateEffect";
+ MakeCurrentLazy();
+ return Effect::Ref(new EffectGL(service_locator(), cg_context_));
+}
+
+Sampler::Ref RendererGL::CreateSampler() {
+ return Sampler::Ref(new SamplerGL(service_locator()));
+}
+
+ParamCache* RendererGL::CreatePlatformSpecificParamCache() {
+ return new ParamCacheGL(semantic_manager_.Get(), this);
+}
+
+
+Texture2D::Ref RendererGL::CreatePlatformSpecificTexture2D(
+ int width,
+ int height,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces) {
+ DLOG(INFO) << "RendererGL CreateTexture2D";
+ MakeCurrentLazy();
+ return Texture2D::Ref(Texture2DGL::Create(service_locator(),
+ format,
+ levels,
+ width,
+ height,
+ enable_render_surfaces));
+}
+
+TextureCUBE::Ref RendererGL::CreatePlatformSpecificTextureCUBE(
+ int edge_length,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces) {
+ DLOG(INFO) << "RendererGL CreateTextureCUBE";
+ MakeCurrentLazy();
+ return TextureCUBE::Ref(TextureCUBEGL::Create(service_locator(),
+ format,
+ levels,
+ edge_length,
+ enable_render_surfaces));
+}
+
+RenderDepthStencilSurface::Ref RendererGL::CreateDepthStencilSurface(
+ int width,
+ int height) {
+ return RenderDepthStencilSurface::Ref(
+ new RenderDepthStencilSurfaceGL(service_locator(),
+ width,
+ height));
+}
+
+const int* RendererGL::GetRGBAUByteNSwizzleTable() {
+ static int swizzle_table[] = { 0, 1, 2, 3, };
+ return swizzle_table;
+}
+
+// This is a factory function for creating Renderer objects. Since
+// we're implementing GL, we only ever return a GL renderer.
+Renderer* Renderer::CreateDefaultRenderer(ServiceLocator* service_locator) {
+ return RendererGL::CreateDefault(service_locator);
+}
+
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/renderer_gles2.h b/o3d/core/cross/gles2/renderer_gles2.h
new file mode 100644
index 0000000..43ba395
--- /dev/null
+++ b/o3d/core/cross/gles2/renderer_gles2.h
@@ -0,0 +1,335 @@
+/*
+ * 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 file contains the definition of the RendererGL class that provides
+// low-level access for O3D to graphics hardware using the OpenGL API
+// and Cg Runtime.
+
+#ifndef O3D_CORE_CROSS_GLES2_RENDERER_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_RENDERER_GLES2_H_
+
+#include "core/cross/gles2/gles2_headers.h"
+#include <build/build_config.h>
+#include "core/cross/renderer.h"
+#include "core/cross/renderer_platform.h"
+#include "core/cross/types.h"
+#include "core/cross/state.h"
+
+namespace o3d {
+
+class Material;
+class Effect;
+class DrawEffect;
+class SemanticManager;
+
+// Implements the genereric Renderer interface using OpenGL and the Cg Runtime.
+class RendererGL : public Renderer {
+ public:
+ // Creates a default Renderer.
+ static RendererGL* CreateDefault(ServiceLocator* service_locator);
+ virtual ~RendererGL();
+
+ // Initialises the renderer for use, claiming hardware resources.
+ virtual InitStatus InitPlatformSpecific(const DisplayWindow& display,
+ bool off_screen);
+
+ // Released all hardware resources.
+ virtual void Destroy();
+
+ // Overridden from Renderer.
+ virtual bool GoFullscreen(const DisplayWindow& display,
+ int mode_id);
+
+ // Overridden from Renderer.
+ virtual bool CancelFullscreen(const DisplayWindow& display,
+ int width, int height);
+
+ // Tells whether we're currently displayed fullscreen or not.
+ virtual bool fullscreen() const {
+ return fullscreen_;
+ }
+
+ // Get a vector of the available fullscreen display modes.
+ // Clears *modes on error.
+ virtual void GetDisplayModes(std::vector<DisplayMode> *modes);
+
+ // Get a single fullscreen display mode by id.
+ // Returns true on success, false on error.
+ virtual bool GetDisplayMode(int id, DisplayMode *mode);
+
+ // Resizes the viewport in OpenGL.
+ virtual void Resize(int width, int height);
+
+ // Creates a StreamBank, returning a platform specific implementation class.
+ virtual StreamBank::Ref CreateStreamBank();
+
+ // Creates a Primitive, returning a platform specific implementation class.
+ virtual Primitive::Ref CreatePrimitive();
+
+ // Creates a DrawElement, returning a platform specific implementation
+ // class.
+ virtual DrawElement::Ref CreateDrawElement();
+
+ // Creates and returns a GL specific float buffer.
+ virtual VertexBuffer::Ref CreateVertexBuffer();
+
+ // Creates and returns a GL specific integer buffer.
+ virtual IndexBuffer::Ref CreateIndexBuffer();
+
+ // Creates and returns a GL specific Effect object.
+ virtual Effect::Ref CreateEffect();
+
+ // Creates and returns a GL specific Sampler object.
+ virtual Sampler::Ref CreateSampler();
+
+ // Creates and returns a platform-specific RenderDepthStencilSurface object
+ // for use as a depth-stencil render target.
+ virtual RenderDepthStencilSurface::Ref CreateDepthStencilSurface(
+ int width,
+ int height);
+
+ // Overridden from Renderer.
+ virtual const int* GetRGBAUByteNSwizzleTable();
+
+ // Makes this renderer active on the current thread if it is not active
+ // already.
+ void MakeCurrentLazy() {
+ if (!IsCurrent())
+ MakeCurrent();
+ }
+
+ // Returns whether or not this renderer is active on the current thread.
+ // Don't worry, the "get" calls are el cheapo.
+ bool IsCurrent() {
+#if defined(OS_MACOSX)
+ if ((mac_agl_context_ != NULL) &&
+ (mac_agl_context_ == aglGetCurrentContext())) {
+ return true;
+ } else if ((mac_cgl_context_ != NULL) &&
+ (mac_cgl_context_ == CGLGetCurrentContext())) {
+ return true;
+ }
+#elif defined(OS_WIN)
+ if ((gl_context_ != NULL) &&
+ (gl_context_ == wglGetCurrentContext())) {
+ return true;
+ }
+#elif defined(OS_LINUX)
+ if ((context_ != NULL) &&
+ (context_ == glXGetCurrentContext())) {
+ return true;
+ }
+#else
+ Error: must port RendererGL::IsCurrent() to your platform.
+#endif
+ return false;
+ }
+
+ // 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_; }
+
+ protected:
+ // Keep the constructor protected so only factory methods can create
+ // renderers.
+ explicit RendererGL(ServiceLocator* service_locator);
+
+ // Overridden from Renderer.
+ virtual bool PlatformSpecificBeginDraw();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificEndDraw();
+
+ // Overridden from Renderer.
+ virtual bool PlatformSpecificStartRendering();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificFinishRendering();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificPresent();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag);
+
+ // Overridden from Renderer.
+ virtual ParamCache* CreatePlatformSpecificParamCache();
+
+ // Sets the viewport. This is the platform specific version.
+ void SetViewportInPixels(int left,
+ int top,
+ int width,
+ int height,
+ float min_z,
+ float max_z);
+
+ // Overridden from Renderer.
+ virtual void SetBackBufferPlatformSpecific();
+
+ // Overridden from Renderer.
+ virtual void SetRenderSurfacesPlatformSpecific(
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface);
+
+ // Overridden from Renderer.
+ virtual Texture2D::Ref CreatePlatformSpecificTexture2D(
+ int width,
+ int height,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces);
+
+ // Overridden from Renderer.
+ virtual TextureCUBE::Ref CreatePlatformSpecificTextureCUBE(
+ int edge_length,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces);
+
+ // Overridden from Renderer.
+ virtual void ApplyDirtyStates();
+
+ private:
+ // Platform-independent GL initialization
+ InitStatus InitCommonGL();
+
+ // Platform-independent GL destruction
+ void DestroyCommonGL();
+
+ // Updates the helper constant used to remap D3D clip coordinates to GL ones.
+ void UpdateHelperConstant(float width, float height);
+
+ ServiceDependency<SemanticManager> semantic_manager_;
+
+ // Indicates we're rendering fullscreen rather than in the plugin region.
+ bool fullscreen_;
+
+
+#ifdef OS_WIN
+ // Handle to the GL device.
+ HWND window_;
+ HDC device_context_;
+ HGLRC gl_context_;
+#endif
+
+#ifdef OS_MACOSX
+ AGLContext mac_agl_context_;
+ CGLContextObj mac_cgl_context_;
+#endif
+
+#ifdef OS_LINUX
+ Display *display_;
+ Window window_;
+ GLXContext context_;
+#endif
+
+ // Handle to the framebuffer-object used while rendering to off-screen
+ // 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_;
+ GLclampf alpha_ref_;
+
+ friend class BlendFunctionHandler;
+ friend class BlendEquationHandler;
+ bool alpha_blend_settings_changed_;
+ bool separate_alpha_blend_enable_;
+ enum {
+ RGB,
+ ALPHA,
+ };
+ enum {
+ SRC,
+ DST,
+ };
+ GLenum blend_function_[2][2]; // SRC/DST, RGB/ALPHA
+ GLenum blend_equation_[2]; // RGB/ALPHA
+
+ bool stencil_settings_changed_;
+ bool separate_stencil_settings_enable_;
+
+ // States for Stencils
+ friend class StencilOperationHandler;
+ friend class StencilRefHandler;
+ friend class StencilMaskHandler;
+ struct StencilStates {
+ GLenum func_;
+ enum {
+ FAIL_OP,
+ ZFAIL_OP,
+ PASS_OP,
+ };
+ int op_[3];
+ };
+
+ enum {
+ FRONT,
+ BACK,
+ };
+ StencilStates stencil_settings_[2];
+
+ enum {
+ READ_MASK,
+ WRITE_MASK,
+ };
+ int stencil_mask_[2];
+ int stencil_ref_;
+
+ // States for PolygonOffset
+ friend class PolygonOffset1Handler;
+ friend class PolygonOffset2Handler;
+ bool polygon_offset_changed_;
+ float polygon_offset_factor_;
+ float polygon_offset_bias_;
+
+ // Sets the stencils states for either front, back or both facing polys.
+ void SetStencilStates(GLenum face, const StencilStates& stencil_states);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_GLES2_RENDERER_GLES2_H_
diff --git a/o3d/core/cross/gles2/sampler_gles2.cc b/o3d/core/cross/gles2/sampler_gles2.cc
new file mode 100644
index 0000000..f275254
--- /dev/null
+++ b/o3d/core/cross/gles2/sampler_gles2.cc
@@ -0,0 +1,217 @@
+/*
+ * 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 file contains the implementation for SamplerGL.
+
+#include "core/cross/gles2/gles2_headers.h"
+#include "core/cross/error.h"
+#include "core/cross/gles2/renderer_gles2.h"
+#include "core/cross/gles2/sampler_gles2.h"
+
+namespace o3d {
+
+SamplerGL::SamplerGL(ServiceLocator* service_locator)
+ : Sampler(service_locator),
+ renderer_(static_cast<RendererGL*>(
+ service_locator->GetService<Renderer>())) {
+}
+
+SamplerGL::~SamplerGL() {
+}
+
+namespace {
+
+unsigned int GLAddressMode(Sampler::AddressMode o3d_mode,
+ unsigned int default_mode) {
+ unsigned int gl_mode = default_mode;
+ switch (o3d_mode) {
+ case Sampler::WRAP:
+ gl_mode = GL_REPEAT;
+ break;
+ case Sampler::MIRROR:
+ gl_mode = GL_MIRRORED_REPEAT;
+ break;
+ case Sampler::CLAMP:
+ gl_mode = GL_CLAMP_TO_EDGE;
+ break;
+ case Sampler::BORDER:
+ gl_mode = GL_CLAMP_TO_BORDER;
+ break;
+ default:
+ DLOG(ERROR) << "Unknown Address mode " << static_cast<int>(o3d_mode);
+ break;
+ }
+ return gl_mode;
+}
+
+unsigned int GLMinFilter(Sampler::FilterType o3d_filter,
+ Sampler::FilterType mip_filter) {
+ switch (o3d_filter) {
+ case Sampler::NONE:
+ return GL_NEAREST;
+ case Sampler::POINT:
+ if (mip_filter == Sampler::NONE)
+ return GL_NEAREST;
+ else if (mip_filter == Sampler::POINT)
+ return GL_NEAREST_MIPMAP_NEAREST;
+ else if (mip_filter == Sampler::LINEAR)
+ return GL_NEAREST_MIPMAP_LINEAR;
+ else if (mip_filter == Sampler::ANISOTROPIC)
+ return GL_NEAREST_MIPMAP_LINEAR;
+ case Sampler::ANISOTROPIC: // Anisotropy is handled in SetTextureAndStates
+ case Sampler::LINEAR:
+ if (mip_filter == Sampler::NONE)
+ return GL_LINEAR;
+ else if (mip_filter == Sampler::POINT)
+ return GL_LINEAR_MIPMAP_NEAREST;
+ else if (mip_filter == Sampler::LINEAR)
+ return GL_LINEAR_MIPMAP_LINEAR;
+ else if (mip_filter == Sampler::ANISOTROPIC)
+ return GL_LINEAR_MIPMAP_LINEAR;
+ }
+ // fall through
+ DLOG(ERROR) << "Unknown filter " << static_cast<int>(o3d_filter);
+ DCHECK(false);
+ return GL_NONE;
+}
+
+unsigned int GLMagFilter(Sampler::FilterType o3d_filter) {
+ switch (o3d_filter) {
+ case Sampler::NONE:
+ case Sampler::POINT:
+ return GL_NEAREST;
+ case Sampler::LINEAR:
+ case Sampler::ANISOTROPIC:
+ return GL_LINEAR;
+ default:
+ DLOG(ERROR) << "Unknown filter " << static_cast<int>(o3d_filter);
+ return GL_LINEAR;
+ }
+}
+
+GLenum GLTextureTarget(Texture* texture) {
+ if (texture->IsA(Texture2D::GetApparentClass())) {
+ return GL_TEXTURE_2D;
+ } else if (texture->IsA(TextureCUBE::GetApparentClass())) {
+ return GL_TEXTURE_CUBE_MAP;
+ } else {
+ DLOG(ERROR) << "Unknown texture target";
+ return 0;
+ }
+}
+
+} // namespace
+
+void SamplerGL::SetTextureAndStates(CGparameter cg_param) {
+ // Get the texture object associated with this sampler.
+ Texture* texture_object = texture();
+
+ if (!texture_object) {
+ texture_object = renderer_->error_texture();
+ if (!texture_object) {
+ O3D_ERROR(service_locator())
+ << "Missing texture for sampler " << name();
+ texture_object = renderer_->fallback_error_texture();
+ }
+ }
+
+ if (!renderer_->SafeToBindTexture(texture_object)) {
+ O3D_ERROR(renderer_->service_locator())
+ << "Attempt to bind texture, " << texture_object->name()
+ << " when drawing to same texture as a RenderSurface";
+ texture_object = renderer_->error_texture();
+ }
+
+ GLuint handle = static_cast<GLuint>(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: 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())) {
+ 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);
+ }
+ }
+}
+
+void SamplerGL::ResetTexture(CGparameter cg_param) {
+ Texture* the_texture = texture();
+ if (the_texture) {
+ // TODO: 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);
+ glBindTexture(target, 0);
+ }
+ }
+}
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/sampler_gles2.h b/o3d/core/cross/gles2/sampler_gles2.h
new file mode 100644
index 0000000..4da4be8
--- /dev/null
+++ b/o3d/core/cross/gles2/sampler_gles2.h
@@ -0,0 +1,65 @@
+/*
+ * 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 file contains the class declaration for SamplerGL.
+
+#ifndef O3D_CORE_CROSS_GLES2_SAMPLER_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_SAMPLER_GLES2_H_
+
+#include "core/cross/sampler.h"
+
+namespace o3d {
+
+class RendererGL;
+
+// SamplerGL is an implementation of the Sampler object for GL.
+class SamplerGL : public Sampler {
+ public:
+ explicit SamplerGL(ServiceLocator* service_locator);
+ virtual ~SamplerGL();
+
+ // Sets the gl texture and sampler states.
+ void SetTextureAndStates(CGparameter cg_param);
+
+ // Unbinds the GL texture.
+ void ResetTexture(CGparameter cg_param);
+
+ private:
+
+ RendererGL* renderer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplerGL);
+};
+} // namespace o3d
+
+
+#endif // O3D_CORE_CROSS_GLES2_SAMPLER_GLES2_H_
diff --git a/o3d/core/cross/gles2/stream_bank_gles2.cc b/o3d/core/cross/gles2/stream_bank_gles2.cc
new file mode 100644
index 0000000..70f6b2a
--- /dev/null
+++ b/o3d/core/cross/gles2/stream_bank_gles2.cc
@@ -0,0 +1,201 @@
+/*
+ * 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 file contains the definition of StreamBankGL.
+
+#include <algorithm>
+
+#include "core/cross/stream.h"
+#include "core/cross/error.h"
+#include "core/cross/gles2/buffer_gles2.h"
+#include "core/cross/gles2/effect_gles2.h"
+#include "core/cross/gles2/stream_bank_gles2.h"
+#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
+#undef min
+#endif
+
+namespace o3d {
+
+namespace {
+
+// Converts from a Field datatype to a suitable GL type
+GLenum GLDataType(const Field& field) {
+ if (field.IsA(FloatField::GetApparentClass())) {
+ return GL_FLOAT;
+ } else if (field.IsA(UByteNField::GetApparentClass())) {
+ switch (field.num_components()) {
+ case 4:
+ return GL_UNSIGNED_BYTE;
+ }
+ }
+ DLOG(ERROR) << "Unknown Stream DataType";
+ return GL_INVALID_ENUM;
+}
+
+} // anonymous namespace
+
+// Number of times to log a repeated event before giving up.
+const int kNumLoggedEvents = 5;
+
+// StreamBankGL functions ------------------------------------------------------
+
+StreamBankGL::StreamBankGL(ServiceLocator* service_locator)
+ : StreamBank(service_locator) {
+ DLOG(INFO) << "StreamBankGL Construct";
+}
+
+StreamBankGL::~StreamBankGL() {
+ DLOG(INFO) << "StreamBankGL Destruct";
+}
+
+bool StreamBankGL::CheckForMissingVertexStreams(
+ ParamCacheGL::VaryingParameterMap& varying_map,
+ Stream::Semantic* missing_semantic,
+ int* missing_semantic_index) {
+ DCHECK(missing_semantic);
+ DCHECK(missing_semantic_index);
+ DLOG(INFO) << "StreamBankGL InsertMissingVertexStreams";
+ // Match CG_VARYING parameters to Buffers with the matching semantics.
+ ParamCacheGL::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);
+ if (stream_index >= 0) {
+ // record the matched stream into the varying parameter map for later
+ // use by StreamBankGL::Draw().
+ i->second = stream_index;
+ DLOG(INFO)
+ << "StreamBankGL Matched CG_PARAMETER \""
+ << cgGetParameterName(cg_param) << " : "
+ << semantic_string << "\" to stream "
+ << stream_index << " \""
+ << vertex_stream_params_.at(
+ stream_index)->stream().field().buffer()->name()
+ << "\"";
+ } else {
+ // no matching stream was found.
+ *missing_semantic = semantic;
+ *missing_semantic_index = index;
+ return false;
+ }
+ }
+ CHECK_GL_ERROR();
+ return true;
+}
+
+bool StreamBankGL::BindStreamsForRendering(
+ const ParamCacheGL::VaryingParameterMap& varying_map,
+ unsigned int* max_vertices) {
+ *max_vertices = UINT_MAX;
+ // Loop over varying params setting up the streams.
+ ParamCacheGL::VaryingParameterMap::const_iterator i;
+ for (i = varying_map.begin(); i != varying_map.end(); ++i) {
+ const Stream& stream = vertex_stream_params_.at(i->second)->stream();
+ const Field& field = stream.field();
+ GLenum type = GLDataType(field);
+ if (type == GL_INVALID_ENUM) {
+ // TODO: support other kinds of buffers.
+ O3D_ERROR(service_locator())
+ << "unsupported field of type '" << field.GetClassName()
+ << "' on StreamBank '" << name() << "'";
+ return false;
+ }
+ VertexBufferGL *vbuffer = down_cast<VertexBufferGL*>(field.buffer());
+ if (!vbuffer) {
+ O3D_ERROR(service_locator())
+ << "stream has no buffer in StreamBank '" << name() << "'";
+ return false;
+ }
+ // TODO support all data types and packings here. Currently it
+ // only supports GL_FLOAT buffers, but buffers of GL_HALF and GL_INT are
+ // also possible as streamed parameter inputs.
+ GLint element_count = field.num_components();
+ if (element_count > 4) {
+ element_count = 0;
+ DLOG_FIRST_N(ERROR, kNumLoggedEvents)
+ << "Unable to find stream for CGparameter: "
+ << cgGetParameterName(i->first);
+ }
+
+ // In the num_elements = 1 case we want to do the D3D stride = 0 thing.
+ // but see below.
+ if (vbuffer->num_elements() == 1) {
+ // TODO: passing a stride of 0 has a different meaning in GL
+ // (compute a stride as if it was packed) than in DX (re-use the vertex
+ // over and over again). The equivalent of the DX behavior is by
+ // disabling the vertex array, and setting a constant value. Currently,
+ // this just avoids de-referencing outside of the vertex buffer, but it
+ // doesn't set the proper value: we'd need to map the buffer, get the
+ // value, and unmap it (slow !!). A better solution is to disallow 0
+ // 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);
+ } else {
+ glBindBufferARB(GL_ARRAY_BUFFER, vbuffer->gl_buffer());
+ cgGLSetParameterPointer(i->first,
+ element_count,
+ GLDataType(field),
+ vbuffer->stride(),
+ BUFFER_OFFSET(field.offset()));
+ cgGLEnableClientState(i->first);
+ *max_vertices = std::min(*max_vertices, stream.GetMaxVertices());
+ }
+ }
+ return true;
+}
+
+// private member functions ----------------------------------------------------
+
+// Searches the array of streams and returns the index of the stream that
+// matches the semantic and index pair. if no match was found, return "-1"
+int StreamBankGL::FindVertexStream(Stream::Semantic semantic, int index) {
+ for (unsigned ii = 0; ii < vertex_stream_params_.size(); ++ii) {
+ const Stream& stream = vertex_stream_params_[ii]->stream();
+ if (stream.semantic() == semantic && stream.semantic_index() == index) {
+ return static_cast<int>(ii);
+ }
+ }
+ return -1;
+}
+
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/stream_bank_gles2.h b/o3d/core/cross/gles2/stream_bank_gles2.h
new file mode 100644
index 0000000..7fd8702
--- /dev/null
+++ b/o3d/core/cross/gles2/stream_bank_gles2.h
@@ -0,0 +1,72 @@
+/*
+ * 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 file contains the declaration of the StreamBankGL class.
+
+#ifndef O3D_CORE_CROSS_GLES2_STREAM_BANK_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_STREAM_BANK_GLES2_H_
+
+#include <map>
+#include "core/cross/stream_bank.h"
+#include "core/cross/gles2/param_cache_gles2.h"
+
+namespace o3d {
+
+// StreamBankGL is the OpenGL implementation of the StreamBank.
+class StreamBankGL : public StreamBank {
+ public:
+ explicit StreamBankGL(ServiceLocator* service_locator);
+ virtual ~StreamBankGL();
+
+ // Sets the streams for rendering.
+ // Parameter:
+ // varying_map: Map of streams.
+ // max_vertrices: pointer to variable to receive the maximum vertices
+ // the streams can render.
+ // Returns:
+ // true if all streams were bound.
+ bool BindStreamsForRendering(
+ const ParamCacheGL::VaryingParameterMap& varying_map,
+ unsigned int* max_vertices);
+
+ // Checks for all required streams before rendering.
+ bool CheckForMissingVertexStreams(
+ ParamCacheGL::VaryingParameterMap& varying_map,
+ Stream::Semantic* missing_semantic,
+ int* missing_semantic_index);
+
+ private:
+ int FindVertexStream(Stream::Semantic semantic, int index);
+};
+} // o3d
+
+#endif // O3D_CORE_CROSS_GLES2_STREAM_BANK_GLES2_H_
diff --git a/o3d/core/cross/gles2/texture_gles2.cc b/o3d/core/cross/gles2/texture_gles2.cc
new file mode 100644
index 0000000..4fd9ae9
--- /dev/null
+++ b/o3d/core/cross/gles2/texture_gles2.cc
@@ -0,0 +1,875 @@
+/*
+ * 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.
+ */
+
+
+// Implementations of the abstract Texture2D and TextureCUBE classes using
+// the OpenGL graphics API.
+
+#include "core/cross/gles2/gles2_headers.h"
+#include "core/cross/error.h"
+#include "core/cross/types.h"
+#include "core/cross/pointer_utils.h"
+#include "core/cross/gles2/renderer_gles2.h"
+#include "core/cross/gles2/render_surface_gles2.h"
+#include "core/cross/gles2/texture_gles2.h"
+#include "core/cross/gles2/utils_gles2.h"
+#include "core/cross/gles2/utils_gles2-inl.h"
+
+namespace o3d {
+
+namespace {
+
+Texture::RGBASwizzleIndices g_gl_abgr32f_swizzle_indices = {0, 1, 2, 3};
+
+} // anonymous namespace.
+
+// Converts an O3D texture format to a GL texture format.
+// Input is 'format'.
+// GL has 2 notions of the format:
+// - the internal format which describes how the format should be stored on the
+// GPU
+// - the (format, type) pair which describes how the input data to glTexImage2D
+// is laid out. If format is 0, the data is compressed and needs to be passed
+// to glCompressedTexImage2D.
+// The internal format is returned in internal_format.
+// The format is the return value of the function.
+// The type is returned in data_type.
+static GLenum GLFormatFromO3DFormat(Texture::Format format,
+ GLenum *internal_format,
+ GLenum *data_type) {
+ switch (format) {
+ case Texture::XRGB8: {
+ *internal_format = GL_RGB;
+ *data_type = GL_UNSIGNED_BYTE;
+ return GL_BGRA;
+ }
+ case Texture::ARGB8: {
+ *internal_format = GL_RGBA;
+ *data_type = GL_UNSIGNED_BYTE;
+ return GL_BGRA;
+ }
+ case Texture::ABGR16F: {
+ *internal_format = GL_RGBA16F_ARB;
+ *data_type = GL_HALF_FLOAT_ARB;
+ return GL_RGBA;
+ }
+ case Texture::R32F: {
+ *internal_format = GL_LUMINANCE32F_ARB;
+ *data_type = GL_FLOAT;
+ return GL_LUMINANCE;
+ }
+ case Texture::ABGR32F: {
+ *internal_format = GL_RGBA32F_ARB;
+ *data_type = GL_FLOAT;
+ return GL_BGRA;
+ }
+ case Texture::DXT1: {
+ if (GL_EXT_texture_compression_s3tc) {
+ *internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ *data_type = 0;
+ return 0;
+ } else {
+ // TODO: we need to convert DXT1 -> RGBA8 but keep around the
+ // pixels so that we can read them back (we won't try to convert back
+ // to DXTC).
+ LOG(ERROR) << "DXT1 compressed textures not supported yet.";
+ *internal_format = 0;
+ *data_type = GL_BYTE;
+ return 0;
+ }
+ }
+ case Texture::DXT3: {
+ if (GL_EXT_texture_compression_s3tc) {
+ *internal_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ *data_type = 0;
+ return 0;
+ } else {
+ // TODO: we need to convert DXT3 -> RGBA8 but keep around the
+ // pixels so that we can read them back (we won't try to convert back
+ // to DXTC).
+ LOG(ERROR) << "DXT3 compressed textures not supported yet.";
+ *internal_format = 0;
+ *data_type = GL_BYTE;
+ return 0;
+ }
+ }
+ case Texture::DXT5: {
+ if (GL_EXT_texture_compression_s3tc) {
+ *internal_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ *data_type = 0;
+ return 0;
+ } else {
+ // TODO: we need to convert DXT3 -> RGBA8 but keep around the
+ // pixels so that we can read them back (we won't try to convert back
+ // to DXTC).
+ LOG(ERROR) << "DXT5 compressed textures not supported yet.";
+ *internal_format = 0;
+ *data_type = GL_BYTE;
+ return 0;
+ }
+ }
+ case Texture::UNKNOWN_FORMAT:
+ break;
+ }
+ // failed to find a matching format
+ LOG(ERROR) << "Unrecognized Texture format type.";
+ *internal_format = 0;
+ *data_type = 0;
+ return 0;
+}
+
+// Updates a GL image from a bitmap, rescaling if necessary.
+static bool UpdateGLImageFromBitmap(GLenum target,
+ unsigned int level,
+ TextureCUBE::CubeFace face,
+ const Bitmap &bitmap,
+ bool resize_to_pot) {
+ DCHECK(bitmap.image_data());
+ unsigned int mip_width = std::max(1U, bitmap.width() >> level);
+ unsigned int mip_height = std::max(1U, bitmap.height() >> level);
+ const uint8 *mip_data = bitmap.GetMipData(level);
+ size_t mip_size =
+ image::ComputeBufferSize(mip_width, mip_height, bitmap.format());
+ scoped_array<uint8> temp_data;
+ if (resize_to_pot) {
+ DCHECK(!Texture::IsCompressedFormat(bitmap.format()));
+ unsigned int pot_width =
+ std::max(1U, image::ComputePOTSize(bitmap.width()) >> level);
+ unsigned int pot_height =
+ std::max(1U, image::ComputePOTSize(bitmap.height()) >> level);
+ size_t pot_size = image::ComputeBufferSize(pot_width, pot_height,
+ bitmap.format());
+ temp_data.reset(new uint8[pot_size]);
+ image::Scale(mip_width, mip_height, bitmap.format(), mip_data,
+ pot_width, pot_height, temp_data.get(),
+ image::ComputePitch(bitmap.format(), pot_width));
+ mip_width = pot_width;
+ mip_height = pot_height;
+ mip_size = pot_size;
+ mip_data = temp_data.get();
+ }
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(bitmap.format(), &gl_internal_format,
+ &gl_data_type);
+ if (gl_format) {
+ glTexSubImage2D(target, level, 0, 0, mip_width, mip_height,
+ gl_format, gl_data_type, mip_data);
+ } else {
+ glCompressedTexSubImage2D(target, level, 0, 0, mip_width, mip_height,
+ gl_internal_format, mip_size, mip_data);
+ }
+ return glGetError() == GL_NO_ERROR;
+}
+
+// Creates the array of GL images for a particular face and upload the pixel
+// data from the bitmap.
+static bool CreateGLImages(GLenum target,
+ GLenum internal_format,
+ GLenum gl_format,
+ GLenum type,
+ TextureCUBE::CubeFace face,
+ Texture::Format format,
+ int levels,
+ int width,
+ int height,
+ bool resize_to_pot) {
+ unsigned int mip_width = width;
+ unsigned int mip_height = height;
+ if (resize_to_pot) {
+ mip_width = image::ComputePOTSize(mip_width);
+ mip_height = image::ComputePOTSize(mip_height);
+ }
+ // glCompressedTexImage2D does't accept NULL as a parameter, so we need
+ // to pass in some data. If we can pass in the original pixel data, we'll
+ // do that, otherwise we'll pass an empty buffer. In that case, prepare it
+ // here once for all.
+ scoped_array<uint8> temp_data;
+ size_t size = image::ComputeBufferSize(mip_width, mip_height, format);
+ temp_data.reset(new uint8[size]);
+ memset(temp_data.get(), 0, size);
+
+ for (int i = 0; i < levels; ++i) {
+ if (gl_format) {
+ glTexImage2D(target, i, internal_format, mip_width, mip_height,
+ 0, gl_format, type, temp_data.get());
+ if (glGetError() != GL_NO_ERROR) {
+ DLOG(ERROR) << "glTexImage2D failed";
+ return false;
+ }
+ } else {
+ size_t mip_size = image::ComputeBufferSize(mip_width, mip_height, format);
+ glCompressedTexImage2DARB(target, i, internal_format, mip_width,
+ mip_height, 0, mip_size, temp_data.get());
+ if (glGetError() != GL_NO_ERROR) {
+ DLOG(ERROR) << "glCompressedTexImage2D failed";
+ return false;
+ }
+ }
+ mip_width = std::max(1U, mip_width >> 1);
+ mip_height = std::max(1U, mip_height >> 1);
+ }
+ return true;
+}
+
+// Texture2DGL -----------------------------------------------------------------
+
+// Constructs a 2D texture object from an existing OpenGL 2D texture.
+// NOTE: the Texture2DGL now owns the GL texture and will destroy it on exit.
+Texture2DGL::Texture2DGL(ServiceLocator* service_locator,
+ GLint texture,
+ Texture::Format format,
+ int levels,
+ int width,
+ int height,
+ bool resize_to_pot,
+ bool enable_render_surfaces)
+ : Texture2D(service_locator,
+ width,
+ height,
+ format,
+ levels,
+ enable_render_surfaces),
+ resize_to_pot_(resize_to_pot),
+ renderer_(static_cast<RendererGL*>(
+ service_locator->GetService<Renderer>())),
+ gl_texture_(texture),
+ backing_bitmap_(Bitmap::Ref(new Bitmap(service_locator))),
+ has_levels_(0),
+ locked_levels_(0) {
+ DLOG(INFO) << "Texture2DGL Construct from GLint";
+ DCHECK_NE(format, Texture::UNKNOWN_FORMAT);
+}
+
+// Creates a new texture object from scratch.
+Texture2DGL* Texture2DGL::Create(ServiceLocator* service_locator,
+ Texture::Format format,
+ int levels,
+ int width,
+ int height,
+ bool enable_render_surfaces) {
+ DLOG(INFO) << "Texture2DGL Create";
+ DCHECK_NE(format, Texture::UNKNOWN_FORMAT);
+ RendererGL *renderer = static_cast<RendererGL *>(
+ service_locator->GetService<Renderer>());
+ renderer->MakeCurrentLazy();
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format,
+ &gl_internal_format,
+ &gl_data_type);
+ if (gl_internal_format == 0) {
+ DLOG(ERROR) << "Unsupported format in Texture2DGL::Create.";
+ return NULL;
+ }
+
+ bool resize_to_pot = !renderer->supports_npot() &&
+ !image::IsPOT(width, height);
+
+ // Creates the OpenGL texture object, with all the required mip levels.
+ GLuint gl_texture = 0;
+ glGenTextures(1, &gl_texture);
+ glBindTexture(GL_TEXTURE_2D, gl_texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,
+ levels - 1);
+
+ if (!CreateGLImages(GL_TEXTURE_2D, gl_internal_format, gl_format,
+ gl_data_type, TextureCUBE::FACE_POSITIVE_X,
+ format, levels, width, height, resize_to_pot)) {
+ DLOG(ERROR) << "Failed to create texture images.";
+ glDeleteTextures(1, &gl_texture);
+ return NULL;
+ }
+ glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ GLint gl_width;
+ GLint gl_height;
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &gl_width);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &gl_height);
+
+ DLOG(INFO) << "Created 2D texture (size=" << gl_width << "x" << gl_height
+ << ", GLuint=" << gl_texture << ")";
+ Texture2DGL *texture = new Texture2DGL(service_locator,
+ gl_texture,
+ format,
+ levels,
+ width,
+ height,
+ resize_to_pot,
+ enable_render_surfaces);
+
+ // If the hardware does not support npot textures, allocate a 0-initialized
+ // mip-chain here for use during Texture2DGL::Lock.
+ if (resize_to_pot) {
+ texture->backing_bitmap_->Allocate(format, width, height, levels,
+ Bitmap::IMAGE);
+ texture->has_levels_ = (1 << levels) - 1;
+ }
+ CHECK_GL_ERROR();
+ return texture;
+}
+
+void Texture2DGL::UpdateBackedMipLevel(unsigned int level) {
+ DCHECK_LT(static_cast<int>(level), levels());
+ DCHECK(backing_bitmap_->image_data());
+ DCHECK_EQ(backing_bitmap_->width(), static_cast<unsigned int>(width()));
+ DCHECK_EQ(backing_bitmap_->height(), static_cast<unsigned int>(height()));
+ DCHECK_EQ(backing_bitmap_->format(), format());
+ renderer_->MakeCurrentLazy();
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ UpdateGLImageFromBitmap(GL_TEXTURE_2D, level, TextureCUBE::FACE_POSITIVE_X,
+ *backing_bitmap_.Get(), resize_to_pot_);
+}
+
+Texture2DGL::~Texture2DGL() {
+ DLOG(INFO) << "Texture2DGL Destruct";
+ if (gl_texture_) {
+ renderer_->MakeCurrentLazy();
+ glDeleteTextures(1, &gl_texture_);
+ gl_texture_ = 0;
+ }
+ CHECK_GL_ERROR();
+}
+
+void Texture2DGL::SetRect(int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect on non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width = image::ComputeMipDimension(level, width());
+ unsigned mip_height = image::ComputeMipDimension(level, height());
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ DCHECK(backing_bitmap_->image_data());
+ DCHECK(!compressed);
+ // We need to update the backing mipmap and then use that to update the
+ // texture.
+ backing_bitmap_->SetRect(
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(level);
+ } else {
+ renderer_->MakeCurrentLazy();
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(), &gl_internal_format,
+ &gl_data_type);
+ if (gl_format) {
+ if (src_pitch == image::ComputePitch(format(), src_width)) {
+ glTexSubImage2D(GL_TEXTURE_2D, level,
+ dst_left, dst_top,
+ src_width, src_height,
+ gl_format,
+ gl_data_type,
+ src_data);
+ } else {
+ int limit = src_height;
+ for (int yy = 0; yy < limit; ++yy) {
+ glTexSubImage2D(GL_TEXTURE_2D, level,
+ dst_left, dst_top + yy,
+ src_width, 1,
+ gl_format,
+ gl_data_type,
+ src_data);
+ src_data = AddPointerOffset<const void*>(src_data, src_pitch);
+ }
+ }
+ } else {
+ glCompressedTexSubImage2D(
+ GL_TEXTURE_2D, level, 0, 0, src_width, src_height,
+ gl_internal_format,
+ image::ComputeMipChainSize(src_width, src_height, format(), 1),
+ src_data);
+ }
+ }
+}
+
+// Locks the given mipmap level of this texture for loading from main memory,
+// and returns a pointer to the buffer.
+bool Texture2DGL::PlatformSpecificLock(
+ int level, void** data, int* pitch, Texture::AccessMode mode) {
+ DLOG(INFO) << "Texture2DGL Lock";
+ DCHECK(data);
+ DCHECK(pitch);
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
+ renderer_->MakeCurrentLazy();
+ if (!backing_bitmap_->image_data()) {
+ DCHECK_EQ(has_levels_, 0u);
+ backing_bitmap_->Allocate(format(), width(), height(), levels(),
+ Bitmap::IMAGE);
+ }
+ *data = backing_bitmap_->GetMipData(level);
+ unsigned int mip_width = image::ComputeMipDimension(level, width());
+ if (!IsCompressed()) {
+ *pitch = image::ComputePitch(format(), mip_width);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
+ if (mode != kWriteOnly && !HasLevel(level)) {
+ DCHECK(!resize_to_pot_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(),
+ &gl_internal_format,
+ &gl_data_type);
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ glGetTexImage(GL_TEXTURE_2D, level, gl_format, gl_data_type, *data);
+ has_levels_ |= 1 << level;
+ }
+ locked_levels_ |= 1 << level;
+ CHECK_GL_ERROR();
+ return true;
+}
+
+// Unlocks the given mipmap level of this texture, uploading the main memory
+// data buffer to GL.
+bool Texture2DGL::PlatformSpecificUnlock(int level) {
+ DLOG(INFO) << "Texture2DGL Unlock";
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
+ if (LockedMode(level) != kReadOnly) {
+ renderer_->MakeCurrentLazy();
+ UpdateBackedMipLevel(level);
+ }
+ locked_levels_ &= ~(1 << level);
+ if (!resize_to_pot_ && (locked_levels_ == 0)) {
+ backing_bitmap_->FreeData();
+ has_levels_ = 0;
+ }
+ CHECK_GL_ERROR();
+ return true;
+}
+
+RenderSurface::Ref Texture2DGL::PlatformSpecificGetRenderSurface(
+ int mip_level) {
+ DCHECK_LT(mip_level, levels());
+ if (!render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to get RenderSurface from non-render-surface-enabled"
+ << " Texture: " << name();
+ return RenderSurface::Ref(NULL);
+ }
+
+ if (mip_level >= levels() || mip_level < 0) {
+ O3D_ERROR(service_locator())
+ << "Attempting to access non-existent mip_level " << mip_level
+ << " in render-target texture \"" << name() << "\".";
+ return RenderSurface::Ref(NULL);
+ }
+
+ return RenderSurface::Ref(new RenderSurfaceGL(
+ service_locator(),
+ width()>> mip_level,
+ height() >> mip_level,
+ 0,
+ mip_level,
+ this));
+}
+
+const Texture::RGBASwizzleIndices& Texture2DGL::GetABGR32FSwizzleIndices() {
+ return g_gl_abgr32f_swizzle_indices;
+}
+
+// TextureCUBEGL ---------------------------------------------------------------
+
+// Creates a texture from a pre-existing GL texture object.
+TextureCUBEGL::TextureCUBEGL(ServiceLocator* service_locator,
+ GLint texture,
+ Texture::Format format,
+ int levels,
+ int edge_length,
+ bool resize_to_pot,
+ bool enable_render_surfaces)
+ : TextureCUBE(service_locator,
+ edge_length,
+ format,
+ levels,
+ enable_render_surfaces),
+ resize_to_pot_(resize_to_pot),
+ renderer_(static_cast<RendererGL*>(
+ service_locator->GetService<Renderer>())),
+ gl_texture_(texture) {
+ DLOG(INFO) << "TextureCUBEGL Construct";
+ for (int ii = 0; ii < static_cast<int>(NUMBER_OF_FACES); ++ii) {
+ backing_bitmaps_[ii] = Bitmap::Ref(new Bitmap(service_locator));
+ has_levels_[ii] = 0;
+ locked_levels_[ii] = 0;
+ }
+}
+
+TextureCUBEGL::~TextureCUBEGL() {
+ DLOG(INFO) << "TextureCUBEGL Destruct";
+ if (gl_texture_) {
+ renderer_->MakeCurrentLazy();
+ glDeleteTextures(1, &gl_texture_);
+ gl_texture_ = 0;
+ }
+ CHECK_GL_ERROR();
+}
+
+static const int kCubemapFaceList[] = {
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+};
+
+// Create a new Cube texture from scratch.
+TextureCUBEGL* TextureCUBEGL::Create(ServiceLocator* service_locator,
+ Texture::Format format,
+ int levels,
+ int edge_length,
+ bool enable_render_surfaces) {
+ DLOG(INFO) << "TextureCUBEGL Create";
+ CHECK_GL_ERROR();
+ RendererGL *renderer = static_cast<RendererGL *>(
+ service_locator->GetService<Renderer>());
+ renderer->MakeCurrentLazy();
+
+ bool resize_to_pot = !renderer->supports_npot() &&
+ !image::IsPOT(edge_length, edge_length);
+
+ // Get gl formats
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format,
+ &gl_internal_format,
+ &gl_data_type);
+ if (gl_internal_format == 0) {
+ DLOG(ERROR) << "Unsupported format in TextureCUBEGL::Create.";
+ return NULL;
+ }
+
+ // Creates the OpenGL texture object, with all the required mip levels.
+ GLuint gl_texture = 0;
+ glGenTextures(1, &gl_texture);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL,
+ levels - 1);
+
+ for (int face = 0; face < static_cast<int>(NUMBER_OF_FACES); ++face) {
+ CreateGLImages(kCubemapFaceList[face], gl_internal_format,
+ gl_format, gl_data_type,
+ static_cast<CubeFace>(face),
+ format, levels, edge_length, edge_length,
+ resize_to_pot);
+ }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ // Create a new texture object, which initializes the base Texture class
+ // from the Bitmap information.
+ TextureCUBEGL* texture = new TextureCUBEGL(service_locator,
+ gl_texture,
+ format,
+ levels,
+ edge_length,
+ resize_to_pot,
+ enable_render_surfaces);
+ // If the hardware does not support npot textures, allocate a 0-initialized
+ // mip-chain here for use during TextureCUBEGL::Lock.
+ if (resize_to_pot) {
+ for (int face = 0; face < static_cast<int>(NUMBER_OF_FACES); ++face) {
+ texture->backing_bitmaps_[face]->Allocate(
+ format, edge_length, edge_length, levels, Bitmap::IMAGE);
+ texture->has_levels_[face] = (1 << levels) - 1;
+ }
+ }
+ CHECK_GL_ERROR();
+ DLOG(INFO) << "Created cube map texture (GLuint=" << gl_texture << ")";
+ return texture;
+}
+
+void TextureCUBEGL::UpdateBackedMipLevel(unsigned int level,
+ TextureCUBE::CubeFace face) {
+ Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
+ DCHECK_LT(static_cast<int>(level), levels());
+ DCHECK(backing_bitmap->image_data());
+ DCHECK_EQ(backing_bitmap->width(), static_cast<unsigned int>(edge_length()));
+ DCHECK_EQ(backing_bitmap->height(), static_cast<unsigned int>(edge_length()));
+ DCHECK_EQ(backing_bitmap->format(), format());
+ renderer_->MakeCurrentLazy();
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ UpdateGLImageFromBitmap(kCubemapFaceList[face], level, face,
+ *backing_bitmap,
+ resize_to_pot_);
+}
+
+RenderSurface::Ref TextureCUBEGL::PlatformSpecificGetRenderSurface(
+ TextureCUBE::CubeFace face,
+ int mip_level) {
+ DCHECK_LT(mip_level, levels());
+ if (!render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to get RenderSurface from non-render-surface-enabled"
+ << " Texture: " << name();
+ return RenderSurface::Ref(NULL);
+ }
+
+ if (mip_level >= levels() || mip_level < 0) {
+ O3D_ERROR(service_locator())
+ << "Attempting to access non-existent mip_level " << mip_level
+ << " in render-target texture \"" << name() << "\".";
+ return RenderSurface::Ref(NULL);
+ }
+
+ return RenderSurface::Ref(new RenderSurfaceGL(
+ service_locator(),
+ edge_length() >> mip_level,
+ edge_length() >> mip_level,
+ kCubemapFaceList[face],
+ mip_level,
+ this));
+}
+
+void TextureCUBEGL::SetRect(TextureCUBE::CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned src_width,
+ unsigned src_height,
+ const void* src_data,
+ int src_pitch) {
+ if (level >= levels() || level < 0) {
+ O3D_ERROR(service_locator())
+ << "Trying to SetRect non-existent level " << level
+ << " on Texture \"" << name() << "\"";
+ return;
+ }
+ if (render_surfaces_enabled()) {
+ O3D_ERROR(service_locator())
+ << "Attempting to SetRect a render-target texture: " << name();
+ return;
+ }
+
+ unsigned mip_width = image::ComputeMipDimension(level, edge_length());
+ unsigned mip_height = mip_width;
+
+ if (dst_left + src_width > mip_width ||
+ dst_top + src_height > mip_height) {
+ O3D_ERROR(service_locator())
+ << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", "
+ << src_width << ", " << src_height << ") out of range for texture << \""
+ << name() << "\"";
+ return;
+ }
+
+ bool entire_rect = dst_left == 0 && dst_top == 0 &&
+ src_width == mip_width && src_height == mip_height;
+ bool compressed = IsCompressed();
+
+ if (compressed && !entire_rect) {
+ O3D_ERROR(service_locator())
+ << "SetRect must be full rectangle for compressed textures";
+ return;
+ }
+
+ if (resize_to_pot_) {
+ Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
+ DCHECK(backing_bitmap->image_data());
+ DCHECK(!compressed);
+ // We need to update the backing mipmap and then use that to update the
+ // texture.
+ backing_bitmap->SetRect(
+ level, dst_left, dst_top, src_width, src_height, src_data, src_pitch);
+ UpdateBackedMipLevel(level, face);
+ } else {
+ // TODO(gman): Should this bind be using a FACE id?
+ renderer_->MakeCurrentLazy();
+ glBindTexture(GL_TEXTURE_2D, gl_texture_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(), &gl_internal_format,
+ &gl_data_type);
+ int gl_face = kCubemapFaceList[face];
+ if (gl_format) {
+ if (src_pitch == image::ComputePitch(format(), src_width)) {
+ glTexSubImage2D(gl_face, level,
+ dst_left, dst_top,
+ src_width, src_height,
+ gl_format,
+ gl_data_type,
+ src_data);
+ } else {
+ int limit = src_height;
+ for (int yy = 0; yy < limit; ++yy) {
+ glTexSubImage2D(gl_face, level,
+ dst_left, dst_top + yy,
+ src_width, 1,
+ gl_format,
+ gl_data_type,
+ src_data);
+ src_data = AddPointerOffset<const void*>(src_data, src_pitch);
+ }
+ }
+ } else {
+ glCompressedTexSubImage2D(
+ gl_face, level, 0, 0, src_width, src_height,
+ gl_internal_format,
+ image::ComputeMipChainSize(src_width, src_height, format(), 1),
+ src_data);
+ }
+ }
+}
+
+// Locks the given face and mipmap level of this texture for loading from
+// main memory, and returns a pointer to the buffer.
+bool TextureCUBEGL::PlatformSpecificLock(
+ CubeFace face, int level, void** data, int* pitch,
+ Texture::AccessMode mode) {
+ DLOG(INFO) << "TextureCUBEGL Lock";
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
+ renderer_->MakeCurrentLazy();
+ Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
+ if (!backing_bitmap->image_data()) {
+ for (int i = 0; i < static_cast<int>(NUMBER_OF_FACES); ++i) {
+ DCHECK_EQ(has_levels_[i], 0u);
+ }
+ backing_bitmap->Allocate(format(), edge_length(), edge_length(), levels(),
+ Bitmap::IMAGE);
+ }
+ *data = backing_bitmap->GetMipData(level);
+ unsigned int mip_width = image::ComputeMipDimension(level, edge_length());
+ if (!IsCompressed()) {
+ *pitch = image::ComputePitch(format(), mip_width);
+ } else {
+ unsigned blocks_across = (mip_width + 3) / 4;
+ unsigned bytes_per_block = format() == Texture::DXT1 ? 8 : 16;
+ unsigned bytes_per_row = bytes_per_block * blocks_across;
+ *pitch = bytes_per_row;
+ }
+ GLenum gl_target = kCubemapFaceList[face];
+ if (mode != kWriteOnly && !HasLevel(face, level)) {
+ // TODO: add some API so we don't have to copy back the data if we
+ // will rewrite it all.
+ DCHECK(!resize_to_pot_);
+ GLenum gl_internal_format = 0;
+ GLenum gl_data_type = 0;
+ GLenum gl_format = GLFormatFromO3DFormat(format(),
+ &gl_internal_format,
+ &gl_data_type);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_);
+ glGetTexImage(gl_target, level, gl_format, gl_data_type, *data);
+ has_levels_[face] |= 1 << level;
+ }
+ CHECK_GL_ERROR();
+
+ locked_levels_[face] |= 1 << level;
+
+ return false;
+}
+
+// Unlocks the given face and mipmap level of this texture.
+bool TextureCUBEGL::PlatformSpecificUnlock(CubeFace face, int level) {
+ DLOG(INFO) << "TextureCUBEGL Unlock";
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, levels());
+ if (LockedMode(face, level) != kReadOnly) {
+ renderer_->MakeCurrentLazy();
+ UpdateBackedMipLevel(level, face);
+ }
+ locked_levels_[face] &= ~(1 << level);
+
+ if (!resize_to_pot_) {
+ // See if we can throw away the backing bitmap.
+ Bitmap* backing_bitmap = backing_bitmaps_[face].Get();
+ bool has_locked_level = false;
+ for (int i = 0; i < static_cast<int>(NUMBER_OF_FACES); ++i) {
+ if (locked_levels_[i]) {
+ has_locked_level = true;
+ break;
+ }
+ }
+ if (!has_locked_level) {
+ backing_bitmap->FreeData();
+ for (int i = 0; i < static_cast<int>(NUMBER_OF_FACES); ++i) {
+ has_levels_[i] = 0;
+ }
+ }
+ }
+ CHECK_GL_ERROR();
+ return false;
+}
+
+const Texture::RGBASwizzleIndices& TextureCUBEGL::GetABGR32FSwizzleIndices() {
+ return g_gl_abgr32f_swizzle_indices;
+}
+
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/texture_gles2.h b/o3d/core/cross/gles2/texture_gles2.h
new file mode 100644
index 0000000..b420eca
--- /dev/null
+++ b/o3d/core/cross/gles2/texture_gles2.h
@@ -0,0 +1,243 @@
+/*
+ * 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 file contains the declarations for Texture2DGL and TextureCUBEGL.
+
+#ifndef O3D_CORE_CROSS_GLES2_TEXTURE_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_TEXTURE_GLES2_H_
+
+// Precompiled header comes before everything else.
+
+// Disable compiler warning for openGL calls that require a void* to
+// be cast to a GLuint
+#if defined(OS_WIN)
+#pragma warning(disable : 4312)
+#pragma warning(disable : 4311)
+#endif
+
+#include "core/cross/bitmap.h"
+#include "core/cross/texture.h"
+#include "core/cross/types.h"
+
+namespace o3d {
+
+class RendererGL;
+
+// Texture2DGL -----------------------------------------------------------------
+
+// Texture2DGL implements the Texture2D interface with OpenGL.
+class Texture2DGL : public Texture2D {
+ public:
+ typedef SmartPointer<Texture2DGL> Ref;
+
+ virtual ~Texture2DGL();
+
+ // Overridden from Texture2D
+ virtual void SetRect(int level,
+ unsigned left,
+ unsigned top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
+
+ // Creates a new Texture2DGL with the given specs. If the GL texture
+ // creation fails then it returns NULL otherwise it returns a pointer to the
+ // newly created Texture object.
+ // The created texture takes ownership of the bitmap data.
+ static Texture2DGL* Create(ServiceLocator* service_locator,
+ Texture::Format format,
+ int levels,
+ int width,
+ int height,
+ bool enable_render_surfaces);
+
+ // Returns the implementation-specific texture handle for this texture.
+ void* GetTextureHandle() const {
+ return reinterpret_cast<void*>(gl_texture_);
+ }
+
+ // Gets the GL texture handle.
+ GLuint gl_texture() const { return gl_texture_; }
+
+ // Gets a RGBASwizzleIndices that contains a mapping from
+ // RGBA to the internal format used by the rendering API.
+ virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+
+ protected:
+ // Overridden from Texture2D
+ virtual bool PlatformSpecificLock(
+ int level, void** texture_data, int* pitch, AccessMode mode);
+
+ // Overridden from Texture2D
+ virtual bool PlatformSpecificUnlock(int level);
+
+ // Overridden from Texture2D
+ virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(int mip_level);
+
+ private:
+ // Initializes the Texture2DGL from a preexisting OpenGL texture handle
+ // and raw Bitmap data.
+ // The texture takes ownership of the bitmap data.
+ Texture2DGL(ServiceLocator* service_locator,
+ GLint texture,
+ Texture::Format format,
+ int levels,
+ int width,
+ int height,
+ bool resize_npot,
+ bool enable_render_surfaces);
+
+ // Updates a mip level, sending it from the backing bitmap to GL, rescaling
+ // it if resize_to_pot_ is set.
+ void UpdateBackedMipLevel(unsigned int level);
+
+ // Returns true if the backing bitmap has the data for the level.
+ bool HasLevel(unsigned int level) const {
+ DCHECK_LT(static_cast<int>(level), levels());
+ return (has_levels_ & (1 << level)) != 0;
+ }
+
+ // Whether or not this texture needs to be resized from NPOT to pot behind
+ // the scenes.
+ bool resize_to_pot_;
+
+ RendererGL* renderer_;
+
+ // The handle of the OpenGL texture object.
+ GLuint gl_texture_;
+
+ // A bitmap used to back the NPOT textures on POT-only hardware, and to back
+ // the pixel buffer for Lock().
+ Bitmap::Ref backing_bitmap_;
+
+ // Bitfield that indicates mip levels that are currently stored in the
+ // backing bitmap.
+ unsigned int has_levels_;
+
+ // Bitfield that indicates which levels are currently locked.
+ unsigned int locked_levels_;
+};
+
+
+// TextureCUBEGL ---------------------------------------------------------------
+
+// TextureCUBEGL implements the TextureCUBE interface with OpenGL.
+class TextureCUBEGL : public TextureCUBE {
+ public:
+ typedef SmartPointer<TextureCUBEGL> Ref;
+ virtual ~TextureCUBEGL();
+
+ // Create a new Cube texture from scratch.
+ static TextureCUBEGL* Create(ServiceLocator* service_locator,
+ Texture::Format format,
+ int levels,
+ int edge_length,
+ bool enable_render_surfaces);
+
+ // Overridden from TextureCUBE
+ virtual void SetRect(CubeFace face,
+ int level,
+ unsigned dst_left,
+ unsigned dst_top,
+ unsigned width,
+ unsigned height,
+ const void* src_data,
+ int src_pitch);
+
+ // Returns the implementation-specific texture handle for this texture.
+ virtual void* GetTextureHandle() const {
+ return reinterpret_cast<void*>(gl_texture_);
+ }
+
+ // Gets the GL texture handle.
+ GLuint gl_texture() const { return gl_texture_; }
+
+ // Gets a RGBASwizzleIndices that contains a mapping from
+ // RGBA to the internal format used by the rendering API.
+ virtual const RGBASwizzleIndices& GetABGR32FSwizzleIndices();
+
+ protected:
+ // Overridden from TextureCUBE
+ virtual bool PlatformSpecificLock(
+ CubeFace face, int level, void** texture_data, int* pitch,
+ AccessMode mode);
+
+ // Overridden from TextureCUBE
+ virtual bool PlatformSpecificUnlock(CubeFace face, int level);
+
+ // Overridden from TextureCUBE.
+ virtual RenderSurface::Ref PlatformSpecificGetRenderSurface(CubeFace face,
+ int level);
+ private:
+ // Creates a texture from a pre-existing GL texture object.
+ TextureCUBEGL(ServiceLocator* service_locator,
+ GLint texture,
+ Texture::Format format,
+ int levels,
+ int edge_length,
+ bool resize_to_pot,
+ bool enable_render_surfaces);
+
+ // Updates a mip level, sending it from the backing bitmap to GL, rescaling
+ // it if resize_to_pot_ is set.
+ void UpdateBackedMipLevel(unsigned int level, CubeFace face);
+
+ // Returns true if the backing bitmap has the data for the level.
+ bool HasLevel(CubeFace face, unsigned int level) const {
+ DCHECK_LT(static_cast<int>(level), levels());
+ return (has_levels_[face] & (1 << level)) != 0;
+ }
+
+ // Whether or not this texture needs to be resized from NPOT to pot behind
+ // the scenes.
+ bool resize_to_pot_;
+
+ RendererGL* renderer_;
+
+ // The handle of the OpenGL texture object.
+ GLuint gl_texture_;
+
+ // Bitmaps used to back the NPOT textures on POT-only hardware.
+ Bitmap::Ref backing_bitmaps_[NUMBER_OF_FACES];
+
+ // Bitfields that indicates mip levels that are currently stored in the
+ // backing bitmap, one per face.
+ unsigned int has_levels_[NUMBER_OF_FACES];
+
+ // Bitfields that indicates which levels are currently locked, one per face.
+ unsigned int locked_levels_[NUMBER_OF_FACES];
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_GLES2_TEXTURE_GLES2_H_
diff --git a/o3d/core/cross/gles2/utils_gles2-inl.h b/o3d/core/cross/gles2/utils_gles2-inl.h
new file mode 100644
index 0000000..f5aea15
--- /dev/null
+++ b/o3d/core/cross/gles2/utils_gles2-inl.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+
+#ifndef O3D_CORE_CROSS_GLES2_UTILS_GLES2_INL_H_
+#define O3D_CORE_CROSS_GLES2_UTILS_GLES2_INL_H_
+
+#include "core/cross/types.h"
+
+namespace o3d {
+
+// Define this to debug GL 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); \
+ } \
+}
+
+#ifdef GL_ERROR_DEBUGGING
+#define CHECK_GL_ERROR() do { \
+ GLenum gl_error = glGetError(); \
+ LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
+} while(0)
+#else // GL_ERROR_DEBUGGING
+#define CHECK_GL_ERROR() void(0)
+#endif // GL_ERROR_DEBUGGING
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_GLES2_UTILS_GLES2_INL_H_
diff --git a/o3d/core/cross/gles2/utils_gles2.cc b/o3d/core/cross/gles2/utils_gles2.cc
new file mode 100644
index 0000000..cec893a
--- /dev/null
+++ b/o3d/core/cross/gles2/utils_gles2.cc
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ */
+
+
+#include "core/cross/stream.h"
+#include "core/cross/types.h"
+#include "core/cross/gles2/utils_gles2.h"
+#include "core/cross/gles2/gles2_headers.h"
+
+// Required OpenGL extensions:
+// GL_ARB_vertex_buffer_object
+// GL_ARB_vertex_program
+// GL_ARB_texture_compression
+// GL_EXT_texture_compression_dxt1
+
+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 OpenGL 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: make this choice a runtime decision in RendererGL
+// 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 OpenGL 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: make this a runtime provided value discovered during
+ // Renderer creation.
+ const unsigned int kMaxAttrIndex = 15u;
+ if (attr > kMaxAttrIndex) {
+ //TODO: 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);
+ }
+ }
+}
+
+#endif
+
+} // namespace o3d
diff --git a/o3d/core/cross/gles2/utils_gles2.h b/o3d/core/cross/gles2/utils_gles2.h
new file mode 100644
index 0000000..4eb71c0
--- /dev/null
+++ b/o3d/core/cross/gles2/utils_gles2.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+
+#ifndef O3D_CORE_CROSS_GLES2_UTILS_GLES2_H_
+#define O3D_CORE_CROSS_GLES2_UTILS_GLES2_H_
+
+#include "base/basictypes.h"
+#include "core/cross/stream.h"
+
+namespace o3d {
+
+bool GetGLProcedures();
+int SemanticNameToGLVertexAttribute(const char* semantic);
+Stream::Semantic GLVertexAttributeToStream(const unsigned int attr, int *index);
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_GLES2_UTILS_GLES2_H_
diff --git a/o3d/core/cross/renderer_platform.h b/o3d/core/cross/renderer_platform.h
index 639459e..faabb28 100644
--- a/o3d/core/cross/renderer_platform.h
+++ b/o3d/core/cross/renderer_platform.h
@@ -48,6 +48,9 @@
#elif defined(OS_WIN) && defined(RENDERER_GL)
#include "core/cross/gl/gl_headers.h"
#include <gl/GL.h>
+#elif defined(OS_WIN) && defined(RENDERER_GLES2)
+#include "core/cross/gles2/gles2_headers.h"
+#include <gl/GL.h>
#endif
#if defined(OS_WIN)
@@ -64,6 +67,8 @@
#include "core/win/d3d9/renderer_d3d9.h"
#elif defined(RENDERER_GL)
#include "core/cross/gl/renderer_gl.h"
+#elif defined(RENDERER_GLES2)
+#include "core/cross/gles2/renderer_gles2.h"
#else
#error Renderer not recognized.
#endif
diff --git a/o3d/core/cross/renderer_test.cc b/o3d/core/cross/renderer_test.cc
index 190aabc..50c719a 100644
--- a/o3d/core/cross/renderer_test.cc
+++ b/o3d/core/cross/renderer_test.cc
@@ -92,6 +92,10 @@ TEST_F(RendererTest, InitAndDestroyRenderer) {
// test that the Cg Context was correctly created
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
+ RendererGL* gles2_renderer = down_cast<RendererGL*>(renderer.get());
+ EXPECT_TRUE(gles2_renderer->cg_context() != NULL);
#endif
// destroy the renderer
renderer->Destroy();
@@ -102,6 +106,9 @@ TEST_F(RendererTest, InitAndDestroyRenderer) {
#elif defined(RENDERER_GL)
// 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/import/cross/precompile.h b/o3d/import/cross/precompile.h
index c858aa4..98ad5ca 100644
--- a/o3d/import/cross/precompile.h
+++ b/o3d/import/cross/precompile.h
@@ -52,6 +52,13 @@
#endif
#endif // defined(RENDERER_GL)
+#if defined(RENDERER_GLES2)
+#include <GL/glew.h>
+#if defined(OS_WIN)
+#include <GL/wglew.h>
+#endif
+#endif // defined(RENDERER_GLES2)
+
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <FCollada.h>
diff --git a/o3d/plugin/plugin.gyp b/o3d/plugin/plugin.gyp
index d320b61..caff190 100644
--- a/o3d/plugin/plugin.gyp
+++ b/o3d/plugin/plugin.gyp
@@ -102,6 +102,14 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:gles2_libs',
+ '../build/libs.gyp:cg_libs',
+ ],
+ },
+ ],
['OS == "mac"',
{
'mac_bundle': 1,
@@ -287,6 +295,14 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:gles2_libs',
+ '../build/libs.gyp:cg_libs',
+ ],
+ },
+ ],
['OS == "mac"',
{
'mac_bundle': 1,
diff --git a/o3d/samples/o3djs/js_list.manifest b/o3d/samples/o3djs/js_list.manifest
index d88fcad..3820b06 100644
--- a/o3d/samples/o3djs/js_list.manifest
+++ b/o3d/samples/o3djs/js_list.manifest
@@ -41,6 +41,7 @@
'io.js',
'loader.js',
'material.js',
+ 'manipulators.js',
'math.js',
'pack.js',
'particles.js',
diff --git a/o3d/standalone/standalone.cc b/o3d/standalone/standalone.cc
new file mode 100644
index 0000000..2b6fc72
--- /dev/null
+++ b/o3d/standalone/standalone.cc
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+int main(int argc, const char** argv) {
+ printf("Hello World\n");
+}
diff --git a/o3d/standalone/standalone.gyp b/o3d/standalone/standalone.gyp
new file mode 100644
index 0000000..3e0c61c
--- /dev/null
+++ b/o3d/standalone/standalone.gyp
@@ -0,0 +1,150 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../build/common.gypi',
+ ],
+ 'target_defaults': {
+ 'include_dirs': [
+ '..',
+ '../..',
+ ],
+ # TODO(rlp): remove this after fixing signed / unsigned issues in
+ # command buffer code and tests.
+ 'target_conditions': [
+ ['OS == "mac"',
+ {
+ 'xcode_settings': {
+ 'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO'
+ },
+ },
+ ],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'standalone',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../<(antlrdir)/antlr.gyp:antlr3c',
+ '../../<(fcolladadir)/fcollada.gyp:fcollada',
+ '../../<(jpegdir)/libjpeg.gyp:libjpeg',
+ '../../<(pngdir)/libpng.gyp:libpng',
+ '../../<(zlibdir)/zlib.gyp:zlib',
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../../native_client/src/shared/imc/imc.gyp:google_nacl_imc',
+ '../compiler/technique/technique.gyp:o3dTechnique',
+ '../core/core.gyp:o3dCore',
+ '../core/core.gyp:o3dCorePlatform',
+ '../utils/utils.gyp:o3dUtils',
+ ],
+ 'sources': [
+ 'standalone.cc',
+ ],
+ 'conditions' : [
+ ['renderer == "gl"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:cg_libs',
+ '../build/libs.gyp:gl_libs',
+ ],
+ },
+ ],
+ ['renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:cg_libs',
+ '../build/libs.gyp:gles2_libs',
+ ],
+ },
+ ],
+ ['OS == "mac"',
+ {
+ 'include_dirs': [
+ '../../third_party/glew/files/include',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/AGL.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/GLUT.framework',
+ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
+ '../../third_party/cg/files/mac/Cg.framework',
+ '../../third_party/glew/files/lib/libMacStaticGLEW.a',
+ ],
+ },
+ },
+ ],
+ ['OS == "win"',
+ {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ 'rpcrt4.lib',
+ '../../<(cgdir)/lib/cg.lib',
+ '../../<(cgdir)/lib/cgGL.lib',
+ ],
+ # Set /SUBSYSTEM:WINDOWS for unit_tests.exe, since
+ # it is a windows app.
+ 'SubSystem': '2',
+ # Don't optimize away unreferenced symbols when
+ # linking. If we didn't do this, then none of the
+ # tests would auto-register.
+ 'OptimizeReferences': '1',
+ },
+ },
+ # We switch it to console post-build so that we have a
+ # windows app that can output to the console and still
+ # open windows.
+ 'msvs_postbuild':
+ 'editbin /SUBSYSTEM:CONSOLE $(OutDir)/$(TargetFileName)',
+ },
+ ],
+ ['OS == "win" and renderer == "d3d9"',
+ {
+ 'include_dirs': [
+ '"$(DXSDK_DIR)/Include"',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '"$(DXSDK_DIR)/Lib/x86/d3dx9.lib"',
+ 'd3d9.lib',
+ '"$(DXSDK_DIR)/Lib/x86/DxErr.lib"',
+ ],
+ },
+ },
+ ],
+ ['OS == "win" and renderer == "gl"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:gl_libs',
+ ],
+ },
+ ],
+ ['OS == "win" and renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:gles2_libs',
+ ],
+ },
+ ],
+ ['OS == "linux"',
+ {
+ },
+ ],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/o3d/tests/tests.gyp b/o3d/tests/tests.gyp
index 129f2d7..6593ec1 100644
--- a/o3d/tests/tests.gyp
+++ b/o3d/tests/tests.gyp
@@ -102,6 +102,14 @@
],
},
],
+ ['renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:cg_libs',
+ '../build/libs.gyp:gles2_libs',
+ ],
+ },
+ ],
['OS == "mac"',
{
'dependencies': [
@@ -210,6 +218,13 @@
],
},
],
+ ['OS == "win" and renderer == "gles2"',
+ {
+ 'dependencies': [
+ '../build/libs.gyp:gles2_libs',
+ ],
+ },
+ ],
['OS == "linux"',
{
'sources': [