summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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': [