hedgewars/uStore.pas
branchwebgl
changeset 8026 4a4f21070479
parent 7866 58d10edc5d21
child 8032 f8fcece14302
--- a/hedgewars/uStore.pas	Sun Nov 11 16:53:16 2012 +0100
+++ b/hedgewars/uStore.pas	Sun Nov 11 17:15:19 2012 +0100
@@ -21,7 +21,10 @@
 
 unit uStore;
 interface
-uses {$IFNDEF PAS2C} StrUtils, {$ENDIF}SysUtils, uConsts, SDLh, GLunit, uTypes, uLandTexture, uCaptions, uChat;
+uses SysUtils, uConsts, SDLh, GLunit, uTypes, uLandTexture, uCaptions, uChat
+     {$IFDEF GL2}, uMatrix{$ENDIF}
+     {$IFNDEF PAS2C}, StrUtils{$ENDIF}
+     ;
 
 procedure initModule;
 procedure freeModule;
@@ -55,6 +58,17 @@
 procedure WarpMouse(x, y: Word); inline;
 procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF};
 
+{$IFDEF GL2}
+procedure UpdateModelviewProjection;
+procedure EnableTexture(enable:Boolean);
+{$ENDIF}
+
+procedure SetTexCoordPointer(p: Pointer;n: Integer);
+procedure SetVertexPointer(p: Pointer;n: Integer);
+procedure SetColorPointer(p: Pointer;n: Integer);
+procedure BeginWater;
+procedure EndWater;
+
 implementation
 uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands,
      uDebug{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF}
@@ -70,6 +84,17 @@
     SDLPrimSurface: PSDL_Surface;
 {$ENDIF}
 
+{$IFDEF GL2}
+    shaderMain: GLuint;
+    shaderWater: GLuint;
+
+    // attributes
+{$ENDIF}
+
+{$IFDEF WEBGL}
+    OpenGLSetupedBefore : boolean;
+{$ENDIF}
+
 function WriteInRect(Surface: PSDL_Surface; X, Y: LongInt; Color: LongWord; Font: THWFont; s: ansistring): TSDL_Rect;
 var w, h: LongInt;
     tmpsurf: PSDL_Surface;
@@ -303,7 +328,7 @@
     i, imflags: LongInt;
 begin
 AddFileLog('StoreLoad()');
-
+WriteLnToConsole('Entering StoreLoad');
 if not reload then
     for fi:= Low(THWFont) to High(THWFont) do
         with Fontz[fi] do
@@ -434,6 +459,8 @@
 if not reload then
     AddProgress;
 IMG_Quit();
+
+WriteLnToConsole('Leaving StoreLoad');
 end;
 
 {$IF NOT DEFINED(S3D_DISABLED) OR DEFINED(USE_VIDEO_RECORDING)}
@@ -662,7 +689,7 @@
 
 function glLoadExtension(extension : shortstring) : boolean;
 begin
-{$IF GLunit = gles11}
+{$IF (GLunit = gles11) OR DEFINED(PAS2C)}
     // FreePascal doesnt come with OpenGL ES 1.1 Extension headers
     extension:= extension; // avoid hint
     glLoadExtension:= false;
@@ -696,12 +723,117 @@
     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;
+    
+    Close(f);
+
+    WriteLnToConsole('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
+        log := GetMem(logLength);
+        glGetShaderInfoLog(shader, logLength, nil, log);
+        WriteLnToConsole('========== Compiler log  ==========');
+        WriteLnToConsole(shortstring(log));
+        WriteLnToConsole('===================================');
+        FreeMem(log, logLength);
+    end;
+
+    if compileResult <> GL_TRUE then
+    begin
+        WriteLnToConsole('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);
+
+    glBindAttribLocation(program_, aVertex, PChar('vertex'));
+    glBindAttribLocation(program_, aTexCoord, PChar('texcoord'));
+    glBindAttribLocation(program_, aColor, PChar('color'));
+
+    glLinkProgram(program_);
+    glDeleteShader(vs);
+    glDeleteShader(fs);
+
+    glGetProgramiv(program_, GL_LINK_STATUS, @linkResult);
+    glGetProgramiv(program_, GL_INFO_LOG_LENGTH, @logLength);
+
+    if logLength > 1 then
+    begin
+        log := GetMem(logLength);
+        glGetProgramInfoLog(program_, logLength, nil, log);
+        WriteLnToConsole('========== Compiler log  ==========');
+        WriteLnToConsole(shortstring(log));
+        WriteLnToConsole('===================================');
+        FreeMem(log, logLength);
+    end;
+
+    if linkResult <> GL_TRUE then
+    begin
+        WriteLnToConsole('Linking program failed, halting');
+        halt(-1);
+    end;
+
+    CompileProgram:= program_;
+end;
+
+{$ENDIF}
+
 procedure SetupOpenGL;
 //var vendor: shortstring = '';
 var buf: array[byte] of char;
-{$IFDEF USE_VIDEO_RECORDING}
-    AuxBufNum: LongInt;
-{$ENDIF}
+{$IFDEF PAS2C}err: GLenum;{$ENDIF}
+{$IFDEF USE_VIDEO_RECORDING}AuxBufNum: LongInt;{$ENDIF}
     tmpstr: AnsiString;
     tmpint: LongInt;
     tmpn: LongInt;
@@ -709,6 +841,19 @@
     buf[0]:= char(0); // avoid compiler hint
     AddFileLog('Setting up OpenGL (using driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))) + ')');
 
+{$IFDEF WEBGL}
+    if OpenGLSetupedBefore then
+        begin
+        glViewport(0, 0, cScreenWidth, cScreenHeight);
+        hglMatrixMode(MATRIX_MODELVIEW);
+        hglLoadIdentity();
+        hglScalef(2.0 / cScreenWidth, -2.0 / cScreenHeight, 1.0);
+        hglTranslatef(0, -cScreenHeight / 2, 0);
+        exit;
+        end
+    OpenGLSetupedBefore := true;
+{$ENDIF}
+
 {$IFDEF SDL13}
     // this function creates an opengles1.1 context by default on mobile devices
     // unless you un-comment this two attributes
@@ -733,7 +878,8 @@
         AddFileLog('Texture size too small for backgrounds, disabling.');
         end;
 
-(*  // find out which gpu we are using (for extension compatibility maybe?)
+(*
+    // find out which gpu we are using (for extension compatibility maybe?)
 {$IFDEF IPHONEOS}
     vendor:= vendor; // avoid hint
     cGPUVendor:= gvApple;
@@ -760,8 +906,12 @@
     glGetIntegerv(GL_AUX_BUFFERS, @AuxBufNum);
     AddFileLog('  |----- Number of auxiliary buffers: ' + inttostr(AuxBufNum));
 {$ENDIF}
+{$IFDEF PAS2C}
+
+    // doesn't seem to print >256 chars
+    AddFileLogRaw(PChar(glGetString(GL_EXTENSIONS)));
+{$ELSE}
     AddFileLog('  \----- Extensions: ');
-{$IFNDEF PAS2C}
     // fetch extentions and store them in string
     tmpstr := StrPas(PChar(glGetString(GL_EXTENSIONS)));
     tmpn := WordCount(tmpstr, [' ']);
@@ -779,9 +929,6 @@
         tmpint := tmpint + 3;
     end;
     until (tmpint > tmpn);
-{$ELSE}
-    // doesn't seem to print >256 chars
-    AddFileLogRaw(PChar(glGetString(GL_EXTENSIONS)));
 {$ENDIF}
     AddFileLog('');
 
@@ -810,6 +957,39 @@
     end;
 {$ENDIF}
 
+{$IFDEF GL2}
+
+{$IFDEF PAS2C}
+    err := glewInit();
+    if err <> GLEW_OK then
+    begin
+        WriteLnToConsole('Failed to initialize GLEW.');
+        halt;
+    end;
+{$ENDIF}
+
+{$IFNDEF PAS2C}
+    if not Load_GL_VERSION_2_0 then
+        halt;
+{$ENDIF}
+
+    shaderWater:= CompileProgram('water');
+    glUseProgram(shaderWater);
+    glUniform1i(glGetUniformLocation(shaderWater, pchar('tex0')), 0);
+    uWaterMVPLocation:= glGetUniformLocation(shaderWater, pchar('mvp'));
+
+    shaderMain:= CompileProgram('default');
+    glUseProgram(shaderMain);
+    glUniform1i(glGetUniformLocation(shaderMain, pchar('tex0')), 0);
+    uMainMVPLocation:= glGetUniformLocation(shaderMain, pchar('mvp'));
+    uMainTintLocation:= glGetUniformLocation(shaderMain, pchar('tint'));
+
+    uCurrentMVPLocation:= uMainMVPLocation;
+
+    Tint(255, 255, 255, 255);
+    UpdateModelviewProjection;
+{$ENDIF}
+
 {$IFNDEF S3D_DISABLED}
     if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then
     begin
@@ -827,18 +1007,31 @@
     end;
 {$ENDIF}
 
-    // set view port to whole window
-    glViewport(0, 0, cScreenWidth, cScreenHeight);
+// set view port to whole window
+glViewport(0, 0, cScreenWidth, cScreenHeight);
 
+{$IFDEF GL2}
+    uMatrix.initModule;
+    hglMatrixMode(MATRIX_MODELVIEW);
+    // prepare default translation/scaling
+    hglLoadIdentity();
+    hglScalef(2.0 / cScreenWidth, -2.0 / cScreenHeight, 1.0);
+    hglTranslatef(0, -cScreenHeight / 2, 0);
+
+    EnableTexture(True);
+    
+    glEnableVertexAttribArray(aVertex);
+    glEnableVertexAttribArray(aTexCoord);
+    glGenBuffers(1, @vBuffer);
+    glGenBuffers(1, @tBuffer);
+    glGenBuffers(1, @cBuffer);
+{$ELSE}
     glMatrixMode(GL_MODELVIEW);
     // prepare default translation/scaling
     glLoadIdentity();
     glScalef(2.0 / cScreenWidth, -2.0 / cScreenHeight, 1.0);
     glTranslatef(0, -cScreenHeight / 2, 0);
 
-    // enable alpha blending
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     // disable/lower perspective correction (will not need it anyway)
     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
     // disable dithering
@@ -847,8 +1040,92 @@
     glEnable(GL_TEXTURE_2D);
     glEnableClientState(GL_VERTEX_ARRAY);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+{$ENDIF}
+
+    // enable alpha blending
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    // disable/lower perspective correction (will not need it anyway)
 end;
 
+{$IFDEF GL2}
+procedure EnableTexture(enable:Boolean);
+begin
+    if enable then
+        glUniform1i(glGetUniformLocation(shaderMain, pchar('enableTexture')), 1)
+    else
+        glUniform1i(glGetUniformLocation(shaderMain, pchar('enableTexture')), 0);
+end;
+{$ENDIF}
+
+procedure SetTexCoordPointer(p: Pointer; n: Integer);
+begin
+    {$IFDEF GL2}
+    glBindBuffer(GL_ARRAY_BUFFER, tBuffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * n * 2, p, GL_STATIC_DRAW);
+    glEnableVertexAttribArray(aTexCoord);
+    glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 0, pointer(0));
+    {$ELSE}
+    glTexCoordPointer(2, GL_FLOAT, 0, p);
+    {$ENDIF}
+end;
+
+procedure SetVertexPointer(p: Pointer; n: Integer);
+begin
+    {$IFDEF GL2}
+    glBindBuffer(GL_ARRAY_BUFFER, vBuffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * n * 2, p, GL_STATIC_DRAW);
+    glEnableVertexAttribArray(aVertex);
+    glVertexAttribPointer(aVertex, 2, GL_FLOAT, GL_FALSE, 0, pointer(0));
+    {$ELSE}
+    glVertexPointer(2, GL_FLOAT, 0, p);
+    {$ENDIF}
+end;
+
+procedure SetColorPointer(p: Pointer; n: Integer);
+begin
+    {$IFDEF GL2}
+    glBindBuffer(GL_ARRAY_BUFFER, cBuffer);
+    glBufferData(GL_ARRAY_BUFFER, n * 4, p, GL_STATIC_DRAW);
+    glEnableVertexAttribArray(aColor);
+    glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, pointer(0));
+    {$ELSE}
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, p);
+    {$ENDIF}
+end;
+
+{$IFDEF GL2}
+procedure UpdateModelviewProjection;
+var
+    mvp: TMatrix4x4f;
+begin
+    //MatrixMultiply(mvp, mProjection, mModelview);
+    hglMVP(mvp);
+    glUniformMatrix4fv(uCurrentMVPLocation, 1, GL_FALSE, @mvp[0, 0]);
+end;
+{$ENDIF}
+
+(*
+procedure UpdateProjection;
+var
+    s: GLfloat;
+begin
+    s:=cScaleFactor;
+    mProjection[0,0]:= s/cScreenWidth; mProjection[0,1]:=  0.0;             mProjection[0,2]:=0.0; mProjection[0,3]:=  0.0;
+    mProjection[1,0]:= 0.0;            mProjection[1,1]:= -s/cScreenHeight; mProjection[1,2]:=0.0; mProjection[1,3]:=  0.0;
+    mProjection[2,0]:= 0.0;            mProjection[2,1]:=  0.0;             mProjection[2,2]:=1.0; mProjection[2,3]:=  0.0;
+    mProjection[3,0]:= cStereoDepth;   mProjection[3,1]:=  s/2;             mProjection[3,2]:=0.0; mProjection[3,3]:=  1.0;
+
+    {$IFDEF GL2}
+    UpdateModelviewProjection;
+    {$ELSE}
+    glMatrixMode(GL_PROJECTION);
+    glLoadMatrixf(@mProjection[0, 0]);
+    glMatrixMode(GL_MODELVIEW);
+    {$ENDIF}    
+end;
+*)
+
 procedure SetScale(f: GLfloat);
 begin
 // leave immediately if scale factor did not change
@@ -856,18 +1133,62 @@
         exit;
 
     if f = cDefaultZoomLevel then
-        glPopMatrix         // "return" to default scaling
+{$IFDEF GL2}
+        hglPopMatrix         // "return" to default scaling
+{$ELSE}
+        glPopMatrix
+{$ENDIF}
     else                    // other scaling
         begin
+{$IFDEF GL2}
+        hglPushMatrix;       // save default scaling
+        hglLoadIdentity;
+        hglScalef(f / cScreenWidth, -f / cScreenHeight, 1.0);
+        hglTranslatef(0, -cScreenHeight / 2, 0);
+{$ELSE}
         glPushMatrix;       // save default scaling
         glLoadIdentity;
         glScalef(f / cScreenWidth, -f / cScreenHeight, 1.0);
         glTranslatef(0, -cScreenHeight / 2, 0);
+{$ENDIF}
         end;
 
     cScaleFactor:= f;
+
+{$IFDEF GL2}
+    UpdateModelviewProjection;
+{$ENDIF}
 end;
 
+procedure BeginWater;
+begin
+    {$IFDEF GL2}
+    glUseProgram(shaderWater);
+    uCurrentMVPLocation:=uWaterMVPLocation;
+    UpdateModelviewProjection;
+    glDisableVertexAttribArray(aTexCoord);
+    glEnableVertexAttribArray(aColor);
+    {$ELSE}
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glEnableClientState(GL_COLOR_ARRAY);
+    {$ENDIF}
+end;
+
+procedure EndWater;
+begin
+    {$IFDEF GL2}
+    glUseProgram(shaderMain);
+    uCurrentMVPLocation:=uMainMVPLocation;
+    UpdateModelviewProjection;
+    glDisableVertexAttribArray(aColor);
+    glEnableVertexAttribArray(aTexCoord);
+    {$ELSE}
+    glDisableClientState(GL_COLOR_ARRAY);
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+    {$ENDIF}
+end;
+
+
 ////////////////////////////////////////////////////////////////////////////////
 procedure AddProgress;
 var r: TSDL_Rect;
@@ -902,6 +1223,7 @@
     DrawTextureFromRect( -squaresize div 2, (cScreenHeight - squaresize) shr 1, @r, ProgrTex);
 
     SwapBuffers;
+
     inc(Step);
 end;
 
@@ -1178,9 +1500,11 @@
     {$ENDIF}
         AddFileLog('Freeing old primary surface...');
     {$IFNDEF SDL13}        
+    {$IFNDEF WEBGL}
         SDL_FreeSurface(SDLPrimSurface);
         SDLPrimSurface:= nil;
     {$ENDIF}
+    {$ENDIF}
 {$ENDIF}
         end;
 
@@ -1230,6 +1554,7 @@
 {$ENDIF}
 
     SetupOpenGL();
+
     if reinit then
         begin
         // clean the window from any previous content
@@ -1261,6 +1586,10 @@
     ProgrTex:= nil;
     SupportNPOTT:= false;
 
+{$IFDEF WEBGL}
+    OpenGLSetupedBefore := false;
+{$ENDIF}
+
     // init all ammo name texture pointers
     for ai:= Low(TAmmoType) to High(TAmmoType) do
     begin
@@ -1279,6 +1608,13 @@
 
 procedure freeModule;
 begin
+{$IFDEF GL2}
+    glDeleteProgram(shaderMain);
+    glDeleteProgram(shaderWater);
+    glDeleteBuffers(1, @vBuffer);
+    glDeleteBuffers(1, @tBuffer);
+    glDeleteBuffers(1, @cBuffer);
+{$ENDIF}
     StoreRelease(false);
     TTF_Quit();
 {$IFDEF SDL13}