merge with HEAD after 0.9.15 release, move consts and vars in their proper files experimental3D
authorkoda
Tue, 04 Jan 2011 12:53:46 +0100
branchexperimental3D
changeset 4812 f924be23ffb4
parent 4347 0ddb100fea61 (diff)
parent 4811 3edc0cdcfe03 (current diff)
child 4814 e19791f08443
merge with HEAD after 0.9.15 release, move consts and vars in their proper files
QTfrontend/CMakeLists.txt
QTfrontend/game.cpp
QTfrontend/gameuiconfig.cpp
QTfrontend/pages.cpp
QTfrontend/pages.h
QTfrontend/predefteams.h
gameServer/HandlerUtils.hs
gameServer/RoomsAndClients.hs
gameServer/ServerState.hs
gameServer/Store.hs
gameServer/hedgewars-server.cabal
gameServer/stresstest3.hs
hedgewars/CCHandlers.inc
hedgewars/GearDrawing.inc
hedgewars/PascalExports.pas
hedgewars/SinTable.inc
hedgewars/hwengine.pas
hedgewars/uConsts.pas
hedgewars/uMisc.pas
hedgewars/uStore.pas
hedgewars/uTypes.pas
hedgewars/uVariables.pas
hedgewars/uWorld.pas
project_files/HedgewarsMobile/Classes/HogButtonView.h
project_files/HedgewarsMobile/Classes/HogButtonView.m
project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj
project_files/HedgewarsMobile/Resources/Frontend-iPad/backButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/background.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/backgroundAndTitle.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/helpButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/localplayButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/netplayButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/startGameButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/title.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/backgroundCenter.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/backgroundTop.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/borderBottom.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/startButton.png
project_files/HedgewarsMobile/Resources/Frontend-iPhone/title_small.png
project_files/HedgewarsMobile/Resources/Overlay/joyButton_attack.png
project_files/HedgewarsMobile/Resources/Overlay/joyButton_backjump.png
project_files/HedgewarsMobile/Resources/Overlay/joyButton_forwardjump.png
project_files/HedgewarsMobile/Resources/Overlay/mediumBackground~ipad.png
project_files/HedgewarsMobile/Resources/Overlay/plus.png
project_files/HedgewarsMobile/Resources/Overlay/smallerBackground@2x-iphone.png
project_files/HedgewarsMobile/Resources/Overlay/smallerBackground~ipad.png
project_files/HedgewarsMobile/Resources/Overlay/smallerBackground~iphone.png
project_files/HedgewarsMobile/Resources/checkbox.png
project_files/HedgewarsMobile/Resources/savesButton.png
project_files/HedgewarsMobile/Resources/settingsButton.png
share/hedgewars/Data/Missions/Campaign/01#Boot Camp.lua
share/hedgewars/Data/Missions/Training/Bazooka.lua
share/hedgewars/Data/Missions/Training/Shotgun.lua
share/hedgewars/Data/Missions/Training/SniperRifle.lua
share/hedgewars/Data/Music/main theme.ogg
--- a/.hgignore	Tue Jan 04 01:21:30 2011 +0100
+++ b/.hgignore	Tue Jan 04 12:53:46 2011 +0100
@@ -32,5 +32,3 @@
 glob:*.orig
 glob:*.bak
 glob:*.rej
-glob:*.qm
-glob:share/hedgewars/Data/misc/hwengine.desktop
--- a/QTfrontend/game.cpp	Tue Jan 04 01:21:30 2011 +0100
+++ b/QTfrontend/game.cpp	Tue Jan 04 12:53:46 2011 +0100
@@ -300,6 +300,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	Tue Jan 04 01:21:30 2011 +0100
+++ b/QTfrontend/gameuiconfig.cpp	Tue Jan 04 12:53:46 2011 +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	Tue Jan 04 01:21:30 2011 +0100
+++ b/QTfrontend/gameuiconfig.h	Tue Jan 04 12:53:46 2011 +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	Tue Jan 04 01:21:30 2011 +0100
+++ b/QTfrontend/pages.cpp	Tue Jan 04 12:53:46 2011 +0100
@@ -669,6 +669,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);
@@ -704,6 +705,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"));
@@ -717,6 +719,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);
@@ -781,8 +802,34 @@
     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);
+        previousQuality = this->SLQuality->value();
+        this->SLQuality->setValue(this->SLQuality->maximum());
+        this->SLQuality->setEnabled(false);
+    } else {
+        this->CBFullscreen->setChecked(previousFullscreenValue);
+        this->CBFullscreen->setEnabled(true);
+        this->SLQuality->setValue(previousQuality);
+        this->SLQuality->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	Tue Jan 04 01:21:30 2011 +0100
+++ b/QTfrontend/pages.h	Tue Jan 04 12:53:46 2011 +0100
@@ -234,6 +234,7 @@
     QComboBox *CBTeamName;
     IconedGroupBox *AGGroupBox;
     QComboBox *CBResolution;
+    QComboBox *CBStereoMode;
     QCheckBox *CBEnableSound;
     QCheckBox *CBEnableFrontendSound;
     QCheckBox *CBEnableMusic;
@@ -254,6 +255,15 @@
     QLineEdit *editNetNick;
     QSlider *SLQuality;
     QCheckBox *CBFrontendEffects;
+
+private:
+    bool previousFullscreenValue;
+    int previousResolutionIndex;
+    int previousQuality;
+
+private slots:
+    void forceFullscreen(int index);
+    void setFullscreen(void);
 };
 
 class PageNet : public AbstractPage
--- a/hedgewars/ArgParsers.inc	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/ArgParsers.inc	Tue Jan 04 12:53:46 2011 +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	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/hwengine.pas	Tue Jan 04 12:53:46 2011 +0100
@@ -226,10 +226,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/options.inc	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/options.inc	Tue Jan 04 12:53:46 2011 +0100
@@ -32,6 +32,7 @@
   {$DEFINE SDL_MIXER_NEWER}
   {$DEFINE SDL_IMAGE_NEWER}
   {$DEFINE HWLIBRARY}
+  {$DEFINE S3D_DISABLED}
   {$DEFINE GLunit:=gles11}
 {$ENDIF}
 
@@ -41,3 +42,5 @@
   {  $DEFINE TRACEAIACTIONS}
   {  $DEFINE COUNTTICKS}
 {$ENDIF}
+
+//also available LUA_DISABLED
\ No newline at end of file
--- a/hedgewars/uConsts.pas	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/uConsts.pas	Tue Jan 04 12:53:46 2011 +0100
@@ -23,15 +23,11 @@
 
 uses    SDLh, uFloat, GLunit;
 
-
 {$INCLUDE "config.inc"}
 
-// typed const is a variable despite const qualifier
-// in freepascal you may actually use var for the same purpose
-
 const
     sfMax = 1000;
-    cDefaultParamNum = 16;
+    cDefaultParamNum = 17;
 
     // message constants
     errmsgCreateSurface   = 'Error creating SDL surface';
--- a/hedgewars/uMisc.pas	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/uMisc.pas	Tue Jan 04 12:53:46 2011 +0100
@@ -23,7 +23,6 @@
 
 uses    SDLh, uConsts, GLunit, uTypes;
 
-
 procedure movecursor(dx, dy: LongInt);
 function  doSurfaceConversion(tmpsurf: PSDL_Surface): PSDL_Surface;
 procedure MakeScreenshot(filename: shortstring);
--- a/hedgewars/uStore.pas	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/uStore.pas	Tue Jan 04 12:53:46 2011 +0100
@@ -378,6 +378,17 @@
     SDL_FreeSurface(MissionIcons);
     FreeTexture(ropeIconTex);
     FreeTexture(HHTexture);
+{$IFNDEF S3D_DISABLED}
+    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
+{$ENDIF}
 end;
 
 
@@ -434,10 +445,10 @@
 {$ELSE}
     glLoadExtension:= glext_LoadExtension(extension);
 {$IFDEF DEBUGFILE}
-    if not glLoadExtension then
-        AddFileLog('OpenGL - "' + extension + '" failed to load')
+    if glLoadExtension then
+        AddFileLog('OpenGL - "' + extension + '" loaded')
     else
-        AddFileLog('OpenGL - "' + extension + '" loaded');
+        AddFileLog('OpenGL - "' + extension + '" failed to load');
 {$ENDIF}
 {$ENDIF}
 end;
@@ -495,16 +506,57 @@
 {$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
         cGPUVendor:= gvATI
     else if StrPos(Str2PChar(vendor), Str2PChar('ati')) <> nil then
         cGPUVendor:= gvIntel;
+{$ENDIF}
 //SupportNPOTT:= glLoadExtension('GL_ARB_texture_non_power_of_two');
-{$ELSE}
-    cGPUVendor:= gvApple;
+{$IFNDEF S3D_DISABLED}
+    if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then
+    begin
+        // prepare left and right frame buffers and associated textures
+        if glLoadExtension('GL_EXT_framebuffer_object') then
+        begin
+            // 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
+        else
+            cStereoMode:= smNone;
+    end;
 {$ENDIF}
 
 {$IFDEF DEBUGFILE}
--- a/hedgewars/uTypes.pas	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/uTypes.pas	Tue Jan 04 12:53:46 2011 +0100
@@ -5,6 +5,9 @@
 
 uses SDLh, uFloat, GLunit, uConsts, Math;
 
+// NOTE: typed const is a variable despite const qualifier
+// in freepascal you may actually use var for the same purpose
+
 type
     HwColor4f = record
         r, g, b, a: byte
@@ -128,6 +131,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;
--- a/hedgewars/uVariables.pas	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/uVariables.pas	Tue Jan 04 12:53:46 2011 +0100
@@ -25,6 +25,7 @@
     recordFileName  : shortstring = '';
     cReadyDelay     : Longword    = 5000;
     cLogfileBase    : shortstring = 'debug';
+    cStereoMode     : TStereoMode = smNone;
 //////////////////////////
 
     alsoShutdownFrontend: boolean = false;
@@ -2077,6 +2078,9 @@
     cntTicks: LongWord;
 {$ENDIF}
     cOffsetY: LongInt;
+    AFRToggle: Boolean;
+    bAFRRight: Boolean;
+
 
     PixelFormat: PSDL_PixelFormat;
     SDLPrimSurface: PSDL_Surface;
@@ -2091,7 +2095,11 @@
     ProgrTex: PTexture;
     MissionIcons: PSDL_Surface;
     ropeIconTex: PTexture;
+    // orientation of the viewport
     rotationQt: GLfloat;
+    // stereoscopic framebuffer and textures
+    framel, framer, depthl, depthr: GLuint;
+    texl, texr: GLuint;
 
 
     VisualGearsList: PVisualGear;
@@ -2271,7 +2279,7 @@
     SDLwindow       := nil;
 {$ENDIF}
 
-    // those values still aren't perfect
+    // those values still are not perfect
     cLeftScreenBorder:= round(-cMinZoomLevel * cScreenWidth);
     cRightScreenBorder:= round(cMinZoomLevel * cScreenWidth + LAND_WIDTH);
     cScreenSpace:= cRightScreenBorder - cLeftScreenBorder;
@@ -2308,6 +2316,7 @@
     //userNick is in uChat
     recordFileName  := '';
     cReadyDelay     := 5000;
+    cStereoMode     := smNone;
 end;
 
 end.
--- a/hedgewars/uWorld.pas	Tue Jan 04 01:21:30 2011 +0100
+++ b/hedgewars/uWorld.pas	Tue Jan 04 12:53:46 2011 +0100
@@ -27,6 +27,7 @@
 
 procedure InitWorld;
 procedure DrawWorld(Lag: LongInt);
+procedure DrawWorldStereo(Lag: LongInt; RM: TRenderMode);
 procedure ShowMission(caption, subcaption, text: ansistring; icon, time : LongInt);
 procedure HideMission;
 procedure ShakeCamera(amount: LongWord);
@@ -63,6 +64,11 @@
     amSel: TAmmoType = amNothing;
     missionTex: PTexture;
     missionTimer: LongInt;
+    stereoDepth: GLfloat = 0;
+
+const cStereo_Sky     = 0.0500;
+      cStereo_Horizon = 0.0250;
+      cStereo_Water   = 0.0125;
 
 procedure InitWorld;
 var i, t: LongInt;
@@ -555,13 +561,6 @@
 
 
 procedure DrawWorld(Lag: LongInt);
-var i, t: LongInt;
-    r: TSDL_Rect;
-    tdx, tdy: Double;
-    s: string[15];
-    highlight: Boolean;
-    offsetX, offsetY, ScreenBottom: LongInt;
-    VertexBuffer: array [0..3] of TVertex2f;
 begin
     if not isPaused then
     begin
@@ -590,6 +589,160 @@
     if not isPaused then
         MoveCamera;
 
+    if cStereoMode = smNone then
+        begin
+        glClear(GL_COLOR_BUFFER_BIT);
+        DrawWorldStereo(Lag, rmDefault)
+        end
+{$IFNDEF S3D_DISABLED}
+    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
+{$ENDIF}
+end;
+
+procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
+begin
+{$IFDEF S3D_DISABLED}
+    exit;
+{$ELSE}
+    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);
+{$ENDIF}
+end;
+ 
+procedure ResetDepth(rm: TRenderMode);
+begin
+{$IFDEF S3D_DISABLED}
+    exit;
+{$ELSE}
+    if rm = rmDefault then exit;
+    glMatrixMode(GL_PROJECTION);
+    glTranslatef(-stereoDepth, 0, 0);
+    glMatrixMode(GL_MODELVIEW);
+    stereoDepth:= 0;
+{$ENDIF}
+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
@@ -601,7 +754,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;
 
@@ -610,11 +765,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);
@@ -657,22 +817,27 @@
         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);
         if SuddenDeathDmg then
             DrawWater(cSDWaterOpacity, - offsetY div 20)
         else
             DrawWater(cWaterOpacity, - offsetY div 20);
+        ChangeDepth(RM, cStereo_Water);
         DrawWaves( 1, 75 - WorldDx div 4, - cWaveHeight - offsetY div 20, 2);
         if SuddenDeathDmg then
             DrawWater(cSDWaterOpacity, - offsetY div 10)
         else
             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);
@@ -842,58 +1007,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;
--- a/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj	Tue Jan 04 01:21:30 2011 +0100
+++ b/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj	Tue Jan 04 12:53:46 2011 +0100
@@ -934,7 +934,7 @@
 		61798934114AB25F00BA94A9 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
 		6179898B114AB3FA00BA94A9 /* SDL_mixer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL_mixer.xcodeproj; path = "../../../Library/SDL-1.3/SDL_mixer/Xcode-iPhoneOS/SDL_mixer.xcodeproj"; sourceTree = SOURCE_ROOT; };
 		61798A0B114AB65600BA94A9 /* SDL_ttf.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SDL_ttf.xcodeproj; path = "../../../Library/SDL-1.3/SDL_ttf/Xcode-iPhoneOS/SDL_ttf.xcodeproj"; sourceTree = SOURCE_ROOT; };
-		61798A5E114AE08600BA94A9 /* Data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Data; sourceTree = "<group>"; };
+		61798A5E114AE08600BA94A9 /* Data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Data; path = ../../../trunk/project_files/HedgewarsMobile/Data; sourceTree = "<group>"; };
 		6183D83C11E2BCE200A88903 /* Default-ipad-Landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-ipad-Landscape.png"; path = "Resources/Icons/Default-ipad-Landscape.png"; sourceTree = "<group>"; };
 		6183D83D11E2BCE200A88903 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = Resources/Icons/Default.png; sourceTree = "<group>"; };
 		61842B23122B619D0096E335 /* HelpPageInGameViewController-iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "HelpPageInGameViewController-iPad.xib"; path = "../Resources/HelpPageInGameViewController-iPad.xib"; sourceTree = "<group>"; };