Compare commits

...

4 Commits

Author SHA1 Message Date
James Turner
506b9130a8 Adjust where we set the deployment SDK on Mac.
Contrary to the CMake docs, settings this value before project()
seems not to work, whereas setting it after works exactly as
desired.
2015-02-18 10:06:03 +00:00
James Turner
5d1b70a7f2 Force SDK version / C++ library on Mac. 2015-02-13 14:47:45 +00:00
Peter Sadrozinski
eff3df57d9 memory reduced tile loading.
- do not save the TileGeometryBin and matcach in the randomObjectCallback
- recreate matcache, and get TileGeometry from scenegraph
- split obj.cxx into three distinct files - loadBTG, load surface geometry, and load tile details
- includes fix for sceneries that have missing materials
2015-02-11 09:04:53 +01:00
Rebecca N. Palmer
2931f3380f Fix UpdateOnceCallback crash (bug 1554/1556/1568)
(cherry picked from commit dc1816bb08)
2015-01-19 15:51:36 +00:00
11 changed files with 2006 additions and 1349 deletions

View File

@@ -6,6 +6,9 @@ include (CheckCXXCompilerFlag)
project(SimGear)
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
# read 'version' file into a variable (stripping any newlines or spaces)
file(READ version versionFile)
string(STRIP ${versionFile} SIMGEAR_VERSION)
@@ -34,7 +37,7 @@ SET(CPACK_INSTALL_CMAKE_PROJECTS ${CMAKE_CURRENT_BINARY_DIR};SimGear;ALL;/)
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${SIMGEAR_VERSION} )
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
@@ -175,12 +178,12 @@ if(SIMGEAR_HEADLESS)
else()
message(STATUS "SimGear mode: NORMAL")
find_package(OpenGL REQUIRED)
if (ENABLE_SOUND)
find_package(OpenAL REQUIRED)
message(STATUS "Sound support: ENABLED")
endif(ENABLE_SOUND)
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
endif(SIMGEAR_HEADLESS)
@@ -197,8 +200,8 @@ else()
# XML_STATIC is important to avoid sg_expat_external.h
# declaring symbols as declspec(import)
add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC)
set(EXPAT_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/3rdparty/expat
set(EXPAT_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/3rdparty/expat
${PROJECT_BINARY_DIR}/3rdparty/expat)
endif(SYSTEM_EXPAT)
@@ -275,12 +278,12 @@ SET(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on wi
# isnan might not be real symbol, so can't check using function_exists
check_cxx_source_compiles(
"#include <cmath>
"#include <cmath>
int main() { return isnan(0.0);} "
HAVE_ISNAN)
check_cxx_source_compiles(
"#include <cmath>
"#include <cmath>
int main() { return std::isnan(0.0);} "
HAVE_STD_ISNAN)
@@ -299,6 +302,9 @@ endif(CMAKE_COMPILER_IS_GNUCXX)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual")
set(WARNING_FLAGS_C "-Wall")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@@ -320,16 +326,16 @@ if(WIN32)
# foreach(warning 4244 4251 4267 4275 4290 4786 4305 4996)
# SET(WARNING_FLAGS "${WARNING_FLAGS} /wd${warning}")
# endforeach(warning)
set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /wd4996 /wd4250 -Dstrdup=_strdup")
if (${MSVC_VERSION} GREATER 1599)
set( MSVC_LD_FLAGS "/FORCE:MULTIPLE" )
endif (${MSVC_VERSION} GREATER 1599)
endif(MSVC)
# assumed on Windows
set(HAVE_GETLOCALTIME 1)
set( WINSOCK_LIBRARY "ws2_32.lib" )
set( RT_LIBRARY "winmm" )
endif(WIN32)
@@ -338,15 +344,15 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
# use BEFORE to ensure local directories are used first,
# use BEFORE to ensure local directories are used first,
# ahead of system-installed libs
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
include_directories(BEFORE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${OPENAL_INCLUDE_DIR}
)
@@ -399,5 +405,5 @@ CONFIGURE_FILE(
IMMEDIATE @ONLY)
ADD_CUSTOM_TARGET(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

View File

@@ -28,11 +28,12 @@ SGPath appleSpecialFolder(int dirType, int domainMask, const SGPath& def)
{
CocoaAutoreleasePool ap;
NSFileManager* fm = [NSFileManager defaultManager];
NSURL* pathUrl = [fm URLForDirectory:dirType
inDomain:domainMask
appropriateForURL:Nil
create:YES
error:nil];
NSSearchPathDirectory d = static_cast<NSSearchPathDirectory>(dirType);
NSURL* pathUrl = [fm URLForDirectory:d
inDomain:domainMask
appropriateForURL:Nil
create:YES
error:nil];
if (!pathUrl) {
return def;;
}

View File

@@ -23,6 +23,7 @@
#include <boost/iterator/iterator_adaptor.hpp>
#include "Effect.hxx"
#include "mat.hxx"
namespace simgear
{
@@ -69,6 +70,8 @@ class EffectGeode : public osg::Geode
META_Node(simgear,EffectGeode);
Effect* getEffect() const { return _effect.get(); }
void setEffect(Effect* effect);
SGMaterial* getMaterial() const { return _material; }
void setMaterial(SGMaterial* mat) { _material = mat; }
virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* = 0) const;
@@ -83,6 +86,7 @@ class EffectGeode : public osg::Geode
void runGenerators(osg::Geometry *geometry);
private:
osg::ref_ptr<Effect> _effect;
SGMaterial* _material;
};
}
#endif

View File

@@ -441,7 +441,7 @@ Effect* SGMaterial::get_effect(int i)
return _status[i].effect.get();
}
Effect* SGMaterial::get_effect(const SGTexturedTriangleBin& triangleBin)
Effect* SGMaterial::get_one_effect(int texIndex)
{
SGGuard<SGMutex> g(_lock);
if (_status.empty()) {
@@ -449,7 +449,7 @@ Effect* SGMaterial::get_effect(const SGTexturedTriangleBin& triangleBin)
return 0;
}
int i = triangleBin.getTextureIndex() % _status.size();
int i = texIndex % _status.size();
return get_effect(i);
}
@@ -460,7 +460,7 @@ Effect* SGMaterial::get_effect()
}
osg::Texture2D* SGMaterial::get_object_mask(const SGTexturedTriangleBin& triangleBin)
osg::Texture2D* SGMaterial::get_one_object_mask(int texIndex)
{
if (_status.empty()) {
SG_LOG( SG_GENERAL, SG_WARN, "No mask available.");
@@ -469,7 +469,7 @@ osg::Texture2D* SGMaterial::get_object_mask(const SGTexturedTriangleBin& triangl
// Note that the object mask is closely linked to the texture/effect
// so we index based on the texture index,
unsigned int i = triangleBin.getTextureIndex() % _status.size();
unsigned int i = texIndex % _status.size();
if (i < _masks.size()) {
return _masks[i].get();
} else {

View File

@@ -119,13 +119,13 @@ public:
/**
* Get the textured state.
*/
simgear::Effect* get_effect(const SGTexturedTriangleBin& triangleBin);
simgear::Effect* get_one_effect(int texIndex);
simgear::Effect* get_effect();
/**
* Get the textured state.
*/
osg::Texture2D* get_object_mask(const SGTexturedTriangleBin& triangleBin);
osg::Texture2D* get_one_object_mask(int texIndex);
/**

View File

@@ -8,9 +8,12 @@ set(HEADERS
SGDirectionalLightBin.hxx
SGLightBin.hxx
SGModelBin.hxx
SGNodeTriangles.hxx
SGOceanTile.hxx
SGReaderWriterBTG.hxx
SGTexturedTriangleBin.hxx
SGTileDetailsCallback.hxx
SGTileGeometryBin.hxx
SGTriangleBin.hxx
SGVasiDrawable.hxx
SGVertexArrayBin.hxx

View File

@@ -0,0 +1,482 @@
// future API - just run through once to convert from OSG to SG
// then we can use these triangle lists for random
// trees/lights/buildings/objects
struct SGTexturedTriangle
{
public:
std::vector<SGVec3f> vertices;
std::vector<SGVec2f> texcoords;
};
struct SGBorderContour
{
public:
SGVec3d start;
SGVec3d end;
};
class SGTriangleInfo
{
public:
SGTriangleInfo( const SGVec3d& center ) {
gbs_center = center;
mt_init(&seed, 123);
}
// API used to build the Info by the visitor
void addGeometry( osg::Geometry* g ) {
geometries.push_back(g);
}
void setMaterial( SGMaterial* m ) {
mat = m;
}
SGMaterial* getMaterial( void ) const {
return mat;
}
// API used to get a specific texture or effect from a material. Materials can have
// multiple textures - use the floor of the x coordinate of the first vertes to select it.
// This will be constant, and give the same result each time to select one effect/texture per drawable.
int getTextureIndex( void ) const {
int texInfo = 0;
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
if ( vertices ) {
const osg::Vec3 *v0 = &vertices->operator[](0);
texInfo = floor(v0->x());
}
return texInfo;
}
// new API - TODO
void getTriangles( std::vector<SGTexturedTriangle>& tris )
{
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
if ( numPrimitiveSets > 0 ) {
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
unsigned int numIndices = ps->getNumIndices();
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
SGTexturedTriangle tri;
tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-2))) );
tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-1))) );
tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-0))) );
tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-2))) );
tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-1))) );
tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-0))) );
}
}
}
void getBorderContours( std::vector<SGBorderContour>& border )
{
// each structure contains a list of target indexes and a count
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
if ( numPrimitiveSets > 0 ) {
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
unsigned int numTriangles = ps->getNumIndices()/3;
// use a map for fast lookup map the segment as a 64 bit int
std::map<uint64_t, int> segCounter;
uint32_t idx1, idx2;
uint64_t key;
for ( unsigned int i=0; i<numTriangles; i+= 3 ) {
// first seg
if ( ps->index(i+0) < ps->index(i+1) ) {
idx1 = ps->index(i+0);
idx2 = ps->index(i+1);
} else {
idx1 = ps->index(i+1);
idx2 = ps->index(i+0);
}
key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
segCounter[key]++;
SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
// second seg
if ( ps->index(i+1) < ps->index(i+2) ) {
idx1 = ps->index(i+1);
idx2 = ps->index(i+2);
} else {
idx1 = ps->index(i+2);
idx2 = ps->index(i+1);
}
key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
segCounter[key]++;
SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
// third seg
if ( ps->index(i+2) < ps->index(i+0) ) {
idx1 = ps->index(i+2);
idx2 = ps->index(i+0);
} else {
idx1 = ps->index(i+0);
idx2 = ps->index(i+2);
}
key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
segCounter[key]++;
SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
}
// return all segments with count = 1 ( border )
std::map<uint64_t, int>::iterator segIt = segCounter.begin();
while ( segIt != segCounter.end() ) {
if ( segIt->second == 1 ) {
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << segIt->first << std::dec << " count is " << segIt->second );
unsigned int iStart = segIt->first >> 32;
unsigned int iEnd = segIt->first & 0x00000000FFFFFFFF;
SGBorderContour bc;
bc.start = toVec3d(toSG(vertices->operator[](iStart)));
bc.end = toVec3d(toSG(vertices->operator[](iEnd)));
border.push_back( bc );
}
segIt++;
}
#if 0
// debug out - requires GDAL
//
//
//
SGGeod geodPos = SGGeod::fromCart(gbs_center);
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
for ( unsigned int i=0; i<border.size(); i++ ){
// de-rotate and translate : todo - create a paralell vertex list so we just do this
// once per vertex, not for every triangle's use of the vertex
SGVec3d sgVStart = hlOr.backTransform( border[i].start) + gbs_center;
SGVec3d sgVEnd = hlOr.backTransform( border[i].end) + gbs_center;
// convert from cartesian to Geodetic, and save as a list of Geods for output
SGGeod gStart = SGGeod::fromCart(sgVStart);
SGGeod gEnd = SGGeod::fromCart(sgVEnd);
SGShapefile::FromSegment( gStart, gEnd, true, "./borders", mat->get_names()[0], "border" );
}
#endif
}
}
// Random buildings API - get num triangles, then get a triangle at index
unsigned int getNumTriangles( void ) const {
unsigned int num_triangles = 0;
if ( !geometries.empty() ) {
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
if ( numPrimitiveSets > 0 ) {
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
unsigned int numIndices = ps->getNumIndices();
num_triangles = numIndices/3;
}
}
return num_triangles;
}
void getTriangle(unsigned int i, std::vector<SGVec3f>& triVerts, std::vector<SGVec2f>& triTCs) const {
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
if ( !geometries.empty() ) {
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
if ( numPrimitiveSets > 0 ) {
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
int idxStart = i*3;
triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+0))) );
triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+1))) );
triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+2))) );
triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+0))) );
triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+1))) );
triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+2))) );
}
}
}
// random lights and trees - just get a list of points on where to add the light / tree
// TODO move this out - and handle in the random light / tree code
// just use generic triangle API.
void addRandomSurfacePoints(float coverage, float offset,
osg::Texture2D* object_mask,
std::vector<SGVec3f>& points)
{
if ( !geometries.empty() ) {
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
if ( numPrimitiveSets > 0 ) {
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
unsigned int numIndices = ps->getNumIndices();
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
SGVec3f v0 = toSG(vertices->operator[](ps->index(i-2)));
SGVec3f v1 = toSG(vertices->operator[](ps->index(i-1)));
SGVec3f v2 = toSG(vertices->operator[](ps->index(i-0)));
SGVec2f t0 = toSG(texcoords->operator[](ps->index(i-2)));
SGVec2f t1 = toSG(texcoords->operator[](ps->index(i-1)));
SGVec2f t2 = toSG(texcoords->operator[](ps->index(i-0)));
SGVec3f normal = cross(v1 - v0, v2 - v0);
// Compute the area
float area = 0.5f*length(normal);
if (area <= SGLimitsf::min())
continue;
// For partial units of area, use a zombie door method to
// create the proper random chance of a light being created
// for this triangle
float unit = area + mt_rand(&seed)*coverage;
SGVec3f offsetVector = offset*normalize(normal);
// generate a light point for each unit of area
while ( coverage < unit ) {
float a = mt_rand(&seed);
float b = mt_rand(&seed);
if ( a + b > 1 ) {
a = 1 - a;
b = 1 - b;
}
float c = 1 - a - b;
SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
if (object_mask != NULL) {
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
// Check this random point against the object mask
// red channel.
osg::Image* img = object_mask->getImage();
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
if (mt_rand(&seed) < img->getColor(x, y).r()) {
points.push_back(randomPoint);
}
} else {
// No object mask, so simply place the object
points.push_back(randomPoint);
}
unit -= coverage;
}
}
}
}
}
void addRandomTreePoints(float wood_coverage,
osg::Texture2D* object_mask,
float vegetation_density,
float cos_max_density_angle,
float cos_zero_density_angle,
std::vector<SGVec3f>& points)
{
if ( !geometries.empty() ) {
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
if ( numPrimitiveSets > 0 ) {
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
unsigned int numIndices = ps->getNumIndices();
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
SGVec3f v0 = toSG(vertices->operator[](ps->index(i-2)));
SGVec3f v1 = toSG(vertices->operator[](ps->index(i-1)));
SGVec3f v2 = toSG(vertices->operator[](ps->index(i-0)));
SGVec2f t0 = toSG(texcoords->operator[](ps->index(i-2)));
SGVec2f t1 = toSG(texcoords->operator[](ps->index(i-1)));
SGVec2f t2 = toSG(texcoords->operator[](ps->index(i-0)));
SGVec3f normal = cross(v1 - v0, v2 - v0);
// Ensure the slope isn't too steep by checking the
// cos of the angle between the slope normal and the
// vertical (conveniently the z-component of the normalized
// normal) and values passed in.
float alpha = normalize(normal).z();
float slope_density = 1.0;
if (alpha < cos_zero_density_angle)
continue; // Too steep for any vegetation
if (alpha < cos_max_density_angle) {
slope_density =
(alpha - cos_zero_density_angle) / (cos_max_density_angle - cos_zero_density_angle);
}
// Compute the area
float area = 0.5f*length(normal);
if (area <= SGLimitsf::min())
continue;
// Determine the number of trees, taking into account vegetation
// density (which is linear) and the slope density factor.
// Use a zombie door method to create the proper random chance
// of a tree being created for partial values.
int woodcount = (int) (vegetation_density * vegetation_density *
slope_density *
area / wood_coverage + mt_rand(&seed));
for (int j = 0; j < woodcount; j++) {
float a = mt_rand(&seed);
float b = mt_rand(&seed);
if ( a + b > 1.0f ) {
a = 1.0f - a;
b = 1.0f - b;
}
float c = 1.0f - a - b;
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
if (object_mask != NULL) {
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
// Check this random point against the object mask
// green (for trees) channel.
osg::Image* img = object_mask->getImage();
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
if (mt_rand(&seed) < img->getColor(x, y).g()) {
// The red channel contains the rotation for this object
points.push_back(randomPoint);
}
} else {
points.push_back(randomPoint);
}
}
}
}
}
}
#if 0
// debug : this will save the tile as a shapefile that can be viewed in QGIS.
// NOTE: this is really slow....
// remember - we need to de-rotate the tile, then translate back to gbs_center.
void dumpBorder() {
//dump the first triangle only of the first geometry, for now...
SG_LOG(SG_TERRAIN, SG_ALERT, "effect geode has " << geometries.size() << " geometries" );
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
if ( vertices ) {
SG_LOG(SG_TERRAIN, SG_ALERT, " geometry has " << vertices->getNumElements() << " vertices" );
}
if ( !geometries.empty() ) {
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
SG_LOG(SG_TERRAIN, SG_ALERT, " geometry has " << numPrimitiveSets << " primitive sets" );
if ( numPrimitiveSets > 0 ) {
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
unsigned int numIndices = ps->getNumIndices();
// create the same quat we used to rotate here
// - use backTransform to go back to original node location
SGGeod geodPos = SGGeod::fromCart(gbs_center);
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
SG_LOG(SG_TERRAIN, SG_ALERT, " primitive set has has " << numIndices << " indices" );
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
if ( numIndices >= 3 ) {
unsigned int v0i = ps->index(i-2);
unsigned int v1i = ps->index(i-1);
unsigned int v2i = ps->index(i-0);
const osg::Vec3 *v0 = &vertices->operator[](v0i);
const osg::Vec3 *v1 = &vertices->operator[](v1i);
const osg::Vec3 *v2 = &vertices->operator[](v2i);
// de-rotate and translate : todo - create a paralell vertex list so we just do this
// once per vertex, not for every triangle's use of the vertex
SGVec3d vec0 = hlOr.backTransform( toVec3d(toSG(*v0))) + gbs_center;
SGVec3d vec1 = hlOr.backTransform( toVec3d(toSG(*v1))) + gbs_center;
SGVec3d vec2 = hlOr.backTransform( toVec3d(toSG(*v2))) + gbs_center;
// convert from cartesian to Geodetic, and save as a list of Geods for output
std::vector<SGGeod> triangle;
triangle.push_back( SGGeod::fromCart(vec0) );
triangle.push_back( SGGeod::fromCart(vec1) );
triangle.push_back( SGGeod::fromCart(vec2) );
SGShapefile::FromGeodList( triangle, true, "./triangles", mat->get_names()[0], "tri" );
}
}
}
}
}
#endif
private:
mt seed;
SGMaterial* mat;
SGVec3d gbs_center;
std::vector<osg::Geometry*> geometries;
std::vector<int> polygon_border; // TODO
};
// This visitor will generate an SGTriangleInfo.
// currently, it looks like it could save multiple lists, which could be the case
// if multiple osg::geods are found with osg::Geometry.
// But right now, we store a single PrimitiveSet under a single EffectGeod.
// so the traversal should only find a single EffectGeod - building a single SGTriangleInfo
class GetNodeTriangles : public osg::NodeVisitor
{
public:
GetNodeTriangles(const SGVec3d& c, std::vector<SGTriangleInfo>* nt) : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ), center(c), nodeTris(nt) {}
// This method gets called for every node in the scene
// graph. Check each node to see if it has user
// out target. If so, save the node's address.
virtual void apply( osg::Node& node )
{
EffectGeode* eg = dynamic_cast<EffectGeode*>(&node);
if ( eg ) {
// get the material from the user info
SGTriangleInfo triInfo( center );
triInfo.setMaterial( eg->getMaterial() );
// let's find the drawables for this node
int numDrawables = eg->getNumDrawables();
for ( int i=0; i<numDrawables; i++ ) {
triInfo.addGeometry( eg->getDrawable(i)->asGeometry() );
}
nodeTris->push_back( triInfo );
}
// Keep traversing the rest of the scene graph.
traverse( node );
}
protected:
SGVec3d center;
std::vector<SGTriangleInfo>* nodeTris;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,304 @@
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "obj.hxx"
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/material/mat.hxx>
#include "SGTexturedTriangleBin.hxx"
using namespace simgear;
typedef std::map<std::string,SGTexturedTriangleBin> SGMaterialTriangleMap;
// Class handling the initial BTG loading : should probably be in its own file
// it is very closely coupled with SGTexturedTriangleBin.hxx
// it was used to load fans, strips, and triangles.
// WS2.0 no longer uses fans or strips, but people still use ws1.0, so we need
// to keep this functionality.
class SGTileGeometryBin : public osg::Referenced {
public:
SGMaterialTriangleMap materialTriangleMap;
SGTileGeometryBin() {}
static SGVec2f
getTexCoord(const std::vector<SGVec2f>& texCoords, const int_list& tc,
const SGVec2f& tcScale, unsigned i)
{
if (tc.empty())
return tcScale;
else if (tc.size() == 1)
return mult(texCoords[tc[0]], tcScale);
else
return mult(texCoords[tc[i]], tcScale);
}
SGVec2f getTexCoordScale(const std::string& name, SGMaterialCache* matcache)
{
if (!matcache)
return SGVec2f(1, 1);
SGMaterial* material = matcache->find(name);
if (!material)
return SGVec2f(1, 1);
return material->get_tex_coord_scale();
}
static void
addTriangleGeometry(SGTexturedTriangleBin& triangles,
const SGBinObject& obj, unsigned grp,
const SGVec2f& tc0Scale,
const SGVec2f& tc1Scale)
{
const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes());
const std::vector<SGVec3f>& normals(obj.get_normals());
const std::vector<SGVec2f>& texCoords(obj.get_texcoords());
const int_list& tris_v(obj.get_tris_v()[grp]);
const int_list& tris_n(obj.get_tris_n()[grp]);
const tci_list& tris_tc(obj.get_tris_tcs()[grp]);
bool num_norms_is_num_verts = true;
if (tris_v.size() != tris_n.size()) {
// If the normal indices do not match, they should be inmplicitly
// the same than the vertex indices.
num_norms_is_num_verts = false;
}
if ( !tris_tc[1].empty() ) {
triangles.hasSecondaryTexCoord(true);
}
for (unsigned i = 2; i < tris_v.size(); i += 3) {
SGVertNormTex v0;
v0.SetVertex( toVec3f(vertices[tris_v[i-2]]) );
v0.SetNormal( num_norms_is_num_verts ? normals[tris_n[i-2]] :
normals[tris_v[i-2]] );
v0.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i-2) );
if (!tris_tc[1].empty()) {
v0.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-2) );
}
SGVertNormTex v1;
v1.SetVertex( toVec3f(vertices[tris_v[i-1]]) );
v1.SetNormal( num_norms_is_num_verts ? normals[tris_n[i-1]] :
normals[tris_v[i-1]] );
v1.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i-1) );
if (!tris_tc[1].empty()) {
v1.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-1) );
}
SGVertNormTex v2;
v2.SetVertex( toVec3f(vertices[tris_v[i]]) );
v2.SetNormal( num_norms_is_num_verts ? normals[tris_n[i]] :
normals[tris_v[i]] );
v2.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i) );
if (!tris_tc[1].empty()) {
v2.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i) );
}
triangles.insert(v0, v1, v2);
}
}
static void
addStripGeometry(SGTexturedTriangleBin& triangles,
const SGBinObject& obj, unsigned grp,
const SGVec2f& tc0Scale,
const SGVec2f& tc1Scale)
{
const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes());
const std::vector<SGVec3f>& normals(obj.get_normals());
const std::vector<SGVec2f>& texCoords(obj.get_texcoords());
const int_list& strips_v(obj.get_strips_v()[grp]);
const int_list& strips_n(obj.get_strips_n()[grp]);
const tci_list& strips_tc(obj.get_strips_tcs()[grp]);
bool num_norms_is_num_verts = true;
if (strips_v.size() != strips_n.size()) {
// If the normal indices do not match, they should be inmplicitly
// the same than the vertex indices.
num_norms_is_num_verts = false;
}
if ( !strips_tc[1].empty() ) {
triangles.hasSecondaryTexCoord(true);
}
for (unsigned i = 2; i < strips_v.size(); ++i) {
SGVertNormTex v0;
v0.SetVertex( toVec3f(vertices[strips_v[i-2]]) );
v0.SetNormal( num_norms_is_num_verts ? normals[strips_n[i-2]] :
normals[strips_v[i-2]] );
v0.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[0], tc0Scale, i-2) );
if (!strips_tc[1].empty()) {
v0.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i-2) );
}
SGVertNormTex v1;
v1.SetVertex( toVec3f(vertices[strips_v[i-1]]) );
v1.SetNormal( num_norms_is_num_verts ? normals[strips_n[i-1]] :
normals[strips_v[i-1]] );
v1.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[1], tc0Scale, i-1) );
if (!strips_tc[1].empty()) {
v1.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i-1) );
}
SGVertNormTex v2;
v2.SetVertex( toVec3f(vertices[strips_v[i]]) );
v2.SetNormal( num_norms_is_num_verts ? normals[strips_n[i]] :
normals[strips_v[i]] );
v2.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[0], tc0Scale, i) );
if (!strips_tc[1].empty()) {
v2.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i) );
}
if (i%2)
triangles.insert(v1, v0, v2);
else
triangles.insert(v0, v1, v2);
}
}
static void
addFanGeometry(SGTexturedTriangleBin& triangles,
const SGBinObject& obj, unsigned grp,
const SGVec2f& tc0Scale,
const SGVec2f& tc1Scale)
{
const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes());
const std::vector<SGVec3f>& normals(obj.get_normals());
const std::vector<SGVec2f>& texCoords(obj.get_texcoords());
const int_list& fans_v(obj.get_fans_v()[grp]);
const int_list& fans_n(obj.get_fans_n()[grp]);
const tci_list& fans_tc(obj.get_fans_tcs()[grp]);
bool num_norms_is_num_verts = true;
if (fans_v.size() != fans_n.size()) {
// If the normal indices do not match, they should be inmplicitly
// the same than the vertex indices.
num_norms_is_num_verts = false;
}
if ( !fans_tc[1].empty() ) {
triangles.hasSecondaryTexCoord(true);
}
SGVertNormTex v0;
v0.SetVertex( toVec3f(vertices[fans_v[0]]) );
v0.SetNormal( num_norms_is_num_verts ? normals[fans_n[0]] :
normals[fans_v[0]] );
v0.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, 0) );
if (!fans_tc[1].empty()) {
v0.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 0) );
}
SGVertNormTex v1;
v1.SetVertex( toVec3f(vertices[fans_v[1]]) );
v1.SetNormal( num_norms_is_num_verts ? normals[fans_n[1]] :
normals[fans_v[1]] );
v1.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, 1) );
if (!fans_tc[1].empty()) {
v1.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 1) );
}
for (unsigned i = 2; i < fans_v.size(); ++i) {
SGVertNormTex v2;
v2.SetVertex( toVec3f(vertices[fans_v[i]]) );
v2.SetNormal( num_norms_is_num_verts ? normals[fans_n[i]] :
normals[fans_v[i]] );
v2.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, i) );
if (!fans_tc[1].empty()) {
v2.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, i) );
}
triangles.insert(v0, v1, v2);
v1 = v2;
}
}
bool
insertSurfaceGeometry(const SGBinObject& obj, SGMaterialCache* matcache)
{
if (obj.get_tris_n().size() < obj.get_tris_v().size() ||
obj.get_tris_tcs().size() < obj.get_tris_v().size()) {
SG_LOG(SG_TERRAIN, SG_ALERT,
"Group list sizes for triangles do not match!");
return false;
}
for (unsigned grp = 0; grp < obj.get_tris_v().size(); ++grp) {
std::string materialName = obj.get_tri_materials()[grp];
SGVec2f tc0Scale = getTexCoordScale(materialName, matcache);
SGVec2f tc1Scale(1.0, 1.0);
addTriangleGeometry(materialTriangleMap[materialName],
obj, grp, tc0Scale, tc1Scale );
}
if (obj.get_strips_n().size() < obj.get_strips_v().size() ||
obj.get_strips_tcs().size() < obj.get_strips_v().size()) {
SG_LOG(SG_TERRAIN, SG_ALERT,
"Group list sizes for strips do not match!");
return false;
}
for (unsigned grp = 0; grp < obj.get_strips_v().size(); ++grp) {
std::string materialName = obj.get_strip_materials()[grp];
SGVec2f tc0Scale = getTexCoordScale(materialName, matcache);
SGVec2f tc1Scale(1.0, 1.0);
addStripGeometry(materialTriangleMap[materialName],
obj, grp, tc0Scale, tc1Scale);
}
if (obj.get_fans_n().size() < obj.get_fans_v().size() ||
obj.get_fans_tcs().size() < obj.get_fans_v().size()) {
SG_LOG(SG_TERRAIN, SG_ALERT,
"Group list sizes for fans do not match!");
return false;
}
for (unsigned grp = 0; grp < obj.get_fans_v().size(); ++grp) {
std::string materialName = obj.get_fan_materials()[grp];
SGVec2f tc0Scale = getTexCoordScale(materialName, matcache);
SGVec2f tc1Scale(1.0, 1.0);
addFanGeometry(materialTriangleMap[materialName],
obj, grp, tc0Scale, tc1Scale );
}
return true;
}
osg::Node* getSurfaceGeometry(SGMaterialCache* matcache, bool useVBOs) const
{
if (materialTriangleMap.empty())
return 0;
EffectGeode* eg = NULL;
osg::Group* group = (materialTriangleMap.size() > 1 ? new osg::Group : NULL);
if (group) {
group->setName("surfaceGeometryGroup");
}
//osg::Geode* geode = new osg::Geode;
SGMaterialTriangleMap::const_iterator i;
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
osg::Geometry* geometry = i->second.buildGeometry(useVBOs);
SGMaterial *mat = NULL;
if (matcache) {
mat = matcache->find(i->first);
}
eg = new EffectGeode;
eg->setName("EffectGeode");
if (mat) {
eg->setMaterial(mat);
eg->setEffect(mat->get_one_effect(i->second.getTextureIndex()));
} else {
eg->setMaterial(NULL);
}
eg->addDrawable(geometry);
eg->runGenerators(geometry); // Generate extra data needed by effect
if (group) {
group->addChild(eg);
}
}
if (group) {
return group;
} else {
return eg;
}
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,9 @@ using namespace osg;
void UpdateOnceCallback::operator()(Node* node, NodeVisitor* nv)
{
ref_ptr<UpdateOnceCallback> prevent_premature_deletion=this;
// workaround for crash bug in OSG 3.2.1
// https://bugs.debian.org/765855
doUpdate(node, nv);
node->removeUpdateCallback(this);
// The callback could be deleted now.