X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_game.pas;h=c46f6e49b4f1d1825e7cc4f03e91b8ae019d357c;hb=4ecfaa7da77e39e45d45762f31362082a5616dec;hp=68b2ee4a987114e6ad98e41b8fb6518357491a37;hpb=e2c0ffbd3c4bc1516930552924062d56447df065;p=d2df-sdl.git diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 68b2ee4..c46f6e4 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *) -{$MODE DELPHI} +{$INCLUDE g_amodes.inc} unit g_game; interface @@ -309,6 +309,10 @@ var P1MoveButton: Byte = 0; P2MoveButton: Byte = 0; +procedure g_ResetDynlights (); +procedure g_AddDynLight (x, y, radius: Integer; r, g, b, a: Single); +procedure g_DynLightExplosion (x, y, radius: Integer; r, g, b: Single); + implementation uses @@ -320,6 +324,80 @@ uses ENet, e_fixedbuffer, g_netmsg, g_netmaster, GL, GLExt, utils, sfs; +type + TDynLight = record + x, y, radius: Integer; + r, g, b, a: Single; + exploCount: Integer; + exploRadius: Integer; + end; + +var + g_dynLights: array of TDynLight = nil; + g_dynLightCount: Integer = 0; + g_playerLight: Boolean = false; + +procedure g_ResetDynlights (); +var + lnum, idx: Integer; +begin + if not gwin_has_stencil then begin g_dynLightCount := 0; exit; end; + lnum := 0; + for idx := 0 to g_dynLightCount-1 do + begin + if g_dynLights[idx].exploCount = -666 then + begin + // skip it + end + else + begin + // explosion + Inc(g_dynLights[idx].exploCount); + if (g_dynLights[idx].exploCount < 10) then + begin + g_dynLights[idx].radius := g_dynLights[idx].exploRadius+g_dynLights[idx].exploCount*8; + g_dynLights[idx].a := 0.4+g_dynLights[idx].exploCount/10; + if (g_dynLights[idx].a > 0.8) then g_dynLights[idx].a := 0.8; + if lnum <> idx then g_dynLights[lnum] := g_dynLights[idx]; + Inc(lnum); + end; + end; + end; + g_dynLightCount := lnum; +end; + +procedure g_AddDynLight (x, y, radius: Integer; r, g, b, a: Single); +begin + if not gwin_has_stencil then exit; + if g_dynLightCount = length(g_dynLights) then SetLength(g_dynLights, g_dynLightCount+1024); + g_dynLights[g_dynLightCount].x := x; + g_dynLights[g_dynLightCount].y := y; + g_dynLights[g_dynLightCount].radius := radius; + g_dynLights[g_dynLightCount].r := r; + g_dynLights[g_dynLightCount].g := g; + g_dynLights[g_dynLightCount].b := b; + g_dynLights[g_dynLightCount].a := a; + g_dynLights[g_dynLightCount].exploCount := -666; + Inc(g_dynLightCount); +end; + +procedure g_DynLightExplosion (x, y, radius: Integer; r, g, b: Single); +begin + if not gwin_has_stencil then exit; + if g_dynLightCount = length(g_dynLights) then SetLength(g_dynLights, g_dynLightCount+1024); + g_dynLights[g_dynLightCount].x := x; + g_dynLights[g_dynLightCount].y := y; + g_dynLights[g_dynLightCount].radius := 0; + g_dynLights[g_dynLightCount].exploRadius := radius; + g_dynLights[g_dynLightCount].r := r; + g_dynLights[g_dynLightCount].g := g; + g_dynLights[g_dynLightCount].b := b; + g_dynLights[g_dynLightCount].a := 0; + g_dynLights[g_dynLightCount].exploCount := 0; + Inc(g_dynLightCount); +end; + + type TEndCustomGameStat = record PlayerStat: TPlayerStatArray; @@ -1285,6 +1363,21 @@ begin if isKeyPressed(KeyWeapon[i], KeyWeapon2[i]) then plr.QueueWeaponSwitch(i); // all choices are passed there, and god will take the best end; + + // HACK: add dynlight here + if gwin_k8_enable_light_experiments then + begin + if e_KeyPressed(IK_F8) and gGameOn and (not gConsoleShow) and (g_ActiveWindow = nil) then + begin + g_playerLight := true; + end; + if e_KeyPressed(IK_F9) and gGameOn and (not gConsoleShow) and (g_ActiveWindow = nil) then + begin + g_playerLight := false; + end; + end; + + if gwin_has_stencil and g_playerLight then g_AddDynLight(plr.GameX+32, plr.GameY+40, 128, 1, 1, 0, 0.6); end; procedure g_Game_Update(); @@ -1295,6 +1388,7 @@ var w: Word; i, b: Integer; begin + g_ResetDynlights(); // Ïîðà âûêëþ÷àòü èãðó: if gExit = EXIT_QUIT then Exit; @@ -1813,6 +1907,8 @@ begin UPSCounter := 0; UPSTime := Time; end; + + if gGameOn then g_Weapon_AddDynLights(); end; procedure g_Game_LoadData(); @@ -2512,22 +2608,22 @@ begin glTranslatef(-x, -y, 0); - g_Map_DrawPanels(PANEL_BACK); - g_Map_DrawPanels(PANEL_STEP); + 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(PANEL_WALL); + g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_WALL); g_Monsters_Draw(); - g_Map_DrawPanels(PANEL_CLOSEDOOR); + g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_CLOSEDOOR); g_GFX_Draw(); g_Map_DrawFlags(); - g_Map_DrawPanels(PANEL_ACID1); - g_Map_DrawPanels(PANEL_ACID2); - g_Map_DrawPanels(PANEL_WATER); - g_Map_DrawPanels(PANEL_FORE); + 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(); @@ -2541,6 +2637,8 @@ 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 @@ -2626,22 +2724,81 @@ begin glTranslatef(a, b+p.IncCam, 0); - g_Map_DrawPanels(PANEL_BACK); - g_Map_DrawPanels(PANEL_STEP); + 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(PANEL_WALL); + g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_WALL); g_Monsters_Draw(); - g_Map_DrawPanels(PANEL_CLOSEDOOR); + g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_CLOSEDOOR); g_GFX_Draw(); g_Map_DrawFlags(); - g_Map_DrawPanels(PANEL_ACID1); - g_Map_DrawPanels(PANEL_ACID2); - g_Map_DrawPanels(PANEL_WATER); - g_Map_DrawPanels(PANEL_FORE); + 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); + + //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 + // 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; + + g_Map_DrawPanels(sX, sY, sWidth, sHeight, PANEL_FORE); if g_debug_HealthBar then begin g_Monsters_DrawHealth(); @@ -3482,6 +3639,7 @@ var State: Byte; OuterLoop: Boolean; newResPath: string; + Len: Word; begin g_Game_Free(); @@ -3531,76 +3689,82 @@ begin Ptr := NetEvent.packet^.data; e_Raw_Seek(0); - MID := e_Raw_Read_Byte(Ptr); - - if (MID = NET_MSG_INFO) and (State = 0) then + while (State = 0) and (RawPos < NetEvent.packet^.dataLength) do begin - NetMyID := e_Raw_Read_Byte(Ptr); - NetPlrUID1 := e_Raw_Read_Word(Ptr); + Len := e_Raw_Read_Word(Ptr); + MID := e_Raw_Read_Byte(Ptr); + e_WriteLog(Format('conn recv %U %U', [Len, MID]), MSG_NOTIFY); - WadName := e_Raw_Read_String(Ptr); - Map := e_Raw_Read_String(Ptr); + if (MID = NET_MSG_INFO) and (State = 0) then + begin + NetMyID := e_Raw_Read_Byte(Ptr); + NetPlrUID1 := e_Raw_Read_Word(Ptr); - gWADHash := e_Raw_Read_MD5(Ptr); + WadName := e_Raw_Read_String(Ptr); + Map := e_Raw_Read_String(Ptr); - gGameSettings.GameMode := e_Raw_Read_Byte(Ptr); - gSwitchGameMode := gGameSettings.GameMode; - gGameSettings.GoalLimit := e_Raw_Read_Word(Ptr); - gGameSettings.TimeLimit := e_Raw_Read_Word(Ptr); - gGameSettings.MaxLives := e_Raw_Read_Byte(Ptr); - gGameSettings.Options := e_Raw_Read_LongWord(Ptr); - T := e_Raw_Read_LongWord(Ptr); + gWADHash := e_Raw_Read_MD5(Ptr); - newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash); - if newResPath = '' then - begin - g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False); - newResPath := g_Res_DownloadWAD(WadName); + gGameSettings.GameMode := e_Raw_Read_Byte(Ptr); + gSwitchGameMode := gGameSettings.GameMode; + gGameSettings.GoalLimit := e_Raw_Read_Word(Ptr); + gGameSettings.TimeLimit := e_Raw_Read_Word(Ptr); + gGameSettings.MaxLives := e_Raw_Read_Byte(Ptr); + gGameSettings.Options := e_Raw_Read_LongWord(Ptr); + T := e_Raw_Read_LongWord(Ptr); + + newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash); if newResPath = '' then begin - g_FatalError(_lc[I_NET_ERR_HASH]); + g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False); + newResPath := g_Res_DownloadWAD(WadName); + if newResPath = '' then + begin + g_FatalError(_lc[I_NET_ERR_HASH]); + enet_packet_destroy(NetEvent.packet); + NetState := NET_STATE_NONE; + Exit; + end; + end; + newResPath := ExtractRelativePath(MapsDir, newResPath); + + gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model, + gPlayer1Settings.Color, + gPlayer1Settings.Team, False)); + + if gPlayer1 = nil then + begin + g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1])); + enet_packet_destroy(NetEvent.packet); NetState := NET_STATE_NONE; Exit; end; - end; - newResPath := ExtractRelativePath(MapsDir, newResPath); - gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model, - gPlayer1Settings.Color, - gPlayer1Settings.Team, False)); + gPlayer1.Name := gPlayer1Settings.Name; + gPlayer1.UID := NetPlrUID1; + gPlayer1.Reset(True); - if gPlayer1 = nil then - begin - g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1])); - - enet_packet_destroy(NetEvent.packet); - NetState := NET_STATE_NONE; - Exit; - end; + if not g_Game_StartMap(newResPath + ':\' + Map, True) then + begin + g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WadName + ':\' + Map])); - gPlayer1.Name := gPlayer1Settings.Name; - gPlayer1.UID := NetPlrUID1; - gPlayer1.Reset(True); + enet_packet_destroy(NetEvent.packet); + NetState := NET_STATE_NONE; + Exit; + end; - if not g_Game_StartMap(newResPath + ':\' + Map, True) then - begin - g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WadName + ':\' + Map])); + gTime := T; + State := 1; + OuterLoop := False; enet_packet_destroy(NetEvent.packet); - NetState := NET_STATE_NONE; - Exit; - end; - - gTime := T; - - State := 1; - OuterLoop := False; - enet_packet_destroy(NetEvent.packet); - break; - end - else - enet_packet_destroy(NetEvent.packet); + break; + end + else + RawPos := RawPos + Len-1; + end; + if State = 1 then break; end else if (NetEvent.kind = ENET_EVENT_TYPE_DISCONNECT) then @@ -3637,7 +3801,7 @@ begin g_Player_Init(); NetState := NET_STATE_GAME; - MC_SEND_FullStateRequest; + MC_SEND_FullStateRequest(); e_WriteLog('NET: Connection successful.', MSG_NOTIFY); end; @@ -6485,9 +6649,6 @@ var begin Parse_Params(pars); - s := Find_Param_Value(pars, '--opengl-dump-exts'); - if s <> '' then gwin_dump_extensions := true; // sorry - // Debug mode: s := Find_Param_Value(pars, '--debug'); if (s <> '') then