From 5eb972ac5e0c6208075efd68dc4fe46a49b9c4b0 Mon Sep 17 00:00:00 2001 From: Bryan Conrad Date: Sun, 23 Feb 2014 11:17:21 -0800 Subject: [PATCH] native s3d implementation --- .gitignore | 2 + project/Build.xml | 4 + project/include/Display.h | 6 + project/include/Matrix.h | 3 +- .../include/renderer/common/HardwareContext.h | 5 +- project/include/renderer/common/S3D.h | 21 + project/include/renderer/common/S3DEye.h | 14 + .../include/renderer/opengl/OpenGLContext.h | 8 +- project/include/renderer/opengl/OpenGLS3D.h | 46 +++ project/src/common/Display.cpp | 67 +++- project/src/common/ExternalInterface.cpp | 9 +- project/src/common/Matrix.cpp | 2 + project/src/common/empty/S3D.cpp | 34 ++ project/src/platform/android/AndroidS3D.cpp | 110 ++++++ project/src/renderer/opengl/OpenGLContext.cpp | 43 ++- project/src/renderer/opengl/OpenGLS3D.cpp | 358 ++++++++++++++++++ 16 files changed, 711 insertions(+), 21 deletions(-) create mode 100644 project/include/renderer/common/S3D.h create mode 100644 project/include/renderer/common/S3DEye.h create mode 100644 project/include/renderer/opengl/OpenGLS3D.h create mode 100644 project/src/common/empty/S3D.cpp create mode 100644 project/src/platform/android/AndroidS3D.cpp create mode 100644 project/src/renderer/opengl/OpenGLS3D.cpp diff --git a/.gitignore b/.gitignore index 0321c2355..195c6fbd9 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ project/vc*.pdb project/winrt/shaders/ *.userprefs *.swp +.idea/ +*.iml diff --git a/project/Build.xml b/project/Build.xml index 2b253b305..333415ecd 100644 --- a/project/Build.xml +++ b/project/Build.xml @@ -170,6 +170,7 @@ + @@ -331,6 +332,8 @@ + + @@ -358,6 +361,7 @@ + diff --git a/project/include/Display.h b/project/include/Display.h index b053eba69..f0fdc7dd9 100644 --- a/project/include/Display.h +++ b/project/include/Display.h @@ -165,6 +165,8 @@ public: void setX(double inValue); double getY(); void setY(double inValue); + double getZ(); + void setZ(double inValue); virtual double getHeight(); virtual void setHeight(double inValue); virtual double getWidth(); @@ -314,6 +316,7 @@ protected: // Decomp double x; double y; + double z; double scaleX; double scaleY; double rotation; @@ -447,6 +450,8 @@ public: Matrix GetFullMatrix(bool inStageScaling); bool FinishEditOnEnter(); + void setAutoS3D(bool enabled) { autos3d = enabled; } + bool getAutoS3D() const { return autos3d; } void setFocusRect(bool inVal) { focusRect = inVal; } bool getFocusRect() const { return focusRect; } UserPoint getMousePos() const { return mLastMousePos; } @@ -478,6 +483,7 @@ protected: EventHandler mHandler; void *mHandlerData; bool focusRect; + bool autos3d; UserPoint mLastMousePos; StageScaleMode scaleMode; StageAlign align; diff --git a/project/include/Matrix.h b/project/include/Matrix.h index 08aab46a4..3582bddb9 100644 --- a/project/include/Matrix.h +++ b/project/include/Matrix.h @@ -11,7 +11,7 @@ class Matrix public: Matrix(double inSX=1,double inSY=1, double inTX=0, double inTY=0) : m00(inSX), m01(0), mtx(inTX), - m10(0), m11(inSY), mty(inTY) + m10(0), m11(inSY), mty(inTY), mtz(0) { } @@ -79,6 +79,7 @@ public: double m00, m01, mtx; double m10, m11, mty; + double mtz; }; diff --git a/project/include/renderer/common/HardwareContext.h b/project/include/renderer/common/HardwareContext.h index 9f9e292cb..066eb18a2 100644 --- a/project/include/renderer/common/HardwareContext.h +++ b/project/include/renderer/common/HardwareContext.h @@ -35,7 +35,10 @@ namespace lime { virtual void SetViewport (const Rect &inRect) = 0; virtual void SetWindowSize (int inWidth, int inHeight) = 0; virtual int Width () const = 0; - + + virtual void EndS3DRender () { }; + virtual void SetS3DEye (int eye) { }; + }; diff --git a/project/include/renderer/common/S3D.h b/project/include/renderer/common/S3D.h new file mode 100644 index 000000000..4abef603c --- /dev/null +++ b/project/include/renderer/common/S3D.h @@ -0,0 +1,21 @@ +#ifndef LIME_S3D_H +#define LIME_S3D_H + +namespace lime { + +enum S3DOrientation { + S3D_ORIENTATION_VERTICAL, + S3D_ORIENTATION_HORIZONTAL +}; + +namespace S3D { + +void SetEnabled (bool enabled); +void SetOrientation (S3DOrientation orientation); +bool GetEnabled (); +bool IsSupported (); + +} // end namespace S3D +} // end namespace lime + +#endif \ No newline at end of file diff --git a/project/include/renderer/common/S3DEye.h b/project/include/renderer/common/S3DEye.h new file mode 100644 index 000000000..a8de41ddd --- /dev/null +++ b/project/include/renderer/common/S3DEye.h @@ -0,0 +1,14 @@ +#ifndef LIME_S3D_EYE_H +#define LIME_S3D_EYE_H + +namespace lime { + + enum S3DEye { + EYE_MIDDLE, + EYE_LEFT, + EYE_RIGHT + }; + +} + +#endif \ No newline at end of file diff --git a/project/include/renderer/opengl/OpenGLContext.h b/project/include/renderer/opengl/OpenGLContext.h index 079b0663c..392527386 100644 --- a/project/include/renderer/opengl/OpenGLContext.h +++ b/project/include/renderer/opengl/OpenGLContext.h @@ -5,6 +5,8 @@ #include #include "renderer/opengl/OGL.h" #include "renderer/common/HardwareContext.h" +#include "renderer/opengl/OpenGLProgram.h" +#include "renderer/opengl/OpenGLS3D.h" namespace lime { @@ -35,6 +37,9 @@ namespace lime { void SetQuality (StageQuality inQ); void SetViewport (const Rect &inRect); void SetWindowSize (int inWidth, int inHeight); + + void EndS3DRender (); + void SetS3DEye (int eye); int Height () const { return mHeight; } int Width () const { return mWidth; } @@ -62,7 +67,8 @@ namespace lime { int mWidth; QuickVec mZombieTextures; QuickVec mZombieVbos; - + + OpenGLS3D mS3D; }; diff --git a/project/include/renderer/opengl/OpenGLS3D.h b/project/include/renderer/opengl/OpenGLS3D.h new file mode 100644 index 000000000..b05db3e16 --- /dev/null +++ b/project/include/renderer/opengl/OpenGLS3D.h @@ -0,0 +1,46 @@ +#ifndef LIME_RENDERER_OPENGL_S3D_H +#define LIME_RENDERER_OPENGL_S3D_H + +#include "renderer/opengl/OGL.h" +#include "renderer/opengl/OpenGLProgram.h" + +namespace lime { + +class OpenGLS3D { +public: + OpenGLS3D (); + ~OpenGLS3D (); + + void Init (); + void EndS3DRender (int inWidth, int inHeight, const Trans4x4 &inTrans); + void SetS3DEye (int eye); + void Resize (int inWidth, int inHeight); + void FocusEye (Trans4x4 &outTrans); + double GetEyeOffset (); + + double mFocalLength; + double mEyeSeparation; + +private: + int mWidth; + int mHeight; + + int mCurrentEye; + OpenGLProgram *mS3DProgram; + GLuint mFramebuffer; + GLuint mRenderbuffer; + GLuint mLeftEyeTexture; + GLuint mRightEyeTexture; + GLuint mEyeMaskTexture; + GLint mLeftImageUniform; + GLint mRightImageUniform; + GLint mMaskImageUniform; + GLint mPixelSizeUniform; + GLint mScreenUniform; + GLuint mS3DVertexBuffer; + GLuint mS3DTextureBuffer; +}; + +}; // namespace lime + +#endif diff --git a/project/src/common/Display.cpp b/project/src/common/Display.cpp index acedcacb0..75a1036a5 100644 --- a/project/src/common/Display.cpp +++ b/project/src/common/Display.cpp @@ -3,6 +3,8 @@ #include "renderer/common/SimpleSurface.h" #include "renderer/common/AutoSurfaceRender.h" #include "renderer/common/BitmapCache.h" +#include "renderer/common/S3D.h" +#include "renderer/common/S3DEye.h" #include #ifndef M_PI @@ -29,6 +31,7 @@ DisplayObject::DisplayObject(bool inInitRef) : Object(inInitRef) mGfx = 0; mDirtyFlags = 0; x = y = 0; + z = 0.1; scaleX = scaleY = 1.0; rotation = 0; visible = true; @@ -334,6 +337,7 @@ Matrix &DisplayObject::GetLocalMatrix() mLocalMatrix.m11 = c*scaleY; mLocalMatrix.mtx = x; mLocalMatrix.mty = y; + mLocalMatrix.mtz = z; } return mLocalMatrix; } @@ -354,6 +358,7 @@ void DisplayObject::UpdateDecomp() mDirtyFlags ^= dirtDecomp; x = mLocalMatrix.mtx; y = mLocalMatrix.mty; + z = mLocalMatrix.mtz; scaleX = sqrt( mLocalMatrix.m00*mLocalMatrix.m00 + mLocalMatrix.m10*mLocalMatrix.m10 ); scaleY = sqrt( mLocalMatrix.m01*mLocalMatrix.m01 + @@ -537,6 +542,23 @@ void DisplayObject::setScaleY(double inValue) } } +double DisplayObject::getZ() +{ + UpdateDecomp(); + return z; +} + +void DisplayObject::setZ(double inValue) +{ + UpdateDecomp(); + if (z!=inValue) + { + mDirtyFlags |= dirtLocalMatrix; + z = inValue; + DirtyCache(true); + } +} + void DisplayObject::setScale9Grid(const DRect &inRect) { scale9Grid = inRect; @@ -1526,6 +1548,7 @@ Stage::Stage(bool inInitRef) : DisplayObjectContainer(inInitRef) mNextWake = 0.0; displayState = sdsNormal; align = saTopLeft; + autos3d = true; #if defined(IPHONE) || defined(ANDROID) || defined(WEBOS) || defined(TIZEN) quality = sqLow; @@ -1673,8 +1696,8 @@ void Stage::HandleEvent(Event &inEvent) { UserPoint pixels(inEvent.x,inEvent.y); hit_obj = HitTest(pixels); - //if (inEvent.type!=etTouchMove) - //ELOG(" type=%d %d,%d obj=%p (%S)", inEvent.type, inEvent.x, inEvent.y, hit_obj, hit_obj?hit_obj->name.c_str():L"(none)"); + // if (inEvent.type!=etTouchMove) + // ELOG(" type=%d %d,%d obj=%p (%S)", inEvent.type, inEvent.x, inEvent.y, hit_obj, hit_obj?hit_obj->name.c_str():L"(none)"); SimpleButton *but = hit_obj ? dynamic_cast(hit_obj) : 0; inEvent.id = hit_obj ? hit_obj->id : id; @@ -1918,21 +1941,41 @@ void Stage::RenderStage() { ColorTransform::TidyCache(); AutoStageRender render(this,opaqueBackground); - if (render.Target().IsHardware()) - render.Target().mHardware->SetQuality(quality); - RenderState state(0, GetAA() ); + S3DEye start = EYE_MIDDLE; + S3DEye end = EYE_MIDDLE; + if(autos3d && S3D::GetEnabled()) { - state.mTransform.mMatrix = &mStageScale; + start = EYE_LEFT; + end = EYE_RIGHT; + + } - state.mClipRect = Rect( render.Width(), render.Height() ); + for(int eye = start; eye <= end; eye++) { - state.mPhase = rpBitmap; - state.mRoundSizeToPOW2 = render.Target().IsHardware(); - Render(render.Target(),state); + render.Target().mHardware->SetS3DEye(eye); - state.mPhase = rpRender; - Render(render.Target(),state); + if (render.Target().IsHardware()) + render.Target().mHardware->SetQuality(quality); + + RenderState state(0, GetAA() ); + + state.mTransform.mMatrix = &mStageScale; + + state.mClipRect = Rect( render.Width(), render.Height() ); + + state.mPhase = rpBitmap; + state.mRoundSizeToPOW2 = render.Target().IsHardware(); + Render(render.Target(),state); + + state.mPhase = rpRender; + Render(render.Target(),state); + + } + + if(autos3d && S3D::GetEnabled()) { + render.Target().mHardware->EndS3DRender(); + } // Clear alpha masks } diff --git a/project/src/common/ExternalInterface.cpp b/project/src/common/ExternalInterface.cpp index 9dd491928..2190d3da8 100644 --- a/project/src/common/ExternalInterface.cpp +++ b/project/src/common/ExternalInterface.cpp @@ -1344,11 +1344,12 @@ value lime_stage_set_focus(value inStage,value inObject,value inDirection) DEFINE_PRIM(lime_stage_set_focus,3); DO_STAGE_PROP(focus_rect,FocusRect,alloc_bool,val_bool) -DO_STAGE_PROP(scale_mode,ScaleMode,alloc_int,val_int) +DO_STAGE_PROP(autos3d,AutoS3D,alloc_bool,val_bool) DO_STAGE_PROP(align,Align,alloc_int,val_int) DO_STAGE_PROP(quality,Quality,alloc_int,val_int) DO_STAGE_PROP(display_state,DisplayState,alloc_int,val_int) DO_STAGE_PROP(multitouch_active,MultitouchActive,alloc_bool,val_bool) +DO_STAGE_PROP(scale_mode,ScaleMode,alloc_int,val_int) DO_PROP_READ(Stage,stage,stage_width,StageWidth,alloc_float); DO_PROP_READ(Stage,stage,stage_height,StageHeight,alloc_float); DO_PROP_READ(Stage,stage,dpi_scale,DPIScale,alloc_float); @@ -1915,6 +1916,7 @@ DEFINE_PRIM(lime_display_object_dismiss_soft_keyboard,1); DO_DISPLAY_PROP(x,X,alloc_float,val_number) DO_DISPLAY_PROP(y,Y,alloc_float,val_number) +DO_DISPLAY_PROP(z,Z,alloc_float,val_number) DO_DISPLAY_PROP(scale_x,ScaleX,alloc_float,val_number) DO_DISPLAY_PROP(scale_y,ScaleY,alloc_float,val_number) DO_DISPLAY_PROP(rotation,Rotation,alloc_float,val_number) @@ -3075,6 +3077,11 @@ TEXT_PROP(max_chars,MaxChars,alloc_int,val_int); TEXT_PROP_GET_IDX(line_text,LineText,alloc_wstring); TEXT_PROP_GET_IDX(line_offset,LineOffset,alloc_int); +value lime_bitmap_data_set_alpha_mode(value a, value b) +{ + return alloc_null(); +} +DEFINE_PRIM(lime_bitmap_data_set_alpha_mode,2); value lime_bitmap_data_create(value* arg, int nargs) { diff --git a/project/src/common/Matrix.cpp b/project/src/common/Matrix.cpp index 6ad93fe88..c744b05e0 100644 --- a/project/src/common/Matrix.cpp +++ b/project/src/common/Matrix.cpp @@ -80,6 +80,8 @@ Matrix Matrix::Mult(const Matrix &inRHS) const t.m11 = m10*inRHS.m01 + m11*inRHS.m11; t.mty = m10*inRHS.mtx + m11*inRHS.mty + mty; + t.mtz = inRHS.mtz + mtz; + return t; } diff --git a/project/src/common/empty/S3D.cpp b/project/src/common/empty/S3D.cpp new file mode 100644 index 000000000..c49a0133a --- /dev/null +++ b/project/src/common/empty/S3D.cpp @@ -0,0 +1,34 @@ +#include +#include +#include + +namespace lime { +namespace S3D { + +void SetEnabled (bool enabled) { } +void SetOrientation (S3DOrientation orientation) { } +bool GetEnabled () { return false; } +bool IsSupported () { return false; } + + +value lime_get_s3d_enabled () { + return alloc_bool (S3D::GetEnabled ()); +} +DEFINE_PRIM (lime_get_s3d_enabled, 0); + + +value lime_set_s3d_enabled (value enabled) { + S3D::SetEnabled (val_bool (enabled)); + return alloc_null (); +} +DEFINE_PRIM (lime_set_s3d_enabled, 1); + + +value lime_get_s3d_supported () { + return alloc_bool (S3D::IsSupported ()); +} +DEFINE_PRIM (lime_get_s3d_supported, 0); + + +} // end namespace S3D +} // end namespace lime diff --git a/project/src/platform/android/AndroidS3D.cpp b/project/src/platform/android/AndroidS3D.cpp new file mode 100644 index 000000000..4fc7d5611 --- /dev/null +++ b/project/src/platform/android/AndroidS3D.cpp @@ -0,0 +1,110 @@ +#include + +#include +#include + +#include + +namespace lime { +namespace S3D { + +const char* MI3D_TN_CTRL_FILE = "/dev/mi3d_tn_ctrl"; + +bool gS3DEnabled = false; +S3DOrientation gS3DOrientation = S3D_ORIENTATION_VERTICAL; + +const int MI3D_GET_TN_STATUS = 128; +const int MI3D_SET_HORIZONTAL_TN_ON = 64; +const int MI3D_SET_TN_OFF = 16; +const int MI3D_SET_VERTICAL_TN_ON = 32; + + +void Enact () { + + unsigned char value = MI3D_SET_TN_OFF; + if (gS3DEnabled) { + + if (gS3DOrientation == S3D_ORIENTATION_VERTICAL) { + + value = MI3D_SET_VERTICAL_TN_ON; + + } else { + + value = MI3D_SET_HORIZONTAL_TN_ON; + + } + + } + + std::fstream file; + file.open (MI3D_TN_CTRL_FILE); + + if (file.is_open ()) { + + file << value; + file.close (); + + } +} + + +void SetEnabled (bool enabled) { + + gS3DEnabled = enabled; + Enact (); + +} + + + +void SetOrientation (S3DOrientation orientation) { + + gS3DOrientation = orientation; + Enact (); + +} + + +bool GetEnabled () { + + return gS3DEnabled; + +} + + +bool IsSupported () { + + std::fstream file; + file.open (MI3D_TN_CTRL_FILE, std::ios_base::in); + + bool result = file.is_open (); + file.close (); + + return result; + +} + +value lime_get_s3d_enabled () { + + return alloc_bool (S3D::GetEnabled ()); + +} +DEFINE_PRIM (lime_get_s3d_enabled, 0); + +value lime_set_s3d_enabled (value enabled) { + + S3D::SetEnabled (val_bool (enabled)); + return alloc_null (); + +} +DEFINE_PRIM (lime_set_s3d_enabled, 1); + +value lime_get_s3d_supported () { + + return alloc_bool (S3D::IsSupported ()); + +} +DEFINE_PRIM (lime_get_s3d_supported, 0); + +} // end namespace S3D +} // end namespace lime diff --git a/project/src/renderer/opengl/OpenGLContext.cpp b/project/src/renderer/opengl/OpenGLContext.cpp index f620585d7..9e60e2012 100644 --- a/project/src/renderer/opengl/OpenGLContext.cpp +++ b/project/src/renderer/opengl/OpenGLContext.cpp @@ -1,4 +1,6 @@ #include "renderer/opengl/OpenGLContext.h" +#include "renderer/common/S3D.h" +#include "renderer/common/S3DEye.h" int sgDrawCount = 0; @@ -54,7 +56,9 @@ namespace lime { e.mColour = 0xff000000; e.mTexOffset = sizeof (float) * 2; e.mStride = sizeof (float) * 4; - + + mS3D.Init (); + } @@ -65,7 +69,7 @@ namespace lime { delete mProg[i]; } - + } @@ -185,16 +189,25 @@ namespace lime { void OpenGLContext::CombineModelView (const Matrix &inModelView) { - + + float eyeOffset = mS3D.GetEyeOffset (); + mTrans[0][0] = inModelView.m00 * mScaleX; mTrans[0][1] = inModelView.m01 * mScaleX; mTrans[0][2] = 0; - mTrans[0][3] = inModelView.mtx * mScaleX + mOffsetX; - + mTrans[0][3] = (inModelView.mtx + eyeOffset) * mScaleX + mOffsetX; + mTrans[1][0] = inModelView.m10 * mScaleY; mTrans[1][1] = inModelView.m11 * mScaleY; mTrans[1][2] = 0; mTrans[1][3] = inModelView.mty * mScaleY + mOffsetY; + + mTrans[2][0] = 0; + mTrans[2][1] = 0; + mTrans[2][2] = -1; + mTrans[2][3] = inModelView.mtz; + + mS3D.FocusEye (mTrans); } @@ -686,8 +699,28 @@ namespace lime { #ifdef ANDROID //__android_log_print(ANDROID_LOG_ERROR, "Lime", "SetWindowSize %d %d", inWidth, inHeight); #endif + + if (mWidth > mHeight) { + S3D::SetOrientation (S3D_ORIENTATION_VERTICAL); + } else { + S3D::SetOrientation (S3D_ORIENTATION_HORIZONTAL); + } + + mS3D.Resize (inWidth, inHeight); } + void OpenGLContext::EndS3DRender() { + + setOrtho (0, mWidth, 0, mHeight); + mS3D.EndS3DRender (mWidth, mHeight, mTrans); + + } + + void OpenGLContext::SetS3DEye(int eye) { + + mS3D.SetS3DEye (eye); + + } } diff --git a/project/src/renderer/opengl/OpenGLS3D.cpp b/project/src/renderer/opengl/OpenGLS3D.cpp new file mode 100644 index 000000000..44d4cd7c3 --- /dev/null +++ b/project/src/renderer/opengl/OpenGLS3D.cpp @@ -0,0 +1,358 @@ +#include "renderer/opengl/OpenGLS3D.h" +#include "renderer/opengl/OpenGLContext.h" +#include "renderer/common/S3D.h" +#include "renderer/common/S3DEye.h" +// #include "common/Display.h" + +namespace lime { + +OpenGLS3D::OpenGLS3D () { + mFocalLength = 0.5; + mEyeSeparation = 0.01; + + mCurrentEye = EYE_MIDDLE; +} + +OpenGLS3D::~OpenGLS3D () { + + glDeleteRenderbuffers (1, &mRenderbuffer); + glDeleteFramebuffers (1, &mFramebuffer); + glDeleteTextures (1, &mLeftEyeTexture); + glDeleteTextures (1, &mRightEyeTexture); + glDeleteTextures (1, &mEyeMaskTexture); + glDeleteBuffers (1, &mS3DVertexBuffer); + glDeleteBuffers (1, &mS3DTextureBuffer); + delete mS3DProgram; + +} + +void OpenGLS3D::Init () { + + // TODO: renderbuffer is only needed when using depth buffer + glGenRenderbuffers (1, &mRenderbuffer); + + glGenFramebuffers (1, &mFramebuffer); + glGenBuffers (1, &mS3DVertexBuffer); + glGenBuffers (1, &mS3DTextureBuffer); + + mCurrentEye = EYE_MIDDLE; + mLeftEyeTexture = mRightEyeTexture = mEyeMaskTexture = 0; + + mS3DProgram = new OpenGLProgram ( + /* vertex */ + "attribute vec3 aVertex;\n" + "attribute vec2 aTexCoord;\n" + "varying vec2 vTexCoord;\n" + "uniform mat4 uTransform;" + "\n" + "void main (void) {\n" + " vTexCoord = aTexCoord;\n" + " gl_Position = vec4 (aVertex, 1.0) * uTransform;\n" + "}\n" + , + + /* fragment */ + #if defined (LIME_GLES) + // TODO: highp precision is required for screens above a certain + // dimension, however, GLES doesn't guarantee highp support in fragment + // shaders + "precision highp float;\n" + "precision highp sampler2D;\n" + #endif + "varying vec2 vTexCoord;\n" + "uniform sampler2D uLeft;\n" + "uniform sampler2D uRight;\n" + "uniform sampler2D uMask;\n" + "\n" + "void main (void)\n" + "{\n" + " float parity = mod (gl_FragCoord.x, 2.0);\n" + " vec4 left = texture2D (uLeft, vTexCoord).rgba;\n" + " vec4 right = texture2D (uRight, vTexCoord).rgba;\n" + " float mask = texture2D (uMask, floor (gl_FragCoord.xy) / vec2 (2.0, 1.0)).x;\n" + " gl_FragColor = mix (left, right, mask);\n" + "}\n" + ); + + + mLeftImageUniform = glGetUniformLocation (mS3DProgram->mProgramId, "uLeft"); + mRightImageUniform = glGetUniformLocation (mS3DProgram->mProgramId, "uRight"); + mMaskImageUniform = glGetUniformLocation (mS3DProgram->mProgramId, "uMask"); + mPixelSizeUniform = glGetUniformLocation (mS3DProgram->mProgramId, "pixelSize"); + +} + +void OpenGLS3D::SetS3DEye (int eye) { + + if (eye == EYE_MIDDLE) { + return; + } + + mCurrentEye = eye; + + GLint texture = mRightEyeTexture; + if (eye == EYE_LEFT) { + texture = mLeftEyeTexture; + } + + glActiveTexture (GL_TEXTURE0); + + // TODO: no need to bind 0 texture here, right? + glBindTexture (GL_TEXTURE_2D, 0); + + glBindFramebuffer (GL_FRAMEBUFFER, mFramebuffer); + glBindRenderbuffer (GL_RENDERBUFFER, mRenderbuffer); + glBindTexture (GL_TEXTURE_2D, texture); + + glFramebufferTexture2D ( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture, 0); + + glClearColor (0, 0, 0, 1.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +} + +void OpenGLS3D::EndS3DRender (int inWidth, int inHeight, const Trans4x4 &inTrans) { + + mCurrentEye = EYE_MIDDLE; + + const GLfloat verts[] = + { + inWidth, inHeight, 0, + 0, inHeight, 0, + inWidth, 0, 0, + 0, 0, 0 + }; + + static const GLfloat textureCoords[] = + { + 1, 1, + 0, 1, + 1, 0, + 0, 0 + }; + + glBindRenderbuffer (GL_RENDERBUFFER, 0); + glBindFramebuffer (GL_FRAMEBUFFER, 0); + + // use the multiplexing shader + mS3DProgram->bind (); + + glClearColor (0, 0, 0, 1.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnableVertexAttribArray (mS3DProgram->vertexSlot); + glEnableVertexAttribArray (mS3DProgram->textureSlot); + + glBindBuffer (GL_ARRAY_BUFFER, mS3DVertexBuffer); + glBufferData (GL_ARRAY_BUFFER, sizeof (GLfloat) * 12, verts, GL_STATIC_DRAW); + glVertexAttribPointer (mS3DProgram->vertexSlot, 3, GL_FLOAT, false, 0, 0); + + glBindBuffer (GL_ARRAY_BUFFER, mS3DTextureBuffer); + glBufferData (GL_ARRAY_BUFFER, sizeof (GLfloat) * 8, textureCoords, GL_STATIC_DRAW); + glVertexAttribPointer (mS3DProgram->textureSlot, 2, GL_FLOAT, false, 0, 0); + + // bind left eye texture + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, mLeftEyeTexture); + glUniform1i (mLeftImageUniform, 0); + + // bind right eye texture + glActiveTexture (GL_TEXTURE1); + glBindTexture (GL_TEXTURE_2D, mRightEyeTexture); + glUniform1i (mRightImageUniform, 1); + + // bind eye mask + glActiveTexture (GL_TEXTURE2); + glBindTexture (GL_TEXTURE_2D, mEyeMaskTexture); + glUniform1i (mMaskImageUniform, 2); + + // supply our matrices and screen info + glUniformMatrix4fv (mS3DProgram->mTransformSlot, 1, false, (const GLfloat*) inTrans); + + // here's where the magic happens + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + // glDisable (GL_TEXTURE_2D); + + // clean up + glBindBuffer (GL_ARRAY_BUFFER, 0); + glDisableVertexAttribArray (mS3DProgram->vertexSlot); + glDisableVertexAttribArray (mS3DProgram->textureSlot); + glUseProgram (0); + + glBindRenderbuffer (GL_RENDERBUFFER, 0); + glBindFramebuffer (GL_FRAMEBUFFER, 0); + + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, 0); + + glActiveTexture (GL_TEXTURE1); + glBindTexture (GL_TEXTURE_2D, 0); + + glActiveTexture (GL_TEXTURE2); + glBindTexture (GL_TEXTURE_2D, 0); + +} + +void OpenGLS3D::Resize (int inWidth, int inHeight) { + + if (mLeftEyeTexture != 0) { + glDeleteTextures (1, &mLeftEyeTexture); + glDeleteTextures (1, &mRightEyeTexture); + glDeleteTextures (1, &mEyeMaskTexture); + } + + int texWidth = inWidth; // UpToPower2 (inWidth); + int texHeight = inHeight; // UpToPower2 (inHeight); + + glGenTextures (1, &mLeftEyeTexture); + glBindTexture (GL_TEXTURE_2D, mLeftEyeTexture); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindTexture (GL_TEXTURE_2D, 0); + + glGenTextures (1, &mRightEyeTexture); + glBindTexture (GL_TEXTURE_2D, mRightEyeTexture); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindTexture (GL_TEXTURE_2D, 0); + + GLubyte maskData[] = { + 0, 0xFF, + 0, 0xFF + }; + + glGenTextures (1, &mEyeMaskTexture); + glBindTexture (GL_TEXTURE_2D, mEyeMaskTexture); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, maskData); + glBindTexture (GL_TEXTURE_2D, 0); + + // create depth buffer + glBindRenderbuffer (GL_RENDERBUFFER, mRenderbuffer); + glBindFramebuffer (GL_FRAMEBUFFER, mFramebuffer); + glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, inWidth, inHeight); + glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mRenderbuffer); + + glBindRenderbuffer (GL_RENDERBUFFER, 0); + glBindFramebuffer (GL_FRAMEBUFFER, 0); + +} + +void OpenGLS3D::FocusEye (Trans4x4 &outTrans) { + + if (mCurrentEye != EYE_MIDDLE) { + + float offset = GetEyeOffset (); + float theta = asin (offset/mFocalLength); + + float m = sin (theta); + float n = cos (theta); + + float a = outTrans[0][0]; + float b = outTrans[0][1]; + float c = outTrans[1][0]; + float d = outTrans[1][1]; + float tx = outTrans[0][3]; + float ty = outTrans[1][3]; + float tz = outTrans[2][3]; + + outTrans[0][0] = (a*n); + outTrans[0][1] = (b*n); + outTrans[0][2] = m; + outTrans[0][3] = (n*tx + m*tz); + + outTrans[1][0] = c; + outTrans[1][1] = d; + outTrans[1][2] = 0; + outTrans[1][3] = ty; + + outTrans[2][0] = -a*m; + outTrans[2][1] = -b*m; + outTrans[2][2] = -n; + outTrans[2][3] = -(n*tz-m*tx); + + } +} + +double OpenGLS3D::GetEyeOffset () { + if (mCurrentEye == EYE_MIDDLE) { + return 0; + } else if (mCurrentEye == EYE_LEFT) { + return -1 * mEyeSeparation; + } + + return mEyeSeparation; +} + +extern HardwareContext *gDirectRenderContext; + +value lime_gl_s3d_set_focal_length (value length) +{ + + OpenGLContext* ctx = dynamic_cast (HardwareContext::current); + if (ctx) { + + ctx->mS3D.mFocalLength = val_float (length); + + } + +} +DEFINE_PRIM (lime_gl_s3d_set_focal_length,1); + +value lime_gl_s3d_get_focal_length () +{ + + OpenGLContext* ctx = dynamic_cast (HardwareContext::current); + if (ctx) { + + return alloc_float (ctx->mS3D.mFocalLength); + + } + + return alloc_null (); + +} +DEFINE_PRIM (lime_gl_s3d_get_focal_length,0); + +value lime_gl_s3d_set_eye_separation (value separation) +{ + + OpenGLContext* ctx = dynamic_cast (HardwareContext::current); + if (ctx) { + + ctx->mS3D.mEyeSeparation = val_float (separation); + + } + +} +DEFINE_PRIM (lime_gl_s3d_set_eye_separation,1); + +value lime_gl_s3d_get_eye_separation () +{ + + OpenGLContext* ctx = dynamic_cast (HardwareContext::current); + if (ctx) { + + return alloc_float (ctx->mS3D.mEyeSeparation); + + } + + return alloc_null (); + +} +DEFINE_PRIM (lime_gl_s3d_get_eye_separation,0); + +};