merge
authorWolfgang Steffens <WolfgangSteff@gmail.com>
Mon, 28 May 2012 10:34:33 +0200
changeset 7136 6f3c9ec79338
parent 7129 0ce4f478ea6c (diff)
parent 7135 4d863aadd0b2 (current diff)
child 7138 f8248bcba8f1
merge
--- a/hedgewars/hwengine.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/hwengine.pas	Mon May 28 10:34:33 2012 +0200
@@ -31,7 +31,7 @@
 
 uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler, uSound,
      uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uRandom, uLandTexture, uCollisions,
-     SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted
+     SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uRender, uDebug, uCommandHandlers, uLandPainted
      {$IFDEF SDL13}, uTouch{$ENDIF}{$IFDEF ANDROID}, GLUnit{$ENDIF};
 
 {$IFDEF HWLIBRARY}
@@ -419,6 +419,7 @@
         uVisualGears.initModule;
         uWorld.initModule;
         uCaptions.initModule;
+        uRender.initModule;
     end;
 end;
 
--- a/hedgewars/options.inc	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/options.inc	Mon May 28 10:34:33 2012 +0200
@@ -28,6 +28,8 @@
 {$MACRO ON}
 {$DEFINE GLunit:=GL}
 
+{$DEFINE GL2}
+
 {$IFDEF ANDROID}
     {$DEFINE SDL13}
     {$DEFINE HWLIBRARY}
--- a/hedgewars/uGearsRender.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uGearsRender.pas	Mon May 28 10:34:33 2012 +0200
@@ -54,9 +54,9 @@
     glDisable(GL_TEXTURE_2D);
     //glEnable(GL_LINE_SMOOTH);
 
-    glPushMatrix;
-
-    glTranslatef(WorldDx, WorldDy, 0);
+    ResetRotation;
+    SetOffset(WorldDx, WorldDy);
+    UpdateModelview;
 
     glLineWidth(4.0);
 
@@ -66,8 +66,6 @@
     glDrawArrays(GL_LINE_STRIP, 0, RopePoints.Count + 2);
     Tint($FF, $FF, $FF, $FF);
 
-    glPopMatrix;
-
     glEnable(GL_TEXTURE_2D);
     //glDisable(GL_LINE_SMOOTH)
     end
--- a/hedgewars/uLandTexture.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uLandTexture.pas	Mon May 28 10:34:33 2012 +0200
@@ -91,7 +91,7 @@
             with LandTextures[x, y] do
                 begin
                 tex:= NewTexture(TEXSIZE, TEXSIZE, Pixels(x, y));
-                glBindTexture(GL_TEXTURE_2D, tex^.id);
+                glBindTexture(GL_TEXTURE_2D, tex^.atlas^.id);
                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, tpHigh);
                 end
 else
@@ -101,7 +101,7 @@
                 if shouldUpdate then
                     begin
                     shouldUpdate:= false;
-                    glBindTexture(GL_TEXTURE_2D, tex^.id);
+                    glBindTexture(GL_TEXTURE_2D, tex^.atlas^.id);
                     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXSIZE, TEXSIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, Pixels(x,y));
                     end
 end;
--- a/hedgewars/uRender.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uRender.pas	Mon May 28 10:34:33 2012 +0200
@@ -22,7 +22,9 @@
 
 interface
 
-uses SDLh, uTypes, GLunit, uConsts;
+uses SDLh, uTypes, GLunit, uConsts, uTextures, math;
+
+procedure initModule;
 
 procedure DrawSprite            (Sprite: TSprite; X, Y, Frame: LongInt);
 procedure DrawSprite            (Sprite: TSprite; X, Y, FrameX, FrameY: LongInt);
@@ -51,11 +53,85 @@
 procedure Tint                  (r, g, b, a: Byte); inline;
 procedure Tint                  (c: Longword); inline;
 
+// This is just temporary and becomes non public once everything changed to GL2
+procedure UpdateModelview;
+procedure ResetModelview;
+procedure SetOffset(X, Y: Longint);
+procedure ResetRotation;
+
 
 implementation
 uses uVariables;
 
 var LastTint: LongWord = 0;
+    Modelview: TMatrix4x4f;
+
+const DegToRad =  0.01745329252; // 2PI / 360
+
+procedure UpdateModelview;
+begin
+glLoadMatrixf(@Modelview[0,0]);
+end;
+
+procedure ResetModelview;
+begin
+Modelview[0,0]:= 1.0; Modelview[1,0]:=0.0; Modelview[3,0]:= 0;
+Modelview[0,1]:= 0.0; Modelview[1,1]:=1.0; Modelview[3,1]:= 0;
+UpdateModelview;
+end;
+
+procedure SetOffset(X, Y: Longint);
+begin
+Modelview[3,0]:= X;
+Modelview[3,1]:= Y;
+end;
+
+procedure AddOffset(X, Y: GLfloat); // probably want to refactor this to use integers
+begin
+Modelview[3,0]:=Modelview[3,0] + Modelview[0,0]*X + Modelview[1,0]*Y;
+Modelview[3,1]:=Modelview[3,1] + Modelview[0,1]*X + Modelview[1,1]*Y;
+end;
+
+procedure SetScale(Scale: GLfloat);
+begin
+Modelview[0,0]:= Scale;
+Modelview[1,1]:= Scale;
+end;
+
+procedure AddScale(Scale: GLfloat);
+begin
+Modelview[0,0]:= Modelview[0,0]*Scale; Modelview[1,0]:= Modelview[1,0]*Scale;
+Modelview[0,1]:= Modelview[0,1]*Scale; Modelview[1,1]:= Modelview[1,1]*Scale;
+end;
+
+procedure AddScale(X, Y: GLfloat);
+begin
+Modelview[0,0]:= Modelview[0,0]*X; Modelview[1,0]:= Modelview[1,0]*Y;
+Modelview[0,1]:= Modelview[0,1]*X; Modelview[1,1]:= Modelview[1,1]*Y;
+end;
+
+
+procedure SetRotation(Angle, ZAxis: GLfloat);
+var s, c: Extended;
+begin
+SinCos(Angle*DegToRad, s, c);
+Modelview[0,0]:= c;       Modelview[1,0]:=-s*ZAxis;
+Modelview[0,1]:= s*ZAxis; Modelview[1,1]:= c;
+end;
+
+procedure ResetRotation;
+begin
+Modelview[0,0]:= 1.0; Modelview[1,0]:=0.0;
+Modelview[0,1]:= 0.0; Modelview[1,1]:=1.0;
+end;
+
+procedure LoadIdentity(out Matrix: TMatrix4x4f);
+begin
+Matrix[0,0]:= 1.0; Matrix[1,0]:=0.0; Matrix[2,0]:=0.0; Matrix[3,0]:=0.0;
+Matrix[0,1]:= 0.0; Matrix[1,1]:=1.0; Matrix[2,1]:=0.0; Matrix[3,1]:=0.0;
+Matrix[0,2]:= 0.0; Matrix[1,2]:=0.0; Matrix[2,2]:=1.0; Matrix[3,2]:=0.0;
+Matrix[0,3]:= 0.0; Matrix[1,3]:=0.0; Matrix[2,3]:=0.0; Matrix[3,3]:=1.0;
+end;
 
 procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
 begin
@@ -71,8 +147,7 @@
 
 procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
 var rr: TSDL_Rect;
-    _l, _r, _t, _b: real;
-    VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
+    VertexBuffer, TextureBuffer: TVertexRect;
 begin
 if (SourceTexture^.h = 0) or (SourceTexture^.w = 0) then
     exit;
@@ -88,12 +163,9 @@
 rr.w:= W;
 rr.h:= H;
 
-_l:= r^.x / SourceTexture^.w * SourceTexture^.rx;
-_r:= (r^.x + r^.w) / SourceTexture^.w * SourceTexture^.rx;
-_t:= r^.y / SourceTexture^.h * SourceTexture^.ry;
-_b:= (r^.y + r^.h) / SourceTexture^.h * SourceTexture^.ry;
+glBindTexture(GL_TEXTURE_2D, SourceTexture^.atlas^.id);
 
-glBindTexture(GL_TEXTURE_2D, SourceTexture^.id);
+ComputeTexcoords(SourceTexture, r, @TextureBuffer);
 
 VertexBuffer[0].X:= X;
 VertexBuffer[0].Y:= Y;
@@ -104,15 +176,6 @@
 VertexBuffer[3].X:= X;
 VertexBuffer[3].Y:= rr.h + Y;
 
-TextureBuffer[0].X:= _l;
-TextureBuffer[0].Y:= _t;
-TextureBuffer[1].X:= _r;
-TextureBuffer[1].Y:= _t;
-TextureBuffer[2].X:= _r;
-TextureBuffer[2].Y:= _b;
-TextureBuffer[3].X:= _l;
-TextureBuffer[3].Y:= _b;
-
 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
 glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
@@ -125,18 +188,17 @@
 
 procedure DrawTexture(X, Y: LongInt; Texture: PTexture; Scale: GLfloat);
 begin
+SetOffset(X, Y);
+ResetRotation;
+SetScale(Scale);
+UpdateModelview;
 
-glPushMatrix;
-glTranslatef(X, Y, 0);
-glScalef(Scale, Scale, 1);
-
-glBindTexture(GL_TEXTURE_2D, Texture^.id);
+glBindTexture(GL_TEXTURE_2D, Texture^.atlas^.id);
 
 glVertexPointer(2, GL_FLOAT, 0, @Texture^.vb);
 glTexCoordPointer(2, GL_FLOAT, 0, @Texture^.tb);
 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(Texture^.vb));
-
-glPopMatrix
+ResetModelview;
 end;
 
 procedure DrawTextureF(Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt);
@@ -145,8 +207,8 @@
 end;
 
 procedure DrawTextureRotatedF(Texture: PTexture; Scale, OffsetX, OffsetY: GLfloat; X, Y, Frame, Dir, w, h: LongInt; Angle: real);
-var ft, fb, fl, fr: GLfloat;
-    hw, nx, ny: LongInt;
+var hw, nx, ny: LongInt;
+    r: TSDL_Rect;
     VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
 begin
 // do not draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
@@ -155,14 +217,13 @@
 if (abs(Y) > H) and ((abs(Y + OffsetY - (0.5 * cScreenHeight)) - W / 2) * cScaleFactor > cScreenHeight) then
     exit;
 
-glPushMatrix;
-glTranslatef(X, Y, 0);
+SetOffset(X, Y);
 if Dir = 0 then Dir:= 1;
 
-glRotatef(Angle, 0, 0, Dir);
-
-glTranslatef(Dir*OffsetX, OffsetY, 0);
-glScalef(Scale, Scale, 1);
+SetRotation(Angle, Dir);
+AddOffset(Dir*OffsetX, OffsetY);
+AddScale(Scale);
+UpdateModelview;
 
 // Any reason for this call? And why only in t direction, not s?
 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@@ -172,12 +233,13 @@
 nx:= round(Texture^.w / w); // number of horizontal frames
 ny:= round(Texture^.h / h); // number of vertical frames
 
-ft:= (Frame mod ny) * Texture^.ry / ny;
-fb:= ((Frame mod ny) + 1) * Texture^.ry / ny;
-fl:= (Frame div ny) * Texture^.rx / nx;
-fr:= ((Frame div ny) + 1) * Texture^.rx / nx;
+r.y:=(Frame mod ny) * h;
+r.x:=(Frame div ny) * w;
+r.w:=w;
+r.h:=h;
+ComputeTexcoords(Texture, @r, @TextureBuffer);
 
-glBindTexture(GL_TEXTURE_2D, Texture^.id);
+glBindTexture(GL_TEXTURE_2D, Texture^.atlas^.id);
 
 VertexBuffer[0].X:= -hw;
 VertexBuffer[0].Y:= w / -2;
@@ -188,20 +250,11 @@
 VertexBuffer[3].X:= -hw;
 VertexBuffer[3].Y:= w / 2;
 
-TextureBuffer[0].X:= fl;
-TextureBuffer[0].Y:= ft;
-TextureBuffer[1].X:= fr;
-TextureBuffer[1].Y:= ft;
-TextureBuffer[2].X:= fr;
-TextureBuffer[2].Y:= fb;
-TextureBuffer[3].X:= fl;
-TextureBuffer[3].Y:= fb;
-
 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
 glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
 
-glPopMatrix
+ResetModelview;
 end;
 
 procedure DrawSpriteRotated(Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
@@ -214,19 +267,18 @@
 
 procedure DrawSpriteRotatedF(Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
 begin
-glPushMatrix;
-glTranslatef(X, Y, 0);
-
+SetOffset(X, Y);
 if Dir < 0 then
-    glRotatef(Angle, 0, 0, -1)
+    SetRotation(Angle, -1.0)
 else
-    glRotatef(Angle, 0, 0,  1);
+    SetRotation(Angle, 1.0);
 if Dir < 0 then
-    glScalef(-1.0, 1.0, 1.0);
+    AddScale(-1.0, 1.0);
+UpdateModelview;
 
 DrawSprite(Sprite, -SpritesData[Sprite].Width div 2, -SpritesData[Sprite].Height div 2, Frame);
 
-glPopMatrix
+ResetModelview;
 end;
 
 procedure DrawTextureRotated(Texture: PTexture; hw, hh, X, Y, Dir: LongInt; Angle: real);
@@ -238,19 +290,18 @@
 if (abs(Y) > 2 * hh) and ((abs(Y - 0.5 * cScreenHeight) - hh) > cScreenHeight / cScaleFactor) then
     exit;
 
-glPushMatrix;
-glTranslatef(X, Y, 0);
+SetOffset(X, Y);
 
 if Dir < 0 then
     begin
     hw:= - hw;
-    glRotatef(Angle, 0, 0, -1);
+    SetRotation(Angle, -1.0);
     end
 else
-    glRotatef(Angle, 0, 0,  1);
+    SetRotation(Angle, 1.0);
+UpdateModelview;
 
-
-glBindTexture(GL_TEXTURE_2D, Texture^.id);
+glBindTexture(GL_TEXTURE_2D, Texture^.atlas^.id);
 
 VertexBuffer[0].X:= -hw;
 VertexBuffer[0].Y:= -hh;
@@ -265,7 +316,7 @@
 glTexCoordPointer(2, GL_FLOAT, 0, @Texture^.tb);
 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
 
-glPopMatrix
+ResetModelview;
 end;
 
 procedure DrawSprite(Sprite: TSprite; X, Y, Frame: LongInt);
@@ -329,8 +380,9 @@
     glDisable(GL_TEXTURE_2D);
     glEnable(GL_LINE_SMOOTH);
 
-    glPushMatrix;
-    glTranslatef(WorldDx, WorldDy, 0);
+    ResetRotation;
+    SetOffset(WorldDx, WorldDy);
+    UpdateModelview;
     glLineWidth(Width);
 
     Tint(r, g, b, a);
@@ -343,7 +395,7 @@
     glDrawArrays(GL_LINES, 0, Length(VertexBuffer));
     Tint($FF, $FF, $FF, $FF);
     
-    glPopMatrix;
+    ResetModelview;
     
     glEnable(GL_TEXTURE_2D);
     glDisable(GL_LINE_SMOOTH);
@@ -352,6 +404,10 @@
 procedure DrawFillRect(r: TSDL_Rect);
 var VertexBuffer: array [0..3] of TVertex2f;
 begin
+SetOffset(0, 0);
+ResetRotation;
+UpdateModelview;
+
 // do not draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
 if (abs(r.x) > r.w) and ((abs(r.x + r.w / 2) - r.w / 2) * cScaleFactor > cScreenWidth) then
     exit;
@@ -375,7 +431,9 @@
 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
 
 Tint($FF, $FF, $FF, $FF);
-glEnable(GL_TEXTURE_2D)
+glEnable(GL_TEXTURE_2D);
+
+ResetModelview;
 end;
 
 procedure DrawCircle(X, Y, Radius, Width: LongInt; r, g, b, a: Byte); 
@@ -396,23 +454,29 @@
     end;
     glDisable(GL_TEXTURE_2D);
     glEnable(GL_LINE_SMOOTH);
-    glPushMatrix;
+    SetOffset(0, 0);
+    ResetRotation;
+    UpdateModelview;
     glLineWidth(Width);
     glVertexPointer(2, GL_FLOAT, 0, @CircleVertex[0]);
     glDrawArrays(GL_LINE_LOOP, 0, 60);
-    glPopMatrix;
     glEnable(GL_TEXTURE_2D);
     glDisable(GL_LINE_SMOOTH);
+    ResetModelview;
 end;
 
 
 procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
-const VertexBuffer: array [0..3] of TVertex2f = (
-        (X: -16; Y: -16),
-        (X:  16; Y: -16),
-        (X:  16; Y:  16),
-        (X: -16; Y:  16));
-var l, r, t, b: real;
+const VertexBuffers: array[0..1] of TVertexRect = (
+        ((x: -16; y: -16),
+         (x:  16; y: -16),
+         (x:  16; y:  16),
+         (x: -16; y:  16)),
+        ((x:  16; y: -16),
+         (x: -16; y: -16),
+         (x: -16; y:  16),
+         (x:  16; y:  16)));
+var r: TSDL_Rect;
     TextureBuffer: array [0..3] of TVertex2f;
 begin
     // do not draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
@@ -421,41 +485,25 @@
     if (abs(Y) > 32) and ((abs(Y - 0.5 * cScreenHeight) - 16) * cScaleFactor > cScreenHeight) then
         exit;
 
-    t:= Pos * 32 / HHTexture^.h;
-    b:= (Pos + 1) * 32 / HHTexture^.h;
+    r.x:=Step * 32;
+    r.y:=Pos * 32;
+    r.w:=32;
+    r.h:=32;
+    ComputeTexcoords(HHTexture, @r, @TextureBuffer);
 
-    if Dir = -1 then
-        begin
-        l:= (Step + 1) * 32 / HHTexture^.w;
-        r:= Step * 32 / HHTexture^.w
-        end
-    else
-        begin
-        l:= Step * 32 / HHTexture^.w;
-        r:= (Step + 1) * 32 / HHTexture^.w
-    end;
-
+    SetOffset(X, Y);
+    SetRotation(Angle, 1.0);
+    UpdateModelview;
 
-    glPushMatrix();
-    glTranslatef(X, Y, 0);
-    glRotatef(Angle, 0, 0, 1);
-
-    glBindTexture(GL_TEXTURE_2D, HHTexture^.id);
+    glBindTexture(GL_TEXTURE_2D, HHTexture^.atlas^.id);
+    if Dir = -1 then
+        glVertexPointer(2, GL_FLOAT, 0, @VertexBuffers[1][0])
+    else
+        glVertexPointer(2, GL_FLOAT, 0, @VertexBuffers[0][0]);
+    glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
+    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
-    TextureBuffer[0].X:= l;
-    TextureBuffer[0].Y:= t;
-    TextureBuffer[1].X:= r;
-    TextureBuffer[1].Y:= t;
-    TextureBuffer[2].X:= r;
-    TextureBuffer[2].Y:= b;
-    TextureBuffer[3].X:= l;
-    TextureBuffer[3].Y:= b;
-
-    glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
-    glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
-    glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
-
-    glPopMatrix
+    ResetModelview;
 end;
 
 procedure DrawScreenWidget(widget: POnScreenWidget);
@@ -532,4 +580,9 @@
     Tint(((c shr 24) and $FF), ((c shr 16) and $FF), (c shr 8) and $FF, (c and $FF))
 end;
 
+procedure initModule;
+begin
+LoadIdentity(Modelview);
+end;
+
 end.
--- a/hedgewars/uStore.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uStore.pas	Mon May 28 10:34:33 2012 +0200
@@ -43,6 +43,7 @@
 
 procedure WarpMouse(x, y: Word); inline;
 procedure SwapBuffers; inline;
+procedure UpdateProjection;
 
 implementation
 uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands,
@@ -57,6 +58,9 @@
 {$ELSE}
     SDLPrimSurface: PSDL_Surface;
 {$ENDIF}
+{$IFDEF GL2}
+    Shader: GLuint;
+{$ENDIF}
 
 function WriteInRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
 var w, h: LongInt;
@@ -625,6 +629,106 @@
     SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); // try to prefer hardware rendering
 end;
 
+{$IFDEF GL2}
+function CompileShader(shaderFile: string; shaderType: GLenum): GLuint;
+var
+    shader: GLuint;
+    f: Textfile;
+    source, line: AnsiString;
+    sourceA: Pchar;
+    lengthA: GLint;
+    compileResult: GLint;
+    logLength: GLint;
+    log: PChar;
+begin
+    Assign(f, Pathz[ptShaders] + '/' + shaderFile);
+    filemode:= 0; // readonly
+    Reset(f);
+    if IOResult <> 0 then
+    begin
+        AddFileLog('Unable to load ' + shaderFile);
+        halt(-1);
+    end;
+
+    source:='';
+    while not eof(f) do
+    begin
+        ReadLn(f, line);
+        source:= source + line + #10;
+    end;
+    
+    CloseFile(f);
+
+    writeln('Compiling shader: ' + Pathz[ptShaders] + '/' + shaderFile);
+
+    sourceA:=PChar(source);
+    lengthA:=Length(source);
+
+    shader:=glCreateShader(shaderType);
+    glShaderSource(shader, 1, @sourceA, @lengthA);
+    glCompileShader(shader);
+    glGetShaderiv(shader, GL_COMPILE_STATUS, @compileResult);
+    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, @logLength);
+
+    if logLength > 1 then
+    begin
+        GetMem(log, logLength);
+        glGetShaderInfoLog(shader, logLength, nil, log);
+        writeln('========== Compiler log  ==========');
+        writeln(log);
+        writeln('===================================');
+        FreeMem(log, logLength);
+    end;
+
+    if compileResult <> GL_TRUE then
+    begin
+        writeln('Shader compilation failed, halting');
+        halt(-1);
+    end;
+
+    CompileShader:= shader;
+end;
+
+function CompileProgram(shaderName: string): GLuint;
+var
+    program_: GLuint;
+    vs, fs: GLuint;
+    linkResult: GLint;
+    logLength: GLint;
+    log: PChar;
+begin
+    program_:= glCreateProgram();
+    vs:= CompileShader(shaderName + '.vs', GL_VERTEX_SHADER);
+    fs:= CompileShader(shaderName + '.fs', GL_FRAGMENT_SHADER);
+    glAttachShader(program_, vs);
+    glAttachShader(program_, fs);
+    glLinkProgram(program_);
+    glDeleteShader(vs);
+    glDeleteShader(fs);
+
+    glGetProgramiv(program_, GL_LINK_STATUS, @linkResult);
+    glGetProgramiv(program_, GL_INFO_LOG_LENGTH, @logLength);
+
+    if logLength > 1 then
+    begin
+        GetMem(log, logLength);
+        glGetProgramInfoLog(program_, logLength, nil, log);
+        writeln('========== Compiler log  ==========');
+        writeln(log);
+        writeln('===================================');
+        FreeMem(log, logLength);
+    end;
+
+    if linkResult <> GL_TRUE then
+    begin
+        writeln('Linking program failed, halting');
+        halt(-1);
+    end;
+
+    CompileProgram:= program_;
+end;
+{$ENDIF}
+
 procedure SetupOpenGL;
 //var vendor: shortstring = '';
 var buf: array[byte] of char;
@@ -682,6 +786,13 @@
     AddFileLog('  \----- Extensions: ' + shortstring(pchar(glGetString(GL_EXTENSIONS))));
     //TODO: don't have the Extensions line trimmed but slipt it into multiple lines
 
+{$IFDEF GL2}
+    Load_GL_VERSION_2_0;
+    Shader:= CompileProgram('default');
+    glUseProgram(Shader);
+    glUniform1i(glGetUniformLocation(Shader, 'tex'), 0);
+{$ENDIF}
+
 {$IFNDEF S3D_DISABLED}
     if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then
     begin
@@ -729,9 +840,7 @@
 
     glMatrixMode(GL_MODELVIEW);
     // prepare default translation/scaling
-    glLoadIdentity();
-    glScalef(2.0 / cScreenWidth, -2.0 / cScreenHeight, 1.0);
-    glTranslatef(0, -cScreenHeight / 2, 0);
+    SetScale(2.0);
 
     // enable alpha blending
     glEnable(GL_BLEND);
@@ -746,23 +855,28 @@
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 end;
 
+procedure UpdateProjection;
+var mat: array[0..15] of GLfloat;
+    s: GLfloat;
+begin
+    s:=cScaleFactor;
+    glMatrixMode(GL_PROJECTION);
+    mat[ 0]:= s/cScreenWidth; mat[ 1]:=  0.0;             mat[ 2]:=0.0; mat[ 3]:=  0.0;
+    mat[ 4]:= 0.0;            mat[ 5]:= -s/cScreenHeight; mat[ 6]:=0.0; mat[ 7]:=  0.0;
+    mat[ 8]:= 0.0;            mat[ 9]:=  0.0;             mat[10]:=1.0; mat[11]:=  0.0;
+    mat[12]:= cStereoDepth;   mat[13]:=  s/2;             mat[14]:=0.0; mat[15]:=  1.0;
+    glLoadMatrixf(@mat);
+    glMatrixMode(GL_MODELVIEW);
+end;
+
 procedure SetScale(f: GLfloat);
 begin
-// leave immediately if scale factor did not change
-    if f = cScaleFactor then
-        exit;
-
-    if f = cDefaultZoomLevel then
-        glPopMatrix         // "return" to default scaling
-    else                    // other scaling
-        begin
-        glPushMatrix;       // save default scaling
-        glLoadIdentity;
-        glScalef(f / cScreenWidth, -f / cScreenHeight, 1.0);
-        glTranslatef(0, -cScreenHeight / 2, 0);
-        end;
-
-    cScaleFactor:= f;
+    // This lazy update conflicts with R7103 at the moment, missing the initial SetScale(2.0)
+    //if cScaleFactor <> f then
+    //begin
+        cScaleFactor:=f;
+        UpdateProjection;
+    //end;
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1033,11 +1147,7 @@
         // chFullScr is called when there is a rotation event and needs the SetScale and SetupOpenGL to set up the new resolution
         // this 6 gl functions are the relevant ones and are hacked together here for optimisation
         glMatrixMode(GL_MODELVIEW);
-        glPopMatrix;
-        glLoadIdentity();
-        glScalef(2.0 / cScreenWidth, -2.0 / cScreenHeight, 1.0);
-        glTranslatef(0, -cScreenHeight / 2, 0);
-        glViewport(0, 0, cScreenWidth, cScreenHeight);
+        SetScale(2.0);
         exit;
 {$ELSE}
         SetScale(cDefaultZoomLevel);
@@ -1151,6 +1261,9 @@
 
 procedure freeModule;
 begin
+{$IFDEF GL2}
+    glDeleteProgram(Shader);
+{$ENDIF}
     StoreRelease(false);
     TTF_Quit();
 {$IFDEF SDL13}
--- a/hedgewars/uTextures.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uTextures.pas	Mon May 28 10:34:33 2012 +0200
@@ -26,6 +26,7 @@
 procedure Surface2GrayScale(surf: PSDL_Surface);
 function  Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture;
 procedure FreeTexture(tex: PTexture);
+procedure ComputeTexcoords(texture: PTexture; r: PSDL_Rect; tb: PVertexRect);
 
 procedure initModule;
 procedure freeModule;
@@ -47,10 +48,44 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
 end;
 
+procedure ComputeTexcoords(texture: PTexture; r: PSDL_Rect; tb: PVertexRect);
+var x0, y0, x1, y1: Real;
+    w, h, aw, ah: LongInt;
+const texelOffset = 0.0;
+begin
+aw:=texture^.atlas^.w;
+ah:=texture^.atlas^.h;
+if texture^.isRotated then
+    begin
+    w:=r^.h;
+    h:=r^.w;
+    end 
+else
+    begin
+    w:=r^.w;
+    h:=r^.h;        
+    end;
+
+x0:= (r^.x +     texelOffset)/aw;
+x1:= (r^.x + w - texelOffset)/aw;
+y0:= (r^.y +     texelOffset)/ah;
+y1:= (r^.y + h - texelOffset)/ah;
+
+tb^[0].X:= x0;
+tb^[0].Y:= y0;
+tb^[1].X:= x1;
+tb^[1].Y:= y0;
+tb^[2].X:= x1;
+tb^[2].Y:= y1;
+tb^[3].X:= x0;
+tb^[3].Y:= y1
+end;
+
 procedure ResetVertexArrays(texture: PTexture);
+var r: TSDL_Rect;
 begin
 with texture^ do
-    begin
+begin
     vb[0].X:= 0;
     vb[0].Y:= 0;
     vb[1].X:= w;
@@ -59,16 +94,13 @@
     vb[2].Y:= h;
     vb[3].X:= 0;
     vb[3].Y:= h;
+end;
 
-    tb[0].X:= 0;
-    tb[0].Y:= 0;
-    tb[1].X:= rx;
-    tb[1].Y:= 0;
-    tb[2].X:= rx;
-    tb[2].Y:= ry;
-    tb[3].X:= 0;
-    tb[3].Y:= ry
-    end;
+r.x:= 0;
+r.y:= 0;
+r.w:= texture^.w;
+r.h:= texture^.h;
+ComputeTexcoords(texture, @r, @texture^.tb);
 end;
 
 function NewTexture(width, height: Longword; buf: Pointer): PTexture;
@@ -84,16 +116,22 @@
     end;
 TextureList:= NewTexture;
 
-NewTexture^.w:= width;
-NewTexture^.h:= height;
-NewTexture^.rx:= 1.0;
-NewTexture^.ry:= 1.0;
+
+// Atlas allocation happens here later on. For now we just allocate one exclusive atlas per sprite
+new(NewTexture^.atlas);
+NewTexture^.atlas^.w:=width;
+NewTexture^.atlas^.h:=height;
+NewTexture^.x:=0;
+NewTexture^.y:=0;
+NewTexture^.w:=width;
+NewTexture^.h:=height;
+NewTexture^.isRotated:=false;
 
 ResetVertexArrays(NewTexture);
 
-glGenTextures(1, @NewTexture^.id);
+glGenTextures(1, @NewTexture^.atlas^.id);
 
-glBindTexture(GL_TEXTURE_2D, NewTexture^.id);
+glBindTexture(GL_TEXTURE_2D, NewTexture^.atlas^.id);
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
 
 SetTextureParameters(true);
@@ -136,20 +174,27 @@
     end;
 TextureList:= Surface2Tex;
 
+// Atlas allocation happens here later on. For now we just allocate one exclusive atlas per sprite
+new(Surface2Tex^.atlas);
+
 Surface2Tex^.w:= surf^.w;
 Surface2Tex^.h:= surf^.h;
+Surface2Tex^.x:=0;
+Surface2Tex^.y:=0;
+Surface2Tex^.isRotated:=false;
+
 
 if (surf^.format^.BytesPerPixel <> 4) then
     begin
     TryDo(false, 'Surface2Tex failed, expecting 32 bit surface', true);
-    Surface2Tex^.id:= 0;
+    Surface2Tex^.atlas^.id:= 0;
     exit
     end;
 
 
-glGenTextures(1, @Surface2Tex^.id);
+glGenTextures(1, @Surface2Tex^.atlas^.id);
 
-glBindTexture(GL_TEXTURE_2D, Surface2Tex^.id);
+glBindTexture(GL_TEXTURE_2D, Surface2Tex^.atlas^.id);
 
 if SDL_MustLock(surf) then
     SDLTry(SDL_LockSurface(surf) >= 0, true);
@@ -164,8 +209,8 @@
     tw:= toPowerOf2(Surf^.w);
     th:= toPowerOf2(Surf^.h);
 
-    Surface2Tex^.rx:= Surf^.w / tw;
-    Surface2Tex^.ry:= Surf^.h / th;
+    Surface2Tex^.atlas^.w:=tw;
+    Surface2Tex^.atlas^.h:=th;
 
     GetMem(tmpp, tw * th * surf^.format^.BytesPerPixel);
 
@@ -195,8 +240,8 @@
     end
 else
     begin
-    Surface2Tex^.rx:= 1.0;
-    Surface2Tex^.ry:= 1.0;
+    Surface2Tex^.atlas^.w:=Surf^.w;
+    Surface2Tex^.atlas^.h:=Surf^.h;
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf^.w, surf^.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf^.pixels);
     end;
 
@@ -214,13 +259,16 @@
 begin
 if tex <> nil then
     begin
+    // Atlas cleanup happens here later on. For now we just free as each sprite has one atlas
+    Dispose(tex^.atlas);
+
     if tex^.NextTexture <> nil then
         tex^.NextTexture^.PrevTexture:= tex^.PrevTexture;
     if tex^.PrevTexture <> nil then
         tex^.PrevTexture^.NextTexture:= tex^.NextTexture
     else
         TextureList:= tex^.NextTexture;
-    glDeleteTextures(1, @tex^.id);
+    glDeleteTextures(1, @tex^.atlas^.id);
     Dispose(tex);
     end
 end;
@@ -236,7 +284,7 @@
     WriteToConsole('FIXME FIXME FIXME. App shutdown without full cleanup of texture list; read game0.log and please report this problem');
     while TextureList <> nil do 
         begin
-        AddFileLog('Texture not freed: width='+inttostr(LongInt(TextureList^.w))+' height='+inttostr(LongInt(TextureList^.h))+' priority='+inttostr(round(TextureList^.priority*1000)));
+        AddFileLog('Sprite not freed: width='+inttostr(LongInt(TextureList^.w))+' height='+inttostr(LongInt(TextureList^.h))+' priority='+inttostr(round(TextureList^.atlas^.priority*1000)));
         FreeTexture(TextureList);
         end
 end;
--- a/hedgewars/uTypes.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uTypes.pas	Mon May 28 10:34:33 2012 +0200
@@ -44,7 +44,8 @@
     // Different files are stored in different folders, this enumeration is used to tell which folder to use
     TPathType = (ptNone, ptData, ptGraphics, ptThemes, ptCurrTheme, ptTeams, ptMaps,
             ptMapCurrent, ptDemos, ptSounds, ptGraves, ptFonts, ptForts,
-            ptLocale, ptAmmoMenu, ptHedgehog, ptVoices, ptHats, ptFlags, ptMissionMaps, ptSuddenDeath, ptButtons);
+            ptLocale, ptAmmoMenu, ptHedgehog, ptVoices, ptHats, ptFlags, ptMissionMaps, ptSuddenDeath, ptButtons,
+            ptShaders);
 
     // Available sprites for displaying stuff
     TSprite = (sprWater, sprCloud, sprBomb, sprBigDigit, sprFrame,
@@ -199,13 +200,30 @@
             X, Y: GLint;
             end;
 
+    TMatrix4x4f = array[0..3, 0..3] of GLfloat;
+
+    PAtlas = ^TAtlas;
     PTexture = ^TTexture;
+
+    TAtlas = record
+                id: GLuint;
+                w, h: LongInt;
+                priority: GLfloat;
+            end;
+
+    PVertexRect = ^TVertexRect;
+    TVertexRect = array[0..3] of TVertex2f;
+    
     TTexture = record
-            id: GLuint;
+            atlas: PAtlas;
             w, h, scale: LongInt;
-            rx, ry: GLfloat;
-            priority: GLfloat;
-            vb, tb: array [0..3] of TVertex2f;
+
+            x, y: LongInt; // Offset in the texture atlas
+            isRotated: boolean; // if true sprite is flipped in the atlas taking w pixels along the y and h pixels along the x axis
+
+            // Cached values for texel coordinates and vertex coordinates            
+            vb, tb: TVertexRect;
+
             PrevTexture, NextTexture: PTexture;
             end;
 
--- a/hedgewars/uVariables.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uVariables.pas	Mon May 28 10:34:33 2012 +0200
@@ -225,8 +225,9 @@
         'Graphics/Hats',                 // ptHats
         'Graphics/Flags',                // ptFlags
         'Missions/Maps',                 // ptMissionMaps
-        'Graphics/SuddenDeath',           // ptSuddenDeath
-        'Graphics/Buttons'                // ptButton
+        'Graphics/SuddenDeath',          // ptSuddenDeath
+        'Graphics/Buttons',              // ptButton
+        'Shaders'                        // ptShaders
     );
 
     Fontz: array[THWFont] of THHFont = (
@@ -2425,6 +2426,7 @@
     SyncTexture,
     ConfirmTexture: PTexture;
     cScaleFactor: GLfloat;
+    cStereoDepth: GLfloat;
     SupportNPOTT: Boolean;
     Step: LongInt;
     squaresize : LongInt;
--- a/hedgewars/uWorld.pas	Mon May 28 01:51:50 2012 -0400
+++ b/hedgewars/uWorld.pas	Mon May 28 10:34:33 2012 +0200
@@ -77,7 +77,6 @@
     amSel: TAmmoType = amNothing;
     missionTex: PTexture;
     missionTimer: LongInt;
-    stereoDepth: GLfloat;
     isFirstFrame: boolean;
     AMAnimType: LongInt;
 
@@ -814,8 +813,9 @@
 
 procedure DrawWaves(Dir, dX, dY: LongInt; tnt: Byte);
 var VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
-    lw, waves, shift: GLfloat;
+    lw, waves: GLfloat;
     sprite: TSprite;
+    r: TSDL_Rect;
 begin
 if SuddenDeathDmg then
     sprite:= sprSDWater
@@ -825,7 +825,6 @@
 cWaveWidth:= SpritesData[sprite].Width;
 
 lw:= cScreenWidth / cScaleFactor;
-waves:= lw * 2 / cWaveWidth;
 
 if SuddenDeathDmg then
     Tint(LongInt(tnt) * SDWaterColorArray[2].r div 255 + 255 - tnt,
@@ -840,7 +839,7 @@
          255
     );
 
-glBindTexture(GL_TEXTURE_2D, SpritesData[sprite].Texture^.id);
+glBindTexture(GL_TEXTURE_2D, SpritesData[sprite].Texture^.atlas^.id);
 
 VertexBuffer[0].X:= -lw;
 VertexBuffer[0].Y:= cWaterLine + WorldDy + dY;
@@ -851,15 +850,12 @@
 VertexBuffer[3].X:= -lw;
 VertexBuffer[3].Y:= VertexBuffer[2].Y;
 
-shift:= - lw / cWaveWidth;
-TextureBuffer[0].X:= shift + (( - WorldDx + LongInt(RealTicks shr 6) * Dir + dX) mod cWaveWidth) / (cWaveWidth - 1);
-TextureBuffer[0].Y:= 0;
-TextureBuffer[1].X:= TextureBuffer[0].X + waves;
-TextureBuffer[1].Y:= TextureBuffer[0].Y;
-TextureBuffer[2].X:= TextureBuffer[1].X;
-TextureBuffer[2].Y:= SpritesData[sprite].Texture^.ry;
-TextureBuffer[3].X:= TextureBuffer[0].X;
-TextureBuffer[3].Y:= TextureBuffer[2].Y;
+// this uses texture repeat mode, when using an atlas rect we need to split to several quads here!
+r.x := -Trunc(lw) + (( - WorldDx + LongInt(RealTicks shr 6) * Dir + dX) mod cWaveWidth);
+r.y:= 0;
+r.w:= Trunc(lw + lw);
+r.h:= SpritesData[sprite].Texture^.h;
+ComputeTexcoords(SpritesData[sprite].Texture, @r, @TextureBuffer);
 
 
 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
@@ -1083,10 +1079,8 @@
         exit
     else if rm = rmLeftEye then
         d:= -d;
-    stereoDepth:= stereoDepth + d;
-    glMatrixMode(GL_PROJECTION);
-    glTranslatef(d, 0, 0);
-    glMatrixMode(GL_MODELVIEW);
+    cStereoDepth:= cStereoDepth + d;
+    UpdateProjection;
 {$ENDIF}
 end;
  
@@ -1098,10 +1092,8 @@
 {$ELSE}
     if rm = rmDefault then
         exit;
-    glMatrixMode(GL_PROJECTION);
-    glTranslatef(-stereoDepth, 0, 0);
-    glMatrixMode(GL_MODELVIEW);
-    stereoDepth:= 0;
+    cStereoDepth:= 0;
+    UpdateProjection;
 {$ENDIF}
 end;
  
@@ -1822,14 +1814,13 @@
     missionTimer:= 0;
     missionTex:= nil;
     cOffsetY:= 0;
-    stereoDepth:= 0;
+    cStereoDepth:= 0;
     AMState:= AMHidden;
     isFirstFrame:= true;
 end;
 
 procedure freeModule;
 begin
-    stereoDepth:= stereoDepth; // avoid hint
     FreeTexture(fpsTexture);
     fpsTexture:= nil;
     FreeTexture(timeTexture);
--- a/share/hedgewars/Data/CMakeLists.txt	Mon May 28 01:51:50 2012 -0400
+++ b/share/hedgewars/Data/CMakeLists.txt	Mon May 28 10:34:33 2012 +0200
@@ -1,3 +1,3 @@
-foreach(dir "Fonts" "Forts" "Graphics" "Locale" "Maps" "Music" "Sounds" "Themes" "Missions" "Names" "misc" "Scripts")
+foreach(dir "Fonts" "Forts" "Graphics" "Locale" "Maps" "Music" "Sounds" "Themes" "Missions" "Names" "misc" "Scripts" "Shaders")
   add_subdirectory(${dir})
 endforeach(dir)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Shaders/CMakeLists.txt	Mon May 28 10:34:33 2012 +0200
@@ -0,0 +1,5 @@
+file(GLOB BaseShaders *.vs *.fs)
+
+install(FILES
+	${BaseShaders}
+	DESTINATION ${SHAREPATH}Data/Shaders)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Shaders/default.fs	Mon May 28 10:34:33 2012 +0200
@@ -0,0 +1,9 @@
+// !!!just testing!!! 
+// This is not GLSL 1.3+ compatible, as its using the compatibility profile!
+uniform sampler2D tex0;
+varying vec4 tint;
+
+void main()
+{
+    gl_FragColor = texture2D(tex0, gl_TexCoord[0].st) * tint;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Shaders/default.vs	Mon May 28 10:34:33 2012 +0200
@@ -0,0 +1,10 @@
+// !!!just testing!!! 
+// This is not GLSL 1.3+ compatible, as its using the compatibility profile!
+varying vec4 tint;
+
+void main()
+{
+    gl_Position = ftransform();
+    gl_TexCoord[0] = gl_MultiTexCoord0;
+    tint = gl_Color;
+}