celestia/src/celengine/meshmanager.cpp

159 lines
3.9 KiB
C++

// meshmanager.cpp
//
// Copyright (C) 2001 Chris Laurel <claurel@shatters.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <iostream>
#include <fstream>
#include "celestia.h"
#include "celutil/debug.h"
#include "celutil/filetype.h"
#include "celmath/mathlib.h"
#include "celmath/perlin.h"
#include "cel3ds/3dsread.h"
#include "3dsmesh.h"
#include "parser.h"
#include "spheremesh.h"
#include "meshmanager.h"
using namespace std;
static Mesh* LoadCelestiaMesh(const string& filename);
static MeshManager* meshManager = NULL;
MeshManager* GetMeshManager()
{
if (meshManager == NULL)
meshManager = new MeshManager("models");
return meshManager;
}
Mesh* MeshInfo::load(const string& baseDir)
{
DPRINTF("Loading mesh: %s\n", source.c_str());
ContentType fileType = DetermineFileType(source);
if (fileType == Content_3DStudio)
{
Mesh3DS* mesh3 = NULL;
M3DScene* scene = Read3DSFile(baseDir + '/' + source);
if (scene != NULL)
{
mesh3 = new Mesh3DS(*scene);
mesh3->normalize();
delete scene;
return mesh3;
}
}
else if (fileType == Content_CelestiaMesh)
{
return LoadCelestiaMesh(baseDir + '/' + source);
}
return NULL;
}
struct NoiseMeshParameters
{
Vec3f size;
Vec3f offset;
float featureHeight;
float octaves;
float slices;
float rings;
};
static float NoiseDisplacementFunc(float u, float v, void* info)
{
float theta = u * (float) PI * 2;
float phi = (v - 0.5f) * (float) PI;
float x = (float) (cos(phi) * cos(theta));
float y = (float) sin(phi);
float z = (float) (cos(phi) * sin(theta));
// assert(info != NULL);
NoiseMeshParameters* params = (NoiseMeshParameters*) info;
return fractalsum(Point3f(x, y, z) + params->offset,
(int) params->octaves) * params->featureHeight;
}
Mesh* LoadCelestiaMesh(const string& filename)
{
ifstream meshFile(filename.c_str(), ios::in);
if (!meshFile.good())
{
DPRINTF("Error opening mesh file: %s\n", filename.c_str());
return NULL;
}
Tokenizer tokenizer(&meshFile);
Parser parser(&tokenizer);
if (tokenizer.nextToken() != Tokenizer::TokenName)
{
DPRINTF("Mesh file %s is invalid.\n", filename.c_str());
return NULL;
}
if (tokenizer.getStringValue() != "SphereDisplacementMesh")
{
DPRINTF("%s: Unrecognized mesh type %s.\n",
filename.c_str(),
tokenizer.getStringValue().c_str());
return NULL;
}
Value* meshDefValue = parser.readValue();
if (meshDefValue == NULL)
{
DPRINTF("%s: Bad mesh file.\n", filename.c_str());
return NULL;
}
if (meshDefValue->getType() != Value::HashType)
{
DPRINTF("%s: Bad mesh file.\n", filename.c_str());
delete meshDefValue;
return NULL;
}
Hash* meshDef = meshDefValue->getHash();
NoiseMeshParameters params;
params.size = Vec3f(1, 1, 1);
params.offset = Vec3f(10, 10, 10);
params.featureHeight = 0.0f;
params.octaves = 1;
params.slices = 20;
params.rings = 20;
meshDef->getVector("Size", params.size);
meshDef->getVector("NoiseOffset", params.offset);
meshDef->getNumber("FeatureHeight", params.featureHeight);
meshDef->getNumber("Octaves", params.octaves);
meshDef->getNumber("Slices", params.slices);
meshDef->getNumber("Rings", params.rings);
delete meshDefValue;
cout << "Read Celestia mesh " << filename << " successfully!";
return new SphereMesh(params.size,
(int) params.rings, (int) params.slices,
NoiseDisplacementFunc,
(void*) &params);
}