X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_gfx.pas;h=2e4dc8730c400582dc59085bb1515a2cbd20ef8f;hb=66a94fecae8b7adff4a52946029944e3cb1870da;hp=bd8d9ae5567495f7b857f9f3a77575c024d4596a;hpb=a7daeef3855f07c8302a60ab31cb20ab74aefc45;p=d2df-sdl.git diff --git a/src/game/g_gfx.pas b/src/game/g_gfx.pas index bd8d9ae..2e4dc87 100644 --- a/src/game/g_gfx.pas +++ b/src/game/g_gfx.pas @@ -14,6 +14,8 @@ * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} +{.$DEFINE D2F_DEBUG_FALL_MPLAT} +{/$DEFINE D2F_DEBUG_PART_AWAKE} unit g_gfx; interface @@ -69,6 +71,10 @@ var gpart_dbg_phys_enabled: Boolean = true; +//WARNING: only for Holmes! +function awmIsSetHolmes (x, y: Integer): Boolean; inline; + + implementation uses @@ -148,12 +154,50 @@ var awakeMapW: Integer = -1; awakeMinX, awakeMinY: Integer; awakeDirty: Boolean = false; + {$IF DEFINED(D2F_DEBUG_PART_AWAKE)} + awakeMapHlm: packed array of LongWord = nil; + {$ENDIF} + + +// ////////////////////////////////////////////////////////////////////////// // +function awmIsSetHolmes (x, y: Integer): Boolean; inline; +begin +{$IF DEFINED(D2F_DEBUG_PART_AWAKE)} + if (Length(awakeMapHlm) = 0) then begin result := false; exit; end; + x := (x-awakeMinX) div mapGrid.tileSize; + y := (y-awakeMinY) div mapGrid.tileSize; + if (x >= 0) and (y >= 0) and (x div 32 < awakeMapW) and (y < awakeMapH) then + begin + if (y*awakeMapW+x div 32 < Length(awakeMapHlm)) then + begin + result := ((awakeMapHlm[y*awakeMapW+x div 32] and (LongWord(1) shl (x mod 32))) <> 0); + end + else + begin + result := false; + end; + end + else + begin + result := false; + end; +{$ELSE} + result := false; +{$ENDIF} +end; // ////////////////////////////////////////////////////////////////////////// // // HACK! using mapgrid procedure awmClear (); inline; begin + {$IF DEFINED(D2F_DEBUG_PART_AWAKE)} + if (Length(awakeMap) > 0) then + begin + if (Length(awakeMapHlm) <> Length(awakeMap)) then SetLength(awakeMapHlm, Length(awakeMap)); + Move(awakeMap[0], awakeMapHlm[0], Length(awakeMap)*sizeof(awakeMap[0])); + end; + {$ENDIF} if awakeDirty and (awakeMapW > 0) then begin FillDWord(awakeMap[0], Length(awakeMap), 0); @@ -171,9 +215,13 @@ begin awakeMinX := mapGrid.gridX0; awakeMinY := mapGrid.gridY0; SetLength(awakeMap, awakeMapW*awakeMapH); - {$IF DEFINED(D2F_DEBUG)} - e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]); + {$IF DEFINED(D2F_DEBUG_PART_AWAKE)} + SetLength(awakeMapHlm, awakeMapW*awakeMapH); + FillDWord(awakeMapHlm[0], Length(awakeMapHlm), 0); {$ENDIF} + //{$IF DEFINED(D2F_DEBUG)} + e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]); + //{$ENDIF} awakeDirty := true; awmClear(); end; @@ -215,6 +263,55 @@ begin end; +// ////////////////////////////////////////////////////////////////////////// // +// st: set mark +// t: mark type +// currently unused +procedure g_Mark (x, y, Width, Height: Integer; t: Byte; st: Boolean=true); +const Extrude = 1; +var + dx, dy, ex, ey: Integer; + v: PLongWord; +begin + if (not gpart_dbg_enabled) or (not gpart_dbg_phys_enabled) then exit; + if (awakeMapW < 1) or (awakeMapH < 1) then exit; + + if (Width < 1) or (Height < 1) then exit; + + // make some border, so we'll hit particles around the panel + ex := x+Width+Extrude-1-awakeMinX; + ey := y+Height+Extrude-1-awakeMinY; + x := (x-Extrude)-awakeMinX; + y := (y-Extrude)-awakeMinY; + + x := x div mapGrid.tileSize; + y := y div mapGrid.tileSize; + ex := ex div mapGrid.tileSize; + ey := ey div mapGrid.tileSize; + + // has something to do? + if (ex < 0) or (ey < 0) or (x >= awakeMapW*32) or (y >= awakeMapH) then exit; + if (x < 0) then x := 0; + if (y < 0) then y := 0; + if (ex >= awakeMapW*32) then ex := awakeMapW*32-1; + if (ey >= awakeMapH) then ey := awakeMapH; + + awakeDirty := true; + for dy := y to ey do + begin + for dx := x to ex do + begin + {$IF DEFINED(D2F_DEBUG)} + assert((dx >= 0) and (dy >= 0) and (dx div 32 < awakeMapW) and (dy < awakeMapH)); + assert(dy*awakeMapW+dx div 32 < Length(awakeMap)); + {$ENDIF} + v := @awakeMap[dy*awakeMapW+dx div 32]; + v^ := v^ or (LongWord(1) shl (dx mod 32)); + end; + end; +end; + + // ////////////////////////////////////////////////////////////////////////// // function TParticle.alive (): Boolean; inline; begin result := (state <> TPartState.Free); end; procedure TParticle.die (); inline; begin state := TPartState.Free; end; @@ -360,24 +457,52 @@ end; procedure TParticle.think (); inline; procedure awake (); begin - state := TPartState.Normal; + if (state = TPartState.Stuck) then + begin + //writeln('awaking particle at (', x, ',', y, ')'); + if (stickDX = 0) then + begin + state := TPartState.Normal; // stuck to a ceiling + end + else + begin + // stuck to a wall, check if wall is still there + if (wallEndY <> Unknown) then + begin + wallEndY := Unknown; + if (g_Map_PanelAtPoint(x+stickDX, y, GridTagObstacle) = nil) then + begin + // a wall was moved out, start falling + state := TPartState.Normal; + if (velY = 0) then velY := 0.1; + if (accelY = 0) then accelY := 0.5; + end; + end; + end; + end + else + begin + state := TPartState.Normal; + if (velY = 0) then velY := 0.1; + if (accelY = 0) then accelY := 0.5; + end; floorY := Unknown; ceilingY := Unknown; - wallEndY := Unknown; - if (velY = 0) then velY := 0.1; - if (accelY = 0) then accelY := 0.5; end; begin // awake sleeping particle, if necessary if awakeDirty then begin + if awmIsSet(x, y) then awake(); + { case state of TPartState.Sleeping, TPartState.Stuck: if awmIsSet(x, y) then awake(); else if (env = TEnvType.EWall) and awmIsSet(x, y) then awake(); end; + } end; case particleType of TPartType.Blood, TPartType.Water: thinkerBloodAndWater(); @@ -402,7 +527,7 @@ procedure TParticle.thinkerBloodAndWater (); ex: Integer; begin state := TPartState.Stuck; - if (dX > 0) then stickDX := 1 else stickDX := -1; + if (dx > 0) then stickDX := 1 else stickDX := -1; freeze(); // find next floor transition findFloor(); @@ -462,12 +587,15 @@ label _done, _gravityagain, _stuckagain; var pan: TPanel; - dX, dY: SmallInt; + dx, dy: SmallInt; ex, ey: Integer; checkEnv: Boolean; floorJustTraced: Boolean; + {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)} + oldFloorY: Integer; + {$ENDIF} begin - if not gpart_dbg_phys_enabled then goto _done; + if not gpart_dbg_phys_enabled then begin x += round(velX); y += round(velY); goto _done; end; if gAdvBlood then begin @@ -481,7 +609,7 @@ begin if (stickDX = 0) then begin // yeah, stuck to a ceiling - assert(ceilingY <> Unknown); + if (ceilingY = Unknown) then findCeiling(); // dropped from a ceiling? if (y > ceilingY) then begin @@ -554,8 +682,8 @@ begin end; // it is important to have it here - dX := round(velX); - dY := round(velY); + dx := round(velX); + dy := round(velY); if (state = TPartState.Normal) then checkAirStreams(); @@ -602,10 +730,10 @@ begin end; // trace movement - if (dX <> 0) then + if (dx <> 0) then begin // has some horizontal velocity - pan := g_Map_traceToNearest(x, y, x+dX, y+dY, GridTagObstacle, @ex, @ey); + pan := g_Map_traceToNearest(x, y, x+dx, y+dy, GridTagObstacle, @ex, @ey); checkEnv := (x <> ex); x := ex; y := ey; @@ -622,11 +750,11 @@ begin // we stuck // the only case when we can have both ceiling and wall is corner; stick to wall in this case // check if we stuck to a wall - if (dX < 0) then dX := -1 else dX := 1; - if (g_Map_PanelAtPoint(x+dX, y, GridTagObstacle) <> nil) then + if (dx < 0) then dx := -1 else dx := 1; + if (g_Map_PanelAtPoint(x+dx, y, GridTagObstacle) <> nil) then begin // stuck to a wall - stickToWall(dX); + stickToWall(dx); end else begin @@ -635,31 +763,31 @@ begin end; end; end - else if (dY <> 0) then + else if (dy <> 0) then begin // has only vertical velocity - if (dY < 0) then + if (dy < 0) then begin // flying up if (ceilingY = Unknown) then findCeiling(); // need to do this anyway - y += dY; + y += dy; if (y <= ceilingY) then begin y := ceilingY; stickToCeiling(); end; // oops, hit a ceiling // environment didn't changed end else begin - while (dY > 0) do + while (dy > 0) do begin // falling down floorJustTraced := (floorY = Unknown); if floorJustTraced then findFloor(); if (floorType = TFloorType.LiquidOut) then env := TEnvType.ELiquid else env := TEnvType.EAir; - y += dY; + y += dy; //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]); if (y >= floorY) then begin // floor transition - dY := y-floorY; + dy := y-floorY; y := floorY; //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]); case floorType of @@ -668,9 +796,16 @@ begin // check if our ground wasn't moved since the last scan if not floorJustTraced then begin - e_LogWritefln('force rescanning vpart at (%d,%d); floorY=%d', [x, y, floorY]); + {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)} + oldFloorY := floorY; + {$ENDIF} findFloor(true); // force trace - e_LogWritefln(' rescanned vpart at (%d,%d); floorY=%d', [x, y, floorY]); + {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)} + if (floorY <> oldFloorY) then + begin + e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]); + end; + {$ENDIF} if (floorType = TFloorType.LiquidOut) then env := TEnvType.ELiquid else env := TEnvType.EAir; if (y <> floorY) then continue; end; @@ -710,10 +845,10 @@ begin else begin // simple blood - dX := round(velX); - dY := round(velY); - y += dY; - x += dX; + dx := round(velX); + dy := round(velY); + y += dy; + x += dx; if (g_Map_PanelAtPoint(x, y, GridTagObstacle) <> nil) then begin die(); exit; end; end; @@ -985,14 +1120,14 @@ end; // ////////////////////////////////////////////////////////////////////////// // procedure TParticle.thinkerBubble (); var - dY: Integer; + dy: Integer; begin - dY := round(velY); + dy := round(velY); - if (dY <> 0) then + if (dy <> 0) then begin - y += dY; - if (dY < 0) then + y += dy; + if (dy < 0) then begin if (y <= ceilingY) then begin die(); exit; end; end @@ -1051,14 +1186,14 @@ begin // tracer will return `false` if we started outside of the liquid {$IF DEFINED(D2F_DEBUG_BUBBLES)} - stt := curTimeMicro(); + stt := getTimeMicro(); ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2); - stt := curTimeMicro()-stt; + stt := getTimeMicro()-stt; e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]); // - stt := curTimeMicro(); + stt := getTimeMicro(); nptr := g_Map_TraceLiquidNonPrecise(x, y, 0, -8, liquidx, liquidTopY); - stt := curTimeMicro()-stt; + stt := getTimeMicro()-stt; e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]); if not nptr then continue; {$ELSE} @@ -1092,14 +1227,16 @@ procedure TParticle.thinkerSpark (); label _done; var - dX, dY: SmallInt; + dx, dy: SmallInt; pan: TPanel; ex, ey: Integer; begin - if not gpart_dbg_phys_enabled then goto _done; + if not gpart_dbg_phys_enabled then begin x += round(velX); y += round(velY); goto _done; end; + + dx := round(velX); + dy := round(velY); - dX := round(velX); - dY := round(velY); + //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY); // apply gravity if (abs(velX) < 0.1) and (abs(velY) < 0.1) then @@ -1109,10 +1246,10 @@ begin end; // flying - if (dX <> 0) then + if (dx <> 0) then begin // has some horizontal velocity - pan := g_Map_traceToNearest(x, y, x+dX, y+dY, (GridTagObstacle or GridTagLiquid), @ex, @ey); + pan := g_Map_traceToNearest(x, y, x+dx, y+dy, (GridTagObstacle or GridTagLiquid), @ex, @ey); if (x <> ex) then begin floorY := Unknown; ceilingY := Unknown; end; // dunno yet x := ex; y := ey; @@ -1124,14 +1261,14 @@ begin accelX := 0; end; end - else if (dY <> 0) then + else if (dy <> 0) then begin // has some vertical velocity - if (dY < 0) then + if (dy < 0) then begin // flying up if (ceilingY = Unknown) then findCeiling(); // need to do this anyway - y += dY; + y += dy; if (y <= ceilingY) then begin // oops, hit a ceiling @@ -1145,7 +1282,7 @@ begin begin // falling down if (floorY = Unknown) then findFloor(); // need to do this anyway - y += dY; + y += dy; if (y >= floorY) then begin // hit something except a floor? @@ -1169,6 +1306,8 @@ _done: velY += accelY; end; + //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY); + time += 1; end; @@ -1384,37 +1523,6 @@ begin end; -// ////////////////////////////////////////////////////////////////////////// // -// st: set mark -// t: mark type -// currently unused -procedure g_Mark (x, y, Width, Height: Integer; t: Byte; st: Boolean=true); -var - cx, ex, ey: Integer; - ts: Integer; -begin - if not gpart_dbg_enabled then exit; - - if (Width < 1) or (Height < 1) then exit; - // make some border, so we'll hit particles lying around the panel - x -= 1; Width += 2; - y -= 1; Height += 2; - ex := x+Width; - ey := y+Height; - ts := mapGrid.tileSize; - while (y < ey) do - begin - cx := x; - while (cx < ex) do - begin - awmSet(cx, y); - Inc(cx, ts); - end; - Inc(y, ts); - end; -end; - - // ////////////////////////////////////////////////////////////////////////// // procedure g_GFX_Init (); begin @@ -1513,7 +1621,6 @@ end; procedure g_GFX_Draw (); var a, len: Integer; - scaled: Boolean; begin if not gpart_dbg_enabled then exit; @@ -1527,15 +1634,13 @@ begin glBegin(GL_POINTS); - scaled := (g_dbg_scale <> 1.0); - len := High(Particles); for a := 0 to len do begin with Particles[a] do begin if not alive then continue; - if scaled or ((x >= sX) and (y >= sY) and (x <= sX+sWidth) and (sY <= sY+sHeight)) then + if (x >= sX) and (y >= sY) and (x <= sX+sWidth) and (sY <= sY+sHeight) then begin glColor4ub(red, green, blue, alpha); glVertex2f(x+0.37, y+0.37);