X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Frenders%2Fopengl%2Fr_textures.pas;h=56d2656c8c17e0e556e70e8525fc06e7e718537e;hb=d0374fd617aa1703e4aa31b8ff3b0f5228636021;hp=ce71ebc727d7e96b0001e0a44a512ba1b9269846;hpb=fa608ea5bf886397e66873b1d3b72cdceb5be3fb;p=d2df-sdl.git diff --git a/src/game/renders/opengl/r_textures.pas b/src/game/renders/opengl/r_textures.pas index ce71ebc..56d2656 100644 --- a/src/game/renders/opengl/r_textures.pas +++ b/src/game/renders/opengl/r_textures.pas @@ -18,17 +18,16 @@ unit r_textures; interface uses - {$IFDEF USE_GLES1} - GLES11, - {$ELSE} - GL, GLEXT, - {$ENDIF} - g_base, // TRectHW + {$I ../../../nogl/noGLuses.inc} + g_base, g_animations, // TRectHW, TAnimInfo utils, - r_atlas + r_atlas, r_fonts ; type + TGLHints = (txNoRepeat); + TGLHintsSet = set of TGLHints; + TGLAtlas = class; TGLAtlasNode = class (TAtlasNode) @@ -65,6 +64,7 @@ interface mHeight: Integer; mCols: Integer; mTile: array of TGLAtlasNode; + mHints: TGLHintsSet; public destructor Destroy; override; @@ -77,12 +77,12 @@ interface property height: Integer read mHeight; property cols: Integer read mCols; property lines: Integer read GetLines; + property hints: TGLHintsSet read mHints; end; TGLMultiTexture = class private mTexture: array of TGLTexture; - mBackanim: Boolean; public destructor Destroy; override; @@ -95,32 +95,73 @@ 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; + + TConvProc = function (x: Integer): Integer; + procedure r_Textures_Initialize; procedure r_Textures_Finalize; - 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_LoadStreamFromFile (const filename: AnsiString; w, h, count: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean; + function r_Textures_LoadFromFile (const filename: AnsiString; hints: TGLHintsSet; log: Boolean = True): TGLTexture; + function r_Textures_LoadMultiFromFile (const filename: AnsiString; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + function r_Textures_LoadMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + + function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; hints: TGLHintsSet; log: Boolean = True): Boolean; + + function r_Textures_LoadFontFromFile (const filename: AnsiString; constref f: TFontInfo; font2enc: TConvProc; log: Boolean = true): TGLFont; + + procedure r_Textures_GL_Bind (id: GLuint); implementation uses SysUtils, Classes, + r_common, e_log, e_res, WADReader, Config, + g_console, // cvar declaration Imaging, ImagingTypes, ImagingUtility ; var + r_GL_MaxTexSize: WORD; + r_GL_RepeatOpt: Boolean; maxTileSize: Integer; - atl: array of TGLAtlas; + atl, ratl: array of TGLAtlas; + currentTexture2D: GLuint; + + procedure r_Textures_GL_Bind (id: GLuint); + begin + if id <> currentTexture2D then + begin + glBindTexture(GL_TEXTURE_2D, id); + currentTexture2D := id; + end + end; (* --------- TGLAtlasNode --------- *) @@ -152,9 +193,9 @@ implementation ASSERT(n.l + x + w - 1 <= n.r); ASSERT(n.t + y + h - 1 <= n.b); ASSERT(n.id > 0); - glBindTexture(GL_TEXTURE_2D, n.id); + r_Textures_GL_Bind(n.id); glTexSubImage2D(GL_TEXTURE_2D, 0, n.l + x, n.t + y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data); - glBindTexture(GL_TEXTURE_2D, 0); + r_Textures_GL_Bind(0); end; (* --------- TGLAtlas --------- *) @@ -188,11 +229,13 @@ implementation glGenTextures(1, @id); if id <> 0 then begin - glBindTexture(GL_TEXTURE_2D, id); + r_Textures_GL_Bind(id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); - glBindTexture(GL_TEXTURE_2D, 0); + r_Textures_GL_Bind(0); end; result := id end; @@ -211,6 +254,20 @@ implementation end; end; + function r_Textures_AllocRepeatAtlas (w, h: Integer): TGLAtlas; + var i: Integer; id: GLuint; + begin + result := nil; + id := r_Textures_AllocHWTexture(w, h); + if id <> 0 then + begin + i := Length(ratl); + SetLength(ratl, i + 1); + ratl[i] := TGLAtlas.Create(w, h, id); + result := ratl[i]; + end; + end; + function r_Textures_AllocNode (w, h: Integer): TGLAtlasNode; var i: Integer; n: TGLAtlasNode; a: TGLAtlas; begin @@ -233,22 +290,56 @@ implementation result := n end; + function r_Textures_AllocRepeatNode (w, h: Integer): TGLAtlasNode; + var i: Integer; n: TGLAtlasNode; a: TGLAtlas; + begin + n := nil; a := nil; + if ratl <> nil then + begin + i := High(ratl); + while (i >= 0) and (ratl[i] <> nil) do DEC(i); + if i >= 0 then a := ratl[i]; + end; + if a = nil then a := r_Textures_AllocRepeatAtlas(w, h); + if a <> nil then + begin + n := a.Alloc(w, h); + if n = nil then + begin + i := High(ratl); while (i >= 0) and (ratl[i] <> a) do DEC(i); + if i >= 0 then ratl[i] := nil; + r_Common_FreeAndNil(a); + end; + end; + result := n + end; + (* --------- TGLTexture --------- *) destructor TGLTexture.Destroy; - var i: Integer; + var i: Integer; a: TGLAtlas; begin if self.mTile <> nil then begin - for i := 0 to High(self.mTile) do + if TGLHints.txNoRepeat in self.hints then (* non repeatable texture -> delete tiles only *) begin - if self.mTile[i] <> nil then + for i := 0 to High(self.mTile) do begin - self.mTile[i].Dealloc; - self.mTile[i] := nil; - end; + if self.mTile[i] <> nil then + begin + self.mTile[i].Dealloc; + self.mTile[i] := nil + end + end + end + else (* repeatable texture -> delete whole atlas *) + begin + a := self.mTile[0].base; + i := High(ratl); while (i >= 0) and (ratl[i] <> a) do DEC(i); + if i >= 0 then ratl[i] := nil; + r_Common_FreeAndNil(a); end; - self.mTile := nil; + SetLength(self.mTile, 0); end; inherited; end; @@ -272,29 +363,44 @@ implementation ASSERT(result <> nil) end; - function r_Textures_Alloc (w, h: Integer): TGLTexture; + function r_Textures_Alloc (w, h: Integer; hints: TGLHintsSet): TGLTexture; var x, y, mw, mh, cols, lines: Integer; t: TGLTexture; begin ASSERT(w > 0); ASSERT(h > 0); - cols := (w + maxTileSize - 1) div maxTileSize; - lines := (h + maxTileSize - 1) div maxTileSize; - t := TGLTexture.Create; - t.mWidth := w; - t.mHeight := h; - t.mCols := cols; - // t.mLines := lines; - SetLength(t.mTile, cols * lines); - for y := 0 to lines - 1 do - begin - mh := Min(maxTileSize, h - y * maxTileSize); - ASSERT(mh > 0); - for x := 0 to cols - 1 do + if TGLHints.txNoRepeat in hints then + begin + cols := (w + maxTileSize - 1) div maxTileSize; + lines := (h + maxTileSize - 1) div maxTileSize; + t := TGLTexture.Create; + t.mWidth := w; + t.mHeight := h; + t.mCols := cols; + // t.mLines := lines; + t.mHints := hints; + SetLength(t.mTile, cols * lines); + for y := 0 to lines - 1 do begin - mw := Min(maxTileSize, w - x * maxTileSize); - ASSERT(mw > 0); - t.mTile[y * cols + x] := r_Textures_AllocNode(mw, mh); - end + mh := Min(maxTileSize, h - y * maxTileSize); + ASSERT(mh > 0); + for x := 0 to cols - 1 do + begin + mw := Min(maxTileSize, w - x * maxTileSize); + ASSERT(mw > 0); + t.mTile[y * cols + x] := r_Textures_AllocNode(mw, mh); + end + end; + end + else + begin + t := TGLTexture.Create; + t.mWidth := w; + t.mHeight := h; + t.mCols := 1; + // t.mLines := 1 + t.mHints := hints; + SetLength(t.mTile, 1); + t.mTile[0] := r_Textures_AllocRepeatNode(w, h); end; result := t; end; @@ -305,8 +411,8 @@ implementation var i: Integer; begin for i := 0 to self.count - 1 do - self.mTexture[i].Free; - self.mTexture := nil; + r_Common_FreeAndNil(self.mTexture[i]); + SetLength(self.mTexture, 0); inherited; end; @@ -335,19 +441,49 @@ implementation (* --------- Init / Fin --------- *) + function IsPOT (v: LongWord): Boolean; + begin + result := (v <> 0) and ((v and (v - 1)) = 0) + end; + + function NextPOT (v: LongWord): LongWord; + begin + DEC(v); + v := v or (v >> 1); + v := v or (v >> 2); + v := v or (v >> 4); + v := v or (v >> 8); + v := v or (v >> 16); + INC(v); + result := v; + end; + function r_Textures_GetMaxHardwareSize (): Integer; var size: GLint = 0; begin - glGetIntegerv(GL_MAX_TEXTURE_SIZE, @size); - if size < 64 then size := 64; - //if size > 512 then size := 512; - //size := 64; // !!! + if r_GL_MaxTexSize <= 0 then + begin + // auto, max possible reccomended by driver + glGetIntegerv(GL_MAX_TEXTURE_SIZE, @size); + size := size div 2; (* hack: on some devices max size may produce invalid texture *) + if size < 64 then size := 64; (* at least 64x64 are guarantied by specification *) + end + else + begin + // selected by user + if IsPOT(r_GL_MaxTexSize) then + size := r_GL_MaxTexSize + else + size := NextPOT(r_GL_MaxTexSize); + end; result := size; end; procedure r_Textures_Initialize; begin + currentTexture2D := 0; maxTileSize := r_Textures_GetMaxHardwareSize(); + e_LogWritefln('Texture Tile Size: %s', [maxTileSize]); end; procedure r_Textures_Finalize; @@ -357,12 +493,29 @@ implementation begin for i := 0 to High(atl) do begin - glDeleteTextures(1, @atl[i].id); - atl[i].id := 0; - atl[i].Free; + if atl[i] <> nil then + begin + glDeleteTextures(1, @atl[i].id); + atl[i].id := 0; + r_Common_FreeAndNil(atl[i]); + end; end; - atl := nil; end; + SetLength(atl, 0); + + if ratl <> nil then + begin + for i := 0 to High(ratl) do + begin + if ratl[i] <> nil then + begin + glDeleteTextures(1, @ratl[i].id); + ratl[i].id := 0; + r_Common_FreeAndNil(ratl[i]); + end; + end; + end; + SetLength(ratl, 0); end; function r_Textures_FixImageData (var img: TImageData): Boolean; @@ -373,14 +526,34 @@ implementation result := true; end; - function r_Textures_LoadFromImage (var img: TImageData): TGLTexture; + function r_Textures_ValidRepeatTexture (w, h: Integer; hints: TGLHintsSet): Boolean; + begin + result := r_GL_RepeatOpt and + not (TGLHints.txNoRepeat in hints) and + (w <= maxTileSize) and + (h <= maxTileSize) and + IsPOT(w) and + IsPOT(h) + end; + + function r_Textures_LoadFromImage (var img: TImageData; hints: TGLHintsSet): 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 + if r_Textures_ValidRepeatTexture(img.width, img.height, hints) then + begin + t := r_Textures_Alloc(img.width, img.height, hints - [TGLHints.txNoRepeat]); + if t <> nil then + begin + n := t.GetTile(0, 0); + ASSERT(n <> nil); + r_Textures_UpdateNode(n, img.bits, 0, 0, n.width, n.height); + result := t + end + end + else if SplitImage(img, c, maxTileSize, maxTileSize, cw, ch, False) then begin - t := r_Textures_Alloc(img.width, img.height); + t := r_Textures_Alloc(img.width, img.height, hints + [TGLHints.txNoRepeat]); if t <> nil then begin ASSERT(cw = t.cols); @@ -400,7 +573,7 @@ implementation end; end; - function r_Textures_LoadFromMemory (data: Pointer; size: LongInt): TGLTexture; + function r_Textures_LoadFromMemory (data: Pointer; size: LongInt; hints: TGLHintsSet): TGLTexture; var img: TImageData; begin result := nil; @@ -410,14 +583,14 @@ implementation try if LoadImageFromMemory(data, size, img) then if r_Textures_FixImageData(img) then - result := r_Textures_LoadFromImage(img) + result := r_Textures_LoadFromImage(img, hints) except end; FreeImage(img); end; end; - function r_Textures_LoadFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture; + function r_Textures_LoadFromFile (const filename: AnsiString; hints: TGLHintsSet; log: Boolean = True): TGLTexture; var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; begin result := nil; @@ -428,14 +601,14 @@ implementation resName := g_ExtractFilePathName(filename); if wad.GetResource(resName, data, size, log) then begin - result := r_Textures_LoadFromMemory(data, size); + result := r_Textures_LoadFromMemory(data, size, hints); FreeMem(data); end; wad.Free 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; hints: TGLHintsSet): TGLMultiTexture; var t: TImageData; a: array of TGLTexture; i: Integer; m: TGLMultiTexture; begin ASSERT(w >= 0); @@ -448,18 +621,17 @@ implementation InitImage(t); if NewImage(w, h, img.Format, t) then if CopyRect(img, w * i, 0, w, h, t, 0, 0) then - a[i] := r_Textures_LoadFromImage(t); + a[i] := r_Textures_LoadFromImage(t, hints); ASSERT(a[i] <> nil); FreeImage(t); 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; hints: TGLHintsSet): TGLMultiTexture; var img: TImageData; begin ASSERT(w > 0); @@ -472,62 +644,90 @@ implementation try if LoadImageFromMemory(data, size, img) then if r_Textures_FixImageData(img) then - result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b) + result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, hints) 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 text: TAnimTextInfo): Boolean; + var cfg: TConfig; + begin + result := false; + if data <> nil then + begin + cfg := TConfig.CreateMem(data, size); + if cfg <> nil then + begin + text.name := cfg.ReadStr('', 'resource', ''); + text.w := cfg.ReadInt('', 'framewidth', 0); + text.h := cfg.ReadInt('', 'frameheight', 0); + text.anim.loop := true; + text.anim.delay := cfg.ReadInt('', 'waitcount', 0); + text.anim.frames := cfg.ReadInt('', 'framecount', 0); + text.anim.back := cfg.ReadBool('', 'backanim', false); + if text.w <= 0 then e_LogWritefln('Warning: bad animation width %s for %s', [text.w, text.name]); + if text.h <= 0 then e_LogWritefln('Warning: bad animation height %s for %s', [text.h, text.name]); + if text.anim.delay <= 0 then e_LogWritefln('Warning: bad animation delay %s for %s', [text.anim.delay, text.name]); + if text.anim.frames <= 0 then e_LogWritefln('Warning: bad animation frame count %s for %s', [text.anim.frames, text.name]); + text.w := MAX(0, text.w); + text.h := MAX(0, text.h); + text.anim.delay := MAX(1, text.anim.delay); + text.anim.frames := MAX(1, text.anim.frames); + cfg.Free; + result := (text.name <> '') and (text.w > 0) and (text.h > 0) and (text.anim.delay > 0) and (text.anim.frames > 0); + end; + end; + end; + + function r_Textures_LoadMultiFromWad (wad: TWADFile; var txt: TAnimTextInfo; hints: TGLHintsSet): 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 r_Textures_FixImageData(img) then - 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, hints); + 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; hints: TGLHintsSet): TGLMultiTexture; var wad: TWADFile; t: TGLTexture; m: TGLMultiTexture; begin result := nil; if (data <> nil) and (size > 0) then begin - t := r_Textures_LoadFromMemory(data, size); + t := r_Textures_LoadFromMemory(data, size, hints); if t <> nil then begin 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 @@ -535,15 +735,15 @@ implementation wad := TWADFile.Create(); if wad.ReadMemory(data, size) then begin - result := r_Textures_LoadMultiFromWad(wad); + result := r_Textures_LoadMultiFromWad(wad, txt, hints); 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; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; begin result := nil; wadName := g_ExtractWadName(filename); @@ -553,14 +753,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, hints); 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; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + var txt: TAnimTextInfo; + begin + result := r_Textures_LoadMultiTextFromFile(filename, txt, hints, log); + end; + + function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer; begin ASSERT(w > 0); @@ -574,7 +780,7 @@ 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, hints); FreeMem(data); end; wad.Free @@ -638,26 +844,29 @@ implementation end; end; - function r_Textures_LoadStreamFromImage (var img: TImageData; w, h, c: Integer; st: TGLTextureArray; rs: TRectArray): Boolean; - var i: Integer; t: TImageData; + function r_Textures_LoadStreamFromImage (var img: TImageData; w, h, c, cw: Integer; st: TGLTextureArray; rs: TRectArray; hints: TGLHintsSet): 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, w * i, 0, w, h, t, 0, 0) then + 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); + st[i] := r_Textures_LoadFromImage(t, hints); end; end; ASSERT(st[i] <> nil); @@ -665,12 +874,13 @@ implementation end; end; - function r_Textures_LoadStreamFromMemory (data: Pointer; size: LongInt; w, h, c: Integer; st: TGLTextureArray; rs: TRectArray): Boolean; + function r_Textures_LoadStreamFromMemory (data: Pointer; size: LongInt; w, h, c, cw: Integer; st: TGLTextureArray; rs: TRectArray; hints: TGLHintsSet): 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; @@ -679,20 +889,25 @@ implementation InitImage(img); try if LoadImageFromMemory(data, size, img) then + begin if r_Textures_FixImageData(img) then - result := r_Textures_LoadStreamFromImage(img, w, h, c, st, rs) + begin + result := r_Textures_LoadStreamFromImage(img, w, h, c, cw, st, rs, hints) + end; + end; except end; FreeImage(img); end; end; - function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean; + function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; hints: TGLHintsSet; 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; @@ -703,11 +918,84 @@ implementation resName := g_ExtractFilePathName(filename); if wad.GetResource(resName, data, size, log) then begin - result := r_Textures_LoadStreamFromMemory(data, size, w, h, count, st, rs); + result := r_Textures_LoadStreamFromMemory(data, size, w, h, count, cw, st, rs, hints); FreeMem(data); end; wad.Free - end + end; + end; + + (* --------- TGLFont --------- *) + + function r_Textures_LoadFontFromFile (const filename: AnsiString; constref f: TFontInfo; font2enc: TConvProc; log: Boolean = true): TGLFont; + var i, ch: Integer; st, stch: TGLTextureArray; font: TGLFont; + begin + result := nil; + SetLength(st, 256); + if r_Textures_LoadStreamFromFile(filename, f.w, f.h, 256, 16, st, nil, [TGLHints.txNoRepeat], log) then + begin + font := TGLFont.Create(); + font.info := f; + font.ch := st; + if Assigned(font2enc) then + begin + SetLength(stch, 256); + for i := 0 to 255 do + begin + ch := font2enc(i); + ASSERT((ch >= 0) and (ch <= 255)); + stch[ch] := st[i]; + end; + font.ch := stch; + SetLength(st, 0); + end; + 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; +initialization + conRegVar('r_gl_maxtexsize', @r_GL_MaxTexSize, '', ''); + conRegVar('r_gl_repeat', @r_GL_RepeatOpt, '', ''); + r_GL_MaxTexSize := 0; // default is automatic value + r_GL_RepeatOpt := true; end.