diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uStore.pas --- a/hedgewars/uStore.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uStore.pas Sun Sep 16 16:54:51 2012 +0200 @@ -21,7 +21,7 @@ unit uStore; interface -uses SysUtils, uConsts, SDLh, GLunit, uTypes, uLandTexture, uCaptions, uChat; +uses {$IFNDEF PAS2C} StrUtils, {$ENDIF}SysUtils, uConsts, SDLh, GLunit, uTypes, uLandTexture, uCaptions, uChat; procedure initModule; procedure freeModule; @@ -32,6 +32,14 @@ procedure AddProgress; procedure FinishProgress; function LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface; + +// loads an image from the game's data files +function LoadDataImage(const path: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +// like LoadDataImage but uses altPath as fallback-path if file not found/loadable in path +function LoadDataImageAltPath(const path, altPath: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +// like LoadDataImage but uses altFile as fallback-filename if file cannot be loaded +function LoadDataImageAltFile(const path: TPathType; const filename, altFile: shortstring; imageFlags: LongInt): PSDL_Surface; + procedure LoadHedgehogHat(HHGear: PGear; newHat: shortstring); procedure SetupOpenGL; procedure SetScale(f: GLfloat); @@ -40,13 +48,17 @@ procedure ShowWeaponTooltip(x, y: LongInt); procedure FreeWeaponTooltip; procedure MakeCrossHairs; +{$IFDEF USE_VIDEO_RECORDING} +procedure InitOffscreenOpenGL; +{$ENDIF} procedure WarpMouse(x, y: Word); inline; procedure SwapBuffers; inline; implementation uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands, - uDebug{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF}; + uDebug{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF} + {$IF NOT DEFINED(SDL13) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF}; //type TGPUVendor = (gvUnknown, gvNVIDIA, gvATI, gvIntel, gvApple); @@ -91,9 +103,7 @@ Color, i: Longword; s: shortstring; begin -s:= UserPathz[ptGraphics] + '/' + cCHFileName; -if not FileExists(s+'.png') then s:= Pathz[ptGraphics] + '/' + cCHFileName; -tmpsurf:= LoadImage(s, ifAlpha or ifCritical); +tmpsurf:= LoadDataImage(ptGraphics, cCHFileName, ifAlpha or ifCritical); for t:= 0 to Pred(TeamsCount) do with TeamsArray[t]^ do @@ -196,13 +206,7 @@ else if (Flag = 'cpu') or (Flag = 'cpu_plain') then Flag:= 'hedgewars'; - flagsurf:= LoadImage(UserPathz[ptFlags] + '/' + Flag, ifNone); - if flagsurf = nil then - flagsurf:= LoadImage(Pathz[ptFlags] + '/' + Flag, ifNone); - if flagsurf = nil then - flagsurf:= LoadImage(UserPathz[ptFlags] + '/hedgewars', ifNone); - if flagsurf = nil then - flagsurf:= LoadImage(Pathz[ptFlags] + '/hedgewars', ifNone); + flagsurf:= LoadDataImageAltFile(ptFlags, Flag, 'hedgewars', ifNone); TryDo(flagsurf <> nil, 'Failed to load flag "' + Flag + '" as well as the default flag', true); case maxLevel of @@ -247,9 +251,7 @@ end end; end; - MissionIcons:= LoadImage(UserPathz[ptGraphics] + '/missions', ifNone); - if MissionIcons = nil then - MissionIcons:= LoadImage(Pathz[ptGraphics] + '/missions', ifCritical); + MissionIcons:= LoadDataImage(ptGraphics, 'missions', ifCritical); iconsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, 28, 28, 32, RMask, GMask, BMask, AMask); if iconsurf <> nil then begin @@ -287,13 +289,7 @@ begin if GraveName = '' then GraveName:= 'Statue'; - texsurf:= LoadImage(UserPathz[ptGraves] + '/' + GraveName, ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptGraves] + '/' + GraveName, ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(UserPathz[ptGraves] + '/Statue', ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptGraves] + '/Statue', ifCritical or ifTransparent); + texsurf:= LoadDataImageAltFile(ptGraves, GraveName, 'Statue', ifCritical or ifTransparent); GraveTex:= Surface2Tex(texsurf, false); SDL_FreeSurface(texsurf) end @@ -305,7 +301,7 @@ fi: THWFont; ai: TAmmoType; tmpsurf: PSDL_Surface; - i: LongInt; + i, imflags: LongInt; begin AddFileLog('StoreLoad()'); @@ -338,43 +334,18 @@ ((cCloudsNumber > 0) or (ii <> sprCloud)) and ((vobCount > 0) or (ii <> sprFlake)) then begin - if AltPath = ptNone then - if ii in [sprHorizont, sprHorizontL, sprHorizontR, sprSky, sprSkyL, sprSkyR, sprChunk] then // FIXME: hack - begin - if not reload then - begin - tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent) - end - else - tmpsurf:= Surface - end - else - begin - if not reload then - begin - tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent or ifCritical) - end - else - tmpsurf:= Surface - end + if reload then + tmpsurf:= Surface else begin - if not reload then - begin - tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(UserPathz[AltPath] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[AltPath] + '/' + FileName, ifAlpha or ifCritical or ifTransparent) - end - else - tmpsurf:= Surface + imflags := (ifAlpha or ifTransparent); + + // these sprites are optional + if not (ii in [sprHorizont, sprHorizontL, sprHorizontR, sprSky, sprSkyL, sprSkyR, sprChunk]) then // FIXME: hack + imflags := (imflags or ifCritical); + + // load the image + tmpsurf := LoadDataImageAltPath(Path, AltPath, FileName, imflags) end; if tmpsurf <> nil then @@ -424,10 +395,8 @@ if not reload then AddProgress; - tmpsurf:= LoadImage(UserPathz[ptGraphics] + '/' + cHHFileName, ifAlpha or ifTransparent); -if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptGraphics] + '/' + cHHFileName, ifAlpha or ifCritical or ifTransparent); - +tmpsurf:= LoadDataImage(ptGraphics, cHHFileName, ifAlpha or ifCritical or ifTransparent); + HHTexture:= Surface2Tex(tmpsurf, false); SDL_FreeSurface(tmpsurf); @@ -468,6 +437,31 @@ IMG_Quit(); end; +{$IF NOT DEFINED(S3D_DISABLED) OR DEFINED(USE_VIDEO_RECORDING)} +procedure CreateFramebuffer(var frame, depth, tex: GLuint); +begin + glGenFramebuffersEXT(1, @frame); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame); + glGenRenderbuffersEXT(1, @depth); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth); + glGenTextures(1, @tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0); +end; + +procedure DeleteFramebuffer(var frame, depth, tex: GLuint); +begin + glDeleteTextures(1, @tex); + glDeleteRenderbuffersEXT(1, @depth); + glDeleteFramebuffersEXT(1, @frame); +end; +{$ENDIF} + procedure StoreRelease(reload: boolean); var ii: TSprite; ai: TAmmoType; @@ -541,15 +535,15 @@ end; end; end; +{$IFDEF USE_VIDEO_RECORDING} + if defaultFrame <> 0 then + DeleteFramebuffer(defaultFrame, depthv, texv); +{$ENDIF} {$IFNDEF S3D_DISABLED} if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then begin - glDeleteTextures(1, @texl); - glDeleteRenderbuffersEXT(1, @depthl); - glDeleteFramebuffersEXT(1, @framel); - glDeleteTextures(1, @texr); - glDeleteRenderbuffersEXT(1, @depthr); - glDeleteFramebuffersEXT(1, @framer) + DeleteFramebuffer(framel, depthl, texl); + DeleteFramebuffer(framer, depthr, texr); end {$ENDIF} end; @@ -598,12 +592,59 @@ LoadImage:= tmpsurf //Result end; + +function LoadDataImage(const path: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +var tmpsurf: PSDL_Surface; +begin + // check for file in user dir (never critical) + tmpsurf:= LoadImage(UserPathz[path] + '/' + filename, imageFlags and (not ifCritical)); + + // if unsuccessful check data dir + if (tmpsurf = nil) then + tmpsurf:= LoadImage(Pathz[path] + '/' + filename, imageFlags); + + LoadDataImage:= tmpsurf; +end; + + +function LoadDataImageAltPath(const path, altPath: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +var tmpsurf: PSDL_Surface; +begin + // if there is no alternative path, just forward and return result + if (altPath = ptNone) then + exit(LoadDataImage(path, filename, imageFlags)); + + // since we have a fallback path this search isn't critical yet + tmpsurf:= LoadDataImage(path, filename, imageFlags and (not ifCritical)); + + // if image still not found try alternative path + if (tmpsurf = nil) then + tmpsurf:= LoadDataImage(altPath, filename, imageFlags); + + LoadDataImageAltPath:= tmpsurf; +end; + +function LoadDataImageAltFile(const path: TPathType; const filename, altFile: shortstring; imageFlags: LongInt): PSDL_Surface; +var tmpsurf: PSDL_Surface; +begin + // if there is no alternative filename, just forward and return result + if (altFile = '') then + exit(LoadDataImage(path, filename, imageFlags)); + + // since we have a fallback filename this search isn't critical yet + tmpsurf:= LoadDataImage(path, filename, imageFlags and (not ifCritical)); + + // if image still not found try alternative filename + if (tmpsurf = nil) then + tmpsurf:= LoadDataImage(path, altFile, imageFlags); + + LoadDataImageAltFile:= tmpsurf; +end; + procedure LoadHedgehogHat(HHGear: PGear; newHat: shortstring); var texsurf: PSDL_Surface; begin -texsurf:= LoadImage(UserPathz[ptHats] + '/' + newHat, ifNone); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptHats] + '/' + newHat, ifNone); + texsurf:= LoadDataImage(ptHats, newHat, ifNone); // only do something if the hat could be loaded if texsurf <> nil then @@ -658,6 +699,12 @@ procedure SetupOpenGL; //var vendor: shortstring = ''; var buf: array[byte] of char; +{$IFDEF USE_VIDEO_RECORDING} + AuxBufNum: LongInt; +{$ENDIF} + tmpstr: AnsiString; + tmpint: LongInt; + tmpn: LongInt; begin buf[0]:= char(0); // avoid compiler hint AddFileLog('Setting up OpenGL (using driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))) + ')'); @@ -709,8 +756,59 @@ AddFileLog(' |----- Vendor: ' + shortstring(pchar(glGetString(GL_VENDOR)))); AddFileLog(' |----- Version: ' + shortstring(pchar(glGetString(GL_VERSION)))); AddFileLog(' |----- Texture Size: ' + inttostr(MaxTextureSize)); - AddFileLog(' \----- Extensions: ' + shortstring(pchar(glGetString(GL_EXTENSIONS)))); - //TODO: don't have the Extensions line trimmed but slipt it into multiple lines +{$IFDEF USE_VIDEO_RECORDING} + glGetIntegerv(GL_AUX_BUFFERS, @AuxBufNum); + AddFileLog(' |----- Number of auxiliary buffers: ' + inttostr(AuxBufNum)); +{$ENDIF} + AddFileLog(' \----- Extensions: '); +{$IFNDEF PAS2C} + // fetch extentions and store them in string + tmpstr := StrPas(PChar(glGetString(GL_EXTENSIONS))); + tmpn := WordCount(tmpstr, [' ']); + tmpint := 1; + + repeat + begin + // print up to 3 extentions per row + // ExtractWord will return empty string if index out of range + AddFileLog(TrimRight( + ExtractWord(tmpint, tmpstr, [' ']) + ' ' + + ExtractWord(tmpint+1, tmpstr, [' ']) + ' ' + + ExtractWord(tmpint+2, tmpstr, [' ']) + )); + tmpint := tmpint + 3; + end; + until (tmpint > tmpn); +{$ELSE} + // doesn't seem to print >256 chars + AddFileLogRaw(PChar(glGetString(GL_EXTENSIONS))); +{$ENDIF} + AddFileLog(''); + + defaultFrame:= 0; +{$IFDEF USE_VIDEO_RECORDING} + if GameType = gmtRecord then + begin + if glLoadExtension('GL_EXT_framebuffer_object') then + begin + CreateFramebuffer(defaultFrame, depthv, texv); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame); + AddFileLog('Using framebuffer for video recording.'); + end + else if AuxBufNum > 0 then + begin + glDrawBuffer(GL_AUX0); + glReadBuffer(GL_AUX0); + AddFileLog('Using auxiliary buffer for video recording.'); + end + else + begin + glDrawBuffer(GL_BACK); + glReadBuffer(GL_BACK); + AddFileLog('Warning: off-screen rendering is not supported; using back buffer but it may not work.'); + end; + end; +{$ENDIF} {$IFNDEF S3D_DISABLED} if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then @@ -718,36 +816,11 @@ // prepare left and right frame buffers and associated textures if glLoadExtension('GL_EXT_framebuffer_object') then begin - // left - glGenFramebuffersEXT(1, @framel); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framel); - glGenRenderbuffersEXT(1, @depthl); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthl); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthl); - glGenTextures(1, @texl); - glBindTexture(GL_TEXTURE_2D, texl); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texl, 0); - - // right - glGenFramebuffersEXT(1, @framer); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framer); - glGenRenderbuffersEXT(1, @depthr); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthr); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthr); - glGenTextures(1, @texr); - glBindTexture(GL_TEXTURE_2D, texr); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texr, 0); + CreateFramebuffer(framel, depthl, texl); + CreateFramebuffer(framer, depthr, texr); // reset - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame) end else cStereoMode:= smNone; @@ -803,9 +876,7 @@ if Step = 0 then begin WriteToConsole(msgLoading + 'progress sprite: '); - texsurf:= LoadImage(UserPathz[ptGraphics] + '/Progress', ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptGraphics] + '/Progress', ifCritical or ifTransparent); + texsurf:= LoadDataImage(ptGraphics, 'Progress', ifCritical or ifTransparent); ProgrTex:= Surface2Tex(texsurf, false); @@ -1021,6 +1092,34 @@ WeaponTooltipTex:= nil end; +{$IFDEF USE_VIDEO_RECORDING} +{$IFDEF SDL13} +procedure InitOffscreenOpenGL; +begin + // create hidden window + SDLwindow:= SDL_CreateWindow('hedgewars (you don''t see this)', + SDL_WINDOWPOS_CENTERED_MASK, SDL_WINDOWPOS_CENTERED_MASK, + cScreenWidth, cScreenHeight, + SDL_WINDOW_HIDDEN or SDL_WINDOW_OPENGL); + SDLTry(SDLwindow <> nil, true); + SetupOpenGL(); +end; +{$ELSE} +procedure InitOffscreenOpenGL; +var ArgCount: LongInt; + PrgName: pchar; +begin + ArgCount:= 1; + PrgName:= 'hwengine'; + glutInit(@ArgCount, @PrgName); + glutInitWindowSize(cScreenWidth, cScreenHeight); + glutCreateWindow('hedgewars (you don''t see this)'); // we don't need a window, but if this function is not called then OpenGL will not be initialized + glutHideWindow(); + SetupOpenGL(); +end; +{$ENDIF} // SDL13 +{$ENDIF} // USE_VIDEO_RECORDING + procedure chFullScr(var s: shortstring); var flags: Longword = 0; reinit: boolean = false; @@ -1046,9 +1145,7 @@ WriteLnToConsole(msgOK); // load engine icon {$IFNDEF DARWIN} - ico:= LoadImage(UserPathz[ptGraphics] + '/hwengine', ifIgnoreCaps); - if ico = nil then - ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps); + ico:= LoadDataImage(ptGraphics, 'hwengine', ifIgnoreCaps); if ico <> nil then begin SDL_WM_SetIcon(ico, 0); @@ -1201,6 +1298,8 @@ procedure SwapBuffers; inline; begin + if GameType = gmtRecord then + exit; {$IFDEF SDL13} SDL_GL_SwapWindow(SDLwindow); {$ELSE}