update the 3d branch after release experimental3D
authorkoda
Mon, 15 Nov 2010 12:37:39 +0100
branchexperimental3D
changeset 4343 19cbea33e4d2
parent 4006 45b63c2a694f (diff)
parent 4341 46b8791e577f (current diff)
child 4345 2c93d6a10869
update the 3d branch after release
QTfrontend/CMakeLists.txt
QTfrontend/pages.cpp
QTfrontend/pages.h
QTfrontend/res/btnMines.png
hedgewars/hwengine.pas
hedgewars/uConsts.pas
hedgewars/uMisc.pas
hedgewars/uStore.pas
hedgewars/uWorld.pas
misc/uSHA.pas
project_files/HedgewarsMobile/Classes/AboutViewController.xib
project_files/HedgewarsMobile/Classes/HelpPageInGameViewController.xib
project_files/HedgewarsMobile/Classes/HelpPageLobbyViewController.xib
project_files/HedgewarsMobile/Classes/SavedGamesViewController.xib
project_files/HedgewarsMobile/Classes/SupportViewController.xib
project_files/HedgewarsMobile/Resources/Frontend-iPad/bricks.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/backgroundBottom.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/backgroundLeft.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/backgroundRight.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/borderTop.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/networkButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/playButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/storeButton.png
project_files/HedgewarsMobile/Resources/Icons/LI-ipad-Landscape.png
project_files/HedgewarsMobile/Resources/Overlay/background_med.png
project_files/HedgewarsMobile/Resources/Overlay/background_small.png
project_files/HedgewarsMobile/Resources/surpise.png
share/hedgewars/Data/Graphics/Grenade.png
share/hedgewars/Data/Graphics/Hats/Reserved/51e46e89a4f7ee3ea760bb587063b202judo.png
share/hedgewars/Data/Graphics/Hats/Reserved/941fc72a68a50cebf562059816e8cb26RSR.png
share/hedgewars/Data/Graphics/Hats/Reserved/afaff8193505e29230b76f8c8dd78170lambda.png
share/hedgewars/Data/Graphics/Hats/Reserved/e587f6146ebfbdefdc028c591643f220Bob.png
share/hedgewars/Data/Graphics/Hats/Reserved/e587f6146ebfbdefdc028c591643f220Bub.png
share/hedgewars/Data/Graphics/Hats/Reserved/e587f6146ebfbdefdc028c591643f220Cororon.png
share/hedgewars/Data/Graphics/Hats/Reserved/e587f6146ebfbdefdc028c591643f220Kululun.png
tools/MissionsEditor/MissionsEditor.pro
tools/MissionsEditor/editor.cpp
tools/MissionsEditor/editor.h
tools/MissionsEditor/editor.ui
tools/MissionsEditor/hedgehogedit.cpp
tools/MissionsEditor/hedgehogedit.h
tools/MissionsEditor/hedgehogedit.ui
tools/MissionsEditor/main.cpp
tools/MissionsEditor/teamedit.cpp
tools/MissionsEditor/teamedit.h
tools/MissionsEditor/teamedit.ui
--- a/.hgignore	Mon Nov 15 04:30:11 2010 +0100
+++ b/.hgignore	Mon Nov 15 12:37:39 2010 +0100
@@ -32,5 +32,3 @@
 glob:*.orig
 glob:*.bak
 glob:*.rej
-glob:*.qm
-glob:share/hedgewars/Data/misc/hwengine.desktop
--- a/QTfrontend/game.cpp	Mon Nov 15 04:30:11 2010 +0100
+++ b/QTfrontend/game.cpp	Mon Nov 15 12:37:39 2010 +0100
@@ -299,6 +299,7 @@
     arguments << (config->isAltDamageEnabled() ? "1" : "0");
     arguments << config->netNick().toUtf8().toBase64();
     arguments << QString::number(config->translateQuality());
+    arguments << QString::number(config->stereoMode());
     arguments << tr("en.txt");
 
     return arguments;
--- a/QTfrontend/gameuiconfig.cpp	Mon Nov 15 04:30:11 2010 +0100
+++ b/QTfrontend/gameuiconfig.cpp	Mon Nov 15 12:37:39 2010 +0100
@@ -48,6 +48,7 @@
     Form->ui.pageOptions->CBFrontendFullscreen->setChecked(ffscr);
 
     Form->ui.pageOptions->SLQuality->setValue(value("video/quality", 5).toUInt());
+    Form->ui.pageOptions->CBStereoMode->setCurrentIndex(value("video/stereo", 0).toUInt());
     Form->ui.pageOptions->CBFrontendEffects->setChecked(frontendEffects);
     Form->ui.pageOptions->CBEnableSound->setChecked(value("audio/sound", true).toBool());
     Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/sound", true).toBool());
@@ -113,6 +114,7 @@
     setValue("video/fullscreen", vid_Fullscreen());
 
     setValue("video/quality", Form->ui.pageOptions->SLQuality->value());
+    setValue("video/stereo", stereoMode());
 
     setValue("frontend/effects", isFrontendEffects());
 
@@ -261,6 +263,11 @@
     return Form->ui.pageOptions->CBAltDamage->isChecked();
 }
 
+quint32 GameUIConfig::stereoMode() const
+{
+    return Form->ui.pageOptions->CBStereoMode->currentIndex();
+}
+
 bool GameUIConfig::appendDateTimeToRecordName()
 {
     return Form->ui.pageOptions->CBNameWithDate->isChecked();
--- a/QTfrontend/gameuiconfig.h	Mon Nov 15 04:30:11 2010 +0100
+++ b/QTfrontend/gameuiconfig.h	Mon Nov 15 12:37:39 2010 +0100
@@ -52,6 +52,7 @@
     bool isFrontendEffects() const;
     bool isFrontendFullscreen() const;
     void resizeToConfigValues();
+    quint32 stereoMode() const;
 
 #ifdef __APPLE__
 #ifdef SPARKLE_ENABLED
--- a/QTfrontend/pages.cpp	Mon Nov 15 04:30:11 2010 +0100
+++ b/QTfrontend/pages.cpp	Mon Nov 15 12:37:39 2010 +0100
@@ -633,6 +633,7 @@
 
             QVBoxLayout * GBAlayout = new QVBoxLayout(AGGroupBox);
             QHBoxLayout * GBAreslayout = new QHBoxLayout(0);
+            QHBoxLayout * GBAstereolayout = new QHBoxLayout(0);
             QHBoxLayout * GBAqualayout = new QHBoxLayout(0);
 
             CBFrontendFullscreen = new QCheckBox(AGGroupBox);
@@ -668,6 +669,7 @@
             CBFullscreen = new QCheckBox(AGGroupBox);
             CBFullscreen->setText(QCheckBox::tr("Fullscreen"));
             GBAlayout->addWidget(CBFullscreen);
+            connect(CBFullscreen, SIGNAL(stateChanged(int)), this, SLOT(setFullscreen(void)));
 
             QLabel * quality = new QLabel(AGGroupBox);
             quality->setText(QLabel::tr("Quality"));
@@ -681,6 +683,25 @@
             SLQuality->setFixedWidth(150);
             GBAqualayout->addWidget(SLQuality);
             GBAlayout->addLayout(GBAqualayout);
+            QLabel * stereo = new QLabel(AGGroupBox);
+            stereo->setText(QLabel::tr("Stereo rendering"));
+            GBAstereolayout->addWidget(stereo);
+
+            CBStereoMode = new QComboBox(AGGroupBox);
+            CBStereoMode->addItem(QComboBox::tr("Disabled"));
+            CBStereoMode->addItem(QComboBox::tr("Red/Cyan"));
+            CBStereoMode->addItem(QComboBox::tr("Cyan/Red"));
+            CBStereoMode->addItem(QComboBox::tr("Red/Blue"));
+            CBStereoMode->addItem(QComboBox::tr("Blue/Red"));
+            CBStereoMode->addItem(QComboBox::tr("Red/Green"));
+            CBStereoMode->addItem(QComboBox::tr("Green/Red"));
+            CBStereoMode->addItem(QComboBox::tr("Side-by-side"));
+            CBStereoMode->addItem(QComboBox::tr("Top-Bottom"));
+            CBStereoMode->addItem(QComboBox::tr("Frame Alternate"));
+            connect(CBStereoMode, SIGNAL(currentIndexChanged(int)), this, SLOT(forceFullscreen(int)));
+
+            GBAstereolayout->addWidget(CBStereoMode);
+            GBAlayout->addLayout(GBAstereolayout);
 
             hr = new QFrame(AGGroupBox);
             hr->setFrameStyle(QFrame::HLine);
@@ -730,7 +751,7 @@
             hr->setFixedHeight(10);
             GBAlayout->addWidget(hr);
 
-                QLabel *restartNote = new QLabel(this);
+            QLabel *restartNote = new QLabel(this);
             restartNote->setText(QString("* ") + QLabel::tr("Restart game to apply"));
             restartNote->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
             GBAlayout->addWidget(restartNote);
@@ -745,8 +766,29 @@
     BtnBack->setFixedHeight(BtnSaveOptions->height());
     BtnBack->setFixedWidth(BtnBack->width()+2);
     BtnBack->setStyleSheet("QPushButton{margin: 22px 0 9px 2px;}");
+}
 
-//    BtnAssociateFiles = addButton("");
+void PageOptions::forceFullscreen(int index)
+{
+    if (index != 0) {
+        previousFullscreenValue = this->CBFullscreen->isChecked();
+        this->CBFullscreen->setChecked(true);
+        this->CBFullscreen->setEnabled(false);
+    } else {
+        this->CBFullscreen->setChecked(previousFullscreenValue);
+        this->CBFullscreen->setEnabled(true);
+    }
+}
+
+void PageOptions::setFullscreen(void)
+{
+    int tmp = this->CBResolution->currentIndex();
+    if (this->CBFullscreen->isChecked())
+        this->CBResolution->setCurrentIndex(0);
+    else
+        this->CBResolution->setCurrentIndex(previousResolutionIndex);
+    previousResolutionIndex = tmp;
+    this->CBResolution->setEnabled(!this->CBFullscreen->isChecked());
 }
 
 PageNet::PageNet(QWidget* parent) : AbstractPage(parent)
--- a/QTfrontend/pages.h	Mon Nov 15 04:30:11 2010 +0100
+++ b/QTfrontend/pages.h	Mon Nov 15 12:37:39 2010 +0100
@@ -222,6 +222,7 @@
     QComboBox *CBTeamName;
     IconedGroupBox *AGGroupBox;
     QComboBox *CBResolution;
+    QComboBox *CBStereoMode;
     QCheckBox *CBEnableSound;
     QCheckBox *CBEnableFrontendSound;
     QCheckBox *CBEnableMusic;
@@ -242,6 +243,14 @@
     QLineEdit *editNetNick;
     QSlider *SLQuality;
     QCheckBox *CBFrontendEffects;
+
+private:
+    bool previousFullscreenValue;
+    int previousResolutionIndex;
+
+private slots:
+    void forceFullscreen(int index);
+    void setFullscreen(void);
 };
 
 class PageNet : public AbstractPage
--- a/hedgewars/ArgParsers.inc	Mon Nov 15 04:30:11 2010 +0100
+++ b/hedgewars/ArgParsers.inc	Mon Nov 15 12:37:39 2010 +0100
@@ -8,6 +8,7 @@
 end;
 
 procedure internalStartGameWithParameters();
+var tmp: LongInt;
 begin
     val(ParamStr(2), cScreenWidth);
     val(ParamStr(3), cScreenHeight);
@@ -23,7 +24,9 @@
     cAltDamage:= ParamStr(13) = '1';
     UserNick:= DecodeBase64(ParamStr(14));
     val(ParamStr(15), cReducedQuality);
-    cLocaleFName:= ParamStr(16)
+    val(ParamStr(16), tmp);
+    cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp)));
+    cLocaleFName:= ParamStr(17);
 end;
 
 procedure setVideo(screenWidth: LongInt; screenHeight: LongInt; bitsStr: LongInt);
--- a/hedgewars/hwengine.pas	Mon Nov 15 04:30:11 2010 +0100
+++ b/hedgewars/hwengine.pas	Mon Nov 15 12:37:39 2010 +0100
@@ -227,10 +227,12 @@
     cAltDamage:= gameArgs[8] = '1';
     val(gameArgs[9], rotationQt);
     recordFileName:= gameArgs[10];
+    cStereoMode:= smNone; // TODO: Enable anaglyph rendering on iPhone?
 {$ENDIF}
 
     cLogfileBase:= 'game';
     initEverything(true);
+
     WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
 {$IFDEF DEBUGFILE}
     AddFileLog('Prefix: "' + PathPrefix +'"');
--- a/hedgewars/uConsts.pas	Mon Nov 15 04:30:11 2010 +0100
+++ b/hedgewars/uConsts.pas	Mon Nov 15 12:37:39 2010 +0100
@@ -152,6 +152,9 @@
 
     TWave = (waveRollup, waveSad, waveWave, waveHurrah, waveLemonade, waveShrug, waveJuggle);
 
+    TRenderMode = (rmDefault, rmLeftEye, rmRightEye);
+    TStereoMode = (smNone, smRedCyan, smCyanRed, smRedBlue, smBlueRed, smRedGreen, smGreenRed, smHorizontal, smVertical, smAFR);
+
     THHFont = record
             Handle: PTTF_Font;
             Height: LongInt;
@@ -195,7 +198,7 @@
     TScreenFade = (sfNone, sfInit, sfToBlack, sfFromBlack, sfToWhite, sfFromWhite);
 const
     sfMax = 1000;
-    cDefaultParamNum = 16;
+    cDefaultParamNum = 17;
 
     // message constants
     errmsgCreateSurface   = 'Error creating SDL surface';
--- a/hedgewars/uMisc.pas	Mon Nov 15 04:30:11 2010 +0100
+++ b/hedgewars/uMisc.pas	Mon Nov 15 12:37:39 2010 +0100
@@ -55,6 +55,7 @@
     isSpeed         : boolean;
     isFirstFrame    : boolean;
 
+    cStereoMode     : TStereoMode;
     fastUntilLag    : boolean;
 
     GameState       : TGameState;
@@ -849,7 +850,6 @@
 {$ENDIF}
 {$I+}
 {$ENDIF}
-
 end;
 
 procedure freeModule;
--- a/hedgewars/uStore.pas	Mon Nov 15 04:30:11 2010 +0100
+++ b/hedgewars/uStore.pas	Mon Nov 15 12:37:39 2010 +0100
@@ -37,6 +37,10 @@
     MissionIcons: PSDL_Surface;
     ropeIconTex: PTexture;
     rotationQt: GLfloat;
+    wScreen: LongInt;
+    hScreen: LongInt;
+    framel, framer, depthl, depthr: GLuint;
+    texl, texr: GLuint;
 
 procedure initModule;
 procedure freeModule;
@@ -883,6 +887,15 @@
     SDL_FreeSurface(MissionIcons);
     FreeTexture(ropeIconTex);
     FreeTexture(HHTexture);
+    if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then
+    begin
+        glDeleteTextures(1, @texl);
+        glDeleteRenderbuffersEXT(1, @depthl);
+        glDeleteFramebuffersEXT(1, @framel);
+        glDeleteTextures(1, @texr);
+        glDeleteRenderbuffersEXT(1, @depthr);
+        glDeleteFramebuffersEXT(1, @framer)
+    end
 end;
 
 
@@ -1241,7 +1254,9 @@
 {$ENDIF}
     end;
 
-{$IFNDEF IPHONEOS}
+{$IFDEF IPHONEOS}
+    cGPUVendor:= gvApple;
+{$ELSE}
     if StrPos(Str2PChar(vendor), Str2PChar('nvidia')) <> nil then
         cGPUVendor:= gvNVIDIA
     else if StrPos(Str2PChar(vendor), Str2PChar('intel')) <> nil then
@@ -1249,8 +1264,43 @@
     else if StrPos(Str2PChar(vendor), Str2PChar('ati')) <> nil then
         cGPUVendor:= gvIntel;
 //SupportNPOTT:= glLoadExtension('GL_ARB_texture_non_power_of_two');
-{$ELSE}
-    cGPUVendor:= gvApple;
+
+    if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then
+    begin
+        // prepare left and right frame buffers and associated textures
+        glLoadExtension('GL_EXT_framebuffer_object');
+
+        // left
+        glGenFramebuffersEXT(1, @framel);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framel);
+        glGenRenderbuffersEXT(1, @depthl);
+        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthl);
+        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight);
+        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthl);
+        glGenTextures(1, @texl);
+        glBindTexture(GL_TEXTURE_2D, texl);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texl, 0);
+
+        // right
+        glGenFramebuffersEXT(1, @framer);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framer);
+        glGenRenderbuffersEXT(1, @depthr);
+        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthr);
+        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight);
+        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthr);
+        glGenTextures(1, @texr);
+        glBindTexture(GL_TEXTURE_2D, texr);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texr, 0);
+
+        // reset
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)
+    end;
 {$ENDIF}
 
 {$IFDEF DEBUGFILE}
--- a/hedgewars/uWorld.pas	Mon Nov 15 04:30:11 2010 +0100
+++ b/hedgewars/uWorld.pas	Mon Nov 15 12:37:39 2010 +0100
@@ -22,18 +22,19 @@
 interface
 uses SDLh, uGears, uConsts, uFloat, uRandom;
 
-
 var FollowGear: PGear;
     WindBarWidth: LongInt;
     bShowAmmoMenu: boolean;
     bSelected: boolean;
     bShowFinger: boolean;
     Frames: Longword;
+    AFRToggle: Boolean;
     WaterColor, DeepWaterColor: TSDL_Color;
     WorldDx: LongInt;
     WorldDy: LongInt;
     SkyOffset: LongInt;
     HorizontOffset: LongInt;
+    bAFRRight: Boolean;
 {$IFDEF COUNTTICKS}
     cntTicks: LongWord;
 {$ENDIF}
@@ -44,6 +45,7 @@
 
 procedure InitWorld;
 procedure DrawWorld(Lag: LongInt);
+procedure DrawWorldStereo(Lag: LongInt; RM: TRenderMode);
 procedure AddCaption(s: shortstring; Color: Longword; Group: TCapGroup);
 procedure ShowMission(caption, subcaption, text: ansistring; icon, time : LongInt);
 procedure HideMission;
@@ -71,6 +73,11 @@
     amSel: TAmmoType = amNothing;
     missionTex: PTexture;
     missionTimer: LongInt;
+    stereoDepth: GLfloat = 0;
+
+const cStereo_Sky     = 0.0750;
+      cStereo_Horizon = 0.0250;
+      cStereo_Water   = 0.0125;
 
 procedure InitWorld;
 var i, t: LongInt;
@@ -535,14 +542,6 @@
 
 
 procedure DrawWorld(Lag: LongInt);
-var i, t: LongInt;
-    r: TSDL_Rect;
-    tdx, tdy: Double;
-    grp: TCapGroup;
-    s: string[15];
-    highlight: Boolean;
-    offset, offsetX, offsetY, ScreenBottom: LongInt;
-    VertexBuffer: array [0..3] of TVertex2f;
 begin
     if not isPaused then
     begin
@@ -571,6 +570,150 @@
     if not isPaused then
         MoveCamera;
 
+    if cStereoMode = smNone then
+        begin
+        glClear(GL_COLOR_BUFFER_BIT);
+        DrawWorldStereo(Lag, rmDefault)
+        end
+    else if (cStereoMode = smAFR) then
+        begin
+        AFRToggle:= not AFRToggle;
+        glClear(GL_COLOR_BUFFER_BIT);
+        if AFRToggle then
+            DrawWorldStereo(Lag, rmLeftEye)
+        else
+            DrawWorldStereo(Lag, rmRightEye)
+        end
+    else if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+        begin
+        // create left fb
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framel);
+        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+        DrawWorldStereo(Lag, rmLeftEye);
+
+        // create right fb
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framer);
+        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+        DrawWorldStereo(0, rmRightEye);
+
+        // detatch drawing from fbs
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+        SetScale(cDefaultZoomLevel);
+
+        // draw left frame
+        glBindTexture(GL_TEXTURE_2D, texl);
+        glBegin(GL_QUADS);
+            if cStereoMode = smHorizontal then
+                begin
+                glTexCoord2f(0.0, 0.0);
+                glVertex2d(cScreenWidth / -2, cScreenHeight);
+                glTexCoord2f(1.0, 0.0);
+                glVertex2d(0, cScreenHeight);
+                glTexCoord2f(1.0, 1.0);
+                glVertex2d(0, 0);
+                glTexCoord2f(0.0, 1.0);
+                glVertex2d(cScreenWidth / -2, 0);
+                end
+            else
+                begin
+                glTexCoord2f(0.0, 0.0);
+                glVertex2d(cScreenWidth / -2, cScreenHeight / 2);
+                glTexCoord2f(1.0, 0.0);
+                glVertex2d(cScreenWidth / 2, cScreenHeight / 2);
+                glTexCoord2f(1.0, 1.0);
+                glVertex2d(cScreenWidth / 2, 0);
+                glTexCoord2f(0.0, 1.0);
+                glVertex2d(cScreenWidth / -2, 0);
+                end;
+        glEnd();
+
+        // draw right frame
+        glBindTexture(GL_TEXTURE_2D, texr);
+        glBegin(GL_QUADS);
+            if cStereoMode = smHorizontal then
+                begin
+                glTexCoord2f(0.0, 0.0);
+                glVertex2d(0, cScreenHeight);
+                glTexCoord2f(1.0, 0.0);
+                glVertex2d(cScreenWidth / 2, cScreenHeight);
+                glTexCoord2f(1.0, 1.0);
+                glVertex2d(cScreenWidth / 2, 0);
+                glTexCoord2f(0.0, 1.0);
+                glVertex2d(0, 0);
+                end
+            else
+                begin
+                glTexCoord2f(0.0, 0.0);
+                glVertex2d(cScreenWidth / -2, cScreenHeight);
+                glTexCoord2f(1.0, 0.0);
+                glVertex2d(cScreenWidth / 2, cScreenHeight);
+                glTexCoord2f(1.0, 1.0);
+                glVertex2d(cScreenWidth / 2, cScreenHeight / 2);
+                glTexCoord2f(0.0, 1.0);
+                glVertex2d(cScreenWidth / -2, cScreenHeight / 2);
+                end;
+        glEnd();
+        SetScale(zoom);
+        end
+    else
+        begin
+        // clear scene
+        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+        // draw left eye in red channel only
+        if cStereoMode = smGreenRed then
+            glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
+        else if cStereoMode = smBlueRed then
+            glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
+        else if cStereoMode = smCyanRed then
+            glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
+        else
+            glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
+        DrawWorldStereo(Lag, rmLeftEye);
+        // draw right eye in selected channel(s) only
+        if cStereoMode = smRedGreen then
+            glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
+        else if cStereoMode = smRedBlue then
+            glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
+        else if cStereoMode = smRedCyan then
+            glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
+        else
+            glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
+        DrawWorldStereo(Lag, rmRightEye);
+        end
+end;
+
+procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
+begin
+    d:= d / 5;
+    if rm = rmDefault then exit
+    else if rm = rmLeftEye then d:= -d;
+    stereoDepth:= stereoDepth + d;
+    glMatrixMode(GL_PROJECTION);
+    glTranslatef(d, 0, 0);
+    glMatrixMode(GL_MODELVIEW)
+end;
+ 
+procedure ResetDepth(rm: TRenderMode);
+begin
+    if rm = rmDefault then exit;
+    glMatrixMode(GL_PROJECTION);
+    glTranslatef(-stereoDepth, 0, 0);
+    glMatrixMode(GL_MODELVIEW);
+    stereoDepth:= 0;
+end;
+ 
+procedure DrawWorldStereo(Lag: LongInt; RM: TRenderMode);
+var i, t: LongInt;
+    r: TSDL_Rect;
+    tdx, tdy: Double;
+    grp: TCapGroup;
+    s: string[15];
+    highlight: Boolean;
+    offset, offsetX, offsetY, screenBottom: LongInt;
+    VertexBuffer: array [0..3] of TVertex2f;
+begin
     if (cReducedQuality and rqNoBackground) = 0 then
     begin
         // Offsets relative to camera - spare them to wimpier cpus, no bg or flakes for them anyway
@@ -582,7 +725,9 @@
             HorizontOffset:= HorizontOffset + ((ScreenBottom-SkyOffset) div 20);
 
         // background
+        ChangeDepth(RM, cStereo_Sky);
         DrawRepeated(sprSky, sprSkyL, sprSkyR, (WorldDx + LAND_WIDTH div 2) * 3 div 8, SkyOffset);
+        ChangeDepth(RM, -cStereo_Horizon);
         DrawRepeated(sprHorizont, sprHorizontL, sprHorizontR, (WorldDx + LAND_WIDTH div 2) * 3 div 5, HorizontOffset);
     end;
 
@@ -591,11 +736,16 @@
     if (cReducedQuality and rq2DWater) = 0 then
     begin
         // Waves
-        DrawWater(255, SkyOffset);
+        DrawWater(255, SkyOffset); 
+        ChangeDepth(RM, -cStereo_Water);
         DrawWaves( 1,  0 - WorldDx div 32, - cWaveHeight + offsetY div 35, 64);
+        ChangeDepth(RM, -cStereo_Water);
         DrawWaves( -1,  25 + WorldDx div 25, - cWaveHeight + offsetY div 38, 48);
+        ChangeDepth(RM, -cStereo_Water);
         DrawWaves( 1,  75 - WorldDx div 19, - cWaveHeight + offsetY div 45, 32);
+        ChangeDepth(RM, -cStereo_Water);
         DrawWaves(-1, 100 + WorldDx div 14, - cWaveHeight + offsetY div 70, 24);
+        ResetDepth(RM);
     end
     else
         DrawWaves(-1, 100, - (cWaveHeight + (cWaveHeight shr 1)), 0);
@@ -635,16 +785,21 @@
     DrawWater(cWaterOpacity, 0);
 
     // Waves
+    ChangeDepth(RM, cStereo_Water);
     DrawWaves( 1, 25 - WorldDx div 9, - cWaveHeight, 12);
 
     if (cReducedQuality and rq2DWater) = 0 then
     begin
         //DrawWater(cWaterOpacity, - offsetY div 40);
+        ChangeDepth(RM, cStereo_Water);
         DrawWaves(-1, 50 + WorldDx div 6, - cWaveHeight - offsetY div 40, 8);
         DrawWater(cWaterOpacity, - offsetY div 20);
+        ChangeDepth(RM, cStereo_Water);
         DrawWaves( 1, 75 - WorldDx div 4, - cWaveHeight - offsetY div 20, 2);
         DrawWater(cWaterOpacity, - offsetY div 10);
+        ChangeDepth(RM, cStereo_Water);
         DrawWaves( -1, 25 + WorldDx div 3, - cWaveHeight - offsetY div 10, 0);
+        ResetDepth(RM);
     end
     else
         DrawWaves(-1, 50, - (cWaveHeight shr 1), 0);
@@ -879,58 +1034,63 @@
 offsetX:= 10;
 {$ENDIF}
 offsetY:= cOffsetY;
-inc(Frames);
+if (RM = rmDefault) or (RM = rmRightEye) then
+begin
+    inc(Frames);
 
-if cShowFPS or (GameType = gmtDemo) then inc(CountTicks, Lag);
-if (GameType = gmtDemo) and (CountTicks >= 1000) then
-   begin
-   i:=GameTicks div 1000;
-   t:= i mod 60;
-   s:= inttostr(t);
-   if t < 10 then s:= '0' + s;
-   i:= i div 60;
-   t:= i mod 60;
-   s:= inttostr(t) + ':' + s;
-   if t < 10 then s:= '0' + s;
-   s:= inttostr(i div 60) + ':' + s;
-
-   if timeTexture <> nil then
-        FreeTexture(timeTexture);
-    timeTexture:= nil;
-
-   tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fnt16].Handle, Str2PChar(s), cWhiteColorChannels);
-   tmpSurface:= doSurfaceConversion(tmpSurface);
-   timeTexture:= Surface2Tex(tmpSurface, false);
-   SDL_FreeSurface(tmpSurface)
-   end;
+    if cShowFPS or (GameType = gmtDemo) then
+        inc(CountTicks, Lag);
+    if (GameType = gmtDemo) and (CountTicks >= 1000) then
+    begin
+        i:=GameTicks div 1000;
+        t:= i mod 60;
+        s:= inttostr(t);
+        if t < 10 then s:= '0' + s;
+        i:= i div 60;
+        t:= i mod 60;
+        s:= inttostr(t) + ':' + s;
+        if t < 10 then s:= '0' + s;
+        s:= inttostr(i div 60) + ':' + s;
+   
+        if timeTexture <> nil then
+            FreeTexture(timeTexture);
+        timeTexture:= nil;
+    
+        tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fnt16].Handle, Str2PChar(s), cWhiteColorChannels);
+        tmpSurface:= doSurfaceConversion(tmpSurface);
+        timeTexture:= Surface2Tex(tmpSurface, false);
+        SDL_FreeSurface(tmpSurface)
+    end;
 
-if timeTexture <> nil then
-   DrawTexture((cScreenWidth shr 1) - 20 - timeTexture^.w - offsetY, offsetX + timeTexture^.h+5, timeTexture);
+    if timeTexture <> nil then
+        DrawTexture((cScreenWidth shr 1) - 20 - timeTexture^.w - offsetY, offsetX + timeTexture^.h+5, timeTexture);
 
-if cShowFPS then
-   begin
-   if CountTicks >= 1000 then
-      begin
-      FPS:= Frames;
-      Frames:= 0;
-      CountTicks:= 0;
-      s:= inttostr(FPS) + ' fps';
-      if fpsTexture <> nil then
-        FreeTexture(fpsTexture);
-    fpsTexture:= nil;
-      tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fnt16].Handle, Str2PChar(s), cWhiteColorChannels);
-      tmpSurface:= doSurfaceConversion(tmpSurface);
-      fpsTexture:= Surface2Tex(tmpSurface, false);
-      SDL_FreeSurface(tmpSurface)
-      end;
-   if fpsTexture <> nil then
-      DrawTexture((cScreenWidth shr 1) - 60 - offsetY, offsetX, fpsTexture);
-   end;
+    if cShowFPS then
+    begin
+        if CountTicks >= 1000 then
+        begin
+            FPS:= Frames;
+            Frames:= 0;
+            CountTicks:= 0;
+            s:= inttostr(FPS) + ' fps';
+            if fpsTexture <> nil then
+                FreeTexture(fpsTexture);
+            fpsTexture:= nil;
+            tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fnt16].Handle, Str2PChar(s), cWhiteColorChannels);
+            tmpSurface:= doSurfaceConversion(tmpSurface);
+            fpsTexture:= Surface2Tex(tmpSurface, false);
+            SDL_FreeSurface(tmpSurface)
+        end;
+        if fpsTexture <> nil then
+            DrawTexture((cScreenWidth shr 1) - 60 - offsetY, offsetX, fpsTexture);
+    end;
 
-if CountTicks >= 1000 then CountTicks:= 0;
+    if CountTicks >= 1000 then CountTicks:= 0;
 
-// lag warning (?)
-inc(SoundTimerTicks, Lag);
+    // lag warning (?)
+    inc(SoundTimerTicks, Lag);
+end;
+
 if SoundTimerTicks >= 50 then
    begin
    SoundTimerTicks:= 0;