From: DeaDDooMER Date: Wed, 28 Dec 2022 19:35:20 +0000 (+0300) Subject: gl: optimize repeatable textures X-Git-Url: http://deadsoftware.ru/gitweb?p=d2df-sdl.git;a=commitdiff_plain;h=203d8922aa34a34fb63e312691c711c419c34ae1 gl: optimize repeatable textures --- diff --git a/src/game/renders/opengl/r_common.pas b/src/game/renders/opengl/r_common.pas index c12cbbb..3319882 100644 --- a/src/game/renders/opengl/r_common.pas +++ b/src/game/renders/opengl/r_common.pas @@ -68,11 +68,11 @@ interface procedure r_Common_StepLoading (incval: Integer); procedure r_Common_DrawLoading (force: Boolean); - function r_Common_LoadTextureFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture; - function r_Common_LoadTextureMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture; - function r_Common_LoadTextureMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; log: Boolean = True): TGLMultiTexture; - function r_Common_LoadTextureMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture; - function r_Common_LoadTextureStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean; + function r_Common_LoadTextureFromFile (const filename: AnsiString; hints: TGLHintsSet; log: Boolean = True): TGLTexture; + function r_Common_LoadTextureMultiFromFile (const filename: AnsiString; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + function r_Common_LoadTextureMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + function r_Common_LoadTextureMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; + function r_Common_LoadTextureStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; hints: TGLHintsSet; log: Boolean = True): Boolean; function r_Common_LoadTextureFontFromFile (const filename: AnsiString; constref f: TFontInfo; font2enc: TConvProc; log: Boolean = true): TGLFont; procedure r_Common_Load; @@ -328,7 +328,7 @@ implementation if name <> here.name then r_Common_FreeThis(here); if (name <> '') and (here.name <> name) then - here.id := r_Textures_LoadFromFile(name); + here.id := r_Textures_LoadFromFile(name, []); // !!! result := here.id <> nil; @@ -437,33 +437,33 @@ implementation r_Common_DrawLoading(false); end; - function r_Common_LoadTextureFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture; + function r_Common_LoadTextureFromFile (const filename: AnsiString; hints: TGLHintsSet; log: Boolean = True): TGLTexture; begin - result := r_Textures_LoadFromFile(filename, log); + result := r_Textures_LoadFromFile(filename, hints, log); r_Common_StepLoading(1); end; - function r_Common_LoadTextureMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture; + function r_Common_LoadTextureMultiFromFile (const filename: AnsiString; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; begin - result := r_Textures_LoadMultiFromFile(filename, log); + result := r_Textures_LoadMultiFromFile(filename, hints, log); r_Common_StepLoading(1); end; - function r_Common_LoadTextureMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; log: Boolean = True): TGLMultiTexture; + function r_Common_LoadTextureMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; begin - result := r_Textures_LoadMultiFromFileAndInfo(filename, w, h, count, log); + result := r_Textures_LoadMultiFromFileAndInfo(filename, w, h, count, hints, log); r_Common_StepLoading(1); end; - function r_Common_LoadTextureMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture; + function r_Common_LoadTextureMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; hints: TGLHintsSet; log: Boolean = True): TGLMultiTexture; begin - result := r_Textures_LoadMultiTextFromFile(filename, txt, log); + result := r_Textures_LoadMultiTextFromFile(filename, txt, hints, log); r_Common_StepLoading(1); end; - function r_Common_LoadTextureStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean; + function r_Common_LoadTextureStreamFromFile (const filename: AnsiString; w, h, count, cw: Integer; st: TGLTextureArray; rs: TRectArray; hints: TGLHintsSet; log: Boolean = True): Boolean; begin - r_Textures_LoadStreamFromFile(filename, w, h, count, cw, st, rs, log); + result := r_Textures_LoadStreamFromFile(filename, w, h, count, cw, st, rs, hints, log); r_Common_StepLoading(1); end; diff --git a/src/game/renders/opengl/r_console.pas b/src/game/renders/opengl/r_console.pas index e5adc32..5c2f519 100644 --- a/src/game/renders/opengl/r_console.pas +++ b/src/game/renders/opengl/r_console.pas @@ -57,7 +57,7 @@ implementation procedure r_Console_Load; begin r_Common_SetLoading(_lc[I_LOAD_CONSOLE], 1); - Background := r_Textures_LoadFromFile(GameWad + ':TEXTURES/CONSOLE'); + Background := r_Textures_LoadFromFile(GameWad + ':TEXTURES/CONSOLE', [TGLHints.txNoRepeat]); end; procedure r_Console_Free; diff --git a/src/game/renders/opengl/r_draw.pas b/src/game/renders/opengl/r_draw.pas index 9db9183..67bd230 100644 --- a/src/game/renders/opengl/r_draw.pas +++ b/src/game/renders/opengl/r_draw.pas @@ -126,6 +126,29 @@ implementation end end; + procedure DrawHWTexture (gltex: GLint; nw, nh, x, y, w, h: Integer; flip: Boolean; rr, gg, bb, aa: Byte; blend: Boolean); + var ax, bx, ay, by: GLfloat; l, t, r, b: Integer; + begin + ax := IfThen(flip, 0, w) / nw; + bx := IfThen(flip, w, 0) / nh; + ay := 0 / nw; + by := h / nh; + l := x; t := y; r := x + w; b := y + h; + glBindTexture(GL_TEXTURE_2D, gltex); + glColor4ub(rr, gg, bb, aa); + if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBegin(GL_QUADS); + glTexCoord2f(ax, ay); glVertex2i(r, t); + glTexCoord2f(bx, ay); glVertex2i(l, t); + glTexCoord2f(bx, by); glVertex2i(l, b); + glTexCoord2f(ax, by); glVertex2i(r, b); + glEnd(); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + end; + procedure r_Draw_Texture (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean); var i, j, first, last, step: Integer; n: TGLAtlasNode; begin @@ -157,6 +180,22 @@ implementation end end; + function r_Draw_IsHWRepeatable (img: TGLTexture): Boolean; + var n: TGLAtlasNode; a: TGLAtlas; + begin + ASSERT(img <> nil); + result := false; + if (img.cols = 1) and (img.lines = 1) then + begin + n := img.GetTile(0, 0); + if (n.width = img.width) and (n.height = img.height) then + begin + a := n.base; + result := (a.GetWidth() = img.width) and (a.GetHeight() = img.height) + end; + end; + end; + procedure r_Draw_TextureRepeat (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean); var i, j: Integer; begin @@ -164,6 +203,8 @@ implementation ASSERT(h >= 0); if img = nil then r_Draw_Texture(nil, x, y, w, h, flip, NTR, NTG, NTB, NTB, blend) + else if r_Draw_IsHWRepeatable(img) then + DrawHWTexture(img.GetTile(0, 0).base.id, img.width, img.height, x, y, w, h, flip, r, g, b, a, blend) else for j := 0 to (h - 1) div img.height do for i := 0 to (w - 1) div img.width do diff --git a/src/game/renders/opengl/r_gui.pas b/src/game/renders/opengl/r_gui.pas index 04d3c3c..37fb217 100644 --- a/src/game/renders/opengl/r_gui.pas +++ b/src/game/renders/opengl/r_gui.pas @@ -65,29 +65,29 @@ implementation r_Common_SetLoading('GUI', 2 + 9 + 14); - MarkerID[FALSE] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MARKER1'); - MarkerID[TRUE] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MARKER2'); + MarkerID[FALSE] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MARKER1', [TGLHints.txNoRepeat]); + MarkerID[TRUE] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MARKER2', [TGLHints.txNoRepeat]); for i := 0 to 8 do - Box[i] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/BOX' + IntToStr(i + 1)); + Box[i] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/BOX' + IntToStr(i + 1), []); // !!! - ScrollLeft := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SLEFT'); - ScrollRight := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SRIGHT'); - ScrollMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SMIDDLE'); - ScrollMarker := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SMARKER'); + ScrollLeft := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SLEFT', [TGLHints.txNoRepeat]); + ScrollRight := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SRIGHT', [TGLHints.txNoRepeat]); + ScrollMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SMIDDLE', []); + ScrollMarker := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SMARKER', [TGLHints.txNoRepeat]); - EditLeft := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/ELEFT'); - EditRight := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/ERIGHT'); - EditMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/EMIDDLE'); + EditLeft := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/ELEFT', [TGLHints.txNoRepeat]); + EditRight := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/ERIGHT', [TGLHints.txNoRepeat]); + EditMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/EMIDDLE', []); - BScrollUp[true] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLUPA'); - BScrollUp[false] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLUPU'); - BScrollDown[true] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLDOWNA'); - BScrollDown[false] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLDOWNU'); - BScrollMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLMIDDLE'); + BScrollUp[true] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLUPA', [TGLHints.txNoRepeat]); + BScrollUp[false] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLUPU', [TGLHints.txNoRepeat]); + BScrollDown[true] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLDOWNA', [TGLHints.txNoRepeat]); + BScrollDown[false] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLDOWNU', [TGLHints.txNoRepeat]); + BScrollMiddle := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/SCROLLMIDDLE', []); - LogoTex := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MAINLOGO'); - nopic := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/NOPIC'); + LogoTex := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/MAINLOGO', [TGLHints.txNoRepeat]); + nopic := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/NOPIC', [TGLHints.txNoRepeat]); end; procedure r_GUI_Free; diff --git a/src/game/renders/opengl/r_loadscreen.pas b/src/game/renders/opengl/r_loadscreen.pas index bc2f236..31d2934 100644 --- a/src/game/renders/opengl/r_loadscreen.pas +++ b/src/game/renders/opengl/r_loadscreen.pas @@ -63,10 +63,10 @@ implementation procedure r_LoadScreen_Load; begin - BarL := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LLEFT'); - BarM := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LMIDDLE'); - BarR := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LRIGHT'); - BarF := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LMARKER'); + BarL := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LLEFT', [TGLHints.txNoRepeat]); + BarM := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LMIDDLE', []); + BarR := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LRIGHT', [TGLHints.txNoRepeat]); + BarF := r_Textures_LoadFromFile(GameWAD + ':TEXTURES/LMARKER', []); end; procedure r_LoadScreen_Free; diff --git a/src/game/renders/opengl/r_map.pas b/src/game/renders/opengl/r_map.pas index 95c76a3..028c724 100644 --- a/src/game/renders/opengl/r_map.pas +++ b/src/game/renders/opengl/r_map.pas @@ -343,9 +343,9 @@ implementation Models[i].anim[d, a].base := nil; Models[i].anim[d, a].mask := nil; if m.anim[d, a].resource <> '' then - Models[i].anim[d, a].base := r_Textures_LoadMultiFromFileAndInfo(prefix + m.anim[d, a].resource, 64, 64, m.anim[d, a].frames, true); + Models[i].anim[d, a].base := r_Textures_LoadMultiFromFileAndInfo(prefix + m.anim[d, a].resource, 64, 64, m.anim[d, a].frames, [TGLHints.txNoRepeat], true); if m.anim[d, a].mask <> '' then - Models[i].anim[d, a].mask := r_Textures_LoadMultiFromFileAndInfo(prefix + m.anim[d, a].mask, 64, 64, m.anim[d, a].frames, true); + Models[i].anim[d, a].mask := r_Textures_LoadMultiFromFileAndInfo(prefix + m.anim[d, a].mask, 64, 64, m.anim[d, a].frames, [TGLHints.txNoRepeat], true); end end; {$IFDEF ENABLE_GIBS} @@ -359,9 +359,9 @@ implementation SetLength(Models[i].gibs.rect, m.GibsCount); for a := 0 to m.GibsCount - 1 do Models[i].gibs.rect[a] := DefaultGibSize; - if r_Textures_LoadStreamFromFile(prefix + m.GibsResource, 32, 32, m.GibsCount, m.GibsCount, Models[i].gibs.base, Models[i].gibs.rect) then + if r_Textures_LoadStreamFromFile(prefix + m.GibsResource, 32, 32, m.GibsCount, m.GibsCount, Models[i].gibs.base, Models[i].gibs.rect, [TGLHints.txNoRepeat]) then begin - if r_Textures_LoadStreamFromFile(prefix + m.GibsMask, 32, 32, m.GibsCount, m.GibsCount, Models[i].gibs.mask, nil) then + if r_Textures_LoadStreamFromFile(prefix + m.GibsMask, 32, 32, m.GibsCount, m.GibsCount, Models[i].gibs.mask, nil, [TGLHints.txNoRepeat]) then begin // ok end; @@ -390,6 +390,7 @@ implementation w, h, count, + [TGLHints.txNoRepeat], False ); end @@ -415,6 +416,7 @@ implementation ItemAnim[i].w, ItemAnim[i].h, ItemAnim[i].anim.frames, + [TGLHints.txNoRepeat], false ); Items[i].frame := 0; @@ -428,7 +430,7 @@ implementation r_Map_LoadMonsterAnim(i, j, d); r_Common_StepLoading(1); end; - VileFire := r_Textures_LoadMultiFromFileAndInfo(GameWAD + ':TEXTURES/FIRE', 64, 128, VileFireAnim.frames); + VileFire := r_Textures_LoadMultiFromFileAndInfo(GameWAD + ':TEXTURES/FIRE', 64, 128, VileFireAnim.frames, [TGLHints.txNoRepeat]); // --------- player models --------- // if PlayerModelsArray <> nil then begin @@ -446,7 +448,7 @@ implementation begin for j := 0 to W_POS_LAST do for k := 0 to W_ACT_LAST do - WeapTextures[i, j, k] := r_Textures_LoadFromFile(GameWAD + ':WEAPONS\' + WeapName[i] + WeapPos[j] + WeapAct[k]); + WeapTextures[i, j, k] := r_Textures_LoadFromFile(GameWAD + ':WEAPONS\' + WeapName[i] + WeapPos[j] + WeapAct[k], [TGLHints.txNoRepeat]); r_Common_StepLoading(1); end; // --------- gfx animations --------- // @@ -455,7 +457,7 @@ implementation for i := 1 to R_GFX_LAST do begin if GFXAnim[i].anim.frames > 0 then - GFXTextures[i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/' + GFXAnim[i].name, GFXAnim[i].w, GFXAnim[i].h, GFXAnim[i].anim.frames); + GFXTextures[i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/' + GFXAnim[i].name, GFXAnim[i].w, GFXAnim[i].h, GFXAnim[i].anim.frames, [TGLHints.txNoRepeat]); end; {$ENDIF} // --------- shots --------- // @@ -463,30 +465,30 @@ implementation for i := 0 to WEAPON_LAST do begin if ShotAnim[i].anim.frames > 0 then - ShotTextures[i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/' + ShotAnim[i].name, ShotAnim[i].w, ShotAnim[i].h, ShotAnim[i].anim.frames); + ShotTextures[i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/' + ShotAnim[i].name, ShotAnim[i].w, ShotAnim[i].h, ShotAnim[i].anim.frames, [TGLHints.txNoRepeat]); end; // --------- flags --------- // r_Common_SetLoading('Flags', 2); FlagTextures[FLAG_NONE] := nil; - FlagTextures[FLAG_RED] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGRED', 64, 64, 5); - FlagTextures[FLAG_BLUE] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGBLUE', 64, 64, 5); - // FlagTextures[FLAG_DOM] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGDOM', 64, 64, 8); + FlagTextures[FLAG_RED] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGRED', 64, 64, 5, [TGLHints.txNoRepeat]); + FlagTextures[FLAG_BLUE] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGBLUE', 64, 64, 5, [TGLHints.txNoRepeat]); + // FlagTextures[FLAG_DOM] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':TEXTURES/FLAGDOM', 64, 64, 8, [TGLHints.txNoRepeat]); // --------- shells --------- // {$IFDEF ENABLE_SHELLS} r_Common_SetLoading('Shells', SHELL_LAST + 1); for i := 0 to SHELL_LAST do - ShellTextures[i] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/' + ShellAnim[i].name); + ShellTextures[i] := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/' + ShellAnim[i].name, [TGLHints.txNoRepeat]); {$ENDIF} // --------- other --------- // r_Common_SetLoading('Effects', 3 * 2 + 3); for b := false to true do begin for i := 0 to 2 do - PunchTextures[b, i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':WEAPONS/' + PunchName[b] + WeapPos[i], 64, 64, PunchAnim.frames); + PunchTextures[b, i] := r_Common_LoadTextureMultiFromFileAndInfo(GameWad + ':WEAPONS/' + PunchName[b] + WeapPos[i], 64, 64, PunchAnim.frames, [TGLHints.txNoRepeat]); end; - InvulPenta := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/PENTA'); - IndicatorTexture := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/PLRIND'); - TalkTexture := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/TALKBUBBLE'); + InvulPenta := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/PENTA', [TGLHints.txNoRepeat]); + IndicatorTexture := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/PLRIND', [TGLHints.txNoRepeat]); + TalkTexture := r_Common_LoadTextureFromFile(GameWad + ':TEXTURES/TALKBUBBLE', [TGLHints.txNoRepeat]); end; procedure r_Map_Free; @@ -545,7 +547,7 @@ implementation TEXTURE_NAME_ACID2: RenTextures[i].spec := TEXTURE_SPECIAL_ACID2; else RenTextures[i].spec := 0; - RenTextures[i].tex := r_Textures_LoadMultiTextFromFile(Textures[i].FullName, txt); + RenTextures[i].tex := r_Textures_LoadMultiTextFromFile(Textures[i].FullName, txt, []); if RenTextures[i].tex = nil then e_LogWritefln('r_Map_LoadTextures: failed to load texture: %s', [Textures[i].FullName]) else @@ -557,7 +559,7 @@ implementation if gMapInfo.SkyFullName <> '' then begin r_Common_SetLoading(_lc[I_LOAD_SKY], 1); - SkyTexture := r_Common_LoadTextureFromFile(gMapInfo.SkyFullName); + SkyTexture := r_Common_LoadTextureFromFile(gMapInfo.SkyFullName, [TGLHints.txNoRepeat]); end; plist.Clear; end; diff --git a/src/game/renders/opengl/r_render.pas b/src/game/renders/opengl/r_render.pas index 4c1f097..7f52d9d 100644 --- a/src/game/renders/opengl/r_render.pas +++ b/src/game/renders/opengl/r_render.pas @@ -127,24 +127,24 @@ implementation r_LoadScreen_Load; r_Common_Load; r_Common_SetLoading('HUD Textures', 5 + (WP_LAST + 1) + 11); - hud := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUD'); - hudbg := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUDBG'); - hudhp[false] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/MED2'); - hudhp[true] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/BMED'); - hudap := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/ARMORHUD'); + hud := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUD', [TGLHints.txNoRepeat]); + hudbg := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/HUDBG', []); + hudhp[false] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/MED2', [TGLHints.txNoRepeat]); + hudhp[true] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/BMED', [TGLHints.txNoRepeat]); + hudap := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/ARMORHUD', [TGLHints.txNoRepeat]); for i := 0 to WP_LAST do - hudwp[i] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/' + WeapName[i]); - hudkey[0] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYR'); - hudkey[1] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYG'); - hudkey[2] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYB'); - hudair := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/AIRBAR'); - hudjet := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/JETBAR'); - hudrflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_BASE'); - hudrflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_STOLEN'); - hudrflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_DROP'); - hudbflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_BASE'); - hudbflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_STOLEN'); - hudbflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_DROP'); + hudwp[i] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/' + WeapName[i], [TGLHints.txNoRepeat]); + hudkey[0] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYR', [TGLHints.txNoRepeat]); + hudkey[1] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYG', [TGLHints.txNoRepeat]); + hudkey[2] := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/KEYB', [TGLHints.txNoRepeat]); + hudair := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/AIRBAR', [TGLHints.txNoRepeat]); + hudjet := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/JETBAR', [TGLHints.txNoRepeat]); + hudrflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_BASE', [TGLHints.txNoRepeat]); + hudrflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_STOLEN', [TGLHints.txNoRepeat]); + hudrflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_R_DROP', [TGLHints.txNoRepeat]); + hudbflag := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_BASE', [TGLHints.txNoRepeat]); + hudbflags := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_STOLEN', [TGLHints.txNoRepeat]); + hudbflagd := r_Common_LoadTextureFromFile(GameWAD + ':TEXTURES/FLAGHUD_B_DROP', [TGLHints.txNoRepeat]); r_Console_Load; r_Map_Load; {$IFDEF ENABLE_MENU} diff --git a/src/game/renders/opengl/r_textures.pas b/src/game/renders/opengl/r_textures.pas index 24ea164..34b5b9e 100644 --- a/src/game/renders/opengl/r_textures.pas +++ b/src/game/renders/opengl/r_textures.pas @@ -29,6 +29,9 @@ interface ; type + TGLHints = (txNoRepeat); + TGLHintsSet = set of TGLHints; + TGLAtlas = class; TGLAtlasNode = class (TAtlasNode) @@ -65,6 +68,7 @@ interface mHeight: Integer; mCols: Integer; mTile: array of TGLAtlasNode; + mHints: TGLHintsSet; public destructor Destroy; override; @@ -77,6 +81,7 @@ interface property height: Integer read mHeight; property cols: Integer read mCols; property lines: Integer read GetLines; + property hints: TGLHintsSet read mHints; end; TGLMultiTexture = class @@ -125,12 +130,12 @@ interface 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; log: Boolean = True): TGLMultiTexture; - function r_Textures_LoadMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture; + 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; 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; function r_Textures_LoadFontFromFile (const filename: AnsiString; constref f: TFontInfo; font2enc: TConvProc; log: Boolean = true): TGLFont; @@ -146,8 +151,9 @@ implementation var r_GL_MaxTexSize: WORD; + r_GL_RepeatOpt: Boolean; maxTileSize: Integer; - atl: array of TGLAtlas; + atl, ratl: array of TGLAtlas; (* --------- TGLAtlasNode --------- *) @@ -216,6 +222,8 @@ implementation if id <> 0 then begin glBindTexture(GL_TEXTURE_2D, 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); @@ -238,6 +246,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 @@ -260,22 +282,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; @@ -299,29 +355,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; @@ -418,6 +489,17 @@ implementation end; end; SetLength(atl, 0); + + if ratl <> nil then + begin + for i := 0 to High(ratl) do + begin + glDeleteTextures(1, @ratl[i].id); + ratl[i].id := 0; + r_Common_FreeAndNil(ratl[i]); + end; + end; + SetLength(ratl, 0); end; function r_Textures_FixImageData (var img: TImageData): Boolean; @@ -428,13 +510,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 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); @@ -454,7 +557,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; @@ -464,14 +567,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; @@ -482,14 +585,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): 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); @@ -502,7 +605,7 @@ 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; @@ -512,7 +615,7 @@ implementation result := m; end; - function r_Textures_LoadMultiFromDataAndInfo (data: Pointer; size: LongInt; w, h, c: Integer): TGLMultiTexture; + function r_Textures_LoadMultiFromDataAndInfo (data: Pointer; size: LongInt; w, h, c: Integer; hints: TGLHintsSet): TGLMultiTexture; var img: TImageData; begin ASSERT(w > 0); @@ -525,7 +628,7 @@ implementation try if LoadImageFromMemory(data, size, img) then if r_Textures_FixImageData(img) then - result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c) + result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, hints) except end; FreeImage(img); @@ -554,7 +657,7 @@ implementation end; end; - function r_Textures_LoadMultiFromWad (wad: TWADFile; var txt: TAnimTextInfo): TGLMultiTexture; + function r_Textures_LoadMultiFromWad (wad: TWADFile; var txt: TAnimTextInfo; hints: TGLHintsSet): TGLMultiTexture; var data: Pointer; size: LongInt; img: TImageData; begin ASSERT(wad <> nil); @@ -570,7 +673,7 @@ implementation 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); + result := r_Textures_LoadMultiFromImageAndInfo(img, txt.w, txt.h, txt.anim.frames, hints); finally FreeMem(data); end; @@ -582,13 +685,13 @@ implementation end; end; - function r_Textures_LoadMultiFromMemory (data: Pointer; size: LongInt; var txt: TAnimTextInfo): 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(); @@ -608,14 +711,14 @@ implementation wad := TWADFile.Create(); if wad.ReadMemory(data, size) then begin - result := r_Textures_LoadMultiFromWad(wad, txt); + result := r_Textures_LoadMultiFromWad(wad, txt, hints); wad.Free; end end end end; - function r_Textures_LoadMultiTextFromFile (const filename: AnsiString; var txt: TAnimTextInfo; log: Boolean = True): TGLMultiTexture; + 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; @@ -626,20 +729,20 @@ implementation resName := g_ExtractFilePathName(filename); if wad.GetResource(resName, data, size, log) then begin - result := r_Textures_LoadMultiFromMemory(data, size, txt); + result := r_Textures_LoadMultiFromMemory(data, size, txt, hints); FreeMem(data); end; wad.Free end end; - function r_Textures_LoadMultiFromFile (const filename: AnsiString; 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, log); + result := r_Textures_LoadMultiTextFromFile(filename, txt, hints, log); end; - function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; log: Boolean = True): TGLMultiTexture; + 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); @@ -653,7 +756,7 @@ implementation resName := g_ExtractFilePathName(filename); if wad.GetResource(resName, data, size, log) then begin - result := r_Textures_LoadMultiFromDataAndInfo(data, size, w, h, count); + result := r_Textures_LoadMultiFromDataAndInfo(data, size, w, h, count, hints); FreeMem(data); end; wad.Free @@ -717,7 +820,7 @@ implementation end; end; - function r_Textures_LoadStreamFromImage (var img: TImageData; w, h, c, cw: Integer; st: TGLTextureArray; rs: TRectArray): Boolean; + 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); @@ -739,7 +842,7 @@ implementation 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); @@ -747,7 +850,7 @@ implementation end; end; - function r_Textures_LoadStreamFromMemory (data: Pointer; size: LongInt; w, h, c, cw: 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); @@ -765,7 +868,7 @@ implementation begin if r_Textures_FixImageData(img) then begin - result := r_Textures_LoadStreamFromImage(img, w, h, c, cw, st, rs) + result := r_Textures_LoadStreamFromImage(img, w, h, c, cw, st, rs, hints) end; end; except @@ -774,7 +877,7 @@ implementation end; end; - function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count, cw: 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); @@ -791,7 +894,7 @@ implementation 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); + result := r_Textures_LoadStreamFromMemory(data, size, w, h, count, cw, st, rs, hints); FreeMem(data); end; wad.Free @@ -805,7 +908,7 @@ implementation begin result := nil; SetLength(st, 256); - if r_Textures_LoadStreamFromFile(filename, f.w, f.h, 256, 16, st, nil, log) then + if r_Textures_LoadStreamFromFile(filename, f.w, f.h, 256, 16, st, nil, [TGLHints.txNoRepeat], log) then begin font := TGLFont.Create(); font.info := f; @@ -868,5 +971,7 @@ implementation 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.