mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
592 lines
22 KiB
C++
592 lines
22 KiB
C++
/*
|
|
This Source Code Form is subject to the
|
|
terms of the Mozilla Public License, v.
|
|
2.0. If a copy of the MPL was not
|
|
distributed with this file, You can
|
|
obtain one at
|
|
http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "scene.h"
|
|
|
|
#include "renderer.h"
|
|
#include "logs.h"
|
|
|
|
namespace scene {
|
|
|
|
// adds provided shape to the cell
|
|
void
|
|
basic_cell::insert( shape_node Shape ) {
|
|
|
|
m_active = true;
|
|
|
|
auto const &shapedata { Shape.data() };
|
|
auto &shapes = (
|
|
shapedata.translucent ?
|
|
m_shapestranslucent :
|
|
m_shapesopaque );
|
|
for( auto &targetshape : shapes ) {
|
|
// try to merge shapes with matching view ranges...
|
|
auto const &targetshapedata { targetshape.data() };
|
|
if( ( shapedata.rangesquared_min == targetshapedata.rangesquared_min )
|
|
&& ( shapedata.rangesquared_max == targetshapedata.rangesquared_max )
|
|
// ...and located close to each other (within arbitrary limit of 25m)
|
|
&& ( glm::length( shapedata.area.center - targetshapedata.area.center ) < 25.0 ) ) {
|
|
|
|
if( true == targetshape.merge( Shape ) ) {
|
|
// if the shape was merged there's nothing left to do
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// otherwise add the shape to the relevant list
|
|
Shape.origin( m_area.center );
|
|
shapes.emplace_back( Shape );
|
|
}
|
|
|
|
// adds provided path to the cell
|
|
void
|
|
basic_cell::insert( TTrack *Path ) {
|
|
|
|
m_active = true;
|
|
|
|
// TODO: add animation hook
|
|
Path->origin( m_area.center );
|
|
m_paths.emplace_back( Path );
|
|
}
|
|
|
|
// adds provided traction piece to the cell
|
|
void
|
|
basic_cell::insert( TTraction *Traction ) {
|
|
|
|
m_active = true;
|
|
|
|
Traction->origin( m_area.center );
|
|
m_traction.emplace_back( Traction );
|
|
}
|
|
|
|
// adds provided model instance to the cell
|
|
void
|
|
basic_cell::insert( TAnimModel *Instance ) {
|
|
|
|
m_active = true;
|
|
|
|
auto const flags = Instance->Flags();
|
|
auto alpha =
|
|
( Instance->Material() != nullptr ?
|
|
Instance->Material()->textures_alpha :
|
|
0x30300030 );
|
|
|
|
// assign model to appropriate render phases
|
|
if( alpha & flags & 0x2F2F002F ) {
|
|
// translucent pieces
|
|
m_instancetranslucent.emplace_back( Instance );
|
|
}
|
|
alpha ^= 0x0F0F000F; // odwrócenie flag tekstur, aby wyłapać nieprzezroczyste
|
|
if( alpha & flags & 0x1F1F001F ) {
|
|
// opaque pieces
|
|
m_instancesopaque.emplace_back( Instance );
|
|
}
|
|
}
|
|
|
|
// generates renderable version of held non-instanced geometry
|
|
void
|
|
basic_cell::create_geometry( geometrybank_handle const &Bank ) {
|
|
|
|
if( false == m_active ) { return; } // nothing to do here
|
|
|
|
for( auto &shape : m_shapesopaque ) { shape.create_geometry( Bank ); }
|
|
for( auto &shape : m_shapestranslucent ) { shape.create_geometry( Bank ); }
|
|
#ifndef EU07_USE_OLD_GROUNDCODE
|
|
for( auto *path : m_paths ) { path->create_geometry( Bank ); }
|
|
for( auto *traction : m_traction ) { traction->create_geometry( Bank ); }
|
|
#endif
|
|
}
|
|
|
|
// sets center point of the section
|
|
void
|
|
basic_cell::center( glm::dvec3 Center ) {
|
|
|
|
m_area.center = Center;
|
|
// NOTE: we should also update origin point for the contained nodes, but in practice we can skip this
|
|
// as all nodes will be added only after the proper center point was set, and won't change
|
|
}
|
|
|
|
|
|
|
|
// adds provided shape to the section
|
|
void
|
|
basic_section::insert( shape_node Shape ) {
|
|
|
|
auto const &shapedata = Shape.data();
|
|
if( ( true == shapedata.translucent )
|
|
|| ( shapedata.rangesquared_max <= 90000.0 )
|
|
|| ( shapedata.rangesquared_min > 0.0 ) ) {
|
|
// small, translucent or not always visible shapes are placed in the sub-cells
|
|
cell( shapedata.area.center ).insert( Shape );
|
|
}
|
|
else {
|
|
// large, opaque shapes are placed on section level
|
|
for( auto &shape : m_shapes ) {
|
|
// check first if the shape can't be merged with one of the shapes already present in the section
|
|
if( true == shape.merge( Shape ) ) {
|
|
// if the shape was merged there's nothing left to do
|
|
return;
|
|
}
|
|
}
|
|
// otherwise add the shape to the section's list
|
|
Shape.origin( m_area.center );
|
|
m_shapes.emplace_back( Shape );
|
|
}
|
|
}
|
|
|
|
// adds provided path to the section
|
|
void
|
|
basic_section::insert( TTrack *Path ) {
|
|
|
|
// 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 );
|
|
}
|
|
|
|
// adds provided path to the section
|
|
void
|
|
basic_section::insert( TTraction *Traction ) {
|
|
|
|
// 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 );
|
|
}
|
|
|
|
// adds provided model instance to the section
|
|
void
|
|
basic_section::insert( TAnimModel *Instance ) {
|
|
|
|
// 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 );
|
|
}
|
|
|
|
// sets center point of the section
|
|
void
|
|
basic_section::center( glm::dvec3 Center ) {
|
|
|
|
m_area.center = Center;
|
|
// set accordingly center points of the section's partitioning cells
|
|
// NOTE: we should also update origin point for the contained nodes, but in practice we can skip this
|
|
// as all nodes will be added only after the proper center point was set, and won't change
|
|
auto const centeroffset = -( EU07_SECTIONSIZE / EU07_CELLSIZE / 2 * EU07_CELLSIZE ) + EU07_CELLSIZE / 2;
|
|
glm::dvec3 sectioncornercenter { m_area.center + glm::dvec3{ centeroffset, 0, centeroffset } };
|
|
auto row { 0 }, column { 0 };
|
|
for( auto &cell : m_cells ) {
|
|
cell.center( sectioncornercenter + glm::dvec3{ column * EU07_CELLSIZE, 0.0, row * EU07_CELLSIZE } );
|
|
if( ++column >= EU07_SECTIONSIZE / EU07_CELLSIZE ) {
|
|
++row;
|
|
column = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// generates renderable version of held non-instanced geometry
|
|
void
|
|
basic_section::create_geometry() {
|
|
|
|
if( true == m_geometrycreated ) { return; }
|
|
else {
|
|
// mark it done for future checks
|
|
m_geometrycreated = true;
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
|
|
for( auto &shape : m_shapes ) {
|
|
shape.create_geometry( m_geometrybank );
|
|
}
|
|
for( auto &cell : m_cells ) {
|
|
cell.create_geometry( m_geometrybank );
|
|
}
|
|
}
|
|
|
|
// provides access to section enclosing specified point
|
|
basic_cell &
|
|
basic_section::cell( glm::dvec3 const &Location ) {
|
|
|
|
auto const column = static_cast<int>( std::floor( ( Location.x - ( m_area.center.x - EU07_SECTIONSIZE / 2 ) ) / EU07_CELLSIZE ) );
|
|
auto const row = static_cast<int>( std::floor( ( Location.z - ( m_area.center.z - EU07_SECTIONSIZE / 2 ) ) / EU07_CELLSIZE ) );
|
|
|
|
return
|
|
m_cells[
|
|
clamp( row, 0, ( EU07_SECTIONSIZE / EU07_CELLSIZE ) - 1 ) * ( EU07_SECTIONSIZE / EU07_CELLSIZE )
|
|
+ clamp( column, 0, ( EU07_SECTIONSIZE / EU07_CELLSIZE ) - 1 ) ] ;
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
glm::dvec3 regioncornercenter { centeroffset, 0, centeroffset };
|
|
auto row { 0 }, column { 0 };
|
|
// ...move through section array assigning centers left to right, front/top to back/bottom
|
|
for( auto §ion : m_sections ) {
|
|
section.center( regioncornercenter + glm::dvec3{ column * EU07_SECTIONSIZE, 0.0, row * EU07_SECTIONSIZE } );
|
|
if( ++column >= EU07_REGIONSIDESECTIONCOUNT ) {
|
|
++row;
|
|
column = 0;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
basic_region::~basic_region() {
|
|
|
|
for( auto section : m_sections ) { if( section != nullptr ) { delete section; } }
|
|
}
|
|
|
|
void
|
|
basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad ) {
|
|
|
|
// shape might need to be split into smaller pieces, so we create list of nodes instead of just single one
|
|
// using deque so we can do single pass iterating and addding generated pieces without invalidating anything
|
|
std::deque<shape_node> shapes { Shape };
|
|
auto &shape = shapes.front();
|
|
if( shape.m_data.vertices.empty() ) { return; }
|
|
|
|
// adjust input if necessary:
|
|
if( Scratchpad.location_rotation != glm::vec3( 0, 0, 0 ) ) {
|
|
// rotate...
|
|
auto const rotation = glm::radians( Scratchpad.location_rotation );
|
|
for( auto &vertex : shape.m_data.vertices ) {
|
|
vertex.position = glm::rotateZ<double>( vertex.position, rotation.z );
|
|
vertex.position = glm::rotateX<double>( vertex.position, rotation.x );
|
|
vertex.position = glm::rotateY<double>( vertex.position, rotation.y );
|
|
vertex.normal = glm::rotateZ( vertex.normal, rotation.z );
|
|
vertex.normal = glm::rotateX( vertex.normal, rotation.x );
|
|
vertex.normal = glm::rotateY( vertex.normal, rotation.y );
|
|
}
|
|
}
|
|
if( ( false == Scratchpad.location_offset.empty() )
|
|
&& ( Scratchpad.location_offset.top() != glm::dvec3( 0, 0, 0 ) ) ) {
|
|
// ...and move
|
|
auto const offset = Scratchpad.location_offset.top();
|
|
for( auto &vertex : shape.m_data.vertices ) {
|
|
vertex.position += offset;
|
|
}
|
|
}
|
|
// calculate bounding area
|
|
for( auto const &vertex : shape.m_data.vertices ) {
|
|
shape.m_data.area.center += vertex.position;
|
|
}
|
|
shape.m_data.area.center /= shape.m_data.vertices.size();
|
|
// trim the shape if needed. trimmed parts will be added to list as separate nodes
|
|
for( std::size_t index = 0; index < shapes.size(); ++index ) {
|
|
while( true == RaTriangleDivider( shapes[ index ], shapes ) ) {
|
|
; // all work is done during expression check
|
|
}
|
|
// with the trimming done we can calculate shape's bounding radius
|
|
shape.compute_radius();
|
|
}
|
|
// move the data into appropriate section(s)
|
|
for( auto &shape : shapes ) {
|
|
|
|
if( point_inside( shape.m_data.area.center ) ) {
|
|
// NOTE: nodes placed outside of region boundaries are discarded
|
|
section( shape.m_data.area.center ).insert( shape );
|
|
}
|
|
else {
|
|
ErrorLog(
|
|
"Bad scenario: shape node" + (
|
|
shape.m_name.empty() ?
|
|
"" :
|
|
" \"" + shape.m_name + "\"" )
|
|
+ " placed in location outside region bounds (" + to_string( shape.m_data.area.center ) + ")" );
|
|
}
|
|
}
|
|
}
|
|
|
|
// inserts provided track in the region
|
|
void
|
|
basic_region::insert_path( TTrack *Path, scratch_data &Scratchpad ) {
|
|
|
|
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
|
auto center = Path->location();
|
|
|
|
if( point_inside( center ) ) {
|
|
// NOTE: nodes placed outside of region boundaries are discarded
|
|
section( center ).insert( Path );
|
|
}
|
|
else {
|
|
// tracks are guaranteed to hava a name so we can skip the check
|
|
ErrorLog( "Bad scenario: track node \"" + Path->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
|
}
|
|
}
|
|
|
|
// inserts provided track in the region
|
|
void
|
|
basic_region::insert_traction( TTraction *Traction, scratch_data &Scratchpad ) {
|
|
|
|
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
|
auto center = Traction->location();
|
|
|
|
if( point_inside( center ) ) {
|
|
// NOTE: nodes placed outside of region boundaries are discarded
|
|
section( center ).insert( Traction );
|
|
}
|
|
else {
|
|
// tracks are guaranteed to hava a name so we can skip the check
|
|
ErrorLog( "Bad scenario: traction node \"" + Traction->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
|
}
|
|
}
|
|
|
|
// inserts provided instance of 3d model in the region
|
|
void
|
|
basic_region::insert_instance( TAnimModel *Instance, scratch_data &Scratchpad ) {
|
|
|
|
// NOTE: bounding area isn't present/filled until track class and wrapper refactoring is done
|
|
auto center = Instance->location();
|
|
|
|
if( point_inside( center ) ) {
|
|
// NOTE: nodes placed outside of region boundaries are discarded
|
|
section( center ).insert( Instance );
|
|
}
|
|
else {
|
|
// tracks are guaranteed to hava a name so we can skip the check
|
|
ErrorLog( "Bad scenario: model node \"" + Instance->name() + "\" placed in location outside region bounds (" + to_string( center ) + ")" );
|
|
}
|
|
}
|
|
|
|
// checks whether specified point is within boundaries of the region
|
|
bool
|
|
basic_region::point_inside( glm::dvec3 const &Location ) {
|
|
|
|
double const regionboundary = EU07_REGIONSIDESECTIONCOUNT / 2 * EU07_SECTIONSIZE;
|
|
return ( ( Location.x > -regionboundary ) && ( Location.x < regionboundary )
|
|
&& ( Location.z > -regionboundary ) && ( Location.z < regionboundary ) );
|
|
}
|
|
|
|
// trims provided shape to fit into a section, adds trimmed part at the end of provided list
|
|
// NOTE: legacy function. TBD, TODO: clean it up?
|
|
bool
|
|
basic_region::RaTriangleDivider( shape_node &Shape, std::deque<shape_node> &Shapes ) {
|
|
|
|
if( Shape.m_data.vertices.size() != 3 ) {
|
|
// tylko gdy jeden trójkąt
|
|
return false;
|
|
}
|
|
|
|
auto const margin { 200.0 };
|
|
auto x0 = EU07_SECTIONSIZE * std::floor( 0.001 * Shape.m_data.area.center.x ) - margin;
|
|
auto x1 = x0 + EU07_SECTIONSIZE + margin * 2;
|
|
auto z0 = EU07_SECTIONSIZE * std::floor( 0.001 * Shape.m_data.area.center.z ) - margin;
|
|
auto z1 = z0 + EU07_SECTIONSIZE + margin * 2;
|
|
|
|
if( ( Shape.m_data.vertices[ 0 ].position.x >= x0 ) && ( Shape.m_data.vertices[ 0 ].position.x <= x1 )
|
|
&& ( Shape.m_data.vertices[ 0 ].position.z >= z0 ) && ( Shape.m_data.vertices[ 0 ].position.z <= z1 )
|
|
&& ( Shape.m_data.vertices[ 1 ].position.x >= x0 ) && ( Shape.m_data.vertices[ 1 ].position.x <= x1 )
|
|
&& ( Shape.m_data.vertices[ 1 ].position.z >= z0 ) && ( Shape.m_data.vertices[ 1 ].position.z <= z1 )
|
|
&& ( Shape.m_data.vertices[ 2 ].position.x >= x0 ) && ( Shape.m_data.vertices[ 2 ].position.x <= x1 )
|
|
&& ( Shape.m_data.vertices[ 2 ].position.z >= z0 ) && ( Shape.m_data.vertices[ 2 ].position.z <= z1 ) ) {
|
|
// trójkąt wystający mniej niż 200m z kw. kilometrowego jest do przyjęcia
|
|
return false;
|
|
}
|
|
// Ra: przerobić na dzielenie na 2 trójkąty, podział w przecięciu z siatką kilometrową
|
|
// Ra: i z rekurencją będzie dzielić trzy trójkąty, jeśli będzie taka potrzeba
|
|
int divide { -1 }; // bok do podzielenia: 0=AB, 1=BC, 2=CA; +4=podział po OZ; +8 na x1/z1
|
|
double
|
|
min { 0.0 },
|
|
mul; // jeśli przechodzi przez oś, iloczyn będzie ujemny
|
|
x0 += margin;
|
|
x1 -= margin; // przestawienie na siatkę
|
|
z0 += margin;
|
|
z1 -= margin;
|
|
// AB na wschodzie
|
|
mul = ( Shape.m_data.vertices[ 0 ].position.x - x0 ) * ( Shape.m_data.vertices[ 1 ].position.x - x0 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 0;
|
|
}
|
|
// BC na wschodzie
|
|
mul = ( Shape.m_data.vertices[ 1 ].position.x - x0 ) * ( Shape.m_data.vertices[ 2 ].position.x - x0 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 1;
|
|
}
|
|
// CA na wschodzie
|
|
mul = ( Shape.m_data.vertices[ 2 ].position.x - x0 ) * ( Shape.m_data.vertices[ 0 ].position.x - x0 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 2;
|
|
}
|
|
// AB na zachodzie
|
|
mul = ( Shape.m_data.vertices[ 0 ].position.x - x1 ) * ( Shape.m_data.vertices[ 1 ].position.x - x1 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 8;
|
|
}
|
|
// BC na zachodzie
|
|
mul = ( Shape.m_data.vertices[ 1 ].position.x - x1 ) * ( Shape.m_data.vertices[ 2 ].position.x - x1 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 9;
|
|
}
|
|
// CA na zachodzie
|
|
mul = ( Shape.m_data.vertices[ 2 ].position.x - x1 ) * ( Shape.m_data.vertices[ 0 ].position.x - x1 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 10;
|
|
}
|
|
// AB na południu
|
|
mul = ( Shape.m_data.vertices[ 0 ].position.z - z0 ) * ( Shape.m_data.vertices[ 1 ].position.z - z0 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 4;
|
|
}
|
|
// BC na południu
|
|
mul = ( Shape.m_data.vertices[ 1 ].position.z - z0 ) * ( Shape.m_data.vertices[ 2 ].position.z - z0 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 5;
|
|
}
|
|
// CA na południu
|
|
mul = ( Shape.m_data.vertices[ 2 ].position.z - z0 ) * ( Shape.m_data.vertices[ 0 ].position.z - z0 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 6;
|
|
}
|
|
// AB na północy
|
|
mul = ( Shape.m_data.vertices[ 0 ].position.z - z1 ) * ( Shape.m_data.vertices[ 1 ].position.z - z1 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 12;
|
|
}
|
|
// BC na północy
|
|
mul = ( Shape.m_data.vertices[ 1 ].position.z - z1 ) * ( Shape.m_data.vertices[ 2 ].position.z - z1 );
|
|
if( mul < min ) {
|
|
min = mul;
|
|
divide = 13;
|
|
}
|
|
// CA na północy
|
|
mul = (Shape.m_data.vertices[2].position.z - z1) * (Shape.m_data.vertices[0].position.z - z1);
|
|
if( mul < min ) {
|
|
divide = 14;
|
|
}
|
|
|
|
// tworzymy jeden dodatkowy trójkąt, dzieląc jeden bok na przecięciu siatki kilometrowej
|
|
Shapes.emplace_back( Shape ); // copy current shape
|
|
auto &newshape = Shapes.back();
|
|
|
|
switch (divide & 3) {
|
|
// podzielenie jednego z boków, powstaje wierzchołek D
|
|
case 0: {
|
|
// podział AB (0-1) -> ADC i DBC
|
|
newshape.m_data.vertices[ 2 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek C jest wspólny
|
|
newshape.m_data.vertices[ 1 ] = Shape.m_data.vertices[ 1 ]; // wierzchołek B przechodzi do nowego
|
|
if( divide & 4 ) {
|
|
Shape.m_data.vertices[ 1 ].set_from_z(
|
|
Shape.m_data.vertices[ 0 ],
|
|
Shape.m_data.vertices[ 1 ],
|
|
( ( divide & 8 ) ?
|
|
z1 :
|
|
z0 ) );
|
|
}
|
|
else {
|
|
Shape.m_data.vertices[ 1 ].set_from_x(
|
|
Shape.m_data.vertices[ 0 ],
|
|
Shape.m_data.vertices[ 1 ],
|
|
( ( divide & 8 ) ?
|
|
x1 :
|
|
x0 ) );
|
|
}
|
|
newshape.m_data.vertices[ 0 ] = Shape.m_data.vertices[ 1 ]; // wierzchołek D jest wspólny
|
|
break;
|
|
}
|
|
case 1: {
|
|
// podział BC (1-2) -> ABD i ADC
|
|
newshape.m_data.vertices[ 0 ] = Shape.m_data.vertices[ 0 ]; // wierzchołek A jest wspólny
|
|
newshape.m_data.vertices[ 2 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek C przechodzi do nowego
|
|
if( divide & 4 ) {
|
|
Shape.m_data.vertices[ 2 ].set_from_z(
|
|
Shape.m_data.vertices[ 1 ],
|
|
Shape.m_data.vertices[ 2 ],
|
|
( ( divide & 8 ) ?
|
|
z1 :
|
|
z0 ) );
|
|
}
|
|
else {
|
|
Shape.m_data.vertices[ 2 ].set_from_x(
|
|
Shape.m_data.vertices[ 1 ],
|
|
Shape.m_data.vertices[ 2 ],
|
|
( ( divide & 8 ) ?
|
|
x1 :
|
|
x0 ) );
|
|
}
|
|
newshape.m_data.vertices[ 1 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek D jest wspólny
|
|
break;
|
|
}
|
|
case 2: {
|
|
// podział CA (2-0) -> ABD i DBC
|
|
newshape.m_data.vertices[ 1 ] = Shape.m_data.vertices[ 1 ]; // wierzchołek B jest wspólny
|
|
newshape.m_data.vertices[ 2 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek C przechodzi do nowego
|
|
if( divide & 4 ) {
|
|
Shape.m_data.vertices[ 2 ].set_from_z(
|
|
Shape.m_data.vertices[ 2 ],
|
|
Shape.m_data.vertices[ 0 ],
|
|
( ( divide & 8 ) ?
|
|
z1 :
|
|
z0 ) );
|
|
}
|
|
else {
|
|
Shape.m_data.vertices[ 2 ].set_from_x(
|
|
Shape.m_data.vertices[ 2 ],
|
|
Shape.m_data.vertices[ 0 ],
|
|
( ( divide & 8 ) ?
|
|
x1 :
|
|
x0 ) );
|
|
}
|
|
newshape.m_data.vertices[ 0 ] = Shape.m_data.vertices[ 2 ]; // wierzchołek D jest wspólny
|
|
break;
|
|
}
|
|
}
|
|
// przeliczenie środków ciężkości obu
|
|
Shape.m_data.area.center = ( Shape.m_data.vertices[ 0 ].position + Shape.m_data.vertices[ 1 ].position + Shape.m_data.vertices[ 2 ].position ) / 3.0;
|
|
newshape.m_data.area.center = ( newshape.m_data.vertices[ 0 ].position + newshape.m_data.vertices[ 1 ].position + newshape.m_data.vertices[ 2 ].position ) / 3.0;
|
|
|
|
return true;
|
|
}
|
|
|
|
// provides access to section enclosing specified point
|
|
basic_section &
|
|
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 ) );
|
|
|
|
auto §ion =
|
|
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
|
|
|
|
//---------------------------------------------------------------------------
|