X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_game.pas;h=d1ffd7ade5d35568897b3a5b825e0ec55a682da4;hb=69e1c288d6d270abd835cde8a87e818d0298799f;hp=3be96517735e7b8f12b98fe79a453dadde11c3e2;hpb=254041134b399e948e554ae99171174a7087ae40;p=d2df-sdl.git diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 3be9651..d1ffd7a 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -96,8 +96,8 @@ procedure g_Game_RestartRound(NoMapRestart: Boolean = False); procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest); procedure g_Game_SaveOptions(); function g_Game_StartMap(Map: String; Force: Boolean = False; const oldMapPath: AnsiString=''): Boolean; -procedure g_Game_ChangeMap(MapPath: String); -procedure g_Game_ExitLevel(Map: Char16); +procedure g_Game_ChangeMap(const MapPath: String); +procedure g_Game_ExitLevel(const Map: AnsiString); function g_Game_GetFirstMap(WAD: String): String; function g_Game_GetNextMap(): String; procedure g_Game_NextLevel(); @@ -324,8 +324,6 @@ var g_rlayer_water: Boolean = true; g_rlayer_fore: Boolean = true; - g_dbg_scale: Single = 1.0; - procedure g_ResetDynlights (); procedure g_AddDynLight (x, y, radius: Integer; r, g, b, a: Single); @@ -337,7 +335,7 @@ function conIsCheatsEnabled (): Boolean; implementation uses - g_textures, g_main, g_window, g_menu, + e_texture, g_textures, g_main, g_window, g_menu, e_input, e_log, g_console, g_items, g_map, g_panel, g_playermodel, g_gfx, g_options, g_weapons, Math, g_triggers, g_monsters, e_sound, CONFIG, @@ -2714,15 +2712,57 @@ begin end; +procedure renderAmbientQuad (hasAmbient: Boolean; constref ambColor: TDFColor); +begin + if not hasAmbient then exit; + e_AmbientQuad(sX, sY, sWidth, sHeight, ambColor.r, ambColor.g, ambColor.b, ambColor.a); +end; + + // setup sX, sY, sWidth, sHeight, and transformation matrix before calling this! +//FIXME: broken for splitscreen mode procedure renderDynLightsInternal (); var + //hasAmbient: Boolean; + //ambColor: TDFColor; lln: Integer; lx, ly, lrad: Integer; + scxywh: array[0..3] of GLint; + wassc: Boolean; begin + if e_NoGraphics then exit; + //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; + if (not g_playerLight) or (not gwin_has_stencil) or (g_dynLightCount < 1) then exit; + + // rendering mode + //ambColor := gCurrentMap['light_ambient'].rgba; + //hasAmbient := (not ambColor.isOpaque) or (not ambColor.isBlack); + + { // this will multiply incoming color to alpha from framebuffer + glEnable(GL_BLEND); + glBlendFunc(GL_DST_ALPHA, GL_ONE); + } + + (* + * light rendering: (INVALID!) + * glStencilFunc(GL_EQUAL, 0, $ff); + * for each light: + * glClear(GL_STENCIL_BUFFER_BIT); + * glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + * draw shadow volume into stencil buffer + * glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer + * glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // don't modify stencil buffer + * turn off blending + * draw color-less quad with light alpha (WARNING! don't touch color!) + * glEnable(GL_BLEND); + * glBlendFunc(GL_DST_ALPHA, GL_ONE); + * draw all geometry up to and including walls (with alpha-testing, probably) -- this does lighting + *) + + wassc := (glIsEnabled(GL_SCISSOR_TEST) <> 0); + if wassc then glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]) else glGetIntegerv(GL_VIEWPORT, @scxywh[0]); // setup OpenGL parameters glStencilMask($FFFFFFFF); @@ -2737,17 +2777,24 @@ begin lx := g_dynLights[lln].x; ly := g_dynLights[lln].y; lrad := g_dynLights[lln].radius; - if lrad < 3 then continue; + 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; + 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 - //FIXME: broken for splitscreen mode - 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 + if (g_dbg_scale = 1.0) then + begin + glScissor((lx-sX)-lrad+2, gPlayerScreenSize.Y-(ly-sY)-lrad-1+2, lrad*2-4, lrad*2-4); + end + else + begin + glScissor(0, 0, gWinSizeX, gWinSizeY); + end; + // no need to clear stencil buffer, light blitting will do it for us... but only for normal scale + if (g_dbg_scale <> 1.0) then glClear(GL_STENCIL_BUFFER_BIT); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // draw extruded panels glDisable(GL_TEXTURE_2D); @@ -2776,16 +2823,44 @@ begin glDisable(GL_STENCIL_TEST); glDisable(GL_BLEND); glDisable(GL_SCISSOR_TEST); - glScissor(0, 0, sWidth, sHeight); + //glScissor(0, 0, sWidth, sHeight); + + glScissor(scxywh[0], scxywh[1], scxywh[2], scxywh[3]); + if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST); +end; + + +function fixViewportForScale (): Boolean; +var + nx0, ny0, nw, nh: Integer; +begin + result := false; + if (g_dbg_scale <> 1.0) then + begin + result := true; + nx0 := round(sX-(gPlayerScreenSize.X-(sWidth*g_dbg_scale))/2/g_dbg_scale); + ny0 := round(sY-(gPlayerScreenSize.Y-(sHeight*g_dbg_scale))/2/g_dbg_scale); + nw := round(sWidth/g_dbg_scale); + nh := round(sHeight/g_dbg_scale); + sX := nx0; + sY := ny0; + sWidth := nw; + sHeight := nh; + end; 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); +procedure renderMapInternal (backXOfs, backYOfs: Integer; setTransMatrix: Boolean); type TDrawCB = procedure (); +var + hasAmbient: Boolean; + ambColor: TDFColor; + doAmbient: Boolean = false; + procedure drawPanelType (profname: AnsiString; panType: DWord; doDraw: Boolean); var tagmask: Integer; @@ -2799,13 +2874,13 @@ type begin pan := TPanel(gDrawPanelList.front()); if ((pan.tag and tagmask) = 0) then break; - if doDraw then pan.Draw(); + if doDraw then pan.Draw(doAmbient, ambColor); gDrawPanelList.popFront(); end; end else begin - if doDraw then g_Map_DrawPanels(panType); + if doDraw then g_Map_DrawPanels(panType, hasAmbient, ambColor); end; profileFrameDraw.sectionEnd(); end; @@ -2825,14 +2900,7 @@ begin profileFrameDraw.sectionBegin('collect'); if gdbg_map_use_accel_render then begin - if (g_dbg_scale <> 1.0) then - begin - g_Map_CollectDrawPanels(sX, sY, round(sWidth/g_dbg_scale)+1, round(sHeight/g_dbg_scale)+1); - end - else - begin - g_Map_CollectDrawPanels(sX, sY, sWidth, sHeight); - end; + g_Map_CollectDrawPanels(sX, sY, sWidth, sHeight); end; profileFrameDraw.sectionEnd(); @@ -2842,10 +2910,26 @@ begin if setTransMatrix then begin + //if (g_dbg_scale <> 1.0) then glTranslatef(0.0, -0.375/2, 0); glScalef(g_dbg_scale, g_dbg_scale, 1.0); - glTranslatef(transX, transY, 0); + glTranslatef(-sX, -sY, 0); end; + // rendering mode + ambColor := gCurrentMap['light_ambient'].rgba; + hasAmbient := (not ambColor.isOpaque) or (not ambColor.isBlack); + + { + if hasAmbient then + begin + //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')'); + glColor4ub(ambColor.r, ambColor.g, ambColor.b, ambColor.a); + glClear(GL_COLOR_BUFFER_BIT); + end; + } + //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')'); + + drawPanelType('*back', PANEL_BACK, g_rlayer_back); drawPanelType('*step', PANEL_STEP, g_rlayer_step); drawOther('items', @g_Items_Draw); @@ -2862,8 +2946,16 @@ begin drawPanelType('*acid2', PANEL_ACID2, g_rlayer_acid2); drawPanelType('*water', PANEL_WATER, g_rlayer_water); drawOther('dynlights', @renderDynLightsInternal); + + if hasAmbient {and ((not g_playerLight) or (not gwin_has_stencil) or (g_dynLightCount < 1))} then + begin + renderAmbientQuad(hasAmbient, ambColor); + end; + + doAmbient := true; drawPanelType('*fore', PANEL_FORE, g_rlayer_fore); + if g_debug_HealthBar then begin g_Monsters_DrawHealth(); @@ -2889,7 +2981,8 @@ begin sWidth := w; sHeight := h; - renderMapInternal(-bx, -by, -x, -y, true); + fixViewportForScale(); + renderMapInternal(-bx, -by, true); glPopMatrix(); end; @@ -2918,24 +3011,33 @@ begin px := p.GameX + PLAYER_RECT_CX; py := p.GameY + PLAYER_RECT_CY+p.Obj.slopeUpLeft; - 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 (g_dbg_scale = 1.0) then + begin + 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 (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 - else if (gMapInfo.Width < gPlayerScreenSize.X) then - begin - // hcenter - a := (gPlayerScreenSize.X-gMapInfo.Width) div 2; - end; + if (gMapInfo.Width = gPlayerScreenSize.X) then a := 0 + else if (gMapInfo.Width < gPlayerScreenSize.X) then + begin + // hcenter + a := (gPlayerScreenSize.X-gMapInfo.Width) div 2; + end; - if (gMapInfo.Height = gPlayerScreenSize.Y) then b := 0 - else if (gMapInfo.Height < gPlayerScreenSize.Y) then + if (gMapInfo.Height = gPlayerScreenSize.Y) then b := 0 + else if (gMapInfo.Height < gPlayerScreenSize.Y) then + begin + // vcenter + b := (gPlayerScreenSize.Y-gMapInfo.Height) div 2; + end; + end + else begin - // vcenter - b := (gPlayerScreenSize.Y-gMapInfo.Height) div 2; + // scaled, ignore level bounds + a := -px+(gPlayerScreenSize.X div 2); + b := -py+(gPlayerScreenSize.Y div 2); end; if p.IncCam <> 0 then @@ -2982,17 +3084,17 @@ begin //glTranslatef(a, b+p.IncCam, 0); + if (p = gPlayer1) then g_Holmes_plrViewSize(sWidth, sHeight); + + fixViewportForScale(); p.viewPortX := sX; p.viewPortY := sY; p.viewPortW := sWidth; p.viewPortH := sHeight; - if (p = gPlayer1) then - begin - g_Holmes_plrView(p.viewPortX, p.viewPortY, p.viewPortW, p.viewPortH); - end; + if (p = gPlayer1) then g_Holmes_plrViewPos(sX, sY); - renderMapInternal(-c, -d, a, b+p.IncCam, true); + renderMapInternal(-c, -d, true); if p.FSpectator then e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4, @@ -4054,7 +4156,7 @@ begin g_Options_Write_Video(GameDir+'/'+CONFIG_FILENAME); end; -procedure g_Game_ChangeMap(MapPath: String); +procedure g_Game_ChangeMap(const MapPath: String); var Force: Boolean; begin @@ -4106,7 +4208,7 @@ begin g_Player_ResetTeams(); - if Pos(':\', Map) > 0 then + if isWadPath(Map) then begin NewWAD := g_ExtractWadName(Map); ResName := g_ExtractFileName(Map); @@ -4238,7 +4340,7 @@ begin MapList := nil; end; -procedure g_Game_ExitLevel(Map: Char16); +procedure g_Game_ExitLevel(const Map: AnsiString); begin gNextMap := Map; @@ -4473,7 +4575,7 @@ end; procedure g_Game_DeleteTestMap(); var a: Integer; - MapName: Char16; + //MapName: AnsiString; WadName: string; { WAD: TWADFile; @@ -4481,16 +4583,16 @@ var time: Integer; } begin - a := Pos('.wad:\', gMapToDelete); - if a = 0 then - Exit; + a := Pos('.wad:\', toLowerCase1251(gMapToDelete)); + if (a = 0) then a := Pos('.wad:/', toLowerCase1251(gMapToDelete)); + if (a = 0) then exit; -// Âûäåëÿåì èìÿ wad-ôàéëà è èìÿ êàðòû: - WadName := Copy(gMapToDelete, 1, a + 3); - Delete(gMapToDelete, 1, a + 5); + // Âûäåëÿåì èìÿ wad-ôàéëà è èìÿ êàðòû + WadName := Copy(gMapToDelete, 1, a+3); + Delete(gMapToDelete, 1, a+5); gMapToDelete := UpperCase(gMapToDelete); - MapName := ''; - CopyMemory(@MapName[0], @gMapToDelete[1], Min(16, Length(gMapToDelete))); + //MapName := ''; + //CopyMemory(@MapName[0], @gMapToDelete[1], Min(16, Length(gMapToDelete))); { // Èìÿ êàðòû íå ñòàíäàðòíîå òåñòîâîå: @@ -5063,6 +5165,19 @@ begin end; end; +procedure PrintHeapStats(); +var + hs: TFPCHeapStatus; +begin + hs := GetFPCHeapStatus(); + e_LogWriteLn ('v===== heap status =====v'); + e_LogWriteFln('max heap size = %d k', [hs.MaxHeapSize div 1024]); + e_LogWriteFln('max heap used = %d k', [hs.MaxHeapUsed div 1024]); + e_LogWriteFln('cur heap size = %d k', [hs.CurrHeapSize div 1024]); + e_LogWriteFln('cur heap used = %d k', [hs.CurrHeapUsed div 1024]); + e_LogWriteFln('cur heap free = %d k', [hs.CurrHeapFree div 1024]); + e_LogWriteLn ('^=======================^'); +end; procedure DebugCommands(P: SArray); var @@ -5178,6 +5293,10 @@ begin begin for a := 1 to 8 do g_Console_Add(e_JoystickStateToString(a)); + end + else if (cmd = 'd_mem') then + begin + PrintHeapStats(); end; end else @@ -5231,7 +5350,7 @@ begin g_Console_Add('player left the map'); gExitByTrigger := True; //g_Game_ExitLevel(gTriggers[a].Data.MapName); - g_Game_ExitLevel(gTriggers[a].trigData.trigMapName); + g_Game_ExitLevel(gTriggers[a].tgcMap); break; end; end; @@ -6101,14 +6220,14 @@ begin begin gExitByTrigger := True; //gNextMap := gTriggers[a].Data.MapName; - gNextMap := gTriggers[a].trigData.trigMapName; + gNextMap := gTriggers[a].tgcMap; Break; end; // Èùåì ñëåäóþùóþ êàðòó â WAD ôàéëå if gNextMap = '' then gNextMap := g_Game_GetNextMap(); // Ïðîâåðÿåì, íå çàäàí ëè WAD ôàéë ðåñóðñíîé ñòðîêîé - if Pos(':\', gNextMap) = 0 then + if not isWadPath(gNextMap) then s := gGameSettings.WAD + ':\' + gNextMap else s := gNextMap; @@ -6492,17 +6611,17 @@ begin with gTriggers[i] do if (TriggerType = TRIGGER_SOUND) and (Sound <> nil) and - (trigData.trigLocal) and + (tgcLocal) and Sound.IsPlaying() then begin if ((gPlayer1 <> nil) and g_CollidePoint(gPlayer1.GameX, gPlayer1.GameY, X, Y, Width, Height)) or ((gPlayer2 <> nil) and g_CollidePoint(gPlayer2.GameX, gPlayer2.GameY, X, Y, Width, Height)) then begin - Sound.SetPan(0.5 - trigData.trigPan/255.0); - Sound.SetVolume(trigData.trigVolume/255.0); + Sound.SetPan(0.5 - tgcPan/255.0); + Sound.SetVolume(tgcVolume/255.0); end else - Sound.SetCoords(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/255.0); + Sound.SetCoords(X+(Width div 2), Y+(Height div 2), tgcVolume/255.0); end; end; @@ -7009,7 +7128,7 @@ begin s := Find_Param_Value(pars, '-exec'); if s <> '' then begin - if Pos(':\', s) = 0 then + if not isWadPath(s) then s := GameDir + '/' + s; {$I-} @@ -7065,5 +7184,5 @@ begin conRegVar('dbg_holmes', @g_holmes_enabled, 'enable/disable Holmes', 'Holmes', true); - conRegVar('dbg_scale', @g_dbg_scale, 0.01, 5.0, 'experimental deBUG scale mode', '', true); + conRegVar('dbg_scale', @g_dbg_scale, 0.01, 100.0, 'experimental deBUG scale mode', '', false); end.