X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Frenders%2Fopengl%2Fr_textures.pas;h=1f3f23885eaef05e98ac9303c6f89459a6e1b4b9;hb=1c7ee44e1a322dcb170a94d39b3a37f36a9a17bd;hp=d24c2ac6708ce570384f7335d34513ae3ee49eaa;hpb=f4dd4b6d0fcdfa236212949133d63b7174585b44;p=d2df-sdl.git diff --git a/src/game/renders/opengl/r_textures.pas b/src/game/renders/opengl/r_textures.pas index d24c2ac..1f3f238 100644 --- a/src/game/renders/opengl/r_textures.pas +++ b/src/game/renders/opengl/r_textures.pas @@ -23,8 +23,9 @@ interface {$ELSE} GL, GLEXT, {$ENDIF} - r_atlas, - utils // SSArray + g_base, g_animations, // TRectHW, TAnimInfo + utils, + r_atlas, r_fonts ; type @@ -81,7 +82,6 @@ interface TGLMultiTexture = class private mTexture: array of TGLTexture; - mBackanim: Boolean; public destructor Destroy; override; @@ -94,7 +94,30 @@ interface property width: Integer read GetWidth; property height: Integer read GetHeight; property count: Integer read GetCount; - property backAnim: Boolean read mBackanim; (* this property must be located at TAnimState? *) + end; + + TGLTextureArray = array of TGLTexture; + + TRectArray = array of TRectWH; + + TGLFont = class sealed (TFont) + private + info: TFontInfo; + ch: TGLTextureArray; + + public + destructor Destroy; override; + function GetChar (c: AnsiChar): TGLTexture; + function GetWidth (c: AnsiChar): Integer; + function GetMaxWidth (): Integer; + function GetMaxHeight (): Integer; + function GetSpace (): Integer; + end; + + TAnimTextInfo = record + name: AnsiString; + w, h: Integer; + anim: TAnimInfo; end; procedure r_Textures_Initialize; @@ -102,7 +125,12 @@ interface function r_Textures_LoadFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture; function r_Textures_LoadMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture; - function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; backanim: Boolean; log: Boolean = True): TGLMultiTexture; + function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; log: Boolean = True): TGLMultiTexture; + function r_Textures_LoadMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture; + + function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean; + + function r_Textures_LoadFontFromFile (const filename: AnsiString; constref f: TFontInfo; skipch: Integer; log: Boolean = true): TGLFont; implementation @@ -115,7 +143,6 @@ implementation var maxTileSize: Integer; atl: array of TGLAtlas; -// tex: array of TGLTexture; (* --------- TGLAtlasNode --------- *) @@ -360,10 +387,17 @@ implementation end; end; + function r_Textures_FixImageData (var img: TImageData): Boolean; + begin + result := false; + if ConvertImage(img, TImageFormat.ifA8R8G8B8) then + if SwapChannels(img, ChannelRed, ChannelBlue) then // wtf + result := true; + end; + function r_Textures_LoadFromImage (var img: TImageData): TGLTexture; var t: TGLTexture; n: TGLAtlasNode; c: TDynImageDataArray; cw, ch, i, j: LongInt; begin - // e_logwritefln('r_Textures_CreateFromImage: w=%s h=%s', [img.width, img.height]); result := nil; if SplitImage(img, c, maxTileSize, maxTileSize, cw, ch, False) then begin @@ -396,9 +430,8 @@ implementation InitImage(img); try if LoadImageFromMemory(data, size, img) then - if ConvertImage(img, TImageFormat.ifA8R8G8B8) then - if SwapChannels(img, ChannelRed, ChannelBlue) then // wth - result := r_Textures_LoadFromImage(img) + if r_Textures_FixImageData(img) then + result := r_Textures_LoadFromImage(img) except end; FreeImage(img); @@ -423,7 +456,7 @@ implementation end end; - function r_Textures_LoadMultiFromImageAndInfo (var img: TImageData; w, h, c: Integer; b: Boolean): TGLMultiTexture; + function r_Textures_LoadMultiFromImageAndInfo (var img: TImageData; w, h, c: Integer): TGLMultiTexture; var t: TImageData; a: array of TGLTexture; i: Integer; m: TGLMultiTexture; begin ASSERT(w >= 0); @@ -442,12 +475,11 @@ implementation end; m := TGLMultiTexture.Create(); m.mTexture := a; - m.mBackanim := b; ASSERT(m.mTexture <> nil); result := m; end; - function r_Textures_LoadMultiFromDataAndInfo (data: Pointer; size: LongInt; w, h, c: Integer; b: Boolean): TGLMultiTexture; + function r_Textures_LoadMultiFromDataAndInfo (data: Pointer; size: LongInt; w, h, c: Integer): TGLMultiTexture; var img: TImageData; begin ASSERT(w > 0); @@ -459,53 +491,65 @@ implementation InitImage(img); try if LoadImageFromMemory(data, size, img) then - if ConvertImage(img, TImageFormat.ifA8R8G8B8) then - if SwapChannels(img, ChannelRed, ChannelBlue) then // wtf - result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b) + if r_Textures_FixImageData(img) then + result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c) except end; FreeImage(img); end; end; - function r_Textures_LoadMultiFromWad (wad: TWADFile): TGLMultiTexture; - var data: Pointer; size: LongInt; TexRes: AnsiString; w, h, c: Integer; b: Boolean; cfg: TConfig; img: TImageData; + function r_Textures_LoadTextFromMemory (data: Pointer; size: LongInt; var txt: TAnimTextInfo): Boolean; + var cfg: TConfig; + begin + result := false; + if data <> nil then + begin + cfg := TConfig.CreateMem(data, size); + if cfg <> nil then + begin + txt.name := cfg.ReadStr('', 'resource', ''); + txt.w := MAX(0, cfg.ReadInt('', 'framewidth', 0)); + txt.h := MAX(0, cfg.ReadInt('', 'frameheight', 0)); + txt.anim.loop := true; + txt.anim.delay := MAX(0, cfg.ReadInt('', 'waitcount', 0)); + txt.anim.frames := MAX(0, cfg.ReadInt('', 'framecount', 0)); + txt.anim.back := cfg.ReadBool('', 'backanim', false); + cfg.Free; + result := (txt.name <> '') and (txt.w > 0) and (txt.h > 0) and (txt.anim.delay > 0) and (txt.anim.frames > 0); + end; + end; + end; + + function r_Textures_LoadMultiFromWad (wad: TWADFile; var txt: TAnimTextInfo): TGLMultiTexture; + var data: Pointer; size: LongInt; img: TImageData; begin ASSERT(wad <> nil); result := nil; if wad.GetResource('TEXT/ANIM', data, size) then begin - cfg := TConfig.CreateMem(data, size); - FreeMem(data); - if cfg <> nil then + if r_Textures_LoadTextFromMemory(data, size, txt) then begin - TexRes := cfg.ReadStr('', 'resource', ''); - w := cfg.ReadInt('', 'framewidth', 0); - h := cfg.ReadInt('', 'frameheight', 0); - c := cfg.ReadInt('', 'framecount', 0); - b := cfg.ReadBool('', 'backanim', false); - if (TexRes <> '') and (w > 0) and (h > 0) and (c > 0) then + FreeMem(data); + if wad.GetResource('TEXTURES/' + txt.name, data, size) then begin - if wad.GetResource('TEXTURES/' + TexRes, data, size) then - begin - InitImage(img); - try - if LoadImageFromMemory(data, size, img) then - if ConvertImage(img, TImageFormat.ifA8R8G8B8) then - if SwapChannels(img, ChannelRed, ChannelBlue) then // wtf - result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b) - finally - FreeMem(data); - end; - FreeImage(img); - end + InitImage(img); + try + if LoadImageFromMemory(data, size, img) then + if r_Textures_FixImageData(img) then + result := r_Textures_LoadMultiFromImageAndInfo(img, txt.w, txt.h, txt.anim.frames); + finally + FreeMem(data); + end; + FreeImage(img); end; - cfg.Free; end + else + FreeMem(data); end; end; - function r_Textures_LoadMultiFromMemory (data: Pointer; size: LongInt): TGLMultiTexture; + function r_Textures_LoadMultiFromMemory (data: Pointer; size: LongInt; var txt: TAnimTextInfo): TGLMultiTexture; var wad: TWADFile; t: TGLTexture; m: TGLMultiTexture; begin result := nil; @@ -517,7 +561,13 @@ implementation m := TGLMultiTexture.Create(); SetLength(m.mTexture, 1); m.mTexture[0] := t; - m.mBackanim := false; + txt.name := ''; + txt.w := m.width; + txt.h := m.height; + txt.anim.loop := true; + txt.anim.delay := 1; + txt.anim.frames := 1; + txt.anim.back := false; result := m; end else if IsWadData(data, size) then @@ -525,15 +575,15 @@ implementation wad := TWADFile.Create(); if wad.ReadMemory(data, size) then begin - result := r_Textures_LoadMultiFromWad(wad); + result := r_Textures_LoadMultiFromWad(wad, txt); wad.Free; end end end end; - function r_Textures_LoadMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture; - var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; t: TGLTexture; + function r_Textures_LoadMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture; + var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; begin result := nil; wadName := g_ExtractWadName(filename); @@ -543,14 +593,20 @@ implementation resName := g_ExtractFilePathName(filename); if wad.GetResource(resName, data, size, log) then begin - result := r_Textures_LoadMultiFromMemory(data, size); + result := r_Textures_LoadMultiFromMemory(data, size, txt); FreeMem(data); end; wad.Free end end; - function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; backanim: Boolean; log: Boolean = True): TGLMultiTexture; + function r_Textures_LoadMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture; + var txt: TAnimTextInfo; + begin + result := r_Textures_LoadMultiTextFromFile(filename, txt, log); + end; + + function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; log: Boolean = True): TGLMultiTexture; var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; begin ASSERT(w > 0); @@ -564,11 +620,215 @@ implementation resName := g_ExtractFilePathName(filename); if wad.GetResource(resName, data, size, log) then begin - result := r_Textures_LoadMultiFromDataAndInfo(data, size, w, h, count, backanim); + result := r_Textures_LoadMultiFromDataAndInfo(data, size, w, h, count); FreeMem(data); end; wad.Free end end; + function r_Textures_GetRect (var img: TImageData): TRectWH; + var i, j, w, h: Integer; done: Boolean; + + function IsVoid (i, j: Integer): Boolean; inline; + begin + result := GetPixel32(img, i, j).Channels[3] = 0 + end; + + begin + w := img.Width; + h := img.Height; + + (* trace x from right to left *) + done := false; i := 0; + while not done and (i < w) do + begin + j := 0; + while (j < h) and IsVoid(i, j) do inc(j); + done := (j < h) and (IsVoid(i, j) = false); + result.x := i; + inc(i); + end; + + (* trace y from up to down *) + done := false; j := 0; + while not done and (j < h) do + begin + i := 0; + while (i < w) and IsVoid(i, j) do inc(i); + done := (i < w) and (IsVoid(i, j) = false); + result.y := j; + inc(j); + end; + + (* trace x from right to left *) + done := false; i := w - 1; + while not done and (i >= 0) do + begin + j := 0; + while (j < h) and IsVoid(i, j) do inc(j); + done := (j < h) and (IsVoid(i, j) = false); + result.width := i - result.x + 1; + dec(i); + end; + + (* trace y from down to up *) + done := false; j := h - 1; + while not done and (j >= 0) do + begin + i := 0; + while (i < w) and IsVoid(i, j) do inc(i); + done := (i < w) and (IsVoid(i, j) = false); + result.height := j - result.y + 1; + dec(j); + end; + end; + + function r_Textures_LoadStreamFromImage (var img: TImageData; w, h, c, cw: Integer; st: TGLTextureArray; rs: TRectArray): Boolean; + var i, x, y: Integer; t: TImageData; + begin + ASSERT(w >= 0); + ASSERT(h >= 0); + ASSERT(c >= 1); + ASSERT(cw >= 1); + ASSERT((st <> nil) and (Length(st) >= c)); + ASSERT((rs = nil) or (Length(rs) >= c)); + result := true; + for i := 0 to c - 1 do + begin + x := i mod cw; + y := i div cw; + InitImage(t); + st[i] := nil; + if NewImage(w, h, img.Format, t) then + begin + if CopyRect(img, x * w, y * h, w, h, t, 0, 0) then + begin + if rs <> nil then + rs[i] := r_Textures_GetRect(t); + st[i] := r_Textures_LoadFromImage(t); + end; + end; + ASSERT(st[i] <> nil); + FreeImage(t); + end; + end; + + function r_Textures_LoadStreamFromMemory (data: Pointer; size: LongInt; w, h, c, cw: Integer; st: TGLTextureArray; rs: TRectArray): Boolean; + var img: TImageData; + begin + ASSERT(w >= 0); + ASSERT(h >= 0); + ASSERT(c >= 1); + ASSERT(cw >= 1); + ASSERT((st <> nil) and (Length(st) >= c)); + ASSERT((rs = nil) or (Length(rs) >= c)); + result := false; + if (data <> nil) and (size > 0) then + begin + InitImage(img); + try + if LoadImageFromMemory(data, size, img) then + begin + if r_Textures_FixImageData(img) then + begin + result := r_Textures_LoadStreamFromImage(img, w, h, c, cw, st, rs) + end; + end; + except + end; + FreeImage(img); + end; + end; + + function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean; + var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; + begin + ASSERT(w > 0); + ASSERT(h > 0); + ASSERT(count >= 1); + ASSERT(cw >= 1); + ASSERT((st <> nil) and (Length(st) >= count)); + ASSERT((rs = nil) or (Length(rs) >= count)); + result := false; + wadName := g_ExtractWadName(filename); + wad := TWADFile.Create(); + if wad.ReadFile(wadName) then + begin + resName := g_ExtractFilePathName(filename); + if wad.GetResource(resName, data, size, log) then + begin + result := r_Textures_LoadStreamFromMemory(data, size, w, h, count, cw, st, rs); + FreeMem(data); + end; + wad.Free + end; + end; + + (* --------- TGLFont --------- *) + + function r_Textures_LoadFontFromFile (const filename: AnsiString; constref f: TFontInfo; skipch: Integer; log: Boolean = true): TGLFont; + var i: Integer; st: TGLTextureArray; font: TGLFont; t: TGLTexture; + begin + ASSERT(skipch >= 0); + result := nil; + SetLength(st, 256); + if r_Textures_LoadStreamFromFile(filename, f.w, f.h, 256, 16, st, nil, log) then + begin + if skipch > 0 then + begin + for i := 0 to 255 do + begin + t := st[i]; + st[i] := st[(i + skipch) mod 256]; + st[(i + skipch) mod 256] := t; + end; + end; + font := TGLFont.Create(); + font.info := f; + font.ch := st; + result := font; + end; + end; + + destructor TGLFont.Destroy; + var i: Integer; + begin + if self.ch <> nil then + for i := 0 to High(self.ch) do + self.ch[i].Free; + self.ch := nil; + end; + + function TGLFont.GetChar (c: AnsiChar): TGLTexture; + begin + result := self.ch[ORD(c)]; + end; + + function TGLFont.GetWidth (c: AnsiChar): Integer; + begin + result := self.info.ch[c].w; + if result = 0 then + result := self.info.w; + if self.info.kern < 0 then + result := result + self.info.kern; + end; + + function TGLFont.GetMaxWidth (): Integer; + begin + result := self.info.w; + if self.info.kern < 0 then + result := result + self.info.kern; + end; + + function TGLFont.GetMaxHeight (): Integer; + begin + result := self.info.h; + end; + + function TGLFont.GetSpace (): Integer; + begin + result := self.info.kern; + end; + end.