# HG changeset patch # User Wolfgang Steffens # Date 1338194073 -7200 # Node ID 6f3c9ec793388aab3b50d11f4b60d940f2da3792 # Parent 0ce4f478ea6c849c30e44fbc557d962bf752e29c# Parent 4d863aadd0b2662f06b00c42cbebf2e28da7c416 merge diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/hwengine.pas --- 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; diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/options.inc --- 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} diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uGearsRender.pas --- 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 diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uLandTexture.pas --- 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; diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uRender.pas --- 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. diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uStore.pas --- 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} diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uTextures.pas --- 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; diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uTypes.pas --- 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; diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uVariables.pas --- 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; diff -r 4d863aadd0b2 -r 6f3c9ec79338 hedgewars/uWorld.pas --- 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); diff -r 4d863aadd0b2 -r 6f3c9ec79338 share/hedgewars/Data/CMakeLists.txt --- 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) diff -r 4d863aadd0b2 -r 6f3c9ec79338 share/hedgewars/Data/Shaders/CMakeLists.txt --- /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) diff -r 4d863aadd0b2 -r 6f3c9ec79338 share/hedgewars/Data/Shaders/default.fs --- /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; +} diff -r 4d863aadd0b2 -r 6f3c9ec79338 share/hedgewars/Data/Shaders/default.vs --- /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; +}