From 10658b989ac4e02b2cb4264351675d8da6d8311b Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Sat, 19 Aug 2017 15:10:35 +0300 Subject: [PATCH] intermediate commit (faster render and coldet; this commit won't build!) --- src/game/g_game.pas | 462 ++++++++++++++++++------------------------- src/game/g_grid.pas | 2 +- src/game/g_map.pas | 420 ++++++++++++++++----------------------- src/game/g_panel.pas | 15 ++ 4 files changed, 377 insertions(+), 522 deletions(-) diff --git a/src/game/g_game.pas b/src/game/g_game.pas index f1dd84f..a50ce72 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -323,7 +323,7 @@ implementation uses g_textures, g_main, g_window, g_menu, - e_input, e_log, g_console, g_items, g_map, + e_input, e_log, g_console, g_items, g_map, g_panel, g_playermodel, g_gfx, g_options, g_weapons, Math, g_triggers, MAPDEF, g_monsters, e_sound, CONFIG, BinEditor, g_language, g_net, SDL, @@ -412,56 +412,6 @@ end; // ////////////////////////////////////////////////////////////////////////// // -(* -procedure drawProfiles (x, y: Integer; title: AnsiString); overload; -var - wdt, hgt: Integer; - yy: Integer; - - { - procedure drawItems (); - begin - repeat - e_TextureFontPrintEx(x+2+4*xprofItLevel, yy, Format('%s: %d', [xprofItName, Integer(xprofItMicro)]), gStdFont, 255, 255, 0, 1, false); - Inc(yy, 16+2); - if xprofItHasChildren then - begin - xprofItDive(); - drawItems(); - xprofItPop(); - end; - until not xprofItNext(); - end; - } - - procedure drawItems (); - var - ii, idx: Integer; - begin - for ii := 0 to xprofTotalCount-1 do - begin - e_TextureFontPrintEx(x+2+4*xprofLevelAt(ii), yy, Format('%s: %d', [xprofNameAt(ii), Integer(xprofMicroAt(ii))]), gStdFont, 255, 255, 0, 1, false); - Inc(yy, 16+2); - end; - end; - -begin - // gScreenWidth - //if not xprofItReset() then exit; - if (xprofTotalCount = 0) then exit; - wdt := 256; - hgt := 16+2+xprofTotalCount*(16+2); // title, items - // background - //e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 255, 255, 255, 200, B_BLEND); - e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 20, 20, 20, 0, B_NONE); - // title - e_TextureFontPrintEx(x+2, y+2, Format('%s: %d', [title, Integer(xprofTotalMicro)]), gStdFont, 255, 255, 0, 1, false); - yy := y+16+2; - drawItems(); -end; -*) - - function calcProfilesHeight (prof: TProfiler): Integer; begin result := 0; @@ -2693,7 +2643,168 @@ begin end; end; + +// setup sX, sY, sWidth, sHeight, and transformation matrix before calling this! +procedure renderDynLightsInternal (); +var + lln: Integer; + lx, ly, lrad: Integer; +begin + //TODO: lights should be in separate grid, i think + // but on the other side: grid may be slower for dynlights, as their lifetime is short + if not gwin_has_stencil or (g_dynLightCount < 1) then exit; + + // setup OpenGL parameters + glStencilMask($FFFFFFFF); + glStencilFunc(GL_ALWAYS, 0, $FFFFFFFF); + glEnable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilFunc(GL_EQUAL, 0, $ff); + + for lln := 0 to g_dynLightCount-1 do + begin + lx := g_dynLights[lln].x; + ly := g_dynLights[lln].y; + lrad := g_dynLights[lln].radius; + if lrad < 3 then continue; + + if lx-sX+lrad < 0 then continue; + if ly-sY+lrad < 0 then continue; + if lx-sX-lrad >= gPlayerScreenSize.X then continue; + if ly-sY-lrad >= gPlayerScreenSize.Y then continue; + + // set scissor to optimize drawing + glScissor((lx-sX)-lrad+2, gPlayerScreenSize.Y-(ly-sY)-lrad-1+2, lrad*2-4, lrad*2-4); + // no need to clear stencil buffer, light blitting will do it for us + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + // draw extruded panels + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no need to modify color buffer + if (lrad > 4) then g_Map_DrawPanelShadowVolumes(lx, ly, lrad); + // render light texture + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // draw light, and clear stencil buffer + // blend it + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_TEXTURE_2D); + // color and opacity + glColor4f(g_dynLights[lln].r, g_dynLights[lln].g, g_dynLights[lln].b, g_dynLights[lln].a); + glBindTexture(GL_TEXTURE_2D, g_Texture_Light()); + glBegin(GL_QUADS); + glTexCoord2f(0.0, 0.0); glVertex2i(lx-lrad, ly-lrad); // top-left + glTexCoord2f(1.0, 0.0); glVertex2i(lx+lrad, ly-lrad); // top-right + glTexCoord2f(1.0, 1.0); glVertex2i(lx+lrad, ly+lrad); // bottom-right + glTexCoord2f(0.0, 1.0); glVertex2i(lx-lrad, ly+lrad); // bottom-left + glEnd(); + end; + + // done + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + glScissor(0, 0, sWidth, sHeight); +end; + + +// setup sX, sY, sWidth, sHeight, and transformation matrix before calling this! +// WARNING! this WILL CALL `glTranslatef()`, but won't restore matrices! +procedure renderMapInternal (backXOfs, backYOfs: Integer; transX, transY: Integer; setTransMatrix: Boolean); +type + TDrawCB = procedure (); + + procedure drawPanelType (profname: AnsiString; panType: DWord); + var + tagmask: Integer; + pan: TPanel; + begin + profileFrameDraw.sectionBegin(profname); + if gdbg_map_use_accel_render then + begin + tagmask := panelTypeToTag(panType); + {$IF TRUE} + while (gDrawPanelList.count > 0) do + begin + pan := TPanel(gDrawPanelList.front()); + if ((pan.tag and tagmask) = 0) then break; + pan.Draw(); + gDrawPanelList.popFront(); + end; + {$ELSE} + e_WriteLog(Format('=== PANELS: %d ===', [gDrawPanelList.count]), MSG_NOTIFY); + while (gDrawPanelList.count > 0) do + begin + pan := TPanel(gDrawPanelList.front()); + e_WriteLog(Format('tagmask: 0x%04x; pan.tag: 0x%04x; pan.ArrIdx: %d', [tagmask, pan.tag, pan.ArrIdx]), MSG_NOTIFY); + pan.Draw(); + gDrawPanelList.popFront(); + end; + {$ENDIF} + end + else + begin + g_Map_DrawPanels(panType); + end; + profileFrameDraw.sectionEnd(); + end; + + procedure drawOther (profname: AnsiString; cb: TDrawCB); + begin + profileFrameDraw.sectionBegin(profname); + if assigned(cb) then cb(); + profileFrameDraw.sectionEnd(); + end; + +begin + profileFrameDraw.sectionBegin('map rendering'); + + // our accelerated renderer will collect all panels to gDrawPanelList + // we can use panel tag to render level parts (see GridTagXXX in g_map.pas) + profileFrameDraw.sectionBegin('pancollect'); + if gdbg_map_use_accel_render then + begin + g_Map_CollectDrawPanels(sX, sY, sWidth, sHeight); + end; + profileFrameDraw.sectionEnd(); + + profileFrameDraw.sectionBegin('map background'); + g_Map_DrawBack(backXOfs, backYOfs); + profileFrameDraw.sectionEnd(); + + if (setTransMatrix) then glTranslatef(transX, transY, 0); + + drawPanelType('panel_back', PANEL_BACK); + drawPanelType('panel_step', PANEL_STEP); + drawOther('items', @g_Items_Draw); + drawOther('weapons', @g_Weapon_Draw); + drawOther('shells', @g_Player_DrawShells); + drawOther('drawall', @g_Player_DrawAll); + drawOther('corpses', @g_Player_DrawCorpses); + drawPanelType('panel_wall', PANEL_WALL); + drawOther('monsters', @g_Monsters_Draw); + drawPanelType('panel_closedoor', PANEL_CLOSEDOOR); + drawOther('gfx', @g_GFX_Draw); + drawOther('flags', @g_Map_DrawFlags); + drawPanelType('panel_acid1', PANEL_ACID1); + drawPanelType('panel_acid2', PANEL_ACID2); + drawPanelType('panel_water', PANEL_WATER); + drawOther('dynlights', @renderDynLightsInternal); + drawPanelType('panel_fore', PANEL_FORE); + + if g_debug_HealthBar then + begin + g_Monsters_DrawHealth(); + g_Player_DrawHealth(); + end; + + profileFrameDraw.mainEnd(); // map rendering +end; + + procedure DrawMapView(x, y, w, h: Integer); + var bx, by: Integer; begin @@ -2701,46 +2812,23 @@ begin bx := Round(x/(gMapInfo.Width - w)*(gBackSize.X - w)); by := Round(y/(gMapInfo.Height - h)*(gBackSize.Y - h)); - g_Map_DrawBack(-bx, -by); sX := x; sY := y; sWidth := w; sHeight := h; - glTranslatef(-x, -y, 0); - - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_BACK); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_STEP); - g_Items_Draw(); - g_Weapon_Draw(); - g_Player_DrawShells(); - g_Player_DrawAll(); - g_Player_DrawCorpses(); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_WALL); - g_Monsters_Draw(); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_CLOSEDOOR); - g_GFX_Draw(); - g_Map_DrawFlags(); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_ACID1); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_ACID2); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_WATER); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_FORE); - if g_debug_HealthBar then - begin - g_Monsters_DrawHealth(); - g_Player_DrawHealth(); - end; + renderMapInternal(-bx, -by, -x, -y, true); glPopMatrix(); end; + procedure DrawPlayer(p: TPlayer); var px, py, a, b, c, d: Integer; //R: TRect; - lln: Integer; - lx, ly, lrad: Integer; + begin if (p = nil) or (p.FDummy) then begin @@ -2760,220 +2848,60 @@ begin px := p.GameX + PLAYER_RECT_CX; py := p.GameY + PLAYER_RECT_CY; - if px > (gPlayerScreenSize.X div 2) then - a := -px + (gPlayerScreenSize.X div 2) - else - a := 0; - if py > (gPlayerScreenSize.Y div 2) then - b := -py + (gPlayerScreenSize.Y div 2) - else - b := 0; - if px > (gMapInfo.Width - (gPlayerScreenSize.X div 2)) then - a := -gMapInfo.Width + gPlayerScreenSize.X; - if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then - b := -gMapInfo.Height + gPlayerScreenSize.Y; - if gMapInfo.Width <= gPlayerScreenSize.X then - a := 0; - if gMapInfo.Height <= gPlayerScreenSize.Y then - b := 0; + if px > (gPlayerScreenSize.X div 2) then a := -px+(gPlayerScreenSize.X div 2) else a := 0; + if py > (gPlayerScreenSize.Y div 2) then b := -py+(gPlayerScreenSize.Y div 2) else b := 0; + + if px > gMapInfo.Width-(gPlayerScreenSize.X div 2) then a := -gMapInfo.Width+gPlayerScreenSize.X; + if py > gMapInfo.Height-(gPlayerScreenSize.Y div 2) then b := -gMapInfo.Height+gPlayerScreenSize.Y; + + if gMapInfo.Width <= gPlayerScreenSize.X then a := 0; + if gMapInfo.Height <= gPlayerScreenSize.Y then b := 0; if p.IncCam <> 0 then begin - if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then + if py > gMapInfo.Height-(gPlayerScreenSize.Y div 2) then begin if p.IncCam > 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2))) then + begin p.IncCam := 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2))); + end; end; - if py < (gPlayerScreenSize.Y div 2) then + if py < gPlayerScreenSize.Y div 2 then begin if p.IncCam < -120+((gPlayerScreenSize.Y div 2)-py) then + begin p.IncCam := -120+((gPlayerScreenSize.Y div 2)-py); + end; end; if p.IncCam < 0 then - while (py+(gPlayerScreenSize.Y div 2)-p.IncCam > gMapInfo.Height) and - (p.IncCam < 0) do - p.IncCam := p.IncCam + 1; + begin + while (py+(gPlayerScreenSize.Y div 2)-p.IncCam > gMapInfo.Height) and (p.IncCam < 0) do p.IncCam := p.IncCam+1; //Inc(p.IncCam); + end; if p.IncCam > 0 then - while (py-(gPlayerScreenSize.Y div 2)-p.IncCam < 0) and - (p.IncCam > 0) do - p.IncCam := p.IncCam - 1; + begin + while (py-(gPlayerScreenSize.Y div 2)-p.IncCam < 0) and (p.IncCam > 0) do p.IncCam := p.IncCam-1; //Dec(p.IncCam); + end; end; - if (px< gPlayerScreenSize.X div 2) or - (gMapInfo.Width-gPlayerScreenSize.X <= 256) then - c := 0 - else - if (px > gMapInfo.Width-(gPlayerScreenSize.X div 2)) then - c := gBackSize.X - gPlayerScreenSize.X - else - c := Round((px-(gPlayerScreenSize.X div 2))/(gMapInfo.Width-gPlayerScreenSize.X)*(gBackSize.X-gPlayerScreenSize.X)); + if (px < gPlayerScreenSize.X div 2) or (gMapInfo.Width-gPlayerScreenSize.X <= 256) then c := 0 + else if (px > gMapInfo.Width-(gPlayerScreenSize.X div 2)) then c := gBackSize.X-gPlayerScreenSize.X + else c := round((px-(gPlayerScreenSize.X div 2))/(gMapInfo.Width-gPlayerScreenSize.X)*(gBackSize.X-gPlayerScreenSize.X)); - if (py-p.IncCam <= gPlayerScreenSize.Y div 2) or - (gMapInfo.Height-gPlayerScreenSize.Y <= 256) then - d := 0 - else - if (py-p.IncCam >= gMapInfo.Height-(gPlayerScreenSize.Y div 2)) then - d := gBackSize.Y - gPlayerScreenSize.Y - else - d := Round((py-p.IncCam-(gPlayerScreenSize.Y div 2))/(gMapInfo.Height-gPlayerScreenSize.Y)*(gBackSize.Y-gPlayerScreenSize.Y)); - - profileFrameDraw.sectionBegin('map background'); - g_Map_DrawBack(-c, -d); - profileFrameDraw.sectionEnd(); + if (py-p.IncCam <= gPlayerScreenSize.Y div 2) or (gMapInfo.Height-gPlayerScreenSize.Y <= 256) then d := 0 + else if (py-p.IncCam >= gMapInfo.Height-(gPlayerScreenSize.Y div 2)) then d := gBackSize.Y-gPlayerScreenSize.Y + else d := round((py-p.IncCam-(gPlayerScreenSize.Y div 2))/(gMapInfo.Height-gPlayerScreenSize.Y)*(gBackSize.Y-gPlayerScreenSize.Y)); sX := -a; sY := -(b+p.IncCam); sWidth := gPlayerScreenSize.X; sHeight := gPlayerScreenSize.Y; - glTranslatef(a, b+p.IncCam, 0); - - profileFrameDraw.sectionBegin('map rendering'); - - profileFrameDraw.sectionBegin('panel_back'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_BACK); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('panel_step'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_STEP); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('items'); - g_Items_Draw(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('weapons'); - g_Weapon_Draw(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('shells'); - g_Player_DrawShells(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('drawall'); - g_Player_DrawAll(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('corpses'); - g_Player_DrawCorpses(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('panel_wall'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_WALL); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('monsters'); - g_Monsters_Draw(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('panel_closedoor'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_CLOSEDOOR); - profileFrameDraw.sectionEnd(); + //glTranslatef(a, b+p.IncCam, 0); - profileFrameDraw.sectionBegin('gfx'); - g_GFX_Draw(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('flags'); - g_Map_DrawFlags(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('panel_acid1'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_ACID1); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('panel_acid2'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_ACID2); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('panel_water'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_WATER); - profileFrameDraw.sectionEnd(); - - //TODO: lights should be in separate grid, i think - // but on the other side: grid may be slower for dynlights, as their lifetime is short - if gwin_has_stencil and (g_dynLightCount > 0) then - begin - profileFrameDraw.sectionBegin('dynlights'); - - // setup OpenGL parameters - glStencilMask($FFFFFFFF); - glStencilFunc(GL_ALWAYS, 0, $FFFFFFFF); - glEnable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); - glClear(GL_STENCIL_BUFFER_BIT); - glStencilFunc(GL_EQUAL, 0, $ff); - - for lln := 0 to g_dynLightCount-1 do - begin - lx := g_dynLights[lln].x; - ly := g_dynLights[lln].y; - lrad := g_dynLights[lln].radius; - if lrad < 3 then continue; - - if lx-sX+lrad < 0 then continue; - if ly-sY+lrad < 0 then continue; - if lx-sX-lrad >= gPlayerScreenSize.X then continue; - if ly-sY-lrad >= gPlayerScreenSize.Y then continue; - - // set scissor to optimize drawing - glScissor((lx-sX)-lrad+2, gPlayerScreenSize.Y-(ly-sY)-lrad-1+2, lrad*2-4, lrad*2-4); - // no need to clear stencil buffer, light blitting will do it for us - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); - // draw extruded panels - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no need to modify color buffer - if (lrad > 4) then g_Map_DrawPanelShadowVolumes(lx, ly, lrad); - // render light texture - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // draw light, and clear stencil buffer - // blend it - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_TEXTURE_2D); - // color and opacity - glColor4f(g_dynLights[lln].r, g_dynLights[lln].g, g_dynLights[lln].b, g_dynLights[lln].a); - glBindTexture(GL_TEXTURE_2D, g_Texture_Light()); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2i(lx-lrad, ly-lrad); // top-left - glTexCoord2f(1.0, 0.0); glVertex2i(lx+lrad, ly-lrad); // top-right - glTexCoord2f(1.0, 1.0); glVertex2i(lx+lrad, ly+lrad); // bottom-right - glTexCoord2f(0.0, 1.0); glVertex2i(lx-lrad, ly+lrad); // bottom-left - glEnd(); - end; - - // done - glDisable(GL_STENCIL_TEST); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - glScissor(0, 0, sWidth, sHeight); - - profileFrameDraw.sectionEnd(); - end - else - begin - profileFrameDraw.sectionBegin('dynlights'); - profileFrameDraw.sectionEnd(); - end; - - profileFrameDraw.sectionBegin('panel_fore'); - g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_FORE); - profileFrameDraw.sectionEnd(); - - if g_debug_HealthBar then - begin - profileFrameDraw.sectionBegin('monster health'); - g_Monsters_DrawHealth(); - profileFrameDraw.sectionEnd(); - - profileFrameDraw.sectionBegin('player health'); - g_Player_DrawHealth(); - profileFrameDraw.sectionEnd(); - end; + renderMapInternal(-c, -d, a, b+p.IncCam, true); if p.FSpectator then e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4, @@ -2999,8 +2927,6 @@ begin glPopMatrix(); - profileFrameDraw.mainEnd(); // map rendering - p.DrawPain(); p.DrawPickup(); p.DrawRulez(); @@ -6906,7 +6832,7 @@ var begin Parse_Params(pars); - s := Find_Param_Value(pars, '--profile-frame'); + s := Find_Param_Value(pars, '--profile-render'); if (s <> '') then g_profile_frame_draw := true; s := Find_Param_Value(pars, '--profile-coldet'); diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas index 17319db..3ed6612 100644 --- a/src/game/g_grid.pas +++ b/src/game/g_grid.pas @@ -25,7 +25,7 @@ const GridCellBucketSize = 8; // WARNING! can't be less than 2! type - GridQueryCB = function (obj: TObject; tag: Integer): Boolean is nested; // return `true` to stop + GridQueryCB = function (obj: TObject; var proxy: PBodyProxyRec; tag: Integer): Boolean is nested; // return `true` to stop type TBodyGrid = class; diff --git a/src/game/g_map.pas b/src/game/g_map.pas index 634eff9..dd2f455 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -20,7 +20,7 @@ interface uses e_graphics, g_basic, MAPSTRUCT, g_textures, Classes, - g_phys, wadreader, BinEditor, g_panel, g_grid, z_aabbtree, md5, xprofiler; + g_phys, wadreader, BinEditor, g_panel, g_grid, z_aabbtree, md5, binheap, xprofiler; type TMapInfo = record @@ -62,7 +62,8 @@ function g_Map_Exist(Res: String): Boolean; procedure g_Map_Free(); procedure g_Map_Update(); -procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); +procedure g_Map_DrawPanels (PanelType: Word); // unaccelerated +procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); procedure g_Map_DrawBack(dx, dy: Integer); function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; @@ -116,6 +117,33 @@ const SKY_STRETCH: Single = 1.5; +const + GridTagInvalid = 0; + + (* draw order: + PANEL_BACK + PANEL_STEP + PANEL_WALL + PANEL_CLOSEDOOR + PANEL_ACID1 + PANEL_ACID2 + PANEL_WATER + PANEL_FORE + *) + // sorted by draw priority + GridTagBack = 1 shl 0; + GridTagStep = 1 shl 1; + GridTagWall = 1 shl 2; + GridTagDoor = 1 shl 3; + GridTagAcid1 = 1 shl 4; + GridTagAcid2 = 1 shl 5; + GridTagWater = 1 shl 6; + GridTagFore = 1 shl 7; + // the following are invisible + GridTagLift = 1 shl 8; + GridTagBlockMon = 1 shl 9; + + var gWalls: TPanelArray; gRenderBackgrounds: TPanelArray; @@ -140,6 +168,9 @@ var gdbg_map_use_tree_coldet: Boolean = false; gdbg_map_dump_coldet_tree_queries: Boolean = false; profMapCollision: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY! + gDrawPanelList: TBinaryHeapObj = nil; // binary heap of all walls we have to render, populated by `g_Map_CollectDrawPanels()` + +function panelTypeToTag (panelType: Word): Integer; // returns GridTagXXX implementation @@ -148,7 +179,7 @@ uses GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG, g_options, MAPREADER, g_triggers, g_player, MAPDEF, Math, g_monsters, g_saveload, g_language, g_netmsg, - utils, sfs, binheap, + utils, sfs, ImagingTypes, Imaging, ImagingUtility, ImagingGif, ImagingNetworkGraphics; @@ -157,22 +188,13 @@ const MUSIC_SIGNATURE = $4953554D; // 'MUSI' FLAG_SIGNATURE = $47414C46; // 'FLAG' - GridTagInvalid = 0; - GridTagWallDoor = $0001; - GridTagBack = $0002; - GridTagFore = $0004; - GridTagWater = $0008; - GridTagAcid1 = $0010; - GridTagAcid2 = $0020; - GridTagStep = $0040; - GridTagLift = $0080; - GridTagBlockMon = $0100; function panelTypeToTag (panelType: Word): Integer; begin case panelType of - PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR: result := GridTagWallDoor; // gWalls + PANEL_WALL: result := GridTagWall; // gWalls + PANEL_OPENDOOR, PANEL_CLOSEDOOR: result := GridTagDoor; // gWalls PANEL_BACK: result := GridTagBack; // gRenderBackgrounds PANEL_FORE: result := GridTagFore; // gRenderForegrounds PANEL_WATER: result := GridTagWater; // gWater @@ -186,6 +208,24 @@ begin end; +function dplLess (a, b: TObject): Boolean; +var + pa, pb: TPanel; +begin + //result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx); + pa := TPanel(a); + pb := TPanel(b); + if (pa.tag < pb.tag) then begin result := true; exit; end; + if (pa.tag > pb.tag) then begin result := false; exit; end; + result := (pa.ArrIdx < pb.ArrIdx); +end; + +procedure dplClear (); +begin + if (gDrawPanelList = nil) then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear(); +end; + + type TPanelID = record PWhere: ^TPanelArray; @@ -203,7 +243,8 @@ var begin result := false; if (flesh = nil) then begin aabb := AABB2D.Create(0, 0, 0, 0); exit; end; - pan := (flesh as TPanel); + //pan := (flesh as TPanel); + pan := TPanel(flesh); aabb := AABB2D.Create(pan.X, pan.Y, pan.X+pan.Width, pan.Y+pan.Height); if (pan.Width < 1) or (pan.Height < 1) then exit; //if (pan.Width = 1) then aabb.maxX += 1; @@ -989,30 +1030,36 @@ var mapX1: Integer = -$3fffffff; mapY1: Integer = -$3fffffff; - procedure fixMinMax (var panels: TPanelArray); + procedure calcBoundingBox (var panels: TPanelArray); var idx: Integer; + pan: TPanel; begin for idx := 0 to High(panels) do begin - if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue; - if mapX0 > panels[idx].X then mapX0 := panels[idx].X; - if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y; - if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1; - if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1; + pan := panels[idx]; + if not pan.visvalid then continue; + if (pan.Width < 1) or (pan.Height < 1) then continue; + if (mapX0 > pan.x0) then mapX0 := pan.x0; + if (mapY0 > pan.y0) then mapY0 := pan.y0; + if (mapX1 < pan.x1) then mapX1 := pan.x1; + if (mapY1 < pan.y1) then mapY1 := pan.y1; end; end; procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer); var idx: Integer; + pan: TPanel; begin tag := panelTypeToTag(tag); for idx := High(panels) downto 0 do begin - panels[idx].tag := tag; - gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag); - mapTree.insertObject(panels[idx], tag, true); // as static object + pan := panels[idx]; + pan.tag := tag; + if not pan.visvalid then continue; + gMapGrid.insertBody(pan, pan.X, pan.Y, pan.Width, pan.Height, tag); + mapTree.insertObject(pan, tag, true); // as static object end; end; @@ -1022,26 +1069,24 @@ begin mapTree.Free(); mapTree := nil; - fixMinMax(gWalls); - fixMinMax(gRenderBackgrounds); - fixMinMax(gRenderForegrounds); - fixMinMax(gWater); - fixMinMax(gAcid1); - fixMinMax(gAcid2); - fixMinMax(gSteps); - fixMinMax(gLifts); - fixMinMax(gBlockMon); - - if (mapX0 < 0) or (mapY0 < 0) then - begin - e_WriteLog(Format('funny map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING); - //raise Exception.Create('we are fucked'); - end; + calcBoundingBox(gWalls); + calcBoundingBox(gRenderBackgrounds); + calcBoundingBox(gRenderForegrounds); + calcBoundingBox(gWater); + calcBoundingBox(gAcid1); + calcBoundingBox(gAcid2); + calcBoundingBox(gSteps); + calcBoundingBox(gLifts); + calcBoundingBox(gBlockMon); + + e_WriteLog(Format('map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING); gMapGrid := TBodyGrid.Create(mapX0, mapY0, mapX1-mapX0+1, mapY1-mapY0+1); mapTree := TDynAABBTreeMap.Create(); - addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR + addPanelsToGrid(gWalls, PANEL_WALL); + addPanelsToGrid(gWalls, PANEL_CLOSEDOOR); + addPanelsToGrid(gWalls, PANEL_OPENDOOR); addPanelsToGrid(gRenderBackgrounds, PANEL_BACK); addPanelsToGrid(gRenderForegrounds, PANEL_FORE); addPanelsToGrid(gWater, PANEL_WATER); @@ -1846,13 +1891,14 @@ begin end; -procedure g_Map_DrawPanelsOld(PanelType: Word); +// old algo +procedure g_Map_DrawPanels (PanelType: Word); - procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False); + procedure DrawPanels (var panels: TPanelArray; drawDoors: Boolean=False); var idx: Integer; begin - if (panels <> nil) and (stp >= 0) and (stp <= 6) then + if (panels <> nil) then begin // alas, no visible set for idx := 0 to High(panels) do @@ -1864,148 +1910,77 @@ procedure g_Map_DrawPanelsOld(PanelType: Word); begin case PanelType of - PANEL_WALL: DrawPanels(0, gWalls); - PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True); - PANEL_BACK: DrawPanels(1, gRenderBackgrounds); - PANEL_FORE: DrawPanels(2, gRenderForegrounds); - PANEL_WATER: DrawPanels(3, gWater); - PANEL_ACID1: DrawPanels(4, gAcid1); - PANEL_ACID2: DrawPanels(5, gAcid2); - PANEL_STEP: DrawPanels(6, gSteps); + PANEL_WALL: DrawPanels(gWalls); + PANEL_CLOSEDOOR: DrawPanels(gWalls, True); + PANEL_BACK: DrawPanels(gRenderBackgrounds); + PANEL_FORE: DrawPanels(gRenderForegrounds); + PANEL_WATER: DrawPanels(gWater); + PANEL_ACID1: DrawPanels(gAcid1); + PANEL_ACID2: DrawPanels(gAcid2); + PANEL_STEP: DrawPanels(gSteps); end; end; -var - gDrawPanelList: TBinaryHeapObj = nil; - -function dplLess (a, b: TObject): Boolean; -begin - result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx); -end; - -procedure dplClear (); -begin - if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear(); -end; - -procedure dplAddPanel (pan: TPanel); -begin - if pan = nil then exit; - gDrawPanelList.insert(pan); -end; - - -procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); -var - ptag: Integer; - - function checker (obj: TObject; tag: Integer): Boolean; +// new algo +procedure g_Map_CollectDrawPanels (x0, y0, wdt, hgt: Integer); + function checker (obj: TObject; ; var proxy: PBodyProxyRectag: Integer): Boolean; var pan: TPanel; begin result := false; // don't stop, ever - //e_WriteLog(Format(' *body: tag:%d; ptag:%d; pantype=%d', [tag, ptag, PanelType]), MSG_NOTIFY); - if (tag <> ptag) then exit; - - if obj = nil then begin e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end; - if not (obj is TPanel) then begin e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end; //pan := (obj as TPanel); - //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY); - - pan := (obj as TPanel); - if (PanelType = PANEL_CLOSEDOOR) then begin if not pan.Door then exit; end else begin if pan.Door then exit; end; - //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY); - dplAddPanel(pan); - end; - - procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False); - var - idx: Integer; - pan: TPanel; - begin - if (panels <> nil) and (stp >= 0) and (stp <= 6) then - begin - // alas, no visible set - for idx := 0 to High(panels) do - begin - if not (drawDoors xor panels[idx].Door) then - begin - pan := panels[idx]; - { - if (pan.Width < 1) or (pan.Height < 1) then continue; - if (pan.X+pan.Width <= x0) or (pan.Y+pan.Height <= y0) then continue; - if (pan.X >= x0+wdt) or (pan.Y >= y0+hgt) then continue; - } - pan.Draw(); - //e_WriteLog(Format(' *body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, PanelType, PanelType]), MSG_NOTIFY); - end; - end; - end; + pan := TPanel(obj); + //if (PanelType = PANEL_CLOSEDOOR) then begin if not pan.Door then exit; end else begin if pan.Door then exit; end; + if ((tag and GridTagDoor) <> 0) <> pan.Door then exit; + //dplAddPanel(pan); + gDrawPanelList.insert(pan); end; begin - //g_Map_DrawPanelsOld(PanelType); exit; - //e_WriteLog('==================', MSG_NOTIFY); - //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); dplClear(); - ptag := panelTypeToTag(PanelType); + //tagmask := panelTypeToTag(PanelType); - if gdbg_map_use_accel_render then + if gdbg_map_use_tree_draw then begin - if gdbg_map_use_tree_draw then - begin - mapTree.aabbQuery(x0, y0, wdt, hgt, checker, ptag); - end - else - begin - gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, ptag); - end; - // sort and draw the list (we need to sort it, or rendering is fucked) - while gDrawPanelList.count > 0 do - begin - (gDrawPanelList.front() as TPanel).Draw(); - gDrawPanelList.popFront(); - end; + mapTree.aabbQuery(x0, y0, wdt, hgt, checker, (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore)); end else begin - //e_WriteLog(Format('+++QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); - case PanelType of - PANEL_WALL: DrawPanels(0, gWalls); - PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True); - PANEL_BACK: DrawPanels(1, gRenderBackgrounds); - PANEL_FORE: DrawPanels(2, gRenderForegrounds); - PANEL_WATER: DrawPanels(3, gWater); - PANEL_ACID1: DrawPanels(4, gAcid1); - PANEL_ACID2: DrawPanels(5, gAcid2); - PANEL_STEP: DrawPanels(6, gSteps); - end; + gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore)); end; - - //e_WriteLog('==================', MSG_NOTIFY); + // list will be rendered in `g_game.DrawPlayer()` + (* + while (gDrawPanelList.count > 0) do + begin + //(gDrawPanelList.front() as TPanel).Draw(); + TPanel(gDrawPanelList.front()).Draw(); + gDrawPanelList.popFront(); + end; + *) end; procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); - function checker (obj: TObject; tag: Integer): Boolean; + function checker (obj: TObject; ; var proxy: PBodyProxyRectag: Integer): Boolean; var pan: TPanel; begin result := false; // don't stop, ever - if (tag <> GridTagWallDoor) then exit; // only walls - pan := (obj as TPanel); + //if (tag <> GridTagWall) and (tag <> GridTagDoor) then exit; // only walls + //pan := (obj as TPanel); + pan := TPanel(obj); pan.DrawShadowVolume(lightX, lightY, radius); end; begin if gdbg_map_use_tree_draw then begin - mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checker, GridTagWallDoor); + mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor)); end else begin - gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, GridTagWallDoor); + gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor)); end; end; @@ -2171,106 +2146,60 @@ end; function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean; - function checker (obj: TObject; tag: Integer): Boolean; + function checker (obj: TObject; ; var proxy: PBodyProxyRectag: Integer): Boolean; var pan: TPanel; - a: Integer; begin result := false; // don't stop, ever - //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); - - if obj = nil then + if ((tag and GridTagLift) <> 0) then begin - e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); - end; - if not (obj is TPanel) then - begin - e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); - exit; - end; - - pan := (obj as TPanel); - a := pan.ArrIdx; - - if WordBool(PanelType and PANEL_WALL) and (tag = GridTagWallDoor) then - begin - if gWalls[a].Enabled and g_Collide(X, Y, Width, Height, gWalls[a].X, gWalls[a].Y, gWalls[a].Width, gWalls[a].Height) then + pan := TPanel(obj); + if ((WordBool(PanelType and (PANEL_LIFTUP)) and (pan.LiftType = 0)) or + (WordBool(PanelType and (PANEL_LIFTDOWN)) and (pan.LiftType = 1)) or + (WordBool(PanelType and (PANEL_LIFTLEFT)) and (pan.LiftType = 2)) or + (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (pan.LiftType = 3))) and + g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height) then begin result := true; exit; end; end; - if WordBool(PanelType and PANEL_WATER) and (tag = GridTagWater) then - begin - if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then - begin - result := True; - exit; - end; - end; - - if WordBool(PanelType and PANEL_ACID1) and (tag = GridTagAcid1) then - begin - if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then - begin - result := True; - exit; - end; - end; - - if WordBool(PanelType and PANEL_ACID2) and (tag = GridTagAcid2) then + if ((pan.tag and GridTagBlockMon) <> 0) then begin - if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then + if ((not b1x3) or (pan.Width+pan.Height >= 64)) and g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height) then begin result := True; exit; end; end; - if WordBool(PanelType and PANEL_STEP) and (tag = GridTagStep) then - begin - if g_Collide(X, Y, Width, Height, gSteps[a].X, gSteps[a].Y, gSteps[a].Width, gSteps[a].Height) then - begin - result := True; - exit; - end; - end; - - if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (tag = GridTagLift) then - begin - if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or - (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or - (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or - (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and - g_Collide(X, Y, Width, Height, gLifts[a].X, gLifts[a].Y, gLifts[a].Width, gLifts[a].Height) then - begin - result := true; - exit; - end; - end; - - if WordBool(PanelType and PANEL_BLOCKMON) and (tag = GridTagBlockMon) then - begin - if ((not b1x3) or ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64)) and - g_Collide(X, Y, Width, Height, gBlockMon[a].X, gBlockMon[a].Y, gBlockMon[a].Width, gBlockMon[a].Height) then - begin - result := True; - exit; - end; - end; + // other shit + result := g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height); end; +var + tagmask: Integer = 0; begin //TODO: detailed profile + if WordBool(PanelType and PANEL_WALL) then tagmask := tagmask or GridTagWall or GridTagDoor; + if WordBool(PanelType and PANEL_WATER) then tagmask := tagmask or GridTagWater; + if WordBool(PanelType and PANEL_ACID1) then tagmask := tagmask or GridTagAcid1; + if WordBool(PanelType and PANEL_ACID2) then tagmask := tagmask or GridTagAcid2; + if WordBool(PanelType and PANEL_STEP) then tagmask := tagmask or GridTagStep; + if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then tagmask := tagmask or GridTagLift; + if WordBool(PanelType and PANEL_BLOCKMON) then tagmask := tagmask or GridTagBlockMon; + + if (tagmask = 0) then begin result := false; exit; end; // just in case + if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('wall coldet'); if gdbg_map_use_accel_coldet then begin if gdbg_map_use_tree_coldet then begin //e_WriteLog(Format('coldet query: x=%d; y=%d; w=%d; h=%d', [X, Y, Width, Height]), MSG_NOTIFY); - result := (mapTree.aabbQuery(X, Y, Width, Height, checker, (GridTagWallDoor or GridTagWater or GridTagAcid1 or GridTagAcid2 or GridTagStep or GridTagLift or GridTagBlockMon)) <> nil); + result := (mapTree.aabbQuery(X, Y, Width, Height, checker, tagmask) <> nil); if (gdbg_map_dump_coldet_tree_queries) and (mapTree.nodesVisited <> 0) then begin //e_WriteLog(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited]), MSG_NOTIFY); @@ -2279,7 +2208,7 @@ begin end else begin - result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWallDoor or GridTagWater or GridTagAcid1 or GridTagAcid2 or GridTagStep or GridTagLift or GridTagBlockMon)); + result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask); end; end else @@ -2299,42 +2228,27 @@ var function checker (obj: TObject; tag: Integer): Boolean; var pan: TPanel; - a: Integer; begin result := false; // don't stop, ever - if (tag <> GridTagWater) and (tag <> GridTagAcid1) and (tag <> GridTagAcid2) then exit; - pan := (obj as TPanel); - a := pan.ArrIdx; - // water - if (tag = GridTagWater) then - begin - if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then - begin - result := true; // water has highest priority, so stop right here - texid := gWater[a].GetTextureID(); - exit; - end; - end; - // acid1 - if (cctype > 1) and (tag = GridTagAcid1) then - begin - if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then - begin - cctype := 1; - texid := gAcid1[a].GetTextureID(); - exit; - end; + if ((tag and (GridTagWater or GridTagAcid1 or GridTagAcid2)) = 0) then exit; + //pan := (obj as TPanel); + pan := TPanel(obj); + // check priorities + case cctype of + 0: if ((tag and GridTagWater) = 0) then exit; // only water + 1: if ((tag and (GridTagWater or GridTagAcid1)) = 0) then exit; // water, acid1 + //2: if ((tag and (GridTagWater or GridTagAcid1 or GridTagAcid2) = 0) then exit; // water, acid1, acid2 end; + // collision? + if not g_Collide(X, Y, Width, Height, pan.X, pan.Y, pan.Width, pan.Height) then exit; + // yeah + texid := pan.GetTextureID(); + // water? water has the highest priority, so stop right here + if ((tag and GridTagWater) <> 0) then begin cctype := 0; result := true; exit; end; // acid2 - if (cctype > 2) and (tag = GridTagAcid2) then - begin - if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then - begin - cctype := 2; - texid := gAcid2[a].GetTextureID(); - exit; - end; - end; + if ((tag and GridTagAcid2) <> 0) then cctype := 2; + // acid1 + if ((tag and GridTagAcid1) <> 0) then cctype := 1; end; begin diff --git a/src/game/g_panel.pas b/src/game/g_panel.pas index 39237f1..ab99604 100644 --- a/src/game/g_panel.pas +++ b/src/game/g_panel.pas @@ -41,6 +41,11 @@ type True: (AnTex: TAnimation); end; + private + function getx1 (): Integer; inline; + function gety1 (): Integer; inline; + function getvisvalid (): Boolean; inline; + public FCurTexture: Integer; // Íîìåð òåêóùåé òåêñòóðû FCurFrame: Integer; @@ -74,6 +79,12 @@ type procedure SaveState(var Mem: TBinMemoryWriter); procedure LoadState(var Mem: TBinMemoryReader); + + property x0: Integer read X; + property y0: Integer read Y; + property x1: Integer read getx1; // inclusive! + property y1: Integer read gety1; // inclusive! + property visvalid: Boolean read getvisvalid; // panel is "visvalid" when it's width and height are positive end; PPanel = ^TPanel; @@ -248,6 +259,10 @@ begin Inherited; end; +function TPanel.getx1 (): Integer; inline; begin result := X+Width-1; end; +function TPanel.gety1 (): Integer; inline; begin result := Y+Height-1; end; +function TPanel.getvisvalid (): Boolean; inline; begin result := (Width > 0) and (Height > 0); end; + procedure TPanel.Draw(); var xx, yy: Integer; -- 2.29.2