reduced memory use, re-enabled debug mode, plugged some of remaining memory leaks

This commit is contained in:
tmj-fstate
2017-10-07 17:20:53 +02:00
parent f6272d37f1
commit 020c71533f
16 changed files with 100 additions and 68 deletions

View File

@@ -31,7 +31,6 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
#include "Mover.h"
#include "usefull.h"
#include "timer.h"
#include "resource.h"
#include "uilayer.h"
#ifdef EU07_BUILD_STATIC
@@ -400,16 +399,6 @@ int main(int argc, char *argv[])
BaseWindowProc = (WNDPROC)::SetWindowLongPtr( Hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc );
// switch off the topmost flag
::SetWindowPos( Hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
const HANDLE icon = ::LoadImage(
::GetModuleHandle( 0 ),
MAKEINTRESOURCE( IDI_ICON1 ),
IMAGE_ICON,
::GetSystemMetrics( SM_CXSMICON ),
::GetSystemMetrics( SM_CYSMICON ),
0 );
if( icon )
::SendMessage( Hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>( icon ) );
#endif
if( ( false == GfxRenderer.Init( window ) )
@@ -466,7 +455,8 @@ int main(int argc, char *argv[])
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)
TPythonInterpreter::killInstance();
delete pConsole;
SafeDelete( pConsole );
SafeDelete( simulation::Region );
glfwDestroyWindow(window);
glfwTerminate();

View File

@@ -210,13 +210,12 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
parser->getTokens();
*parser >> token;
// str = AnsiString(token.c_str());
if (token != "none")
asNodeName = token; // nazwa obiektu powiązanego
if (asName.substr(0, 5) == "none_")
Type = tp_Ignored; // Ra: takie są ignorowane
m_ignored = true; // Ra: takie są ignorowane
switch (Type)
{
@@ -226,7 +225,7 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
// if (Type==tp_UpdateValues) iFlags=0; //co modyfikować
parser->getTokens(1, false); // case sensitive
*parser >> token;
Params[0].asText = new char[token.size() + 1]; // BUG: source of memory leak
Params[0].asText = new char[token.size() + 1];
strcpy(Params[0].asText, token.c_str());
if (token != "*") // czy ma zostać bez zmian?
iFlags |= update_memstring;
@@ -605,7 +604,7 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
// str = AnsiString(token.c_str());
} while (token != "endevent");
break;
case tp_Ignored: // ignorowany
// case tp_Ignored: // ignorowany
case tp_Unknown: // nieznany
do
{
@@ -777,10 +776,7 @@ event_manager::insert( TEvent *Event ) {
// can be cleaned up if pointers to events were replaced with handles
ErrorLog( "Bad event: encountered duplicated event, \"" + Event->asName + "\"" );
duplicate->Append( Event ); // doczepka (taki wirtualny multiple bez warunków)
// BUG: source of memory leak.
// erasing original type of event prevents it from proper resource de-allocation on exit
// TODO: mark ignored event with separate flag or ideally refactor the whole thing
duplicate->Type = tp_Ignored; // dezaktywacja pierwotnego - taka proteza na wsteczną zgodność
duplicate->m_ignored = true; // dezaktywacja pierwotnego - taka proteza na wsteczną zgodność
}
}
@@ -788,7 +784,7 @@ event_manager::insert( TEvent *Event ) {
if( lookup == m_eventmap.end() ) {
// if it's first event with such name, it's potential candidate for the execution queue
m_eventmap.emplace( Event->asName, m_events.size() - 1 );
if( ( Event->Type != tp_Ignored )
if( ( Event->m_ignored != true )
&& ( Event->asName.find( "onstart" ) != std::string::npos ) ) {
// event uruchamiany automatycznie po starcie
AddToQuery( Event, nullptr );
@@ -815,7 +811,7 @@ event_manager::FindEvent( std::string const &Name ) {
bool
event_manager::AddToQuery( TEvent *Event, TDynamicObject *Owner ) {
if( Event->bEnabled ) {
if( ( false == Event->m_ignored ) && ( true == Event->bEnabled ) ) {
// jeśli może być dodany do kolejki (nie używany w skanowaniu)
if( !Event->iQueued ) // jeśli nie dodany jeszcze do kolejki
{ // kolejka eventów jest posortowana względem (fStartTime)
@@ -902,8 +898,8 @@ event_manager::CheckQuery() {
}
else // a jak nazwa jest unikalna, to kolejka idzie dalej
QueryRootEvent = QueryRootEvent->evNext; // NULL w skrajnym przypadku
if (m_workevent->bEnabled)
{ // w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć
if( ( false == m_workevent->m_ignored ) && ( true == m_workevent->bEnabled ) ) {
// w zasadzie te wyłączone są skanowane i nie powinny się nigdy w kolejce znaleźć
--m_workevent->iQueued; // teraz moze być ponownie dodany do kolejki
WriteLog( "EVENT LAUNCHED" + ( m_workevent->Activator ? ( " by " + m_workevent->Activator->asName ) : "" ) + ": " + m_workevent->asName );
switch (m_workevent->Type)
@@ -1270,7 +1266,7 @@ event_manager::InitEvents() {
}
else {
// nie ma komórki, to nie będzie działał poprawnie
Current->Type = tp_Ignored; // deaktywacja
Current->m_ignored = true; // deaktywacja
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" );
}
break;
@@ -1297,7 +1293,7 @@ event_manager::InitEvents() {
}
else {
// nie ma komórki, to nie będzie działał poprawnie
Current->Type = tp_Ignored; // deaktywacja
Current->m_ignored = true; // deaktywacja
ErrorLog( "Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\"" );
}
break;

View File

@@ -30,7 +30,7 @@ enum TEventType {
tp_TrackVel,
tp_Multiple,
tp_AddValues,
tp_Ignored,
// tp_Ignored, // NOTE: refactored to separate flag
tp_CopyValues,
tp_WhoIs,
tp_LogValues,
@@ -84,6 +84,7 @@ class TEvent // zmienne: ev*
public:
std::string asName;
bool m_ignored { false }; // replacement for tp_ignored
bool bEnabled = false; // false gdy ma nie być dodawany do kolejki (skanowanie sygnałów)
int iQueued = 0; // ile razy dodany do kolejki
TEvent *evNext = nullptr; // następny w kolejce
@@ -99,7 +100,8 @@ class TEvent // zmienne: ev*
std::string asNodeName; // McZapkie-100302 - dodalem zeby zapamietac nazwe toru
TEvent *evJoined = nullptr; // kolejny event z tą samą nazwą - od wersji 378
double fRandomDelay = 0.0; // zakres dodatkowego opóźnienia // standardowo nie będzie dodatkowego losowego opóźnienia
public: // metody
public:
// metody
TEvent(std::string const &m = "");
~TEvent();
void Init();

View File

@@ -2485,9 +2485,15 @@ void TGround::InitTracks()
{ // jak coś pójdzie źle, to robimy z tego normalny tor
// Track->ModelAssign(tmp->Model->GetContainer(NULL)); //wiązanie toru z modelem
// obrotnicy
#ifdef EU07_USE_OLD_GROUNDCODE
Track->RaAssign(
Current, Model ? Model->Model : NULL, FindEvent( Current->asName + ":done" ),
FindEvent( Current->asName + ":joined" ) ); // wiązanie toru z modelem obrotnicy
#else
Track->RaAssign(
Current, Model ? Model->Model : NULL, simulation::Events.FindEvent(Current->asName + ":done"),
simulation::Events.FindEvent(Current->asName + ":joined")); // wiązanie toru z modelem obrotnicy
#endif
// break; //jednak połączę z sąsiednim, jak ma się wysypywać null track
}
if (!Model) // jak nie ma modelu
@@ -2867,12 +2873,21 @@ bool TGround::InitLaunchers()
}
else
EventLauncher->MemCell = nullptr;
#ifdef EU07_USE_OLD_GROUNDCODE
EventLauncher->Event1 = ( EventLauncher->asEvent1Name != "none") ?
FindEvent(EventLauncher->asEvent1Name) :
nullptr;
EventLauncher->Event2 = ( EventLauncher->asEvent2Name != "none") ?
FindEvent(EventLauncher->asEvent2Name) :
nullptr;
#else
EventLauncher->Event1 = ( EventLauncher->asEvent1Name != "none") ?
simulation::Events.FindEvent(EventLauncher->asEvent1Name) :
nullptr;
EventLauncher->Event2 = ( EventLauncher->asEvent2Name != "none") ?
simulation::Events.FindEvent(EventLauncher->asEvent2Name) :
nullptr;
#endif
}
return true;
}
@@ -3526,7 +3541,7 @@ bool TGround::Update(double dt, int iter)
if (bDynamicRemove)
{ // jeśli jest coś do usunięcia z listy, to trzeba na końcu
for (TGroundNode *Current = nRootDynamic; Current; Current = Current->nNext)
if (!Current->DynamicObject->bEnabled)
if ( false == Current->DynamicObject->bEnabled)
{
DynamicRemove(Current->DynamicObject); // usunięcie tego i podłączonych
Current = nRootDynamic; // sprawdzanie listy od początku

View File

@@ -1147,7 +1147,8 @@ TModel3d::~TModel3d() {
if (iFlags & 0x0200) {
// wczytany z pliku tekstowego, submodele sprzątają same
Root = nullptr;
SafeDelete( Root );
// Root = nullptr;
}
else {
// wczytano z pliku binarnego (jest właścicielem tablic)

View File

@@ -174,12 +174,21 @@ TTraction::Load( cParser *parser, glm::dvec3 const &pOrigin ) {
}
std::size_t
#ifdef EU07_USE_OLD_GROUNDCODE
TTraction::create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ) {
#else
TTraction::create_geometry( geometrybank_handle const &Bank ) {
#endif
if( m_geometry != null_handle ) {
return GfxRenderer.Vertices( m_geometry ).size() / 2;
}
#ifdef EU07_USE_OLD_GROUNDCODE
if( Bank != 0 ) {
m_origin = Origin;
}
#endif
vertex_array vertices;
double ddp = std::hypot( pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z );

View File

@@ -64,7 +64,11 @@ class TTraction : public editor::basic_node {
m_origin = Origin; }
// creates geometry data in specified geometry bank. returns: number of created elements, or NULL
// NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks
#ifdef EU07_USE_OLD_GROUNDCODE
std::size_t create_geometry( geometrybank_handle const &Bank, glm::dvec3 const &Origin ); // wypełnianie VBO
#else
std::size_t create_geometry( geometrybank_handle const &Bank );
#endif
int TestPoint(glm::dvec3 const &Point);
void Connect(int my, TTraction *with, int to);
void Init();

View File

@@ -45,6 +45,9 @@ public:
point_inside( float const X, float const Y, float const Z ) const;
// tests if the sphere is in frustum, returns the distance between origin and sphere centre
inline
float
sphere_inside( glm::dvec3 const &Center, float const Radius ) const { return sphere_inside( static_cast<float>( Center.x ), static_cast<float>( Center.y ), static_cast<float>( Center.z ), Radius ); }
inline
float
sphere_inside( glm::vec3 const &Center, float const Radius ) const { return sphere_inside( Center.x, Center.y, Center.z, Radius ); }
inline

Binary file not shown.

View File

@@ -1598,7 +1598,7 @@ opengl_renderer::Render( TSubRect *Groundsubcell ) {
}
#else
void
opengl_renderer::Render( scene::basic_region &Region ) {
opengl_renderer::Render( scene::basic_region *Region ) {
m_sectionqueue.clear();
m_cellqueue.clear();
@@ -1617,14 +1617,14 @@ opengl_renderer::Render( scene::basic_region &Region ) {
for( int column = originx; column <= originx + segmentcount; ++column ) {
if( column < 0 ) { continue; }
if( column >= scene::EU07_REGIONSIDESECTIONCOUNT ) { break; }
auto &section { Region.m_sections[ row * scene::EU07_REGIONSIDESECTIONCOUNT + column ] };
if( ( true == section.m_active )
auto *section { Region->m_sections[ row * scene::EU07_REGIONSIDESECTIONCOUNT + column ] };
if( ( section != nullptr )
#ifdef EU07_USE_DEBUG_CULLING
&& ( m_worldcamera.camera.visible( section.m_area ) ) ) {
&& ( m_worldcamera.camera.visible( section->m_area ) ) ) {
#else
&& ( m_renderpass.camera.visible( section.m_area ) ) ) {
&& ( m_renderpass.camera.visible( section->m_area ) ) ) {
#endif
m_sectionqueue.emplace_back( &section );
m_sectionqueue.emplace_back( section );
}
}
}
@@ -2817,7 +2817,7 @@ opengl_renderer::Render_Alpha( TSubRect *Groundsubcell ) {
}
#else
void
opengl_renderer::Render_Alpha( scene::basic_region &Region ) {
opengl_renderer::Render_Alpha( scene::basic_region *Region ) {
// sort the nodes based on their distance to viewer
std::sort(
@@ -2827,17 +2827,6 @@ opengl_renderer::Render_Alpha( scene::basic_region &Region ) {
return ( Left.first ) < ( Right.first ); } );
Render_Alpha( std::rbegin( m_cellqueue ), std::rend( m_cellqueue ) );
/*
::glDisable( GL_LIGHTING ); // linie nie powinny świecić
for( auto subcellpair = std::rbegin( m_cellqueue ); subcellpair != std::rend( m_cellqueue ); ++subcellpair ) {
// druty na końcu, żeby się nie robiły białe plamy na tle lasu
tmp = subcellpair->second;
for( node = tmp->nRenderWires; node; node = node->nNext3 ) {
Render_Alpha( node );
}
}
::glEnable( GL_LIGHTING );
*/
}
void
@@ -2882,6 +2871,8 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque
// third pass draws the wires;
// wires use section vbos, but for the time being we want to draw them at the very end
{
::glDisable( GL_LIGHTING ); // linie nie powinny świecić
auto first{ First };
while( first != Last ) {
@@ -2909,6 +2900,8 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque
++first;
}
::glEnable( GL_LIGHTING );
}
}

View File

@@ -283,7 +283,7 @@ private:
Render( TSubRect *Groundsubcell );
#else
void
Render( scene::basic_region &Region );
Render( scene::basic_region *Region );
void
Render( section_sequence::iterator First, section_sequence::iterator Last );
void
@@ -316,7 +316,7 @@ private:
Render_Alpha( TSubRect *Groundsubcell );
#else
void
Render_Alpha( scene::basic_region &Region );
Render_Alpha( scene::basic_region *Region );
void
Render_Alpha( cell_sequence::reverse_iterator First, cell_sequence::reverse_iterator Last );
void

View File

@@ -2,7 +2,7 @@
// Microsoft Visual C++ generated include file.
// Used by maszyna.rc
//
#define IDI_ICON1 101
//#define GLFW_ICON 101
// Next default values for new objects
//

View File

@@ -119,8 +119,6 @@ basic_cell::center( glm::dvec3 Center ) {
void
basic_section::insert( shape_node Shape ) {
m_active = true;
auto const &shapedata = Shape.data();
if( ( true == shapedata.translucent )
|| ( shapedata.rangesquared_max <= 90000.0 )
@@ -147,7 +145,6 @@ basic_section::insert( shape_node Shape ) {
void
basic_section::insert( TTrack *Path ) {
m_active = true;
// pass the node to the appropriate partitioning cell
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
cell( Path->location() ).insert( Path );
@@ -157,7 +154,6 @@ basic_section::insert( TTrack *Path ) {
void
basic_section::insert( TTraction *Traction ) {
m_active = true;
// pass the node to the appropriate partitioning cell
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
cell( Traction->location() ).insert( Traction );
@@ -167,7 +163,6 @@ basic_section::insert( TTraction *Traction ) {
void
basic_section::insert( TAnimModel *Instance ) {
m_active = true;
// pass the node to the appropriate partitioning cell
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
cell( Instance->location() ).insert( Instance );
@@ -203,8 +198,6 @@ basic_section::create_geometry() {
m_geometrycreated = true;
}
if( false == m_active ) { return; } // nothing to do here
// since sections can be empty, we're doing lazy initialization of the geometry bank, when something may actually use it
if( m_geometrybank == null_handle ) {
m_geometrybank = GfxRenderer.Create_Bank();
@@ -235,6 +228,8 @@ basic_section::cell( glm::dvec3 const &Location ) {
basic_region::basic_region() {
m_sections.fill( nullptr );
/*
// initialize centers of sections:
// calculate center of 'top left' region section...
auto const centeroffset = -( EU07_REGIONSIDESECTIONCOUNT / 2 * EU07_SECTIONSIZE ) + EU07_SECTIONSIZE / 2;
@@ -248,6 +243,12 @@ basic_region::basic_region() {
column = 0;
}
}
*/
}
basic_region::~basic_region() {
for( auto section : m_sections ) { if( section != nullptr ) { delete section; } }
}
void
@@ -568,10 +569,21 @@ basic_region::section( glm::dvec3 const &Location ) {
auto const column = static_cast<int>( std::floor( Location.x / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) );
auto const row = static_cast<int>( std::floor( Location.z / EU07_SECTIONSIZE + EU07_REGIONSIDESECTIONCOUNT / 2 ) );
return
auto &section =
m_sections[
clamp( row, 0, EU07_REGIONSIDESECTIONCOUNT - 1 ) * EU07_REGIONSIDESECTIONCOUNT
+ clamp( column, 0, EU07_REGIONSIDESECTIONCOUNT - 1 ) ] ;
if( section == nullptr ) {
// there's no guarantee the section exists at this point, so check and if needed, create it
section = new basic_section();
// assign center of the section
auto const centeroffset = -( EU07_REGIONSIDESECTIONCOUNT / 2 * EU07_SECTIONSIZE ) + EU07_SECTIONSIZE / 2;
glm::dvec3 regioncornercenter { centeroffset, 0, centeroffset };
section->center( regioncornercenter + glm::dvec3{ column * EU07_SECTIONSIZE, 0.0, row * EU07_SECTIONSIZE } );
}
return *section;
}
} // scene

View File

@@ -114,7 +114,6 @@ private:
// members
// placement and visibility
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_SECTIONSIZE + 0.25 * EU07_SECTIONSIZE ) };
bool m_active { false }; // whether the section holds any actual data, itself or in the cells
// content
cell_array m_cells; // partitioning scheme
shapenode_sequence m_shapes; // large pieces of opaque geometry and (legacy) terrain
@@ -132,6 +131,8 @@ class basic_region {
public:
// constructors
basic_region();
// destructor
~basic_region();
// methods
// inserts provided shape in the region
void
@@ -149,7 +150,7 @@ public:
private:
// types
using section_array = std::array<basic_section, EU07_REGIONSIDESECTIONCOUNT * EU07_REGIONSIDESECTIONCOUNT>;
using section_array = std::array<basic_section *, EU07_REGIONSIDESECTIONCOUNT * EU07_REGIONSIDESECTIONCOUNT>;
// methods
// checks whether specified point is within boundaries of the region

View File

@@ -22,11 +22,16 @@ path_table Paths;
traction_table Traction;
instance_manager Instances;
light_array Lights;
scene::basic_region Region;
scene::basic_region *Region { nullptr };
bool
state_manager::deserialize( std::string const &Scenariofile ) {
// TODO: move initialization to separate routine so we can reuse it
SafeDelete( Region );
Region = new scene::basic_region();
// TODO: check first for presence of serialized binary files
// if this fails, fall back on the legacy text format
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global::asCurrentSceneryPath, Global::bLoadTraction );
@@ -245,7 +250,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
auto *path { deserialize_path( Input, Scratchpad, nodedata ) };
// duplicates of named tracks are currently experimentally allowed
if( simulation::Paths.insert( path ) ) {
simulation::Region.insert_path( path, Scratchpad );
simulation::Region->insert_path( path, Scratchpad );
}
else {
ErrorLog( "Bad scenario: track with duplicate name, \"" + path->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
@@ -262,7 +267,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
auto *traction { deserialize_traction( Input, Scratchpad, nodedata ) };
// duplicates of named tracks are currently discarded
if( simulation::Traction.insert( traction ) ) {
simulation::Region.insert_traction( traction, Scratchpad );
simulation::Region->insert_traction( traction, Scratchpad );
}
else {
ErrorLog( "Bad scenario: traction piece with duplicate name, \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
@@ -286,7 +291,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
if( instance == nullptr ) { return; }
if( simulation::Instances.insert( instance ) ) {
simulation::Region.insert_instance( instance, Scratchpad );
simulation::Region->insert_instance( instance, Scratchpad );
}
else {
ErrorLog( "Bad scenario: 3d model instance with duplicate name, \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
@@ -297,7 +302,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|| ( nodedata.type == "triangle_strip" )
|| ( nodedata.type == "triangle_fan" ) ) {
simulation::Region.insert_shape( scene::shape_node().deserialize( Input, nodedata ), Scratchpad );
simulation::Region->insert_shape( scene::shape_node().deserialize( Input, nodedata ), Scratchpad );
}
else if( ( nodedata.type == "lines" )
|| ( nodedata.type == "line_strip" )

View File

@@ -66,7 +66,8 @@ extern path_table Paths;
extern traction_table Traction;
extern instance_manager Instances;
extern light_array Lights;
extern scene::basic_region Region;
extern scene::basic_region *Region;
} // simulation