hedgewars/uRender.pas
branchqmlfrontend
changeset 10886 99273b7afbff
parent 10817 48a53259fad8
parent 10873 84c00d1127d6
child 11071 3851ce4f2061
--- a/hedgewars/uRender.pas	Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uRender.pas	Thu Apr 02 21:09:56 2015 +0300
@@ -48,6 +48,7 @@
 
 procedure DrawCircle            (X, Y, Radius, Width: LongInt);
 procedure DrawCircle            (X, Y, Radius, Width: LongInt; r, g, b, a: Byte);
+procedure DrawCircleFilled      (X, Y, Radius: LongInt; r, g, b, a: Byte);
 
 procedure DrawLine              (X0, Y0, X1, Y1, Width: Single; color: LongWord); inline;
 procedure DrawLine              (X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
@@ -59,12 +60,16 @@
 procedure DrawWaves             (Dir, dX, dY, oX: LongInt; tnt: Byte);
 
 procedure RenderClear           ();
-procedure RenderSetClearColor      (r, g, b, a: real);
+procedure RenderClear           (mode: TRenderMode);
+procedure RenderSetClearColor   (r, g, b, a: real);
 procedure Tint                  (r, g, b, a: Byte); inline;
 procedure Tint                  (c: Longword); inline;
 procedure untint(); inline;
 procedure setTintAdd            (f: boolean); inline;
 
+// call this to finish the rendering of current frame
+procedure FinishRender();
+
 function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline;
 
 // 0 => not offscreen, <0 => left/top of screen >0 => right/below of screen
@@ -74,13 +79,14 @@
 procedure SetScale(f: GLfloat);
 procedure UpdateViewLimits();
 
-procedure RenderSetup();
+procedure RendererSetup();
+procedure RendererCleanup();
+
+procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
+procedure ResetDepth(rm: TRenderMode);
 
 // TODO everything below this should not need a public interface
 
-procedure CreateFramebuffer(var frame, depth, tex: GLuint);
-procedure DeleteFramebuffer(var frame, depth, tex: GLuint);
-
 procedure EnableTexture(enable:Boolean);
 
 procedure SetTexCoordPointer(p: Pointer;n: Integer); inline;
@@ -89,14 +95,9 @@
 
 procedure UpdateModelviewProjection(); inline;
 
-procedure openglLoadIdentity    (); inline;
-procedure openglTranslProjMatrix(X, Y, Z: GLFloat); inline;
 procedure openglPushMatrix      (); inline;
 procedure openglPopMatrix       (); inline;
 procedure openglTranslatef      (X, Y, Z: GLfloat); inline;
-procedure openglScalef          (ScaleX, ScaleY, ScaleZ: GLfloat); inline;
-procedure openglRotatef         (RotX, RotY, RotZ: GLfloat; dir: LongInt); inline;
-procedure openglTint            (r, g, b, a: Byte); inline;
 
 
 implementation
@@ -123,6 +124,20 @@
     LastColorPointerN, LastTexCoordPointerN, LastVertexPointerN: Integer;
 {$ENDIF}
 
+{$IFDEF USE_S3D_RENDERING}
+    // texture/vertex buffers for left/right/default eye modes
+    texLRDtb, texLvb, texRvb: array [0..3] of TVertex2f;
+{$ENDIF}
+
+procedure openglLoadIdentity    (); forward;
+procedure openglTranslProjMatrix(X, Y, Z: GLFloat); forward;
+procedure openglScalef          (ScaleX, ScaleY, ScaleZ: GLfloat); forward;
+procedure openglRotatef         (RotX, RotY, RotZ: GLfloat; dir: LongInt); forward;
+procedure openglTint            (r, g, b, a: Byte); forward;
+
+procedure CreateFramebuffer(var frame, depth, tex: GLuint); forward;
+procedure DeleteFramebuffer(var frame, depth, tex: GLuint); forward;
+
 function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline;
 begin
     isAreaOffscreen:= (isDxAreaOffscreen(X, Width) <> 0) or (isDyAreaOffscreen(Y, Height) <> 0);
@@ -147,11 +162,92 @@
     glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
 end;
 
+{$IFDEF USE_S3D_RENDERING}
+procedure RenderClear(mode: TRenderMode);
+var frame: GLuint;
+begin
+    if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+        begin
+        case mode of
+            rmLeftEye:  frame:= frameL;
+            rmRightEye: frame:= frameR;
+            else
+                frame:= defaultFrame;
+        end;
+
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame);
+
+        RenderClear();
+        end
+    else
+        begin
+        // draw left eye in red channel only
+        if mode = rmLeftEye then
+            begin
+            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+            RenderClear();
+            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);
+            end
+        else
+            begin
+            // 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);
+            end;
+        end;
+end;
+{$ENDIF}
+
 procedure RenderSetClearColor(r, g, b, a: real);
 begin
     glClearColor(r, g, b, a);
 end;
 
+procedure FinishRender();
+begin
+
+{$IFDEF USE_S3D_RENDERING}
+if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+    begin
+    RenderClear(rmDefault);
+
+    SetScale(cDefaultZoomLevel);
+
+
+    // same for all
+    SetTexCoordPointer(@texLRDtb, Length(texLRDtb));
+
+
+    // draw left frame
+    glBindTexture(GL_TEXTURE_2D, texl);
+    SetVertexPointer(@texLvb, Length(texLvb));
+    //UpdateModelviewProjection;
+    glDrawArrays(GL_TRIANGLE_FAN, 0, Length(texLvb));
+
+    // draw right frame
+    glBindTexture(GL_TEXTURE_2D, texl);
+    SetVertexPointer(@texRvb, Length(texRvb));
+    //UpdateModelviewProjection;
+    glDrawArrays(GL_TRIANGLE_FAN, 0, Length(texRvb));
+
+    SetScale(zoom);
+    end;
+{$ENDIF}
+end;
+
 {$IFDEF GL2}
 function CompileShader(shaderFile: string; shaderType: GLenum): GLuint;
 var
@@ -302,14 +398,42 @@
     glDeleteRenderbuffersEXT(1, @depth);
     glDeleteFramebuffersEXT(1, @frame);
 end;
+{$ENDIF}
 
+procedure RendererCleanup();
+begin
+{$IFNDEF PAS2C}
+{$IFDEF USE_VIDEO_RECORDING}
+    if defaultFrame <> 0 then
+        DeleteFramebuffer(defaultFrame, depthv, texv);
 {$ENDIF}
-procedure RenderSetup();
+{$IFDEF USE_S3D_RENDERING}
+    if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+        begin
+        DeleteFramebuffer(framel, depthl, texl);
+        DeleteFramebuffer(framer, depthr, texr);
+        end
+{$ENDIF}
+{$ENDIF}
+end;
+
+procedure RendererSetup();
 var AuxBufNum: LongInt = 0;
     tmpstr: ansistring;
     tmpint: LongInt;
     tmpn: LongInt;
 begin
+{$IFDEF MOBILE}
+    // TODO: this function creates an opengles1.1 context
+    // un-comment below and add proper logic to support opengles2.0
+    //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+    //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+    if SDLGLcontext = nil then
+        SDLGLcontext:= SDL_GL_CreateContext(SDLwindow);
+    SDLTry(SDLGLcontext <> nil, true);
+    SDL_GL_SetSwapInterval(1);
+{$ENDIF}
+
     // suppress hint/warning
     AuxBufNum:= AuxBufNum;
 
@@ -426,12 +550,66 @@
             CreateFramebuffer(framel, depthl, texl);
             CreateFramebuffer(framer, depthr, texr);
 
+
+
+
             // reset
             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame)
             end
         else
             cStereoMode:= smNone;
     end;
+
+    // set up vertex/texture buffers for frame textures
+    texLRDtb[0].X:= 0.0;
+    texLRDtb[0].Y:= 0.0;
+    texLRDtb[1].X:= 1.0;
+    texLRDtb[1].Y:= 0.0;
+    texLRDtb[2].X:= 1.0;
+    texLRDtb[2].Y:= 1.0;
+    texLRDtb[3].X:= 0.0;
+    texLRDtb[3].Y:= 1.0;
+
+    if cStereoMode = smHorizontal then
+        begin
+        texLvb[0].X:= cScreenWidth / -2;
+        texLvb[0].Y:= cScreenHeight;
+        texLvb[1].X:= 0;
+        texLvb[1].Y:= cScreenHeight;
+        texLvb[2].X:= 0;
+        texLvb[2].Y:= 0;
+        texLvb[3].X:= cScreenWidth / -2;
+        texLvb[3].Y:= 0;
+
+        texRvb[0].X:= 0;
+        texRvb[0].Y:= cScreenHeight;
+        texRvb[1].X:= cScreenWidth / 2;
+        texRvb[1].Y:= cScreenHeight;
+        texRvb[2].X:= cScreenWidth / 2;
+        texRvb[2].Y:= 0;
+        texRvb[3].X:= 0;
+        texRvb[3].Y:= 0;
+        end
+    else
+        begin
+        texLvb[0].X:= cScreenWidth / -2;
+        texLvb[0].Y:= cScreenHeight / 2;
+        texLvb[1].X:= cScreenWidth / 2;
+        texLvb[1].Y:= cScreenHeight / 2;
+        texLvb[2].X:= cScreenWidth / 2;
+        texLvb[2].Y:= 0;
+        texLvb[3].X:= cScreenWidth / -2;
+        texLvb[3].Y:= 0;
+
+        texRvb[0].X:= cScreenWidth / -2;
+        texRvb[0].Y:= cScreenHeight;
+        texRvb[1].X:= cScreenWidth / 2;
+        texRvb[1].Y:= cScreenHeight;
+        texRvb[2].X:= cScreenWidth / 2;
+        texRvb[2].Y:= cScreenHeight / 2;
+        texRvb[3].X:= cScreenWidth / -2;
+        texRvb[3].Y:= cScreenHeight / 2;
+        end;
 {$ENDIF}
 
 // set view port to whole window
@@ -1220,6 +1398,25 @@
     glDisable(GL_LINE_SMOOTH);
 end;
 
+procedure DrawCircleFilled(X, Y, Radius: LongInt; r, g, b, a: Byte);
+var
+    i: LongInt;
+begin
+    VertexBuffer[0].X := X;
+    VertexBuffer[0].Y := Y;
+
+    for i := 1 to 19 do begin
+        VertexBuffer[i].X := X + Radius*cos(i*pi/9);
+        VertexBuffer[i].Y := Y + Radius*sin(i*pi/9);
+    end;
+
+    EnableTexture(False);
+    Tint(r, g, b, a);
+    SetVertexPointer(@VertexBuffer[0], 20);
+    glDrawArrays(GL_TRIANGLE_FAN, 0, 20);
+    Untint();
+    EnableTexture(True);
+end;
 
 procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
 const VertexBuffer: array [0..3] of TVertex2f = (
@@ -1387,11 +1584,6 @@
 firsti:= -1;
 afteri:=  0;
 
-if GameTicks < 2000 then
-    lol:= 2000 - GameTicks
-else
-    lol:= 0;
-
 if InTopY < 0 then
     InTopY:= 0;
 
@@ -1403,6 +1595,13 @@
     end
 else
     begin
+
+    // animate water walls raise animation at start of game
+    if GameTicks < 2000 then
+        lol:= 2000 - GameTicks
+    else
+        lol:= 0;
+
     if InLeftX > ViewLeftX then
         begin
         VertexBuffer[0].X:= OutLeftX - lol;
@@ -1712,6 +1911,42 @@
         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 end;
 
+procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
+var tmp: LongInt;
+begin
+{$IFNDEF USE_S3D_RENDERING}
+    rm:= rm; d:= d; tmp:= tmp; // avoid hint
+{$ELSE}
+    d:= d / 5;
+    if rm = rmDefault then
+        exit
+    else if rm = rmLeftEye then
+        d:= -d;
+    cStereoDepth:= cStereoDepth + d;
+    openglTranslProjMatrix(d, 0, 0);
+    tmp:= round(d / cScaleFactor * cScreenWidth);
+    ViewLeftX := ViewLeftX  - tmp;
+    ViewRightX:= ViewRightX - tmp;
+{$ENDIF}
+end;
+
+procedure ResetDepth(rm: TRenderMode);
+var tmp: LongInt;
+begin
+{$IFNDEF USE_S3D_RENDERING}
+    rm:= rm; tmp:= tmp; // avoid hint
+{$ELSE}
+    if rm = rmDefault then
+        exit;
+    openglTranslProjMatrix(-cStereoDepth, 0, 0);
+    tmp:= round(cStereoDepth / cScaleFactor * cScreenWidth);
+    ViewLeftX := ViewLeftX  + tmp;
+    ViewRightX:= ViewRightX + tmp;
+    cStereoDepth:= 0;
+{$ENDIF}
+end;
+
+
 procedure initModule;
 begin
     LastTint:= cWhiteColor + 1;