16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-17 23:39:18 +02:00

build 171030: binary serialization for region terrain

This commit is contained in:
tmj-fstate
2017-10-30 23:41:22 +01:00
parent 9edf912405
commit 071a156527
12 changed files with 531 additions and 44 deletions

View File

@@ -137,10 +137,10 @@ TGauge::Load_mapping( cParser &Input ) {
TSoundsManager::GetFromName( value, true ) :
nullptr );
}
else if( key.find( "sound" ) == 0 ) {
else if( key.compare( 0, std::min<std::size_t>( key.size(), 5 ), "sound" ) == 0 ) {
// sounds assigned to specific gauge values, defined by key soundFoo: where Foo = value
auto const indexstart = key.find_first_of( "-1234567890" );
auto const indexend = key.find_first_not_of( "-1234567890", indexstart );
auto const indexstart { key.find_first_of( "-1234567890" ) };
auto const indexend { key.find_first_not_of( "-1234567890", indexstart ) };
if( indexstart != std::string::npos ) {
m_soundfxvalues.emplace(
std::stoi( key.substr( indexstart, indexend - indexstart ) ),

View File

@@ -94,10 +94,10 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
}
filename += ".mat";
for( char &c : filename ) {
// change forward slashes to windows ones. NOTE: probably not strictly necessary, but eh
c = ( c == '/' ? '\\' : c );
}
// change forward slashes to windows ones. NOTE: probably not strictly necessary, but eh
std::replace(
std::begin( filename ), std::end( filename ),
'/', '\\' );
if( filename.find( '\\' ) == std::string::npos ) {
// jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną
filename = szTexturePath + filename;

164
scene.cpp
View File

@@ -14,9 +14,12 @@ http://mozilla.org/MPL/2.0/.
#include "globals.h"
#include "timer.h"
#include "logs.h"
#include "sn_utils.h"
namespace scene {
std::string const EU07_FILEEXTENSION_REGION { ".sbt" };
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
basic_cell::update_traction( TDynamicObject *Vehicle, int const Pantographindex ) {
@@ -173,6 +176,56 @@ basic_cell::RaAnimate( unsigned int const Framestamp ) {
m_framestamp = Framestamp;
}
// sends content of the class to provided stream
void
basic_cell::serialize( std::ostream &Output ) const {
// region file version 0, cell data
// bounding area
m_area.serialize( Output );
// NOTE: cell activation flag is set dynamically on load
// cell shapes
// shape count followed by opaque shape data
sn_utils::ls_uint32( Output, m_shapesopaque.size() );
for( auto const &shape : m_shapesopaque ) {
shape.serialize( Output );
}
// shape count followed by translucent shape data
sn_utils::ls_uint32( Output, m_shapestranslucent.size() );
for( auto const &shape : m_shapestranslucent ) {
shape.serialize( Output );
}
// cell lines
// line count followed by lines data
sn_utils::ls_uint32( Output, m_lines.size() );
for( auto const &lines : m_lines ) {
lines.serialize( Output );
}
}
// restores content of the class from provided stream
void
basic_cell::deserialize( std::istream &Input ) {
// region file version 0, cell data
// bounding area
m_area.deserialize( Input );
// cell shapes
// shape count followed by opaque shape data
auto itemcount { sn_utils::ld_uint32( Input ) };
while( itemcount-- ) {
m_shapesopaque.emplace_back( shape_node().deserialize( Input ) );
}
itemcount = sn_utils::ld_uint32( Input );
while( itemcount-- ) {
m_shapestranslucent.emplace_back( shape_node().deserialize( Input ) );
}
itemcount = sn_utils::ld_uint32( Input );
while( itemcount-- ) {
m_lines.emplace_back( lines_node().deserialize( Input ) );
}
}
// adds provided shape to the cell
void
basic_cell::insert( shape_node Shape ) {
@@ -545,6 +598,51 @@ basic_section::radio_stop( glm::dvec3 const &Location, float const Radius ) {
}
}
// sends content of the class to provided stream
void
basic_section::serialize( std::ostream &Output ) const {
auto const sectionstartpos { Output.tellp() };
// region file version 0, section data
// section size
sn_utils::ls_uint32( Output, 0 );
// bounding area
m_area.serialize( Output );
// section shapes: shape count followed by shape data
sn_utils::ls_uint32( Output, m_shapes.size() );
for( auto const &shape : m_shapes ) {
shape.serialize( Output );
}
// partitioned data
for( auto const &cell : m_cells ) {
cell.serialize( Output );
}
// all done; calculate and record section size
auto const sectionendpos { Output.tellp() };
Output.seekp( sectionstartpos );
sn_utils::ls_uint32( Output, static_cast<uint32_t>( ( sizeof( uint32_t ) + ( sectionendpos - sectionstartpos ) ) ) );
Output.seekp( sectionendpos );
}
// restores content of the class from provided stream
void
basic_section::deserialize( std::istream &Input ) {
// region file version 0, section data
// bounding area
m_area.deserialize( Input );
// section shapes: shape count followed by shape data
auto shapecount { sn_utils::ld_uint32( Input ) };
while( shapecount-- ) {
m_shapes.emplace_back( shape_node().deserialize( Input ) );
}
// partitioned data
for( auto &cell : m_cells ) {
cell.deserialize( Input );
}
}
// adds provided shape to the section
void
basic_section::insert( shape_node Shape ) {
@@ -767,15 +865,73 @@ basic_region::update_traction( TDynamicObject *Vehicle, int const Pantographinde
// stores content of the class in file with specified name
void
basic_region::serialize( std::string const &Scenariofile ) {
// TODO: implement
basic_region::serialize( std::string const &Scenariofile ) const {
auto filename { Global::asCurrentSceneryPath + Scenariofile };
if( ( filename.rfind( '.' ) != std::string::npos )
&& ( filename.rfind( '.' ) != filename.rfind( ".." ) + 1 ) ) {
// trim extension, it's typically going to be for different file type
filename.erase( filename.rfind( '.' ) );
}
filename += EU07_FILEEXTENSION_REGION;
std::ofstream output { filename, std::ios::binary };
// region file version 0
// header: EU07SBT + version (0-255)
sn_utils::ls_uint32( output, MAKE_ID4( 'E', 'U', '0', '7' ) );
sn_utils::ls_uint32( output, MAKE_ID4( 'S', 'B', 'T', 0 ) );
// sections
// TBD, TODO: build table of sections and file offsets, if we postpone section loading until they're within range
for( auto section : m_sections ) {
// length of section data, followed by section data (if any)
if( section != nullptr ) {
section->serialize( output ); }
else {
sn_utils::ls_uint32( output, 0 ); }
}
}
// restores content of the class from file with specified name. returns: true on success, false otherwise
bool
basic_region::deserialize( std::string const &Scenariofile ) {
// TODO: implement
return false;
auto filename { Global::asCurrentSceneryPath + Scenariofile };
if( ( filename.rfind( '.' ) != std::string::npos )
&& ( filename.rfind( '.' ) != filename.rfind( ".." ) + 1 ) ) {
// trim extension, it's typically going to be for different file type
filename.erase( filename.rfind( '.' ) );
}
filename += EU07_FILEEXTENSION_REGION;
if( false == FileExists( filename ) ) {
return false;
}
// region file version 0
// file type and version check
std::ifstream input( filename, std::ios::binary );
uint32_t headermain { sn_utils::ld_uint32( input ) };
uint32_t headertype { sn_utils::ld_uint32( input ) };
if( ( headermain != MAKE_ID4( 'E', 'U', '0', '7' )
|| ( headertype != MAKE_ID4( 'S', 'B', 'T', 0 ) ) ) ) {
// wrong file type
ErrorLog( "Bad file: \"" + filename + "\" is of either unrecognized type or version" );
return false;
}
// sections
// TBD, TODO: build table of sections and file offsets, if we postpone section loading until they're within range
for( auto &section : m_sections ) {
// length of section data, followed by section data (if any)
auto const sectionsize { sn_utils::ld_uint32( input ) };
if( sectionsize != 0 ) {
section = new basic_section();
section->deserialize( input );
}
}
return true;
}
// legacy method, links specified path piece with potential neighbours

14
scene.h
View File

@@ -81,6 +81,12 @@ public:
// legacy method, updates geometry for pieces in the animation list
void
RaAnimate( unsigned int const Framestamp );
// sends content of the class to provided stream
void
serialize( std::ostream &Output ) const;
// restores content of the class from provided stream
void
deserialize( std::istream &Input );
// adds provided shape to the cell
void
insert( shape_node Shape );
@@ -186,6 +192,12 @@ public:
// legacy method, triggers radio-stop procedure for all vehicles in 2km radius around specified location
void
radio_stop( glm::dvec3 const &Location, float const Radius );
// sends content of the class to provided stream
void
serialize( std::ostream &Output ) const;
// restores content of the class from provided stream
void
deserialize( std::istream &Input );
// adds provided shape to the section
void
insert( shape_node Shape );
@@ -272,7 +284,7 @@ public:
update_sounds();
// stores content of the class in file with specified name
void
serialize( std::string const &Scenariofile );
serialize( std::string const &Scenariofile ) const;
// restores content of the class from file with specified name. returns: true on success, false otherwise
bool
deserialize( std::string const &Scenariofile );

View File

@@ -12,10 +12,126 @@ http://mozilla.org/MPL/2.0/.
#include "renderer.h"
#include "logs.h"
#include "sn_utils.h"
// stores content of the struct in provided output stream
void
lighting_data::serialize( std::ostream &Output ) const {
sn_utils::s_vec4( Output, diffuse );
sn_utils::s_vec4( Output, ambient );
sn_utils::s_vec4( Output, specular );
}
// restores content of the struct from provided input stream
void
lighting_data::deserialize( std::istream &Input ) {
diffuse = sn_utils::d_vec4( Input );
ambient = sn_utils::d_vec4( Input );
specular = sn_utils::d_vec4( Input );
}
namespace scene {
// restores content of the node from provded input stream
// stores content of the struct in provided output stream
void
bounding_area::serialize( std::ostream &Output ) const {
// center
sn_utils::s_dvec3( Output, center );
// radius
sn_utils::ls_float32( Output, radius );
}
// restores content of the struct from provided input stream
void
bounding_area::deserialize( std::istream &Input ) {
center = sn_utils::d_dvec3( Input );
radius = sn_utils::ld_float32( Input );
}
// sends content of the struct to provided stream
void
shape_node::shapenode_data::serialize( std::ostream &Output ) const {
// bounding area
area.serialize( Output );
// visibility
sn_utils::ls_float64( Output, rangesquared_min );
sn_utils::ls_float64( Output, rangesquared_max );
sn_utils::s_bool( Output, visible );
// material
sn_utils::s_bool( Output, translucent );
// NOTE: material handle is created dynamically on load
sn_utils::s_str(
Output,
( material != null_handle ?
GfxRenderer.Material( material ).name :
"" ) );
lighting.serialize( Output );
// geometry
sn_utils::s_dvec3( Output, origin );
// NOTE: geometry handle is created dynamically on load
// vertex count, followed by vertex data
sn_utils::ls_uint32( Output, vertices.size() );
for( auto const &vertex : vertices ) {
vertex.serialize( Output );
}
}
// restores content of the struct from provided input stream
void
shape_node::shapenode_data::deserialize( std::istream &Input ) {
// bounding area
area.deserialize( Input );
// visibility
rangesquared_min = sn_utils::ld_float64( Input );
rangesquared_max = sn_utils::ld_float64( Input );
visible = sn_utils::d_bool( Input );
// material
translucent = sn_utils::d_bool( Input );
auto const materialname { sn_utils::d_str( Input ) };
if( false == materialname.empty() ) {
material = GfxRenderer.Fetch_Material( materialname );
}
lighting.deserialize( Input );
// geometry
origin = sn_utils::d_dvec3( Input );
// NOTE: geometry handle is acquired during geometry creation
// vertex data
vertices.resize( sn_utils::ld_uint32( Input ) );
for( auto &vertex : vertices ) {
vertex.deserialize( Input );
}
}
// sends content of the class to provided stream
void
shape_node::serialize( std::ostream &Output ) const {
// name
sn_utils::s_str( Output, m_name );
// node data
m_data.serialize( Output );
}
// restores content of the node from provided input stream
shape_node &
shape_node::deserialize( std::istream &Input ) {
// name
m_name = sn_utils::d_str( Input );
// node data
m_data.deserialize( Input );
return *this;
}
// restores content of the node from provided input stream
shape_node &
shape_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
@@ -104,7 +220,9 @@ shape_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
triangles,
triangle_strip,
triangle_fan
} const nodetype = (
};
subtype const nodetype = (
Nodedata.type == "triangles" ? triangles :
Nodedata.type == "triangle_strip" ? triangle_strip :
triangle_fan );
@@ -320,6 +438,72 @@ shape_node::compute_radius() {
// sends content of the struct to provided stream
void
lines_node::linesnode_data::serialize( std::ostream &Output ) const {
// bounding area
area.serialize( Output );
// visibility
sn_utils::ls_float64( Output, rangesquared_min );
sn_utils::ls_float64( Output, rangesquared_max );
sn_utils::s_bool( Output, visible );
// material
sn_utils::ls_float32( Output, line_width );
lighting.serialize( Output );
// geometry
sn_utils::s_dvec3( Output, origin );
// NOTE: geometry handle is created dynamically on load
// vertex count, followed by vertex data
sn_utils::ls_uint32( Output, vertices.size() );
for( auto const &vertex : vertices ) {
vertex.serialize( Output );
}
}
// restores content of the struct from provided input stream
void
lines_node::linesnode_data::deserialize( std::istream &Input ) {
// bounding area
area.deserialize( Input );
// visibility
rangesquared_min = sn_utils::ld_float64( Input );
rangesquared_max = sn_utils::ld_float64( Input );
visible = sn_utils::d_bool( Input );
// material
line_width = sn_utils::ld_float32( Input );
lighting.deserialize( Input );
// geometry
origin = sn_utils::d_dvec3( Input );
// NOTE: geometry handle is acquired during geometry creation
// vertex data
vertices.resize( sn_utils::ld_uint32( Input ) );
for( auto &vertex : vertices ) {
vertex.deserialize( Input );
}
}
// sends content of the class to provided stream
void
lines_node::serialize( std::ostream &Output ) const {
// name
sn_utils::s_str( Output, m_name );
// node data
m_data.serialize( Output );
}
// restores content of the node from provided input stream
lines_node &
lines_node::deserialize( std::istream &Input ) {
// name
m_name = sn_utils::d_str( Input );
// node data
m_data.deserialize( Input );
return *this;
}
// restores content of the node from provded input stream
lines_node &
lines_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
@@ -350,7 +534,9 @@ lines_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) {
lines,
line_strip,
line_loop
} const nodetype = (
};
subtype const nodetype = (
Nodedata.type == "lines" ? lines :
Nodedata.type == "line_strip" ? line_strip :
line_loop );

View File

@@ -22,6 +22,13 @@ struct lighting_data {
glm::vec4 diffuse { 0.8f, 0.8f, 0.8f, 1.0f };
glm::vec4 ambient { 0.2f, 0.2f, 0.2f, 1.0f };
glm::vec4 specular { 0.0f, 0.0f, 0.0f, 1.0f };
// stores content of the struct in provided output stream
void
serialize( std::ostream &Output ) const;
// restores content of the struct from provided input stream
void
deserialize( std::istream &Input );
};
inline
@@ -50,6 +57,12 @@ struct bounding_area {
center( Center ),
radius( Radius )
{}
// stores content of the struct in provided output stream
void
serialize( std::ostream &Output ) const;
// restores content of the struct from provided input stream
void
deserialize( std::istream &Input );
};
struct node_data {
@@ -68,23 +81,37 @@ class shape_node {
public:
// types
struct shapenode_data {
// members:
// placement and visibility
scene::bounding_area area; // bounding area, in world coordinates
bool visible { true }; // visibility flag
double rangesquared_min { 0.0 }; // visibility range, min
double rangesquared_max { 0.0 }; // visibility range, max
bool visible { true }; // visibility flag
// material data
material_handle material { 0 };
lighting_data lighting;
bool translucent { false }; // whether opaque or translucent
material_handle material { null_handle };
lighting_data lighting;
// geometry data
std::vector<world_vertex> vertices; // world space source data of the geometry
glm::dvec3 origin; // world position of the relative coordinate system origin
geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
std::vector<world_vertex> vertices; // world space source data of the geometry
// methods:
// sends content of the struct to provided stream
void
serialize( std::ostream &Output ) const;
// restores content of the struct from provided input stream
void
deserialize( std::istream &Input );
};
// methods
// restores content of the node from provded input stream
// sends content of the class to provided stream
void
serialize( std::ostream &Output ) const;
// restores content of the node from provided input stream
shape_node &
deserialize( std::istream &Input );
// restores content of the node from provided input stream
shape_node &
deserialize( cParser &Input, scene::node_data const &Nodedata );
// imports data from provided submodel
@@ -144,22 +171,36 @@ class lines_node {
public:
// types
struct linesnode_data {
// members:
// placement and visibility
scene::bounding_area area; // bounding area, in world coordinates
bool visible { true }; // visibility flag
double rangesquared_min { 0.0 }; // visibility range, min
double rangesquared_max { 0.0 }; // visibility range, max
bool visible { true }; // visibility flag
// material data
float line_width { 1.f }; // thickness of stored lines
lighting_data lighting;
float line_width; // thickness of stored lines
// geometry data
std::vector<world_vertex> vertices; // world space source data of the geometry
glm::dvec3 origin; // world position of the relative coordinate system origin
geometry_handle geometry { 0, 0 }; // relative origin-centered chunk of geometry held by gfx renderer
std::vector<world_vertex> vertices; // world space source data of the geometry
// methods:
// sends content of the struct to provided stream
void
serialize( std::ostream &Output ) const;
// restores content of the struct from provided input stream
void
deserialize( std::istream &Input );
};
// methods
// restores content of the node from provded input stream
// sends content of the class to provided stream
void
serialize( std::ostream &Output ) const;
// restores content of the node from provided input stream
lines_node &
deserialize( std::istream &Input );
// restores content of the node from provided input stream
lines_node &
deserialize( cParser &Input, scene::node_data const &Nodedata );
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed

View File

@@ -349,30 +349,37 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
else if( nodedata.type == "model" ) {
if( nodedata.range_min < 0.0 ) {
// convert and import 3d terrain
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
// model import can potentially fail
if( instance == nullptr ) { return; }
// go through submodels, and import them as shapes
auto const cellcount = instance->TerrainCount() + 1; // zliczenie submodeli
for( auto i = 1; i < cellcount; ++i ) {
auto *submodel = instance->TerrainSquare( i - 1 );
simulation::Region->insert_shape(
scene::shape_node().convert( submodel ),
Scratchpad,
false );
// if there's more than one group of triangles in the cell they're held as children of the primary submodel
submodel = submodel->ChildGet();
while( submodel != nullptr ) {
// 3d terrain
if( false == Scratchpad.binary.terrain ) {
// if we're loading data from text .scn file convert and import
auto *instance { deserialize_model( Input, Scratchpad, nodedata ) };
// model import can potentially fail
if( instance == nullptr ) { return; }
// go through submodels, and import them as shapes
auto const cellcount = instance->TerrainCount() + 1; // zliczenie submodeli
for( auto i = 1; i < cellcount; ++i ) {
auto *submodel = instance->TerrainSquare( i - 1 );
simulation::Region->insert_shape(
scene::shape_node().convert( submodel ),
Scratchpad,
false );
submodel = submodel->NextGet();
// if there's more than one group of triangles in the cell they're held as children of the primary submodel
submodel = submodel->ChildGet();
while( submodel != nullptr ) {
simulation::Region->insert_shape(
scene::shape_node().convert( submodel ),
Scratchpad,
false );
submodel = submodel->NextGet();
}
}
// with the import done we can get rid of the source model
delete instance;
}
else {
// if binary terrain file was present, we already have this data
skip_until( Input, "endmodel" );
}
// with the import done we can get rid of the source model
delete instance;
}
else {
// regular instance of 3d mesh

View File

@@ -75,6 +75,28 @@ std::string sn_utils::d_str(std::istream &s)
return r;
}
bool sn_utils::d_bool(std::istream& s)
{
return ( ld_uint16( s ) == 1 );
}
glm::dvec3 sn_utils::d_dvec3(std::istream& s)
{
return {
ld_float64(s),
ld_float64(s),
ld_float64(s) };
}
glm::vec4 sn_utils::d_vec4( std::istream& s)
{
return {
ld_float32(s),
ld_float32(s),
ld_float32(s),
ld_float32(s) };
}
void sn_utils::ls_uint16(std::ostream &s, uint16_t v)
{
uint8_t buf[2];
@@ -133,4 +155,28 @@ void sn_utils::s_str(std::ostream &s, std::string v)
{
const char* buf = v.c_str();
s.write(buf, v.size() + 1);
}
}
void sn_utils::s_bool(std::ostream &s, bool v)
{
ls_uint16(
s,
( true == v ?
1 :
0 ) );
}
void sn_utils::s_dvec3(std::ostream &s, glm::dvec3 const &v)
{
ls_float64(s, v.x);
ls_float64(s, v.y);
ls_float64(s, v.z);
}
void sn_utils::s_vec4(std::ostream &s, glm::vec4 const &v)
{
ls_float32(s, v.x);
ls_float32(s, v.y);
ls_float32(s, v.z);
ls_float32(s, v.w);
}

View File

@@ -13,6 +13,9 @@ public:
static float ld_float32(std::istream&);
static double ld_float64(std::istream&);
static std::string d_str(std::istream&);
static bool d_bool(std::istream&);
static glm::dvec3 d_dvec3(std::istream&);
static glm::vec4 d_vec4(std::istream&);
static void ls_uint16(std::ostream&, uint16_t);
static void ls_uint32(std::ostream&, uint32_t);
@@ -20,4 +23,7 @@ public:
static void ls_float32(std::ostream&, float);
static void ls_float64(std::ostream&, double);
static void s_str(std::ostream&, std::string);
static void s_bool(std::ostream&, bool);
static void s_dvec3(std::ostream&, glm::dvec3 const &);
static void s_vec4(std::ostream&, glm::vec4 const &);
};

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 17
#define VERSION_MINOR 1028
#define VERSION_MINOR 1030
#define VERSION_REVISION 0

View File

@@ -11,6 +11,37 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "vertex.h"
#include "sn_utils.h"
void
world_vertex::serialize( std::ostream &s ) const {
sn_utils::ls_float64( s, position.x );
sn_utils::ls_float64( s, position.y );
sn_utils::ls_float64( s, position.z );
sn_utils::ls_float32( s, normal.x );
sn_utils::ls_float32( s, normal.y );
sn_utils::ls_float32( s, normal.z );
sn_utils::ls_float32( s, texture.x );
sn_utils::ls_float32( s, texture.y );
}
void
world_vertex::deserialize( std::istream &s ) {
position.x = sn_utils::ld_float64( s );
position.y = sn_utils::ld_float64( s );
position.z = sn_utils::ld_float64( s );
normal.x = sn_utils::ld_float32( s );
normal.y = sn_utils::ld_float32( s );
normal.z = sn_utils::ld_float32( s );
texture.x = sn_utils::ld_float32( s );
texture.y = sn_utils::ld_float32( s );
}
template <>
world_vertex &

View File

@@ -50,6 +50,8 @@ struct world_vertex {
Left *= Right;
return Left; }
// methods
void serialize( std::ostream& ) const;
void deserialize( std::istream& );
// wyliczenie współrzędnych i mapowania punktu na środku odcinka v1<->v2
void
set_half( world_vertex const &Vertex1, world_vertex const &Vertex2 ) {