From b6f1c72ae50eb213dbed6fc9662cfa996ed7e6fe Mon Sep 17 00:00:00 2001 From: Chris Laurel Date: Mon, 26 Feb 2001 09:56:35 +0000 Subject: [PATCH] This commit was generated by cvs2svn to compensate for changes in r4, which included commits to RCS files with non-trunk default branches. --- src/3dschunk.h | 58 ++ src/3dsmesh.cpp | 245 ++++++++ src/3dsmesh.h | 33 + src/3dsmodel.cpp | 257 ++++++++ src/3dsmodel.h | 126 ++++ src/3dsread.cpp | 645 +++++++++++++++++++ src/3dsread.h | 22 + src/Ijl.h | 1341 +++++++++++++++++++++++++++++++++++++++ src/aabox.h | 113 ++++ src/astro.cpp | 242 +++++++ src/astro.h | 72 +++ src/basictypes.h | 24 + src/bigfix.cpp | 187 ++++++ src/bigfix.h | 47 ++ src/body.cpp | 341 ++++++++++ src/body.h | 144 +++++ src/celestia.h | 28 + src/color.cpp | 53 ++ src/color.h | 60 ++ src/config.cpp | 121 ++++ src/config.h | 23 + src/console.cpp | 254 ++++++++ src/console.h | 95 +++ src/constellation.cpp | 165 +++++ src/constellation.h | 34 + src/debug.cpp | 42 ++ src/dispmap.cpp | 44 ++ src/dispmap.h | 50 ++ src/filetype.cpp | 62 ++ src/filetype.h | 28 + src/gl.h | 32 + src/glext.cpp | 228 +++++++ src/glext.h | 318 ++++++++++ src/gui.cpp | 152 +++++ src/gui.h | 84 +++ src/mathlib.h | 115 ++++ src/mesh.h | 20 + src/meshmanager.cpp | 160 +++++ src/meshmanager.h | 32 + src/observer.cpp | 84 +++ src/observer.h | 58 ++ src/orbit.cpp | 81 +++ src/orbit.h | 45 ++ src/packdb.cpp | 446 +++++++++++++ src/packnames.cpp | 125 ++++ src/parser.cpp | 524 ++++++++++++++++ src/parser.h | 96 +++ src/perlin.cpp | 333 ++++++++++ src/perlin.h | 19 + src/quaternion.h | 595 ++++++++++++++++++ src/readstars.cpp | 81 +++ src/render.cpp | 1385 +++++++++++++++++++++++++++++++++++++++++ src/render.h | 201 ++++++ src/resmanager.cpp | 60 ++ src/resmanager.h | 38 ++ src/rng.cpp | 45 ++ src/rng.h | 22 + src/selection.h | 32 + src/simulation.cpp | 821 ++++++++++++++++++++++++ src/simulation.h | 150 +++++ src/slurp.c | 13 + src/solarsys.cpp | 444 +++++++++++++ src/solarsys.h | 42 ++ src/spheremesh.cpp | 328 ++++++++++ src/spheremesh.h | 51 ++ src/star.cpp | 166 +++++ src/star.h | 79 +++ src/starcat.c | 271 ++++++++ src/stardb.cpp | 354 +++++++++++ src/stardb.h | 65 ++ src/starname.cpp | 63 ++ src/starname.h | 32 + src/startest.cpp | 138 ++++ src/stellarclass.cpp | 93 +++ src/stellarclass.h | 115 ++++ src/texfont.cpp | 527 ++++++++++++++++ src/texfont.h | 82 +++ src/texmanager.cpp | 34 + src/texmanager.h | 32 + src/texture.cpp | 442 +++++++++++++ src/texture.h | 58 ++ src/tokenizer.cpp | 374 +++++++++++ src/tokenizer.h | 82 +++ src/trilist.cpp | 178 ++++++ src/trilist.h | 60 ++ src/univcoord.cpp | 108 ++++ src/univcoord.h | 56 ++ src/vecgl.h | 88 +++ src/vecmath.h | 972 +++++++++++++++++++++++++++++ src/visstars.cpp | 150 +++++ src/visstars.h | 53 ++ src/winmain.cpp | 1084 ++++++++++++++++++++++++++++++++ 92 files changed, 17972 insertions(+) create mode 100644 src/3dschunk.h create mode 100644 src/3dsmesh.cpp create mode 100644 src/3dsmesh.h create mode 100644 src/3dsmodel.cpp create mode 100644 src/3dsmodel.h create mode 100644 src/3dsread.cpp create mode 100644 src/3dsread.h create mode 100644 src/Ijl.h create mode 100644 src/aabox.h create mode 100644 src/astro.cpp create mode 100644 src/astro.h create mode 100644 src/basictypes.h create mode 100644 src/bigfix.cpp create mode 100644 src/bigfix.h create mode 100644 src/body.cpp create mode 100644 src/body.h create mode 100644 src/celestia.h create mode 100644 src/color.cpp create mode 100644 src/color.h create mode 100644 src/config.cpp create mode 100644 src/config.h create mode 100644 src/console.cpp create mode 100644 src/console.h create mode 100644 src/constellation.cpp create mode 100644 src/constellation.h create mode 100644 src/debug.cpp create mode 100644 src/dispmap.cpp create mode 100644 src/dispmap.h create mode 100644 src/filetype.cpp create mode 100644 src/filetype.h create mode 100644 src/gl.h create mode 100644 src/glext.cpp create mode 100644 src/glext.h create mode 100644 src/gui.cpp create mode 100644 src/gui.h create mode 100644 src/mathlib.h create mode 100644 src/mesh.h create mode 100644 src/meshmanager.cpp create mode 100644 src/meshmanager.h create mode 100644 src/observer.cpp create mode 100644 src/observer.h create mode 100644 src/orbit.cpp create mode 100644 src/orbit.h create mode 100644 src/packdb.cpp create mode 100644 src/packnames.cpp create mode 100644 src/parser.cpp create mode 100644 src/parser.h create mode 100644 src/perlin.cpp create mode 100644 src/perlin.h create mode 100644 src/quaternion.h create mode 100644 src/readstars.cpp create mode 100644 src/render.cpp create mode 100644 src/render.h create mode 100644 src/resmanager.cpp create mode 100644 src/resmanager.h create mode 100644 src/rng.cpp create mode 100644 src/rng.h create mode 100644 src/selection.h create mode 100644 src/simulation.cpp create mode 100644 src/simulation.h create mode 100644 src/slurp.c create mode 100644 src/solarsys.cpp create mode 100644 src/solarsys.h create mode 100644 src/spheremesh.cpp create mode 100644 src/spheremesh.h create mode 100644 src/star.cpp create mode 100644 src/star.h create mode 100644 src/starcat.c create mode 100644 src/stardb.cpp create mode 100644 src/stardb.h create mode 100644 src/starname.cpp create mode 100644 src/starname.h create mode 100644 src/startest.cpp create mode 100644 src/stellarclass.cpp create mode 100644 src/stellarclass.h create mode 100644 src/texfont.cpp create mode 100644 src/texfont.h create mode 100644 src/texmanager.cpp create mode 100644 src/texmanager.h create mode 100644 src/texture.cpp create mode 100644 src/texture.h create mode 100644 src/tokenizer.cpp create mode 100644 src/tokenizer.h create mode 100644 src/trilist.cpp create mode 100644 src/trilist.h create mode 100644 src/univcoord.cpp create mode 100644 src/univcoord.h create mode 100644 src/vecgl.h create mode 100644 src/vecmath.h create mode 100644 src/visstars.cpp create mode 100644 src/visstars.h create mode 100644 src/winmain.cpp diff --git a/src/3dschunk.h b/src/3dschunk.h new file mode 100644 index 00000000..9fdc24cb --- /dev/null +++ b/src/3dschunk.h @@ -0,0 +1,58 @@ +// 3dschunk.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _3DSCHUNK_H_ +#define _3DSCHUNK_H_ + +enum M3DChunkType +{ + M3DCHUNK_NULL = 0x0000, + M3DCHUNK_VERSION = 0x0002, + M3DCHUNK_COLOR_FLOAT = 0x0010, + M3DCHUNK_COLOR_24 = 0x0011, + M3DCHUNK_LIN_COLOR_F = 0x0013, + M3DCHUNK_INT_PERCENTAGE = 0x0030, + M3DCHUNK_FLOAT_PERCENTAGE = 0x0031, + M3DCHUNK_MASTER_SCALE = 0x0100, + + M3DCHUNK_BACKGROUND_COLOR = 0x1200, + + M3DCHUNK_MESHDATA = 0x3d3d, + M3DCHUNK_MESH_VERSION = 0x3d3e, + + M3DCHUNK_NAMED_OBJECT = 0x4000, + M3DCHUNK_TRIANGLE_MESH = 0x4100, + M3DCHUNK_POINT_ARRAY = 0x4110, + M3DCHUNK_POINT_FLAG_ARRAY = 0x4111, + M3DCHUNK_FACE_ARRAY = 0x4120, + M3DCHUNK_MESH_MATERIAL_GROUP = 0x4130, + M3DCHUNK_MESH_TEXTURE_COORDS = 0x4140, + M3DCHUNK_MESH_SMOOTH_GROUP = 0x4150, + M3DCHUNK_MESH_MATRIX = 0x4160, + M3DCHUNK_MAGIC = 0x4d4d, + + M3DCHUNK_MATERIAL_NAME = 0xa000, + M3DCHUNK_MATERIAL_AMBIENT = 0xa010, + M3DCHUNK_MATERIAL_DIFFUSE = 0xa020, + M3DCHUNK_MATERIAL_SPECULAR = 0xa030, + M3DCHUNK_MATERIAL_SHININESS = 0xa040, + M3DCHUNK_MATERIAL_SHIN2PCT = 0xa041, + M3DCHUNK_MATERIAL_TRANSPARENCY = 0xa050, + M3DCHUNK_MATERIAL_XPFALL = 0xa052, + M3DCHUNK_MATERIAL_REFBLUR = 0xa053, + M3DCHUNK_MATERIAL_SELF_ILLUM = 0xa084, + M3DCHUNK_MATERIAL_WIRESIZE = 0xa087, + M3DCHUNK_MATERIAL_XPFALLIN = 0xa08a, + M3DCHUNK_MATERIAL_SHADING = 0xa100, + M3DCHUNK_MATERIAL_ENTRY = 0xafff, + + M3DCHUNK_KFDATA = 0xb000, +}; + +#endif // _3DSCHUNK_H_ diff --git a/src/3dsmesh.cpp b/src/3dsmesh.cpp new file mode 100644 index 00000000..7204aa44 --- /dev/null +++ b/src/3dsmesh.cpp @@ -0,0 +1,245 @@ +// 3dsmesh.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 "gl.h" +#include "3dsmesh.h" + +using namespace std; + + +static TriangleList* convertTriangleMesh(M3DTriangleMesh& mesh, + const M3DScene& scene); + +Mesh3DS::Mesh3DS(const M3DScene& scene) +{ + for (int i = 0; i < scene.getModelCount(); i++) + { + M3DModel* model = scene.getModel(i); + if (model != NULL) + { + for (int j = 0; j < model->getTriMeshCount(); j++) + { + M3DTriangleMesh* mesh = model->getTriMesh(j); + if (mesh != NULL) + { + triLists.insert(triLists.end(), + convertTriangleMesh(*mesh, scene)); + } + } + } + } +} + + +Mesh3DS::~Mesh3DS() +{ + for (TriListVec::iterator i = triLists.begin(); i != triLists.end(); i++) + if (*i != NULL) + delete *i; +} + + +void Mesh3DS::render() +{ + for (TriListVec::iterator i = triLists.begin(); i != triLists.end(); i++) + (*i)->render(); +} + + +void Mesh3DS::normalize() +{ + AxisAlignedBox bbox; + + for (TriListVec::iterator i = triLists.begin(); i != triLists.end(); i++) + bbox.include((*i)->getBoundingBox()); + + Point3f center = bbox.getCenter(); + Vec3f extents = bbox.getExtents(); + float maxExtent = extents.x; + if (extents.y > maxExtent) + maxExtent = extents.y; + if (extents.z > maxExtent) + maxExtent = extents.z; + + printf("Normalize: %f\n", maxExtent); + + for (i = triLists.begin(); i != triLists.end(); i++) + (*i)->transform(Point3f(0, 0, 0) - center, 1.0f / maxExtent); +} + + +static TriangleList* convertTriangleMesh(M3DTriangleMesh& mesh, + const M3DScene& scene) +{ + TriangleList* tl = new TriangleList(); + int nFaces = mesh.getFaceCount(); + int nVertices = mesh.getVertexCount(); + bool smooth = (mesh.getSmoothingGroupCount() == nFaces); + int i; + + Vec3f* faceNormals = new Vec3f[nFaces]; + Vec3f* vertexNormals = new Vec3f[nFaces * 3]; + int* faceCounts = new int[nVertices]; + int** vertexFaces = new int*[nVertices]; + + for (i = 0; i < nVertices; i++) + { + faceCounts[i] = 0; + vertexFaces[i] = NULL; + } + + // generate face normals + for (i = 0; i < nFaces; i++) + { + uint16 v0, v1, v2; + mesh.getFace(i, v0, v1, v2); + + faceCounts[v0]++; + faceCounts[v1]++; + faceCounts[v2]++; + + Point3f p0 = mesh.getVertex(v0); + Point3f p1 = mesh.getVertex(v1); + Point3f p2 = mesh.getVertex(v2); + faceNormals[i] = cross(p1 - p0, p2 - p1); + faceNormals[i].normalize(); + } + + if (!smooth && 0) + { + for (i = 0; i < nFaces; i++) + { + vertexNormals[i * 3] = faceNormals[i]; + vertexNormals[i * 3 + 1] = faceNormals[i]; + vertexNormals[i * 3 + 2] = faceNormals[i]; + } + } + else + { + // allocate space for vertex face indices + for (i = 0; i < nVertices; i++) + { + vertexFaces[i] = new int[faceCounts[i] + 1]; + vertexFaces[i][0] = faceCounts[i]; + } + + for (i = 0; i < nFaces; i++) + { + uint16 v0, v1, v2; + mesh.getFace(i, v0, v1, v2); + vertexFaces[v0][faceCounts[v0]--] = i; + vertexFaces[v1][faceCounts[v1]--] = i; + vertexFaces[v2][faceCounts[v2]--] = i; + } + +#if 0 + for (i = 0; i < nVertices; i++) + { + printf("%d: ", i); + for (int j = 1; j < vertexFaces[i][0]; j++) + { + printf("%d ", vertexFaces[i][j]); + } + printf("\n"); + } +#endif + + // average face normals to compute the vertex normals + for (i = 0; i < nFaces; i++) + { + uint16 v0, v1, v2; + mesh.getFace(i, v0, v1, v2); + uint32 smoothingGroups = mesh.getSmoothingGroups(i); + + int j; + Vec3f v = Vec3f(0, 0, 0); + for (j = 1; j <= vertexFaces[v0][0]; j++) + { + int k = vertexFaces[v0][j]; + // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0) + if (faceNormals[i] * faceNormals[k] > 0.5f) + v += faceNormals[k]; + } + v.normalize(); + vertexNormals[i * 3] = v; + + v = Vec3f(0, 0, 0); + for (j = 1; j <= vertexFaces[v1][0]; j++) + { + int k = vertexFaces[v1][j]; + // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0) + if (faceNormals[i] * faceNormals[k] > 0.5f) + v += faceNormals[k]; + } + v.normalize(); + vertexNormals[i * 3 + 1] = v; + + v = Vec3f(0, 0, 0); + for (j = 1; j <= vertexFaces[v2][0]; j++) + { + int k = vertexFaces[v2][j]; + // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0) + if (faceNormals[i] * faceNormals[k] > 0.5f) + v += faceNormals[k]; + } + v.normalize(); + vertexNormals[i * 3 + 2] = v; + } + } + + // build the triangle list + for (i = 0; i < nFaces; i++) + { + uint16 v0, v1, v2; + mesh.getFace(i, v0, v1, v2); + + tl->addTriangle(mesh.getVertex(v0), vertexNormals[i * 3], + mesh.getVertex(v1), vertexNormals[i * 3 + 1], + mesh.getVertex(v2), vertexNormals[i * 3 + 2]); + } + + // set the color + { + string materialName = mesh.getMaterialName(); + if (materialName.length() > 0) + { + tl->setColorMode(1); + int nMaterials = scene.getMaterialCount(); + for (i = 0; i < nMaterials; i++) + { + M3DMaterial* material = scene.getMaterial(i); + if (materialName == material->getName()) + { + M3DColor diffuse = material->getDiffuseColor(); + tl->setColor(Vec3f(diffuse.red, diffuse.green, diffuse.blue)); + break; + } + } + } + } + + // clean up + if (faceNormals != NULL) + delete[] faceNormals; + if (vertexNormals != NULL) + delete[] vertexNormals; + if (faceCounts != NULL) + delete[] faceCounts; + if (vertexFaces != NULL) + { + for (i = 0; i < nVertices; i++) + { + if (vertexFaces[i] != NULL) + delete[] vertexFaces[i]; + } + delete[] vertexFaces; + } + + return tl; +} diff --git a/src/3dsmesh.h b/src/3dsmesh.h new file mode 100644 index 00000000..3e52f62e --- /dev/null +++ b/src/3dsmesh.h @@ -0,0 +1,33 @@ +// 3dsmesh.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _3DSMESH_H_ +#define _3DSMESH_H_ + +#include +#include "mesh.h" +#include "trilist.h" +#include "3dsmodel.h" + + +class Mesh3DS : public Mesh +{ + public: + Mesh3DS(const M3DScene& scene); + ~Mesh3DS(); + + void render(); + void normalize(); + + private: + typedef std::vector TriListVec; + TriListVec triLists; +}; + +#endif // _3DSMESH_H_ diff --git a/src/3dsmodel.cpp b/src/3dsmodel.cpp new file mode 100644 index 00000000..a9c94980 --- /dev/null +++ b/src/3dsmodel.cpp @@ -0,0 +1,257 @@ +// 3dsmodel.cpp +// +// Copyright (C) 2000, Chris Laurel +// +// 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 "3dsmodel.h" + +using namespace std; + + +M3DColor::M3DColor() : + red(0), green(0), blue(0) +{ +} + +M3DColor::M3DColor(float _red, float _green, float _blue) : + red(_red), green(_green), blue(_blue) +{ +} + + +M3DMaterial::M3DMaterial() : + ambient(0, 0, 0), + diffuse(0, 0, 0), + specular(0, 0, 0) +{ +} + +string M3DMaterial::getName() const +{ + return name; +} + +void M3DMaterial::setName(string _name) +{ + name = _name; +} + +M3DColor M3DMaterial::getDiffuseColor() const +{ + return diffuse; +} + +void M3DMaterial::setDiffuseColor(M3DColor color) +{ + diffuse = color; +} + +M3DColor M3DMaterial::getAmbientColor() const +{ + return ambient; +} + +void M3DMaterial::setAmbientColor(M3DColor color) +{ + ambient = color; +} + +M3DColor M3DMaterial::getSpecularColor() const +{ + return specular; +} + +void M3DMaterial::setSpecularColor(M3DColor color) +{ + specular = color; +} + + +M3DTriangleMesh::M3DTriangleMesh() +{ + matrix = Mat4f::identity(); +} + +M3DTriangleMesh::~M3DTriangleMesh() +{ +} + +Mat4f M3DTriangleMesh::getMatrix() const +{ + return matrix; +} + +void M3DTriangleMesh::setMatrix(const Mat4f& m) +{ + matrix = m; +} + +Point3f M3DTriangleMesh::getVertex(uint16 n) const +{ + return points[n]; +} + +uint16 M3DTriangleMesh::getVertexCount() const +{ + return (uint16) (points.size()); +} + +void M3DTriangleMesh::addVertex(Point3f p) +{ + points.insert(points.end(), p); +} + +void M3DTriangleMesh::getFace(uint16 n, uint16& v0, uint16& v1, uint16& v2) const +{ + int m = (int) n * 3; + v0 = faces[m]; + v1 = faces[m + 1]; + v2 = faces[m + 2]; +} + +uint16 M3DTriangleMesh::getFaceCount() const +{ + return (uint16) (faces.size() / 3); +} + +void M3DTriangleMesh::addFace(uint16 v0, uint16 v1, uint16 v2) +{ + faces.insert(faces.end(), v0); + faces.insert(faces.end(), v1); + faces.insert(faces.end(), v2); +} + +uint32 M3DTriangleMesh::getSmoothingGroups(uint16 face) const +{ + if (face < smoothingGroups.size()) + return smoothingGroups[face]; + else + return 0; +} + +void M3DTriangleMesh::addSmoothingGroups(uint32 smGroups) +{ + smoothingGroups.insert(smoothingGroups.end(), smGroups); +} + +uint16 M3DTriangleMesh::getSmoothingGroupCount() const +{ + return (uint16) (smoothingGroups.size()); +} + +string M3DTriangleMesh::getMaterialName() const +{ + return materialName; +} + +void M3DTriangleMesh::setMaterialName(string _materialName) +{ + materialName = _materialName; +} + + + +M3DModel::M3DModel() +{ +} + +M3DModel::~M3DModel() +{ + for (int i = 0; i < triMeshes.size(); i++) + if (triMeshes[i] != NULL) + delete triMeshes[i]; +} + +M3DTriangleMesh* M3DModel::getTriMesh(uint32 n) +{ + if (n < triMeshes.size()) + return triMeshes[n]; + else + return NULL; +} + +uint32 M3DModel::getTriMeshCount() +{ + return triMeshes.size(); +} + +void M3DModel::addTriMesh(M3DTriangleMesh* triMesh) +{ + triMeshes.insert(triMeshes.end(), triMesh); +} + +void M3DModel::setName(const string _name) +{ + name = _name; +} + +const string M3DModel::getName() const +{ + return name; +} + + +M3DScene::M3DScene() +{ +} + +M3DScene::~M3DScene() +{ + int i; + for (i = 0; i < models.size(); i++) + if (models[i] != NULL) + delete models[i]; + for (i = 0; i < materials.size(); i++) + if (materials[i] != NULL) + delete materials[i]; +} + +M3DModel* M3DScene::getModel(uint32 n) const +{ + if (n < models.size()) + return models[n]; + else + return NULL; +} + +uint32 M3DScene::getModelCount() const +{ + return models.size(); +} + +void M3DScene::addModel(M3DModel* model) +{ + models.insert(models.end(), model); +} + +M3DMaterial* M3DScene::getMaterial(uint32 n) const +{ + if (n < materials.size()) + return materials[n]; + else + return NULL; +} + +uint32 M3DScene::getMaterialCount() const +{ + return materials.size(); +} + +void M3DScene::addMaterial(M3DMaterial* material) +{ + materials.insert(materials.end(), material); +} + +M3DColor M3DScene::getBackgroundColor() const +{ + return backgroundColor; +} + +void M3DScene::setBackgroundColor(M3DColor color) +{ + backgroundColor = color; +} diff --git a/src/3dsmodel.h b/src/3dsmodel.h new file mode 100644 index 00000000..246e4ff7 --- /dev/null +++ b/src/3dsmodel.h @@ -0,0 +1,126 @@ +// 3dsmodel.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _3DSMODEL_H_ +#define _3DSMODEL_H_ + +#include +#include +#include "basictypes.h" +#include "vecmath.h" + + +class M3DColor +{ + public: + M3DColor(); + M3DColor(float, float, float); + + public: + float red, green, blue; +}; + + +class M3DMaterial +{ + public: + M3DMaterial(); + + std::string getName() const; + void setName(std::string); + M3DColor getAmbientColor() const; + void setAmbientColor(M3DColor); + M3DColor getDiffuseColor() const; + void setDiffuseColor(M3DColor); + M3DColor getSpecularColor() const; + void setSpecularColor(M3DColor); + + private: + std::string name; + M3DColor ambient; + M3DColor diffuse; + M3DColor specular; +}; + + +class M3DTriangleMesh +{ + public: + M3DTriangleMesh(); + ~M3DTriangleMesh(); + + Mat4f getMatrix() const; + void setMatrix(const Mat4f&); + + Point3f getVertex(uint16) const; + uint16 getVertexCount() const; + void addVertex(Point3f); + + void getFace(uint16, uint16&, uint16&, uint16&) const; + uint16 getFaceCount() const; + void addFace(uint16, uint16, uint16); + + void addSmoothingGroups(uint32); + uint32 getSmoothingGroups(uint16) const; + uint16 getSmoothingGroupCount() const; + + std::string getMaterialName() const; + void setMaterialName(std::string); + + private: + std::vector points; + std::vector faces; + std::vector smoothingGroups; + Mat4f matrix; + std::string materialName; +}; + + +class M3DModel +{ + public: + M3DModel(); + ~M3DModel(); + + M3DTriangleMesh* getTriMesh(uint32); + uint32 getTriMeshCount(); + void addTriMesh(M3DTriangleMesh*); + void setName(const std::string); + const std::string getName() const; + + private: + std::string name; + std::vector triMeshes; +}; + + +class M3DScene +{ + public: + M3DScene(); + ~M3DScene(); + + M3DModel* getModel(uint32) const; + uint32 getModelCount() const; + void addModel(M3DModel*); + + M3DMaterial* getMaterial(uint32) const; + uint32 getMaterialCount() const; + void addMaterial(M3DMaterial*); + + M3DColor getBackgroundColor() const; + void setBackgroundColor(M3DColor); + + private: + std::vector models; + std::vector materials; + M3DColor backgroundColor; +}; + +#endif // _3DSMODEL_H_ diff --git a/src/3dsread.cpp b/src/3dsread.cpp new file mode 100644 index 00000000..d91eacca --- /dev/null +++ b/src/3dsread.cpp @@ -0,0 +1,645 @@ +// 3dsread.cpp +// +// Copyright (C) 2000, Chris Laurel +// +// 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 + +#include "vecmath.h" +#include "3dschunk.h" +#include "3dsmodel.h" +#include "3dsread.h" + + +using namespace std; + +typedef bool (*ProcessChunkFunc)(ifstream& in, + unsigned short chunkType, + int contentSize, + void*); + +static int read3DSChunk(ifstream& in, + ProcessChunkFunc chunkFunc, + void* obj); + +// For pretty printing debug info +static int logIndent = 0; + + +static int readInt(ifstream& in) +{ + unsigned char b[4]; + in.read(reinterpret_cast(b), 4); + return ((int) b[3] << 24) + ((int) b[2] << 16) + + ((int) b[1] << 8) + (int) b[0]; +} + +static short readShort(ifstream& in) +{ + unsigned char b[2]; + in.read(reinterpret_cast(b), 2); + return ((short) b[1] << 8) + (short) b[0]; +} + +static unsigned short readUshort(ifstream& in) +{ + unsigned char b[2]; + in.read(reinterpret_cast(b), 2); + return ((unsigned short) b[1] << 8) + (unsigned short) b[0]; +} + +static char readChar(ifstream& in) +{ + char c; + in.read(&c, 1); + return c; +} + + +static int readString(ifstream& in, char* s, int maxLength) +{ + for (int count = 0; count < maxLength; count++) + { + in.read(s + count, 1); + if (s[count] == '\0') + break; + } + + return count; +} + +static string readString(ifstream& in) +{ + char s[1024]; + int maxLength = sizeof(s); + + for (int count = 0; count < maxLength; count++) + { + in.read(s + count, 1); + if (s[count] == '\0') + break; + } + + return string(s); +} + + +static float readFloat(ifstream& in) +{ + int i = readInt(in); + return *((float*) &i); +} + + +static void skipBytes(ifstream& in, int count) +{ + char c; + while (count-- > 0) + in.get(c); +} + + +void indent() +{ + for (int i = 0; i < logIndent; i++) + cout << " "; +} + +void logChunk(uint16 chunkType, int chunkSize) +{ + char* name = NULL; + + switch (chunkType) + { + case M3DCHUNK_NULL: + name = "M3DCHUNK_NULL"; break; + case M3DCHUNK_VERSION: + name = "M3DCHUNK_VERSION"; break; + case M3DCHUNK_COLOR_FLOAT: + name = "M3DCHUNK_COLOR_FLOAT"; break; + case M3DCHUNK_COLOR_24: + name = "M3DCHUNK_COLOR_24"; break; + case M3DCHUNK_LIN_COLOR_F: + name = "M3DCHUNK_LIN_COLOR_F"; break; + case M3DCHUNK_INT_PERCENTAGE: + name = "M3DCHUNK_INT_PERCENTAGE"; break; + case M3DCHUNK_FLOAT_PERCENTAGE: + name = "M3DCHUNK_FLOAT_PERCENTAGE"; break; + case M3DCHUNK_MASTER_SCALE: + name = "M3DCHUNK_MASTER_SCALE"; break; + case M3DCHUNK_BACKGROUND_COLOR: + name = "M3DCHUNK_BACKGROUND_COLOR"; break; + case M3DCHUNK_MESHDATA: + name = "M3DCHUNK_MESHDATA"; break; + case M3DCHUNK_MESH_VERSION: + name = "M3DCHUNK_MESHVERSION"; break; + case M3DCHUNK_NAMED_OBJECT: + name = "M3DCHUNK_NAMED_OBJECT"; break; + case M3DCHUNK_TRIANGLE_MESH: + name = "M3DCHUNK_TRIANGLE_MESH"; break; + case M3DCHUNK_POINT_ARRAY: + name = "M3DCHUNK_POINT_ARRAY"; break; + case M3DCHUNK_POINT_FLAG_ARRAY: + name = "M3DCHUNK_POINT_FLAG_ARRAY"; break; + case M3DCHUNK_FACE_ARRAY: + name = "M3DCHUNK_FACE_ARRAY"; break; + case M3DCHUNK_MESH_MATERIAL_GROUP: + name = "M3DCHUNK_MESH_MATERIAL_GROUP"; break; + case M3DCHUNK_MESH_TEXTURE_COORDS: + name = "M3DCHUNK_MESH_TEXTURE_COORDS"; break; + case M3DCHUNK_MESH_SMOOTH_GROUP: + name = "M3DCHUNK_MESH_SMOOTH_GROUP"; break; + case M3DCHUNK_MESH_MATRIX: + name = "M3DCHUNK_MESH_MATRIX"; break; + case M3DCHUNK_MAGIC: + name = "M3DCHUNK_MAGIC"; break; + case M3DCHUNK_MATERIAL_NAME: + name = "M3DCHUNK_MATERIAL_NAME"; break; + case M3DCHUNK_MATERIAL_AMBIENT: + name = "M3DCHUNK_MATERIAL_AMBIENT"; break; + case M3DCHUNK_MATERIAL_DIFFUSE: + name = "M3DCHUNK_MATERIAL_DIFFUSE"; break; + case M3DCHUNK_MATERIAL_SPECULAR: + name = "M3DCHUNK_MATERIAL_SPECULAR"; break; + case M3DCHUNK_MATERIAL_SHININESS: + name = "M3DCHUNK_MATERIAL_SHININESS"; break; + case M3DCHUNK_MATERIAL_SHIN2PCT: + name = "M3DCHUNK_MATERIAL_SHIN2PCT"; break; + case M3DCHUNK_MATERIAL_TRANSPARENCY: + name = "M3DCHUNK_MATERIAL_TRANSPARENCY"; break; + case M3DCHUNK_MATERIAL_XPFALL: + name = "M3DCHUNK_MATERIAL_XPFALL"; break; + case M3DCHUNK_MATERIAL_REFBLUR: + name = "M3DCHUNK_MATERIAL_REFBLUR"; break; + case M3DCHUNK_MATERIAL_ENTRY: + name = "M3DCHUNK_MATERIAL_ENTRY"; break; + case M3DCHUNK_KFDATA: + name = "M3DCHUNK_KFDATA"; + default: + break; + } + + indent(); + + if (name == NULL) + { + cout << "Chunk ID " << setw(4) << hex << setfill('0') << chunkType; + cout << setw(0) << dec << ", size = " << chunkSize << '\n'; + } + else + { + cout << name << ", size = " << chunkSize << '\n'; + } + + cout.flush(); +} + + +int read3DSChunk(ifstream& in, + ProcessChunkFunc chunkFunc, + void* obj) +{ + unsigned short chunkType = readUshort(in); + int chunkSize = readInt(in); + int contentSize = chunkSize - 6; + + logChunk(chunkType, chunkSize); + bool chunkWasRead = chunkFunc(in, chunkType, contentSize, obj); + + if (!chunkWasRead) + { + skipBytes(in, contentSize); + } + + return chunkSize; +} + + +int read3DSChunks(ifstream& in, + int nBytes, + ProcessChunkFunc chunkFunc, + void* obj) +{ + int bytesRead = 0; + + logIndent++; + while (bytesRead < nBytes) + bytesRead += read3DSChunk(in, chunkFunc, obj); + logIndent--; + + if (bytesRead != nBytes) + cout << "Expected " << nBytes << " bytes but read " << bytesRead << '\n'; + return bytesRead; +} + + +M3DColor readColor(ifstream& in, int nBytes) +{ + unsigned char r = (unsigned char) readChar(in); + unsigned char g = (unsigned char) readChar(in); + unsigned char b = (unsigned char) readChar(in); + + return M3DColor((float) r / 255.0f, + (float) g / 255.0f, + (float) b / 255.0f); +} + + +M3DColor readFloatColor(ifstream& in, int nBytes) +{ + float r = readFloat(in); + float g = readFloat(in); + float b = readFloat(in); + + return M3DColor((float) r / 255.0f, + (float) g / 255.0f, + (float) b / 255.0f); +} + + +Mat4f readMeshMatrix(ifstream& in, int nBytes) +{ + float m00 = readFloat(in); + float m01 = readFloat(in); + float m02 = readFloat(in); + float m10 = readFloat(in); + float m11 = readFloat(in); + float m12 = readFloat(in); + float m20 = readFloat(in); + float m21 = readFloat(in); + float m22 = readFloat(in); + float m30 = readFloat(in); + float m31 = readFloat(in); + float m32 = readFloat(in); + + cout << m00 << " " << m01 << " " << m02 << '\n'; + cout << m10 << " " << m11 << " " << m12 << '\n'; + cout << m20 << " " << m21 << " " << m22 << '\n'; + cout << m30 << " " << m31 << " " << m32 << '\n'; + + return Mat4f(Vec4f(m00, m01, m02, 0), + Vec4f(m10, m11, m12, 0), + Vec4f(m20, m21, m22, 0), + Vec4f(m30, m31, m32, 1)); +} + + +bool stubProcessChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + return false; +} + + +void readPointArray(ifstream& in, M3DTriangleMesh* triMesh) +{ + uint16 nPoints = readUshort(in); + + for (int i = 0; i < (int) nPoints; i++) + { + float x = readFloat(in); + float y = readFloat(in); + float z = readFloat(in); + triMesh->addVertex(Point3f(x, y, z)); + } +} + + +bool processFaceArrayChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + M3DTriangleMesh* triMesh = (M3DTriangleMesh*) obj; + + if (chunkType == M3DCHUNK_MESH_MATERIAL_GROUP) + { + // For now, we just assume that there is only one material group + // per triangle mesh, and that the material applies to all faces in + // the mesh. + string materialName = readString(in); + uint16 nFaces = readUshort(in); + + for (uint16 i = 0; i < nFaces; i++) + { + readUshort(in); + } + + triMesh->setMaterialName(materialName); + + return true; + } + else if (chunkType == M3DCHUNK_MESH_SMOOTH_GROUP) + { + uint16 nFaces = triMesh->getFaceCount(); + + for (uint16 i = 0; i < nFaces; i++) + { + uint32 groups = (uint32) readInt(in); + // cout << setw(8) << hex << setfill('0') << groups << dec << setw(0) << '\n'; + triMesh->addSmoothingGroups(groups); + } + return true; + } + else + { + return false; + } +} + + +void readFaceArray(ifstream& in, M3DTriangleMesh* triMesh, int contentSize) +{ + uint16 nFaces = readUshort(in); + + for (int i = 0; i < (int) nFaces; i++) + { + uint16 v0 = readUshort(in); + uint16 v1 = readUshort(in); + uint16 v2 = readUshort(in); + uint16 flags = readUshort(in); + triMesh->addFace(v0, v1, v2); + } + + int bytesLeft = contentSize - (8 * nFaces + 2); + if (bytesLeft > 0) + { + read3DSChunks(in, + bytesLeft, + processFaceArrayChunk, + (void*) triMesh); + } +} + + +bool processTriMeshChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + M3DTriangleMesh* triMesh = (M3DTriangleMesh*) obj; + + if (chunkType == M3DCHUNK_POINT_ARRAY) + { + readPointArray(in, triMesh); + return true; + } + else if (chunkType == M3DCHUNK_FACE_ARRAY) + { + readFaceArray(in, triMesh, contentSize); + return true; + } + else if (chunkType == M3DCHUNK_MESH_MATRIX) + { + triMesh->setMatrix(readMeshMatrix(in, contentSize)); + return true; + } + else + { + return false; + } +} + + +bool processModelChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + M3DModel* model = (M3DModel*) obj; + + if (chunkType == M3DCHUNK_TRIANGLE_MESH) + { + M3DTriangleMesh* triMesh = new M3DTriangleMesh(); + read3DSChunks(in, contentSize, processTriMeshChunk, (void*) triMesh); + model->addTriMesh(triMesh); + return true; + } + else + { + return false; + } +} + + +bool processColorChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + M3DColor* color = (M3DColor*) obj; + + if (chunkType == M3DCHUNK_COLOR_24) + { + *color = readColor(in, contentSize); + return true; + } + else if (chunkType == (M3DCHUNK_COLOR_FLOAT)) + { + *color = readFloatColor(in, contentSize); + return true; + } + else + { + return false; + } +} + + +bool processMaterialChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + M3DMaterial* material = (M3DMaterial*) obj; + + if (chunkType == M3DCHUNK_MATERIAL_NAME) + { + string name = readString(in); + material->setName(name); + return true; + } + else if (chunkType == M3DCHUNK_MATERIAL_AMBIENT) + { + M3DColor ambient; + read3DSChunks(in, contentSize, processColorChunk, (void*) &ambient); + material->setAmbientColor(ambient); + return true; + } + else if (chunkType == M3DCHUNK_MATERIAL_DIFFUSE) + { + M3DColor diffuse; + read3DSChunks(in, contentSize, processColorChunk, (void*) &diffuse); + material->setDiffuseColor(diffuse); + return true; + } + else if (chunkType == M3DCHUNK_MATERIAL_SPECULAR) + { + M3DColor specular; + read3DSChunks(in, contentSize, processColorChunk, (void*) &specular); + material->setSpecularColor(specular); + return true; + } + else + { + return false; + } +} + + +bool processSceneChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + M3DScene* scene = (M3DScene*) obj; + + if (chunkType == M3DCHUNK_NAMED_OBJECT) + { + string name = readString(in); + + M3DModel* model = new M3DModel(); + model->setName(name); + indent(); cout << " [" << name << "]\n"; + read3DSChunks(in, + contentSize - (name.length() + 1), + processModelChunk, + (void*) model); + scene->addModel(model); + + return true; + } + else if (chunkType == M3DCHUNK_MATERIAL_ENTRY) + { + M3DMaterial* material = new M3DMaterial(); + read3DSChunks(in, + contentSize, + processMaterialChunk, + (void*) material); + scene->addMaterial(material); + + return true; + } + else if (chunkType == M3DCHUNK_BACKGROUND_COLOR) + { + M3DColor color; + read3DSChunks(in, contentSize, processColorChunk, (void*) &color); + scene->setBackgroundColor(color); + return true; + } + else + { + return false; + } +} + + +bool processTopLevelChunk(ifstream& in, + unsigned short chunkType, + int contentSize, + void* obj) +{ + M3DScene* scene = (M3DScene*) obj; + + if (chunkType == M3DCHUNK_MESHDATA) + { + read3DSChunks(in, contentSize, processSceneChunk, (void*) scene); + return true; + } + else + { + return false; + } +} + + +M3DScene* Read3DSFile(ifstream& in) +{ + unsigned short chunkType = readUshort(in); + if (chunkType != M3DCHUNK_MAGIC) + { + cerr << "Wrong magic number in header\n"; + return NULL; + } + + int chunkSize = readInt(in); + if (in.bad()) + { + cerr << "Error reading 3DS file.\n"; + return NULL; + } + + cout << "3DS file, " << chunkSize << " bytes\n"; + M3DScene* scene = new M3DScene(); + int contentSize = chunkSize - 6; + + read3DSChunks(in, contentSize, processTopLevelChunk, (void*) scene); + + return scene; +} + + +M3DScene* Read3DSFile(string filename) +{ + ifstream in(filename.c_str(), ios::in | ios::binary); + if (!in.good()) + { + cerr << "Error opening " << filename << '\n'; + return NULL; + } + else + { + M3DScene* scene = Read3DSFile(in); + in.close(); + return scene; + } +} + + +M3DScene* Read3DSFile(char* filename) +{ + ifstream in(filename, ios::in | ios::binary); + if (!in.good()) + { + cerr << "Error opening " << filename << '\n'; + return NULL; + } + else + { + M3DScene* scene = Read3DSFile(in); + in.close(); + return scene; + } +} + + +#if 0 +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "Usage: 3dsread \n"; + exit(1); + } + + ifstream in(argv[1], ios::in | ios::binary); + if (!in.good()) + { + cerr << "Error opening " << argv[1] << '\n'; + exit(1); + } + else + { + read3DSFile(in); + in.close(); + } + + return 0; +} +#endif diff --git a/src/3dsread.h b/src/3dsread.h new file mode 100644 index 00000000..414b3454 --- /dev/null +++ b/src/3dsread.h @@ -0,0 +1,22 @@ +// 3dsread.h +// +// Copyright (C) 2000, Chris Laurel +// +// 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. + +#ifndef _3DSREAD_H_ +#define _3DSREAD_H_ + +#include +#include +#include +#include "3dsmodel.h" + +M3DScene* Read3DSFile(std::ifstream& in); +M3DScene* Read3DSFile(std::string filename); +M3DScene* Read3DSFile(char* filename); + +#endif // _3DSREAD_H_ diff --git a/src/Ijl.h b/src/Ijl.h new file mode 100644 index 00000000..7a0c7823 --- /dev/null +++ b/src/Ijl.h @@ -0,0 +1,1341 @@ +/*M* +// +// +// INTEL CORPORATION PROPRIETARY INFORMATION +// This software is supplied under the terms of a license agreement or +// nondisclosure agreement with Intel Corporation and may not be copied +// or disclosed except in accordance with the terms of that agreement. +// Copyright (c) 1998 Intel Corporation. All Rights Reserved. +// +// +// File: +// ijl.h +// +// Purpose: +// IJL Common Header File +// This file contains: definitions for data types, data +// structures, error codes, and function prototypes used +// in the Intel(R) JPEG Library (IJL). +// +// Version: +// 1.0 beta 1 +// +*M*/ + +#ifndef __IJL_H__ +#define __IJL_H__ + + +#if defined( __cplusplus ) +extern "C" { +#endif + + +#ifndef IJL_ALL_WARNINGS + +#if _MSC_VER >= 1000 + +/* nonstandard extension used : nameless struct/union */ +#pragma warning(disable : 4201) +/* nonstandard extension used : bit field types other than int */ +#pragma warning(disable : 4214) +/* unreferenced inline function has been removed */ +#pragma warning(disable : 4514) +/* named type definition in parentheses */ +#pragma warning(disable : 4115) + +#endif /* _MSC_VER >= 1000 */ + +#endif /* IJL_ALL_WARNINGS */ + + + + +#define _X86_ +#define WIN32_LEAN_AND_MEAN +#include + + +#ifdef _MSC_VER +# pragma pack (8) +#endif + + +/* ///////////////////////////////////////////////////////////////////////// +// Macros/Constants */ + +#define IJL_NONE 0 +#define IJL_OTHER 255 +#define JBUFSIZE 4096 // Size of file I/O buffer (4K). + + +#ifndef INT64 +#define INT64 __int64 +#endif +#ifndef UINT64 +#define UINT64 unsigned INT64 +#endif + + +#if defined( _IJL_STDIMP_ ) + +# define IJLAPI(type,name,arg) \ + extern type WINAPI name arg + +#else + +# if !defined( _IJL_API_ ) + +# define IJLAPI(type,name,arg) \ + extern __declspec(dllimport) type WINAPI name arg + +# else + +# define IJLAPI(type,name,arg) \ + extern __declspec(dllexport) type WINAPI name arg + +# endif // _IJL_API_ + +#endif //_IJL_STDIMP_ + + + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: IJLibVersion +// +// Purpose: Stores library version info. +// +// Context: +// +// Example: +// major - 1 +// minor - 0 +// build - 1 +// Name - "ijl10.dll" +// Version - "1.0.1 Beta1" +// InternalVersion - "1.0.1.1" +// BuildDate - "Sep 22 1998" +// CallConv - "DLL" +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _IJLibVersion +{ + int major; + int minor; + int build; + LPCTSTR Name; + LPCTSTR Version; + LPCTSTR InternalVersion; + LPCTSTR BuildDate; + LPCTSTR CallConv; + +} IJLibVersion; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: IJLIOTYPE +// +// Purpose: Possible types of data read/write/other operations to be +// performed by the functions IJL_Read and IJL_Write. +// +// See the Developer's Guide for details on appropriate usage. +// +// Fields: +// +// IJL_JFILE_XXXXXXX Indicates JPEG data in a stdio file. +// +// IJL_JBUFF_XXXXXXX Indicates JPEG data in an addressable buffer. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ + IJL_SETUP = -1, + + + // Read JPEG parameters (i.e., height, width, channels, + // sampling, etc.) from a JPEG bit stream. + IJL_JFILE_READPARAMS = 0, + IJL_JBUFF_READPARAMS = 1, + + // Read a JPEG Interchange Format image. + IJL_JFILE_READWHOLEIMAGE = 2, + IJL_JBUFF_READWHOLEIMAGE = 3, + + // Read JPEG tables from a JPEG Abbreviated Format bit stream. + IJL_JFILE_READHEADER = 4, + IJL_JBUFF_READHEADER = 5, + + // Read image info from a JPEG Abbreviated Format bit stream. + IJL_JFILE_READENTROPY = 6, + IJL_JBUFF_READENTROPY = 7, + + // Write an entire JFIF bit stream. + IJL_JFILE_WRITEWHOLEIMAGE = 8, + IJL_JBUFF_WRITEWHOLEIMAGE = 9, + + // Write a JPEG Abbreviated Format bit stream. + IJL_JFILE_WRITEHEADER = 10, + IJL_JBUFF_WRITEHEADER = 11, + + // Write image info to a JPEG Abbreviated Format bit stream. + IJL_JFILE_WRITEENTROPY = 12, + IJL_JBUFF_WRITEENTROPY = 13, + + + // Scaled Decoding Options: + + // Reads a JPEG image scaled to 1/2 size. + IJL_JFILE_READONEHALF = 14, + IJL_JBUFF_READONEHALF = 15, + + // Reads a JPEG image scaled to 1/4 size. + IJL_JFILE_READONEQUARTER = 16, + IJL_JBUFF_READONEQUARTER = 17, + + // Reads a JPEG image scaled to 1/8 size. + IJL_JFILE_READONEEIGHTH = 18, + IJL_JBUFF_READONEEIGHTH = 19, + + // Reads an embedded thumbnail from a JFIF bit stream. + IJL_JFILE_READTHUMBNAIL = 20, + IJL_JBUFF_READTHUMBNAIL = 21 + +} IJLIOTYPE; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: IJL_COLOR +// +// Purpose: Possible color space formats. +// +// Note these formats do *not* necessarily denote +// the number of channels in the color space. +// There exists separate "channel" fields in the +// JPEG_CORE_PROPERTIES data structure specifically +// for indicating the number of channels in the +// JPEG and/or DIB color spaces. +// +// See the Developer's Guide for details on appropriate usage. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ + IJL_RGB = 1, // Red-Green-Blue color space. + IJL_BGR = 2, // Reversed channel ordering from IJL_RGB. + IJL_YCBCR = 3, // Luminance-Chrominance color space as defined + // by CCIR Recommendation 601. + IJL_G = 4, // Grayscale color space. + IJL_RGBA_FPX = 5, // FlashPix RGB 4 channel color space that + // has pre-multiplied opacity. + IJL_YCBCRA_FPX = 6 // FlashPix YCbCr 4 channel color space that + // has pre-multiplied opacity. + +// IJL_OTHER // Some other color space not defined by the IJL. + // (This means no color space conversion will + // be done by the IJL.) + +} IJL_COLOR; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: IJL_JPGSUBSAMPLING +// +// Purpose: Possible subsampling formats used in the JPEG. +// +// See the Developer's Guide for details on appropriate usage. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ + IJL_411 = 1, // Valid on a JPEG w/ 3 channels. + IJL_422 = 2, // Valid on a JPEG w/ 3 channels. + + IJL_4114 = 3, // Valid on a JPEG w/ 4 channels. + IJL_4224 = 4, // Valid on a JPEG w/ 4 channels. + +// IJL_NONE = Corresponds to "No Subsampling". +// Valid on a JPEG w/ any number of channels. + +// IJL_OTHER = Valid entry, but only used internally to the IJL. + +} IJL_JPGSUBSAMPLING; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: IJL_DIBSUBSAMPLING +// +// Purpose: Possible subsampling formats used in the DIB. +// +// See the Developer's Guide for details on appropriate usage. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ +// IJL_NONE = Corresponds to "No Subsampling". + +} IJL_DIBSUBSAMPLING; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: HUFFMAN_TABLE +// +// Purpose: Stores Huffman table information in a fast-to-use format. +// +// Context: Used by Huffman encoder/decoder to access Huffman table +// data. Raw Huffman tables are formatted to fit this +// structure prior to use. +// +// Fields: +// huff_class 0 == DC Huffman or lossless table, 1 == AC table. +// ident Huffman table identifier, 0-3 valid (Extended Baseline). +// huffelem Huffman elements for codes <= 8 bits long; +// contains both zero run-length and symbol length in bits. +// huffval Huffman values for codes 9-16 bits in length. +// mincode Smallest Huffman code of length n. +// maxcode Largest Huffman code of length n. +// valptr Starting index into huffval[] for symbols of length k. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _HUFFMAN_TABLE +{ + int huff_class; + int ident; + unsigned int huffelem[256]; + unsigned short huffval[256]; + unsigned short mincode[17]; + unsigned short maxcode[18]; + unsigned short valptr[17]; + +} HUFFMAN_TABLE; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: JPEGHuffTable +// +// Purpose: Stores pointers to JPEG-binary spec compliant +// Huffman table information. +// +// Context: Used by interface and table methods to specify encoder +// tables to generate and store JPEG images. +// +// Fields: +// bits Points to number of codes of length i (<=16 supported). +// vals Value associated with each Huffman code. +// hclass 0 == DC table, 1 == AC table. +// ident Specifies the identifier for this table. +// 0-3 for extended JPEG compliance. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct +{ + unsigned char* bits; + unsigned char* vals; + unsigned char hclass; + unsigned char ident; + +} JPEGHuffTable; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: QUANT_TABLE +// +// Purpose: Stores quantization table information in a +// fast-to-use format. +// +// Context: Used by quantizer/dequantizer to store formatted +// quantization tables. +// +// Fields: +// precision 0 => elements contains 8-bit elements, +// 1 => elements contains 16-bit elements. +// ident Table identifier (0-3). +// elements Pointer to 64 table elements + 16 extra elements to catch +// input data errors that may cause malfunction of the +// Huffman decoder. +// elarray Space for elements (see above) plus 8 bytes to align +// to a quadword boundary. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _QUANT_TABLE +{ + int precision; + int ident; + short* elements; + short elarray [84]; + +} QUANT_TABLE; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: JPEGQuantTable +// +// Purpose: Stores pointers to JPEG binary spec compliant +// quantization table information. +// +// Context: Used by interface and table methods to specify encoder +// tables to generate and store JPEG images. +// +// Fields: +// quantizer Zig-zag order elements specifying quantization factors. +// ident Specifies identifier for this table. +// 0-3 valid for Extended Baseline JPEG compliance. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct +{ + unsigned char* quantizer; + unsigned char ident; + +} JPEGQuantTable; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: FRAME_COMPONENT +// +// Purpose: One frame-component structure is allocated per component +// in a frame. +// +// Context: Used by Huffman decoder to manage components. +// +// Fields: +// ident Component identifier. The tables use this ident to +// determine the correct table for each component. +// hsampling Horizontal subsampling factor for this component, +// 1-4 are legal. +// vsampling Vertical subsampling factor for this component, +// 1-4 are legal. +// quant_sel Quantization table selector. The quantization table +// used by this component is determined via this selector. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _FRAME_COMPONENT +{ + int ident; + int hsampling; + int vsampling; + int quant_sel; + +} FRAME_COMPONENT; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: FRAME +// +// Purpose: Stores frame-specific data. +// +// Context: One Frame structure per image. +// +// Fields: +// precision Sample precision in bits. +// width Width of the source image in pixels. +// height Height of the source image in pixels. +// MCUheight Height of a frame MCU. +// MCUwidth Width of a frame MCU. +// max_hsampling Max horiz sampling ratio of any component in the frame. +// max_vsampling Max vert sampling ratio of any component in the frame. +// ncomps Number of components/channels in the frame. +// horMCU Number of horizontal MCUs in the frame. +// totalMCU Total number of MCUs in the frame. +// comps Array of 'ncomps' component descriptors. +// restart_interv Indicates number of MCUs after which to restart the +// entropy parameters. +// SeenAllDCScans Used when decoding Multiscan images to determine if +// all channels of an image have been decoded. +// SeenAllACScans (See SeenAllDCScans) +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _FRAME +{ + int precision; + int width; + int height; + int MCUheight; + int MCUwidth; + int max_hsampling; + int max_vsampling; + int ncomps; + int horMCU; + long totalMCU; + FRAME_COMPONENT* comps; + int restart_interv; + int SeenAllDCScans; + int SeenAllACScans; + +} FRAME; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: SCAN_COMPONENT +// +// Purpose: One scan-component structure is allocated per component +// of each scan in a frame. +// +// Context: Used by Huffman decoder to manage components within scans. +// +// Fields: +// comp Component number, index to the comps member of FRAME. +// hsampling Horizontal sampling factor. +// vsampling Vertical sampling factor. +// dc_table DC Huffman table pointer for this scan. +// ac_table AC Huffman table pointer for this scan. +// quant_table Quantization table pointer for this scan. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct +{ + int comp; + int hsampling; + int vsampling; + HUFFMAN_TABLE* dc_table; + HUFFMAN_TABLE* ac_table; + QUANT_TABLE* quant_table; + +} SCAN_COMPONENT; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: SCAN +// +// Purpose: One SCAN structure is allocated per scan in a frame. +// +// Context: Used by Huffman decoder to manage scans. +// +// Fields: +// ncomps Number of image components in a scan, 1-4 legal. +// gray_scale If TRUE, decode only the Y channel. +// start_spec Start coefficient of spectral or predictor selector. +// end_spec End coefficient of spectral selector. +// approx_high High bit position in successive approximation +// Progressive coding. +// approx_low Low bit position in successive approximation +// Progressive coding. +// restart_interv Restart interval, 0 if disabled. +// curxMCU Next horizontal MCU index to be processed after +// an interrupted SCAN. +// curyMCU Next vertical MCU index to be processed after +// an interrupted SCAN. +// dc_diff Array of DC predictor values for DPCM modes. +// comps Array of ncomps SCAN_COMPONENT component identifiers. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _SCAN +{ + int ncomps; + int gray_scale; + int start_spec; + int end_spec; + int approx_high; + int approx_low; + UINT restart_interv; + DWORD curxMCU; + DWORD curyMCU; + int dc_diff[4]; + SCAN_COMPONENT* comps; + +} SCAN; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: DCTTYPE +// +// Purpose: Possible algorithms to be used to perform the discrete +// cosine transform (DCT). +// +// Fields: +// IJL_AAN The AAN (Arai, Agui, and Nakajima) algorithm from +// Trans. IEICE, vol. E 71(11), 1095-1097, Nov. 1988. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ + IJL_AAN = 0 + +} DCTTYPE; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: PROCESSOR_TYPE +// +// Purpose: Possible types of processors. +// Note that the enums are defined in ascending order +// depending upon their various IA32 instruction support. +// +// Fields: +// +// IJL_OTHER_PROC +// Does not support the CPUID instruction and +// assumes no Pentium(R) processor instructions. +// +// IJL_PENTIUM_PROC +// Corresponds to an Intel(R) Pentium(R) processor +// (or a 100% compatible) that supports the +// Pentium(R) processor instructions. +// +// IJL_PENTIUM_PRO_PROC +// Corresponds to an Intel(R) Pentium(R) Pro processor +// (or a 100% compatible) that supports the +// Pentium(R) Pro processor instructions. +// +// IJL_PENTIUM_PROC_MMX_TECH +// Corresponds to an Intel(R) Pentium(R) processor +// with MMX(TM) technology (or a 100% compatible) +// that supports the MMX(TM) instructions. +// +// IJL_PENTIUM_II_PROC +// Corresponds to an Intel(R) Pentium(R) II processor +// (or a 100% compatible) that supports both the +// Pentium(R) Pro processor instructions and the +// MMX(TM) instructions. +// +// Any additional processor types that support a superset +// of both the Pentium(R) Pro processor instructions and the +// MMX(TM) instructions should be given an enum value greater +// than IJL_PENTIUM_II_PROC. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ + IJL_OTHER_PROC = 0, + IJL_PENTIUM_PROC = 1, + IJL_PENTIUM_PRO_PROC = 2, + IJL_PENTIUM_PROC_MMX_TECH = 3, + IJL_PENTIUM_II_PROC = 4 + +} PROCESSOR_TYPE; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: ENTROPYSTRUCT +// +// Purpose: Stores the decoder state information necessary to "jump" +// to a particular MCU row in a compressed entropy stream. +// +// Context: Used to persist the decoder state within Decode_Scan when +// decoding using ROIs. +// +// Fields: +// offset Offset (in bytes) into the entropy stream +// from the beginning. +// dcval1 DC val at the beginning of the MCU row +// for component 1. +// dcval2 DC val at the beginning of the MCU row +// for component 2. +// dcval3 DC val at the beginning of the MCU row +// for component 3. +// dcval4 DC val at the beginning of the MCU row +// for component 4. +// bit_buffer_64 64-bit Huffman bit buffer. Stores current +// bit buffer at the start of a MCU row. +// Also used as a 32-bit buffer on 32-bit +// architectures. +// bitbuf_bits_valid Number of valid bits in the above bit buffer. +// unread_marker Have any markers been decoded but not +// processed at the beginning of a MCU row? +// This entry holds the unprocessed marker, or +// 0 if none. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct +{ + DWORD offset; + int dcval1; + int dcval2; + int dcval3; + int dcval4; + UINT64 bit_buffer_64; + int bitbuf_bits_valid; + BYTE unread_marker; + +} ENTROPYSTRUCT; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: STATE +// +// Purpose: Stores the active state of the IJL. +// +// Context: Used by all low-level routines to store pseudo-global or +// state variables. +// +// Fields: +// bit_buffer_64 64-bit bitbuffer utilized by Huffman +// encoder/decoder algorithms utilizing routines +// designed for MMX(TM) technology. +// bit_buffer_32 32-bit bitbuffer for all other Huffman +// encoder/decoder algorithms. +// bitbuf_bits_valid Number of bits in the above two fields that +// are valid. +// +// cur_entropy_ptr Current position (absolute address) in +// the entropy buffer. +// start_entropy_ptr Starting position (absolute address) of +// the entropy buffer. +// end_entropy_ptr Ending position (absolute address) of +// the entropy buffer. +// entropy_bytes_processed Number of bytes actually processed +// (passed over) in the entropy buffer. +// entropy_buf_maxsize Max size of the entropy buffer. +// entropy_bytes_left Number of bytes left in the entropy buffer. +// Prog_EndOfBlock_Run Progressive block run counter. +// +// DIB_ptr Temporary offset into the input/output DIB. +// +// unread_marker If a marker has been read but not processed, +// stick it in this field. +// processor_type (0, 1, or 2) == current processor does not +// support MMX(TM) instructions. +// (3 or 4) == current processor does +// support MMX(TM) instructions. +// cur_scan_comp On which component of the scan are we working? +// file Process file handle, or +// 0x00000000 if no file is defined. +// JPGBuffer Entropy buffer (~4K). +// +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _STATE +{ + // Bit buffer. + UINT64 bit_buffer_64; + DWORD bit_buffer_32; + int bitbuf_bits_valid; + + // Entropy. + BYTE* cur_entropy_ptr; + BYTE* start_entropy_ptr; + BYTE* end_entropy_ptr; + long entropy_bytes_processed; + long entropy_buf_maxsize; + int entropy_bytes_left; + int Prog_EndOfBlock_Run; + + // Input or output DIB. + BYTE* DIB_ptr; + + // Control. + BYTE unread_marker; + PROCESSOR_TYPE processor_type; + int cur_scan_comp; + HANDLE file; + BYTE JPGBuffer [JBUFSIZE]; + +} STATE; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: FAST_MCU_PROCESSING_TYPE +// +// Purpose: Advanced Control Option. Do NOT modify. +// WARNING: Used for internal reference only. +// +// Fields: +// +// IJL_(sampling)_(JPEG color space)_(sampling)_(DIB color space) +// Decode is read left to right w/ upsampling. +// Encode is read right to left w/ subsampling. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ + IJL_NO_CC_OR_US = 0, + + IJL_111_YCBCR_111_RGB = 1, + IJL_111_YCBCR_111_BGR = 2, + + IJL_411_YCBCR_111_RGB = 3, + IJL_411_YCBCR_111_BGR = 4, + + IJL_422_YCBCR_111_RGB = 5, + IJL_422_YCBCR_111_BGR = 6, + + IJL_111_YCBCR_1111_RGBA_FPX = 7, + IJL_411_YCBCR_1111_RGBA_FPX = 8, + IJL_422_YCBCR_1111_RGBA_FPX = 9, + + IJL_1111_YCBCRA_FPX_1111_RGBA_FPX = 10, + IJL_4114_YCBCRA_FPX_1111_RGBA_FPX = 11, + IJL_4224_YCBCRA_FPX_1111_RGBA_FPX = 12, + + IJL_111_RGB_1111_RGBA_FPX = 13, + + IJL_1111_RGBA_FPX_1111_RGBA_FPX = 14 + +} FAST_MCU_PROCESSING_TYPE; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: JPEG_PROPERTIES +// +// Purpose: Stores low-level and control information. It is used by +// both the encoder and decoder. An advanced external user +// may access this structure to expand the interface +// capability. +// +// See the Developer's Guide for an expanded description +// of this structure and its use. +// +// Context: Used by all interface methods and most IJL routines. +// +// Fields: +// +// iotype IN: Specifies type of data operation +// (read/write/other) to be +// performed by IJL_Read or IJL_Write. +// roi IN: Rectangle-Of-Interest to read from, or +// write to, in pixels. +// dcttype IN: DCT alogrithm to be used. +// fast_processing OUT: Supported fast pre/post-processing path. +// This is set by the IJL. +// interrupt IN: Signals an interrupt has been requested. +// +// DIBBytes IN: Pointer to buffer of uncompressed data. +// DIBWidth IN: Width of uncompressed data. +// DIBHeight IN: Height of uncompressed data. +// DIBPadBytes IN: Padding (in bytes) at end of each +// row in the uncompressed data. +// DIBChannels IN: Number of components in the +// uncompressed data. +// DIBColor IN: Color space of uncompressed data. +// DIBSubsampling IN: Required to be IJL_NONE. +// DIBLineBytes OUT: Number of bytes in an output DIB line +// including padding. +// +// JPGFile IN: Pointer to file based JPEG. +// JPGBytes IN: Pointer to buffer based JPEG. +// JPGSizeBytes IN: Max buffer size. Used with JPGBytes. +// OUT: Number of compressed bytes written. +// JPGWidth IN: Width of JPEG image. +// OUT: After reading (except READHEADER). +// JPGHeight IN: Height of JPEG image. +// OUT: After reading (except READHEADER). +// JPGChannels IN: Number of components in JPEG image. +// OUT: After reading (except READHEADER). +// JPGColor IN: Color space of JPEG image. +// JPGSubsampling IN: Subsampling of JPEG image. +// OUT: After reading (except READHEADER). +// JPGThumbWidth OUT: JFIF embedded thumbnail width [0-255]. +// JPGThumbHeight OUT: JFIF embedded thumbnail height [0-255]. +// +// cconversion_reqd OUT: If color conversion done on decode, TRUE. +// upsampling_reqd OUT: If upsampling done on decode, TRUE. +// jquality IN: [0-100] where highest quality is 100. +// jinterleaveType IN/OUT: 0 => MCU interleaved file, and +// 1 => 1 scan per component. +// numxMCUs OUT: Number of MCUs in the x direction. +// numyMCUs OUT: Number of MCUs in the y direction. +// +// nqtables IN/OUT: Number of quantization tables. +// maxquantindex IN/OUT: Maximum index of quantization tables. +// nhuffActables IN/OUT: Number of AC Huffman tables. +// nhuffDctables IN/OUT: Number of DC Huffman tables. +// maxhuffindex IN/OUT: Maximum index of Huffman tables. +// jFmtQuant IN/OUT: Formatted quantization table info. +// jFmtAcHuffman IN/OUT: Formatted AC Huffman table info. +// jFmtDcHuffman IN/OUT: Formatted DC Huffman table info. +// +// jEncFmtQuant IN/OUT: Pointer to one of the above, or +// to externally persisted table. +// jEncFmtAcHuffman IN/OUT: Pointer to one of the above, or +// to externally persisted table. +// jEncFmtDcHuffman IN/OUT: Pointer to one of the above, or +// to externally persisted table. +// +// use_default_qtables IN: Set to default quantization tables. +// Clear to supply your own. +// use_default_htables IN: Set to default Huffman tables. +// Clear to supply your own. +// rawquanttables IN: Up to 4 sets of quantization tables. +// rawhufftables IN: Alternating pairs (DC/AC) of up to 4 +// sets of raw Huffman tables. +// HuffIdentifierAC IN: Indicates what channel the user- +// supplied Huffman AC tables apply to. +// HuffIdentifierDC IN: Indicates what channel the user- +// supplied Huffman DC tables apply to. +// +// jframe OUT: Structure with frame-specific info. +// needframe OUT: TRUE when a frame has been detected. +// +// jscan Persistence for current scan pointer when +// interrupted. +// +// state OUT: Contains info on the state of the IJL. +// SawAdobeMarker OUT: Decoder saw an APP14 marker somewhere. +// AdobeXform OUT: If SawAdobeMarker TRUE, this indicates +// the JPEG color space given by that marker. +// +// rowoffsets Persistence for the decoder MCU row origins +// when decoding by ROI. Offsets (in bytes +// from the beginning of the entropy data) +// to the start of each of the decoded rows. +// Fill the offsets with -1 if they have not +// been initalized and NULL could be the +// offset to the first row. +// +// MCUBuf OUT: Quadword aligned internal buffer. +// Big enough for the largest MCU +// (10 blocks) with extra room for +// additional operations. +// tMCUBuf OUT: Version of above, without alignment. +// +// processor_type OUT: Determines type of processor found +// during initialization. +// +// ignoreDCTs IN: Assert to bypass DCTs when processing +// data. Required for conformance +// testing. +// +// progressive_found OUT: 1 when progressive image detected. +// coef_buffer IN: Pointer to a larger buffer containing +// frequency coefficients when they +// cannot be decoded dynamically +// (i.e., as in progressive decoding). +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct +{ + // Compression/Decompression control. + IJLIOTYPE iotype; // default = IJL_SETUP + RECT roi; // default = 0 + DCTTYPE dcttype; // default = IJL_AAN + FAST_MCU_PROCESSING_TYPE fast_processing; // default = IJL_NO_CC_OR_US + DWORD interrupt; // default = FALSE + + // DIB specific I/O data specifiers. + BYTE* DIBBytes; // default = NULL + DWORD DIBWidth; // default = 0 + int DIBHeight; // default = 0 + DWORD DIBPadBytes; // default = 0 + DWORD DIBChannels; // default = 3 + IJL_COLOR DIBColor; // default = IJL_BGR + IJL_DIBSUBSAMPLING DIBSubsampling; // default = IJL_NONE + int DIBLineBytes; // default = 0 + + // JPEG specific I/O data specifiers. + LPTSTR JPGFile; // default = NULL + BYTE* JPGBytes; // default = NULL + DWORD JPGSizeBytes; // default = 0 + DWORD JPGWidth; // default = 0 + DWORD JPGHeight; // default = 0 + DWORD JPGChannels; // default = 3 + IJL_COLOR JPGColor; // default = IJL_YCBCR + IJL_JPGSUBSAMPLING JPGSubsampling; // default = IJL_411 + DWORD JPGThumbWidth; // default = 0 + DWORD JPGThumbHeight; // default = 0 + + // JPEG conversion properties. + DWORD cconversion_reqd; // default = TRUE + DWORD upsampling_reqd; // default = TRUE + DWORD jquality; // default = 75 + DWORD jinterleaveType; // default = 0 + DWORD numxMCUs; // default = 0 + DWORD numyMCUs; // default = 0 + + // Tables. + DWORD nqtables; + DWORD maxquantindex; + DWORD nhuffActables; + DWORD nhuffDctables; + DWORD maxhuffindex; + + QUANT_TABLE jFmtQuant[4]; + HUFFMAN_TABLE jFmtAcHuffman[4]; + HUFFMAN_TABLE jFmtDcHuffman[4]; + + short* jEncFmtQuant[4]; + HUFFMAN_TABLE* jEncFmtAcHuffman[4]; + HUFFMAN_TABLE* jEncFmtDcHuffman[4]; + + // Allow user-defined tables. + DWORD use_default_qtables; + DWORD use_default_htables; + + JPEGQuantTable rawquanttables[4]; + JPEGHuffTable rawhufftables[8]; + BYTE HuffIdentifierAC[4]; + BYTE HuffIdentifierDC[4]; + + // Frame specific members. + FRAME jframe; + int needframe; + + // SCAN persistent members. + SCAN* jscan; + + // State members. + STATE state; + DWORD SawAdobeMarker; + DWORD AdobeXform; + + // ROI decoder members. + ENTROPYSTRUCT* rowoffsets; + + // Intermediate buffers. + BYTE* MCUBuf; + BYTE tMCUBuf[720*2]; // ??? + + // Processor detected. + PROCESSOR_TYPE processor_type; + + // Test specific members. + DWORD ignoreDCTs; + + // Progressive mode members. + int progressive_found; + short* coef_buffer; + +} JPEG_PROPERTIES; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: JPEG_CORE_PROPERTIES +// +// Purpose: This is the primary data structure between the IJL and +// the external user. It stores JPEG state information +// and controls the IJL. It is user-modifiable. +// +// See the Developer's Guide for details on appropriate usage. +// +// Context: Used by all low-level IJL routines to store +// pseudo-global information. +// +// Fields: +// +// UseJPEGPROPERTIES Set this flag != 0 if you wish to override +// the JPEG_CORE_PROPERTIES "IN" parameters with +// the JPEG_PROPERTIES parameters. +// +// DIBBytes IN: Pointer to buffer of uncompressed data. +// DIBWidth IN: Width of uncompressed data. +// DIBHeight IN: Height of uncompressed data. +// DIBPadBytes IN: Padding (in bytes) at end of each +// row in the uncompressed data. +// DIBChannels IN: Number of components in the +// uncompressed data. +// DIBColor IN: Color space of uncompressed data. +// DIBSubsampling IN: Required to be IJL_NONE. +// +// JPGFile IN: Pointer to file based JPEG. +// JPGBytes IN: Pointer to buffer based JPEG. +// JPGSizeBytes IN: Max buffer size. Used with JPGBytes. +// OUT: Number of compressed bytes written. +// JPGWidth IN: Width of JPEG image. +// OUT: After reading (except READHEADER). +// JPGHeight IN: Height of JPEG image. +// OUT: After reading (except READHEADER). +// JPGChannels IN: Number of components in JPEG image. +// OUT: After reading (except READHEADER). +// JPGColor IN: Color space of JPEG image. +// JPGSubsampling IN: Subsampling of JPEG image. +// OUT: After reading (except READHEADER). +// JPGThumbWidth OUT: JFIF embedded thumbnail width [0-255]. +// JPGThumbHeight OUT: JFIF embedded thumbnail height [0-255]. +// +// cconversion_reqd OUT: If color conversion done on decode, TRUE. +// upsampling_reqd OUT: If upsampling done on decode, TRUE. +// jquality IN: [0-100] where highest quality is 100. +// +// jprops "Low-Level" IJL data structure. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef struct _JPEG_CORE_PROPERTIES +{ + DWORD UseJPEGPROPERTIES; // default = 0 + + // DIB specific I/O data specifiers. + BYTE* DIBBytes; // default = NULL + DWORD DIBWidth; // default = 0 + int DIBHeight; // default = 0 + DWORD DIBPadBytes; // default = 0 + DWORD DIBChannels; // default = 3 + IJL_COLOR DIBColor; // default = IJL_BGR + IJL_DIBSUBSAMPLING DIBSubsampling; // default = IJL_NONE + + // JPEG specific I/O data specifiers. + LPTSTR JPGFile; // default = NULL + BYTE* JPGBytes; // default = NULL + DWORD JPGSizeBytes; // default = 0 + DWORD JPGWidth; // default = 0 + DWORD JPGHeight; // default = 0 + DWORD JPGChannels; // default = 3 + IJL_COLOR JPGColor; // default = IJL_YCBCR + IJL_JPGSUBSAMPLING JPGSubsampling; // default = IJL_411 + DWORD JPGThumbWidth; // default = 0 + DWORD JPGThumbHeight; // default = 0 + + // JPEG conversion properties. + DWORD cconversion_reqd; // default = TRUE + DWORD upsampling_reqd; // default = TRUE + DWORD jquality; // default = 75 + + // Low-level properties. + JPEG_PROPERTIES jprops; + +} JPEG_CORE_PROPERTIES; + + +/*D* +//////////////////////////////////////////////////////////////////////////// +// Name: IJLERR +// +// Purpose: Listing of possible "error" codes returned by the IJL. +// +// See the Developer's Guide for details on appropriate usage. +// +// Context: Used for error checking. +// +//////////////////////////////////////////////////////////////////////////// +*D*/ + +typedef enum +{ + // The following "error" values indicate an "OK" condition. + IJL_OK = 0, + IJL_INTERRUPT_OK = 1, + IJL_ROI_OK = 2, + + // The following "error" values indicate an error has occurred. + IJL_EXCEPTION_DETECTED = -1, + IJL_INVALID_ENCODER = -2, + IJL_UNSUPPORTED_SUBSAMPLING = -3, + IJL_UNSUPPORTED_BYTES_PER_PIXEL = -4, + IJL_MEMORY_ERROR = -5, + IJL_BAD_HUFFMAN_TABLE = -6, + IJL_BAD_QUANT_TABLE = -7, + IJL_INVALID_JPEG_PROPERTIES = -8, + IJL_ERR_FILECLOSE = -9, + IJL_INVALID_FILENAME = -10, + IJL_ERROR_EOF = -11, + IJL_PROG_NOT_SUPPORTED = -12, + IJL_ERR_NOT_JPEG = -13, + IJL_ERR_COMP = -14, + IJL_ERR_SOF = -15, + IJL_ERR_DNL = -16, + IJL_ERR_NO_HUF = -17, + IJL_ERR_NO_QUAN = -18, + IJL_ERR_NO_FRAME = -19, + IJL_ERR_MULT_FRAME = -20, + IJL_ERR_DATA = -21, + IJL_ERR_NO_IMAGE = -22, + IJL_FILE_ERROR = -23, + IJL_INTERNAL_ERROR = -24, + IJL_BAD_RST_MARKER = -25, + IJL_THUMBNAIL_DIB_TOO_SMALL = -26, + IJL_THUMBNAIL_DIB_WRONG_COLOR = -27, + IJL_RESERVED = -99 + +} IJLERR; + + + + +/* ///////////////////////////////////////////////////////////////////////// +// Function Prototypes (API Calls) // +///////////////////////////////////////////////////////////////////////// */ + + +/*F* +//////////////////////////////////////////////////////////////////////////// +// Name: ijlInit +// +// Purpose: Used to initalize the IJL. +// +// See the Developer's Guide for details on appropriate usage. +// +// Context: Always call this before anything else. +// Also, only call this with a new jcprops structure, or +// after calling IJL_Free. Otherwise, dynamically +// allocated memory may be leaked. +// +// Returns: Any IJLERR value. IJL_OK indicates success. +// +// Parameters: +// jcprops Pointer to an externally allocated +// JPEG_CORE_PROPERTIES structure. +// +//////////////////////////////////////////////////////////////////////////// +*F*/ + +IJLAPI(IJLERR, ijlInit, ( JPEG_CORE_PROPERTIES* jcprops )); + + +/*F* +//////////////////////////////////////////////////////////////////////////// +// Name: ijlFree +// +// Purpose: Used to properly close down the IJL. +// +// See the Developer's Guide for details on appropriate usage. +// +// Context: Always call this when done using the IJL to perform +// clean-up of dynamically allocated memory. +// Note, IJL_Init will have to be called to use the +// IJL again. +// +// Returns: Any IJLERR value. IJL_OK indicates success. +// +// Parameters: +// jcprops Pointer to an externally allocated +// JPEG_CORE_PROPERTIES structure. +// +//////////////////////////////////////////////////////////////////////////// +*F*/ + +IJLAPI(IJLERR, ijlFree, ( JPEG_CORE_PROPERTIES* jcprops )); + + +/*F* +//////////////////////////////////////////////////////////////////////////// +// Name: IJL_Read +// +// Purpose: Used to read JPEG data (entropy, or header, or both) into +// a user-supplied buffer (to hold the image data) and/or +// into the JPEG_CORE_PROPERTIES structure (to hold the +// header info). +// +// Context: See the Developer's Guide for a detailed description +// on the use of this function. The jcprops main data +// members are checked for consistency. +// +// Returns: Any IJLERR value. IJL_OK indicates success. +// +// Parameters: +// jcprops Pointer to an externally allocated +// JPEG_CORE_PROPERTIES structure. +// iotype Specifies what type of read operation to perform. +// +//////////////////////////////////////////////////////////////////////////// +*F*/ + +IJLAPI(IJLERR, ijlRead, ( JPEG_CORE_PROPERTIES* jcprops, IJLIOTYPE iotype )); + + +/*F* +//////////////////////////////////////////////////////////////////////////// +// Name: ijlWrite +// +// Purpose: Used to write JPEG data (entropy, or header, or both) into +// a user-supplied buffer (to hold the image data) and/or +// into the JPEG_CORE_PROPERTIES structure (to hold the +// header info). +// +// Context: See the Developer's Guide for a detailed description +// on the use of this function. The jcprops main data +// members are checked for consistency. +// +// Returns: Any IJLERR value. IJL_OK indicates success. +// +// Parameters: +// jcprops Pointer to an externally allocated +// JPEG_CORE_PROPERTIES structure. +// iotype Specifies what type of write operation to perform. +// +//////////////////////////////////////////////////////////////////////////// +*F*/ + +IJLAPI(IJLERR, ijlWrite, ( JPEG_CORE_PROPERTIES* jcprops, IJLIOTYPE iotype )); + + +/*F* +//////////////////////////////////////////////////////////////////////////// +// Name: ijlGetLibVersion +// +// Purpose: To identify the version number of the IJL. +// +// Context: Call to get the IJL version number. +// +// Returns: pointer to IJLibVersion struct +// +// Parameters: none +// +//////////////////////////////////////////////////////////////////////////// +*F*/ + +IJLAPI(const IJLibVersion*, ijlGetLibVersion, (void)); + + +/*F* +//////////////////////////////////////////////////////////////////////////// +// Name: ijlErrorStr +// +// Purpose: Gets the string to describe error code. +// +// Context: Is called to get descriptive string on arbitrary IJLERR code. +// +// Returns: pointer to string +// +// Parameters: IJLERR - IJL error code +// +//////////////////////////////////////////////////////////////////////////// +*F*/ + +//IJLAPI(const LPCTSTR, ijlErrorStr, (IJLERR code)); + + + + +#if defined( __cplusplus ) +} +#endif + +#endif // __IJL_H__ diff --git a/src/aabox.h b/src/aabox.h new file mode 100644 index 00000000..da01f96d --- /dev/null +++ b/src/aabox.h @@ -0,0 +1,113 @@ +// aabox.h +// +// Copyright (C) 2001, Chris Laurel +// +// Axis-aligned bounding box class +// +// 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. + +#ifndef _AABOX_H_ +#define _AABOX_H_ + +#include "vecmath.h" + +class AxisAlignedBox +{ + public: + inline AxisAlignedBox(); + AxisAlignedBox(Point3f _min, Point3f _max) : + minimum(_min), maximum(_max) {}; + AxisAlignedBox(Point3f center) : + minimum(center), maximum(center) {}; + + inline Point3f getMinimum() const; + inline Point3f getMaximum() const; + inline Point3f getCenter() const; + inline Vec3f getExtents() const; + + inline bool empty() const; + inline bool contains(const Point3f&) const; + + inline void include(const Point3f&); + inline void include(const AxisAlignedBox&); + + private: + Point3f minimum; + Point3f maximum; +}; + + +AxisAlignedBox::AxisAlignedBox() : + minimum(1.0e20f, 1.0e20f, 1.0e20f), + maximum(-1.0e20f, -1.0e20f, -1.0e20f) +{ +} + +Point3f AxisAlignedBox::getMinimum() const +{ + return minimum; +} + +Point3f AxisAlignedBox::getMaximum() const +{ + return maximum; +} + +Point3f AxisAlignedBox::getCenter() const +{ + return Point3f((minimum.x + maximum.x) * 0.5f, + (minimum.y + maximum.y) * 0.5f, + (minimum.z + maximum.z) * 0.5f); +} + +Vec3f AxisAlignedBox::getExtents() const +{ + return maximum - minimum; +} + +bool AxisAlignedBox::empty() const +{ + return maximum.x < minimum.x || maximum.y < minimum.y || maximum.z < minimum.z; +} + +bool AxisAlignedBox::contains(const Point3f& p) const +{ + return (p.x >= minimum.x && p.x <= maximum.x && + p.y >= minimum.y && p.y <= maximum.y && + p.z >= minimum.z && p.z <= maximum.z); +} + + +void AxisAlignedBox::include(const Point3f& p) +{ + if (p.x < minimum.x) minimum.x = p.x; + if (p.x > maximum.x) maximum.x = p.x; + if (p.y < minimum.y) minimum.y = p.y; + if (p.y > maximum.y) maximum.y = p.y; + if (p.z < minimum.z) minimum.z = p.z; + if (p.z > maximum.z) maximum.z = p.z; +} + +void AxisAlignedBox::include(const AxisAlignedBox& b) +{ + if (b.minimum.x < minimum.x) minimum.x = b.minimum.x; + if (b.maximum.x > maximum.x) maximum.x = b.maximum.x; + if (b.minimum.y < minimum.y) minimum.y = b.minimum.y; + if (b.maximum.y > maximum.y) maximum.y = b.maximum.y; + if (b.minimum.z < minimum.z) minimum.z = b.minimum.z; + if (b.maximum.z > maximum.z) maximum.z = b.maximum.z; +} + +#if 0 +AxisAlignedBox union(const AxisAlignedBox& a, const AxisAlignedBox& b) +{ + AxisAlignedBox box(a); + box.union(b); + return box; +} +#endif + +#endif // _AABOX_H_ diff --git a/src/astro.cpp b/src/astro.cpp new file mode 100644 index 00000000..6c9502e7 --- /dev/null +++ b/src/astro.cpp @@ -0,0 +1,242 @@ +// astro.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include +#include "celestia.h" +#include "astro.h" + +using namespace std; + +#define SOLAR_ABSMAG 4.83f +#define LN_MAG 1.085736 +#define LY_PER_PARSEC 3.26 +#define KM_PER_LY 9466411842000.000 +#define KM_PER_AU 149597870.7 +#define AU_PER_LY (KM_PER_LY / KM_PER_AU) + +// epoch J2000: 12 UT on 1 Jan 2000 +#define J2000 2451545.0 + +// epoch B1950: 22:09 UT on 21 Dec 1949 +#define B1950 2433282.423 + + +float astro::lumToAbsMag(float lum) +{ + return (float) (SOLAR_ABSMAG - log(lum) * LN_MAG); +} + +// Return the apparent magnitude of a star with lum times solar +// luminosity viewed at lyrs light years +float astro::lumToAppMag(float lum, float lyrs) +{ + return absToAppMag(lumToAbsMag(lum), lyrs); +} + +float astro::absMagToLum(float mag) +{ + return (float) exp((SOLAR_ABSMAG - mag) / LN_MAG); +} + +float astro::appMagToLum(float mag, float lyrs) +{ + return absMagToLum(appToAbsMag(mag, lyrs)); +} + +float astro::absToAppMag(float absMag, float lyrs) +{ + return (float) (absMag - 5 + 5 * log10(lyrs / LY_PER_PARSEC)); +} + +float astro::appToAbsMag(float appMag, float lyrs) +{ + return (float) (appMag + 5 - 5 * log10(lyrs / LY_PER_PARSEC)); +} + +float astro::lightYearsToParsecs(float ly) +{ + return ly / (float) LY_PER_PARSEC; +} + +float astro::parsecsToLightYears(float pc) +{ + return pc * (float) LY_PER_PARSEC; +} + +float astro::lightYearsToKilometers(float ly) +{ + return ly * (float) KM_PER_LY; +} + +double astro::lightYearsToKilometers(double ly) +{ + return ly * KM_PER_LY; +} + +float astro::kilometersToLightYears(float km) +{ + return km / (float) KM_PER_LY; +} + +double astro::kilometersToLightYears(double km) +{ + return km / KM_PER_LY; +} + +float astro::lightYearsToAU(float ly) +{ + return ly * (float) AU_PER_LY; +} + +double astro::lightYearsToAU(double ly) +{ + return ly * AU_PER_LY; +} + +float astro::AUtoLightYears(float au) +{ + return au / (float) AU_PER_LY; +} + +float astro::AUtoKilometers(float au) +{ + return au * (float) KM_PER_AU; +} + +float astro::kilometersToAU(float km) +{ + return km / (float) KM_PER_AU; +} + +double astro::secondsToJulianDate(double sec) +{ + return sec / 86400.0; +} + +double astro::julianDateToSeconds(double jd) +{ + return jd * 86400.0; +} + + +// Compute the fraction of a sphere which is illuminated and visible +// to a viewer. The source of illumination is assumed to be at (0, 0, 0) +float astro::sphereIlluminationFraction(Point3d spherePos, + Point3d viewerPos) +{ + return 1.0f; +} + +// Convert the position in univeral coordinates to a star-centric +// coordinates in units of kilometers. Note that there are three different +// precisions used here: star coordinates are stored as floats in units of +// light years, position within a solar system are doubles in units of +// kilometers, and p is highest-precision in units of light years. +Point3d astro::heliocentricPosition(UniversalCoord universal, + Point3f starPosition) +{ + // Get the offset vector + Vec3d v = universal - Point3d(starPosition.x, starPosition.y, starPosition.z); + + // . . . and convert it to kilometers + return Point3d(lightYearsToKilometers(v.x), + lightYearsToKilometers(v.y), + lightYearsToKilometers(v.z)); +} + +// universalPosition is the inverse operation of heliocentricPosition +UniversalCoord astro::universalPosition(Point3d heliocentric, + Point3f starPosition) +{ + return UniversalCoord(starPosition) + + Vec3d(kilometersToLightYears(heliocentric.x), + kilometersToLightYears(heliocentric.y), + kilometersToLightYears(heliocentric.z)); +} + + +astro::Date::Date(int Y, int M, int D) +{ + year = Y; + month = M; + day = D; + hour = 0; + minute = 0; + seconds = 0.0; +} + + +astro::Date::Date(double jd) +{ + int a = (int) (jd + 0.5); + double c; + if (a < 2299161) + { + c = a + 1524; + } + else + { + double b = (int) ((a - 1867216.25) / 36524.25); + c = a + b - (int) (b / 4) + 1525; + } + + int d = (int) ((c - 122.1) / 365.25); + int e = (int) (365.25 * d); + int f = (int) ((c - e) / 30.6001); + + double dday = c - e - (int) (30.6001 * f) + ((jd + 0.5) - (int) (jd + 0.5)); + month = f - 1 - 12 * (int) (f / 14.0); + year = d - 4715 - (int) ((7.0 + month) / 10.0); + day = (int) dday; + + double dhour = (dday - day) * 24; + hour = (int) dhour; + + double dminute = (dhour - hour) * 60; + minute = (int) dminute; + + seconds = (dminute - minute) * 60; +} + + +// Convert a calendar date to a Julian date +astro::Date::operator double() const +{ + int y = year, m = month; + if (month <= 2) + { + y = year - 1; + m = month + 12; + } + + // Correct for the lost days in Oct 1582 when the Gregorian calendar + // replaced the Julian calendar. + int B = -2; + if (year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15)))) + { + B = y / 400 - y / 100; + } + + return (floor(365.25 * y) + + floor(30.6001 * (m + 1)) + B + 1720996.5 + + day + hour / 24.0 + minute / 1440.0 + seconds / 86400.0); +} + + +ostream& operator<<(ostream& s, const astro::Date d) +{ + s << d.year << ' ' << setw(2) << setfill('0') << d.month << ' '; + s << setw(2) << setfill('0') << d.day << ' '; + s << setw(2) << setfill('0') << d.hour << ':'; + s << setw(2) << setfill('0') << d.minute << ':'; + s << setw(2) << setfill('0') << (int) d.seconds; + return s; +} + diff --git a/src/astro.h b/src/astro.h new file mode 100644 index 00000000..42464b07 --- /dev/null +++ b/src/astro.h @@ -0,0 +1,72 @@ +// astro.h +// +// Copyright (C) 2001 Chris Laurel +// +// 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. + +#ifndef _ASTRO_H_ +#define _ASTRO_H_ + +#include +#include "vecmath.h" +#include "univcoord.h" + + +namespace astro +{ + class Date + { + public: + Date(int Y, int M, int D); + Date(double); + + operator double() const; + + public: + int year; + int month; + int day; + int hour; + int minute; + double seconds; + }; + + float lumToAbsMag(float lum); + float lumToAppMag(float lum, float lyrs); + float absMagToLum(float mag); + float appMagToLum(float mag, float lyrs); + float absToAppMag(float absMag, float lyrs); + float appToAbsMag(float appMag, float lyrs); + float lightYearsToParsecs(float); + float parsecsToLightYears(float); + float lightYearsToKilometers(float); + double lightYearsToKilometers(double); + float kilometersToLightYears(float); + double kilometersToLightYears(double); + float lightYearsToAU(float); + double lightYearsToAU(double); + float AUtoLightYears(float); + float AUtoKilometers(float); + float kilometersToAU(float); + + double secondsToJulianDate(double); + double julianDateToSeconds(double); + + float sphereIlluminationFraction(Point3d spherePos, + Point3d viewerPos); + + Point3d heliocentricPosition(UniversalCoord universal, + Point3f starPosition); + UniversalCoord universalPosition(Point3d heliocentric, + Point3f starPosition); +}; + +// Convert a date structure to a Julian date + +std::ostream& operator<<(std::ostream& s, const astro::Date); + +#endif // _ASTRO_H_ + diff --git a/src/basictypes.h b/src/basictypes.h new file mode 100644 index 00000000..6896eb5a --- /dev/null +++ b/src/basictypes.h @@ -0,0 +1,24 @@ +// basictypes.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _BASICTYPES_H_ +#define _BASICTYPES_H_ + +typedef unsigned int uint; + +// Fixed size types +typedef int int32; +typedef unsigned int uint32; +typedef short int16; +typedef unsigned short uint16; +typedef char int8; +typedef unsigned char uint8; + +#endif // _BASICTYPES_H_ + diff --git a/src/bigfix.cpp b/src/bigfix.cpp new file mode 100644 index 00000000..2ee0943b --- /dev/null +++ b/src/bigfix.cpp @@ -0,0 +1,187 @@ +// bigfix.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include +#include "bigfix.h" + + +/*** Constructors ***/ + +// Create a BigFix initialized to zero +BigFix::BigFix() +{ + for (int i = 0; i < N_WORDS; i++) + n[i] = 0; +} + + +BigFix::BigFix(int i) +{ + n[N_WORDS / 2] = (unsigned short) (i & 0xffff); + n[N_WORDS / 2 + 1] = (unsigned short) ((i >> 16) & 0xffff); + + // Sign extend if negative + if (i < 0) + { + for (int j = N_WORDS / 2 + 2; j < N_WORDS; j++) + n[j] = 0xffff; + } +} + + +BigFix::BigFix(double d) +{ + int sign = 1; + + if (d < 0) + { + sign = -1; + d = -d; + } + + double e = floor(d / (65536.0 * 65536.0 * 65536.0)); + + // Check for overflow + if (e < 32767) + { + n[7] = (unsigned short) e; + d -= n[7] * 65536 * 65536 * 65536; + n[6] = (unsigned short) (d / (65536.0 * 65536.0)); + d -= n[6] * 65536 * 65536; + n[5] = (unsigned short) (d / 65536); + d -= n[5] * 65536; + n[4] = (unsigned short) d; + d -= n[4]; + n[3] = (unsigned short) (d * 65536); + d -= n[3] / 65536; + n[2] = (unsigned short) (d * 65536 * 65536); + d -= n[2] / 65536; + n[1] = (unsigned short) (d * 65536 * 65536 * 65536); + d -= n[1] / 65536; + n[0] = (unsigned short) (d * 65536 * 65536 * 65536 * 65536); + } + + if (sign < 0) + *this = -*this; +} + + +BigFix::operator double() const +{ + double d = 0; + double e = 1.0 / (65536.0 * 65536.0 * 65536.0 * 65536.0); + BigFix f; + + if ((n[N_WORDS - 1] & 0x8000) == 0) + f = *this; + else + f = -*this; + + for (int i = 0; i < N_WORDS; i++) + { + d += e * f.n[i]; + e *= 65536; + } + + return ((n[N_WORDS - 1] & 0x8000) == 0) ? d : -d; +} + + +BigFix::operator float() const +{ + return (float) (double) *this; +} + + +BigFix BigFix::operator-() const +{ + int i; + BigFix f; + + for (i = 0; i < N_WORDS; i++) + f.n[i] = ~n[i]; + + unsigned int carry = 1; + i = 0; + while (carry != 0 && i < N_WORDS) + { + unsigned int m = f.n[i] + carry; + f.n[i] = (unsigned short) (m & 0xffff); + carry = m >> 16; + i++; + } + + return f; +} + + +BigFix operator+(BigFix a, BigFix b) +{ + unsigned int carry = 0; + BigFix c; + + for (int i = 0; i < N_WORDS; i++) + { + unsigned int m = a.n[i] + b.n[i] + carry; + c.n[i] = (unsigned short) (m & 0xffff); + carry = m >> 16; + } + + return c; +} + + +BigFix operator-(BigFix a, BigFix b) +{ + return a + -b; +} + + +BigFix operator*(BigFix a, BigFix b) +{ + return BigFix(); +} + + +bool operator==(BigFix a, BigFix b) +{ + for (int i = 0; i < N_WORDS; i++) + if (a.n[i] != b.n[i]) + return false; + return true; +} + + +bool operator!=(BigFix a, BigFix b) +{ + return !(a == b); +} + + +int BigFix::sign() +{ + if ((n[N_WORDS - 1] & 0x8000) != 0) + return -1; + + for (int i = 0; i < N_WORDS - 1; i++) + if (n[N_WORDS] != 0) + return 1; + + return 0; +} + + +// For debugging +void BigFix::dump() +{ + for (int i = 7; i >= 0; i--) + printf("%04x ", n[i]); + printf("\n"); +} diff --git a/src/bigfix.h b/src/bigfix.h new file mode 100644 index 00000000..754d8910 --- /dev/null +++ b/src/bigfix.h @@ -0,0 +1,47 @@ +// bigfix.h +// +// Copyright (C) 2001, Chris Laurel +// +// 128-bit fixed point (64.64) numbers for high-precision celestial +// coordinates. When you need millimeter accurate navigation across a scale +// of thousands of light years, doubles just don't do it. +// +// 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. + + +#ifndef _BIGFIX_H_ +#define _BIGFIX_H_ + +#define N_WORDS 8 + +class BigFix +{ +public: + BigFix(); + BigFix(int); + BigFix(double); + + operator double() const; + operator float() const; + + BigFix operator-() const; + + friend BigFix operator+(BigFix, BigFix); + friend BigFix operator-(BigFix, BigFix); + friend BigFix operator*(BigFix, BigFix); + friend bool operator==(BigFix, BigFix); + friend bool operator!=(BigFix, BigFix); + + int sign(); + + // for debugging + void dump(); + +private: + unsigned short n[N_WORDS]; // high 16-bits is n[N_WORDS - 1] +}; + +#endif // _BIGFIX_H_ diff --git a/src/body.cpp b/src/body.cpp new file mode 100644 index 00000000..cbe610f2 --- /dev/null +++ b/src/body.cpp @@ -0,0 +1,341 @@ +// body.cpp +// +// Copyright (C) 2001 Chris Laurel + + +#include +#include "mathlib.h" +#include "astro.h" +#include "body.h" + +using namespace std; + + +Body::Body(PlanetarySystem* _system) : + orbit(NULL), + satellites(NULL), + rings(NULL), + rotationPeriod(1), + color(1.0f, 1.0f, 1.0f), + oblateness(0), + appearanceFlags(0) +{ + system = _system; +} + + +PlanetarySystem* Body::getSystem() const +{ + return system; +} + + +string Body::getName() const +{ + return name; +} + + +void Body::setName(const string _name) +{ + name = _name; +} + + +Orbit* Body::getOrbit() const +{ + return orbit; +} + + +void Body::setOrbit(Orbit* _orbit) +{ + if (orbit == NULL) + delete orbit; + orbit = _orbit; +} + + +float Body::getRadius() const +{ + return radius; +} + + +void Body::setRadius(float _radius) +{ + radius = _radius; +} + + +float Body::getMass() const +{ + return mass; +} + + +void Body::setMass(float _mass) +{ + mass = _mass; +} + + +float Body::getOblateness() const +{ + return oblateness; +} + + +void Body::setOblateness(float _oblateness) +{ + oblateness = _oblateness; +} + + +float Body::getObliquity() const +{ + return obliquity; +} + + +void Body::setObliquity(float _obliquity) +{ + obliquity = _obliquity; +} + + +float Body::getAlbedo() const +{ + return albedo; +} + + +void Body::setAlbedo(float _albedo) +{ + albedo = _albedo; +} + + +float Body::getRotationPeriod() const +{ + return rotationPeriod; +} + + +void Body::setRotationPeriod(float _rotationPeriod) +{ + rotationPeriod = _rotationPeriod; +} + + +Color Body::getColor() const +{ + return color; +} + + +void Body::setColor(Color _color) +{ + color = _color; +} + + +string Body::getTexture() const +{ + return texture; +} + + +void Body::setTexture(const string _texture) +{ + texture = _texture; +} + + +string Body::getMesh() const +{ + return mesh; +} + + +void Body::setMesh(const string _mesh) +{ + mesh = _mesh; +} + + +uint32 Body::getAppearanceFlags() const +{ + return appearanceFlags; +} + + +void Body::setAppearanceFlags(uint32 flags) +{ + appearanceFlags = flags; +} + + +bool Body::getAppearanceFlag(uint32 flag) const +{ + return (appearanceFlags & flag) != 0; +} + + +void Body::setAppearanceFlag(uint32 flag, bool on) +{ + appearanceFlags &= ~flag; + appearanceFlags |= on ? flag : 0; +} + + +const PlanetarySystem* Body::getSatellites() const +{ + return satellites; +} + +void Body::setSatellites(PlanetarySystem* ssys) +{ + satellites = ssys; +} + + +RingSystem* Body::getRings() const +{ + return rings; +} + +void Body::setRings(RingSystem& _rings) +{ + if (rings == NULL) + rings = new RingSystem(_rings); + else + *rings = _rings; +} + + +// Get a matrix which converts from local to heliocentric coordinates +Mat4d Body::getLocalToHeliocentric(double when) +{ + Point3d pos = orbit->positionAtTime(when); + Mat4d frame = Mat4d::xrotation(-obliquity) * Mat4d::translation(pos); + + // Recurse up the hierarchy . . . + if (system != NULL && system->getPrimaryBody() != NULL) + frame = frame * system->getPrimaryBody()->getLocalToHeliocentric(when); + + return frame; +} + + +// Return the position of the center of the body in heliocentric coordinates +Point3d Body::getHeliocentricPosition(double when) +{ + return Point3d(0.0, 0.0, 0.0) * getLocalToHeliocentric(when); +} + + +#define SOLAR_IRRADIANCE 1367.6 +#define SOLAR_POWER 3.8462e26 + +float Body::getLuminosity(const Star& sun, + float distanceFromSun) const +{ + // Compute the total power of the star in Watts + double power = SOLAR_POWER * sun.getLuminosity(); + + // Compute the irradiance at a distance of 1au from the star in W/m^2 + double irradiance = power / sphereArea(astro::AUtoKilometers(1.0) * 1000); + + // Compute the irradiance at the body's distance from the star + double satIrradiance = power / sphereArea(distanceFromSun * 1000); + + // Compute the total energy hitting the planet + double incidentEnergy = satIrradiance * circleArea(radius * 1000); + + double reflectedEnergy = incidentEnergy * albedo; + + // Compute the luminosity (i.e. power relative to solar power) + return (float) (reflectedEnergy / SOLAR_POWER); +} + + +float Body::getApparentMagnitude(const Star& sun, + float distanceFromSun, + float distanceFromViewer) const +{ + return astro::lumToAppMag(getLuminosity(sun, distanceFromSun), + astro::kilometersToLightYears(distanceFromViewer)); +} + + +// Return the apparent magnitude of the body, corrected for the phase. +float Body::getApparentMagnitude(const Star& sun, + const Vec3d& sunPosition, + const Vec3d& viewerPosition) const +{ + double distanceToViewer = viewerPosition.length(); + double distanceToSun = sunPosition.length(); + float illuminatedFraction = (float) (1.0 + (viewerPosition / distanceToViewer) * + (sunPosition / distanceToSun)) / 2.0; + + return astro::lumToAppMag(getLuminosity(sun, distanceToSun) * illuminatedFraction, + astro::kilometersToLightYears(distanceToViewer)); +} + + + +/**** Implementation of PlanetarySystem ****/ + +PlanetarySystem::PlanetarySystem(Body* _primary) : primary(_primary) +{ + if (primary != NULL && primary->getSystem() != NULL) + starNumber = primary->getSystem()->getStarNumber(); + else + starNumber = Star::InvalidStar; +} + +PlanetarySystem::PlanetarySystem(uint32 _starNumber) : + primary(NULL), starNumber(_starNumber) +{ +} + + +Body* PlanetarySystem::find(string _name, bool deepSearch) const +{ + for (int i = 0; i < satellites.size(); i++) + { + if (satellites[i]->getName() == _name) + { + return satellites[i]; + } + else if (deepSearch && satellites[i]->getSatellites() != NULL) + { + Body* body = satellites[i]->getSatellites()->find(_name, deepSearch); + if (body != NULL) + return body; + } + } + + return NULL; +} + + +bool PlanetarySystem::traverse(TraversalFunc func, void* info) const +{ + for (int i = 0; i < getSystemSize(); i++) + { + Body* body = getBody(i); + // assert(body != NULL); + if (!func(body, info)) + return false; + if (body->getSatellites() != NULL) + { + if (!body->getSatellites()->traverse(func, info)) + return false; + } + } + + return true; +} + diff --git a/src/body.h b/src/body.h new file mode 100644 index 00000000..1d2b0c56 --- /dev/null +++ b/src/body.h @@ -0,0 +1,144 @@ +// body.h +// +// Copyright (C) 2001 Chris Laurel + +#ifndef _BODY_H_ +#define _BODY_H_ + +#include +#include +#include "color.h" +#include "orbit.h" +#include "star.h" + + +class Body; + +class PlanetarySystem +{ + public: + PlanetarySystem(Body* _primary); + PlanetarySystem(uint32 _starNumber); + + uint32 getStarNumber() const { return starNumber; }; + Body* getPrimaryBody() const { return primary; }; + int getSystemSize() const { return satellites.size(); }; + Body* getBody(int i) const { return satellites[i]; }; + void addBody(Body* body) { satellites.insert(satellites.end(), body); }; + + enum TraversalResult + { + ContinueTraversal = 0, + StopTraversal = 1 + }; + + typedef bool (*TraversalFunc)(Body*, void*); + + bool traverse(TraversalFunc, void*) const; + Body* find(std::string, bool deepSearch = false) const; + + private: + uint32 starNumber; + Body* primary; + std::vector satellites; +}; + + +class RingSystem +{ + public: + float innerRadius; + float outerRadius; + Color color; + + RingSystem(float inner, float outer) : + innerRadius(inner), outerRadius(outer), color(1.0f, 1.0f, 1.0f) + { } + RingSystem(float inner, float outer, Color _color) : + innerRadius(inner), outerRadius(outer), color(_color) + { } +}; + + +class Body +{ + public: + Body(PlanetarySystem*); + + PlanetarySystem* getSystem() const; + std::string getName() const; + void setName(const std::string); + Orbit* getOrbit() const; + void setOrbit(Orbit*); + float getRadius() const; + void setRadius(float); + float getMass() const; + void setMass(float); + float getOblateness() const; + void setOblateness(float); + float getObliquity() const; + void setObliquity(float); + float getAlbedo() const; + void setAlbedo(float); + float getRotationPeriod() const; + void setRotationPeriod(float); + + const PlanetarySystem* getSatellites() const; + void setSatellites(PlanetarySystem*); + + RingSystem* getRings() const; + void setRings(RingSystem&); + + void setColor(Color); + Color getColor() const; + void setTexture(std::string); + std::string getTexture() const; + void setMesh(std::string); + std::string getMesh() const; + void setAppearanceFlags(uint32); + uint32 getAppearanceFlags() const; + void setAppearanceFlag(uint32, bool); + bool getAppearanceFlag(uint32) const; + + float getLuminosity(const Star& sun, + float distanceFromSun) const; + float getApparentMagnitude(const Star& sun, + float distanceFromSun, + float distanceFromViewer) const; + float getApparentMagnitude(const Star& sun, + const Vec3d& sunPosition, + const Vec3d& viewerPosition) const; + + Mat4d getLocalToHeliocentric(double when); + Point3d getHeliocentricPosition(double when); + + // Appearance flags + enum { + BlendTexture = 1, + }; + + private: + std::string name; + + PlanetarySystem* system; + Orbit* orbit; + + float radius; + float mass; + float oblateness; + float obliquity; // aka 'axial tilt' + float albedo; + float rotationPeriod; + + Color color; + std::string texture; + std::string mesh; + uint32 appearanceFlags; + + RingSystem* rings; + + PlanetarySystem* satellites; +}; + +#endif // _BODY_H_ + diff --git a/src/celestia.h b/src/celestia.h new file mode 100644 index 00000000..68a8d691 --- /dev/null +++ b/src/celestia.h @@ -0,0 +1,28 @@ +// celestia.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _CELESTIA_H_ +#define _CELESTIA_H_ + +#if _MSC_VER >= 1000 +// Make VC shut up about long variable names from templates +#pragma warning(disable : 4786) +#endif // _MSC_VER + +#ifndef DEBUG +#define DPRINTF // +#else +#define DPRINTF DebugPrint +extern void DebugPrint(char *format, ...); +#endif + +extern void Log(char *format, ...); + +#endif // _CELESTIA_H_ + diff --git a/src/color.cpp b/src/color.cpp new file mode 100644 index 00000000..09e73f48 --- /dev/null +++ b/src/color.cpp @@ -0,0 +1,53 @@ +// color.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 "mathlib.h" +#include "color.h" + + +Color::Color() +{ + c[Red] = c[Green] = c[Blue] = 0; + c[Alpha] = 0xff; +} + + +Color::Color(float r, float g, float b) +{ + c[Red] = (unsigned char) (clamp(r) * 255.99f); + c[Green] = (unsigned char) (clamp(g) * 255.99f); + c[Blue] = (unsigned char) (clamp(b) * 255.99f); + c[Alpha] = 0xff; +} + + +Color::Color(float r, float g, float b, float a) +{ + c[Red] = (unsigned char) (clamp(r) * 255.99f); + c[Green] = (unsigned char) (clamp(g) * 255.99f); + c[Blue] = (unsigned char) (clamp(b) * 255.99f); + c[Alpha] = (unsigned char) (clamp(a) * 255.99f); +} + + +Color::Color(unsigned char r, unsigned char g, unsigned char b) +{ + c[Red] = r; + c[Green] = g; + c[Blue] = b; + c[Alpha] = 0xff; +} + + +Color::Color(Color& color, float alpha) +{ + *this = color; + c[Alpha] = (unsigned char) (clamp(alpha) * 255.99f); +} + diff --git a/src/color.h b/src/color.h new file mode 100644 index 00000000..af89be2d --- /dev/null +++ b/src/color.h @@ -0,0 +1,60 @@ +// color.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _COLOR_H_ +#define _COLOR_H_ + +class Color +{ + public: + Color(); + Color(float, float, float); + Color(float, float, float, float); + Color(unsigned char, unsigned char, unsigned char); + Color(Color&, float); + + enum { + Red = 0, + Green = 1, + Blue = 2, + Alpha = 3 + }; + + inline float red() const; + inline float green() const; + inline float blue() const; + inline float alpha() const; + + private: + unsigned char c[4]; +}; + + +float Color::red() const +{ + return c[Red] * (1.0f / 255.0f); +} + +float Color::green() const +{ + return c[Green] * (1.0f / 255.0f); +} + +float Color::blue() const +{ + return c[Blue] * (1.0f / 255.0f); +} + +float Color::alpha() const +{ + return c[Alpha] * (1.0f / 255.0f); +} + +#endif // _COLOR_H_ + diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 00000000..14bb4eac --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,121 @@ +// config.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include +#include "celestia.h" +#include "parser.h" +#include "config.h" + +using namespace std; + + +CelestiaConfig* ReadCelestiaConfig(string filename) +{ + ifstream configFile(filename.c_str()); + if (!configFile.good()) + { + DPRINTF("Error opening config file."); + return NULL; + } + + Tokenizer tokenizer(&configFile); + Parser parser(&tokenizer); + + if (tokenizer.nextToken() != Tokenizer::TokenName) + { + DPRINTF("%s:%d 'Configuration' expected.\n", filename.c_str(), + tokenizer.getLineNumber()); + return NULL; + } + + if (tokenizer.getStringValue() != "Configuration") + { + DPRINTF("%s:%d 'Configuration' expected.\n", filename.c_str(), + tokenizer.getLineNumber()); + return NULL; + } + + Value* configParamsValue = parser.readValue(); + if (configParamsValue == NULL || configParamsValue->getType() != Value::HashType) + { + DPRINTF("%s: Bad configuration file.\n", filename.c_str()); + return NULL; + } + + Hash* configParams = configParamsValue->getHash(); + + CelestiaConfig* config = new CelestiaConfig(); + + configParams->getString("StarDatabase", config->starDatabaseFile); + configParams->getString("StarNameDatabase", config->starNamesFile); + + Value* solarSystemsVal = configParams->getValue("SolarSystemCatalogs"); + if (solarSystemsVal != NULL) + { + if (solarSystemsVal->getType() != Value::ArrayType) + { + DPRINTF("%s: SolarSystemCatalogs must be an array.\n", filename.c_str()); + } + else + { + Array* solarSystems = solarSystemsVal->getArray(); + // assert(solarSystems != NULL); + + for (Array::iterator iter = solarSystems->begin(); iter != solarSystems->end(); iter++) + { + Value* catalogNameVal = *iter; + // assert(catalogNameVal != NULL); + if (catalogNameVal->getType() == Value::StringType) + { + config->solarSystemFiles.insert(config->solarSystemFiles.end(), + catalogNameVal->getString()); + } + else + { + DPRINTF("%s: Solar system catalog name must be a string.\n", + filename.c_str()); + } + } + } + } + + Value* labelledStarsVal = configParams->getValue("LabelledStars"); + if (labelledStarsVal != NULL) + { + if (labelledStarsVal->getType() != Value::ArrayType) + { + DPRINTF("%s: LabelledStars must be an array.\n", filename.c_str()); + } + else + { + Array* labelledStars = labelledStarsVal->getArray(); + // assert(labelledStars != NULL); + + for (Array::iterator iter = labelledStars->begin(); iter != labelledStars->end(); iter++) + { + Value* starNameVal = *iter; + // assert(starNameVal != NULL); + if (starNameVal->getType() == Value::StringType) + { + config->labelledStars.insert(config->labelledStars.end(), + starNameVal->getString()); + } + else + { + DPRINTF("%s: Star name must be a string.\n", filename.c_str()); + } + } + } + } + + delete configParamsValue; + + return config; +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 00000000..0a1b854f --- /dev/null +++ b/src/config.h @@ -0,0 +1,23 @@ +// config.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include + +struct CelestiaConfig +{ + std::string starDatabaseFile; + std::string starNamesFile; + std::vector solarSystemFiles; + std::vector labelledStars; +}; + + +CelestiaConfig* ReadCelestiaConfig(string filename); + diff --git a/src/console.cpp b/src/console.cpp new file mode 100644 index 00000000..b6f62b56 --- /dev/null +++ b/src/console.cpp @@ -0,0 +1,254 @@ +// console.cpp +// +// Copyright (C) 2000, Chris Laurel +// +// Text console class for OpenGL + +#include +#include +#include +#include +#include "gl.h" +#include "texfont.h" +#include "console.h" + +using namespace std; + + +Console::Console(int rows, int cols) : + ostream(&sbuf), + nRows(rows), + nColumns(cols), + cursorRow(0), + cursorColumn(0), + font(NULL), + xscale(1.0f), + yscale(1.0f) +{ + text = new char*[nRows]; + for (int i = 0; i < nRows; i++) + text[i] = new char[nColumns]; + clear(); + sbuf.setConsole(this); +} + + +Console::~Console() +{ + if (text != NULL) + { + for (int i = 0; i < nRows; i++) + { + if (text[i] != NULL) + delete[] text[i]; + } + delete[] text; + } +} + + +#if 0 +Console& Console::operator<<(string s) +{ + int len = s.length(); + for (int i = 0; i < len; i++) + print(s[i]); + + return *this; +} +#endif + + +void Console::setFont(TexFont* _font) +{ + font = _font; +} + + +TexFont* Console::getFont() +{ + return font; +} + + +void Console::setScale(float _xscale, float _yscale) +{ + xscale = _xscale; + yscale = _yscale; +} + + +void Console::clear() +{ + for (int i = 0; i < nRows; i++) + memset(text[i], '\0', nColumns); +} + + +void Console::home() +{ + cursorColumn = 0; + cursorRow = 0; +} + + +void Console::scrollUp() +{ + for (int i = 1; i < nRows; i++) + { + strcpy(text[i - 1], text[i]); + } + memset(text[nRows - 1], '\0', nColumns); +} + + +void Console::scrollDown() +{ + for (int i = nRows - 1; i > 0; i++) + { + strcpy(text[i], text[i - 1]); + } + memset(text[0], '\0', nColumns); +} + + +void Console::cursorRight() +{ + if (cursorColumn < nColumns - 1) + cursorColumn++; +} + + +void Console::cursorLeft() +{ + if (cursorColumn > 0) + cursorColumn--; +} + + +void Console::CR() +{ + cursorColumn = 0; +} + + +void Console::LF() +{ + cursorRow++; + if (cursorRow == nRows) + { + cursorRow--; + scrollUp(); + } +} + + +void Console::setCharAt(char c, int row, int col) +{ + if (row >= 0 && row < nRows && col >= 0 && col < nColumns) + text[row][col] = c; +} + + +void Console::print(char c) +{ + switch (c) + { + case '\n': + CR(); + LF(); + break; + case '\r': + CR(); + break; + case '\b': + cursorLeft(); + break; + default: + text[cursorRow][cursorColumn] = c; + cursorRight(); + break; + } +} + + +void Console::print(char* s) +{ + while (*s != '\0') + print(*s++); +} + + +void Console::printf(char* format, ...) +{ + va_list args; + va_start(args, format); + + char buf[1024]; + vsprintf(buf, format, args); + print(buf); + + va_end(args); +} + + +void Console::render() +{ + float width = 1.8f; + float height = 1.8f; + float top = 0.9f; + float left = -0.9f; + float aspectRatio = 4.0f / 3.0f; + float charHeight = height / (float) nRows; + float charWidth = charHeight / aspectRatio / 2.0f; + float scale = 0.005f; + + if (font == NULL) + return; + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, font->texobj); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(-1, 0.9f, -1); + glScalef(xscale, yscale, 1); + + for (int i = 0; i < nRows; i++) + { + float x = left; + char* s = text[i]; + + glPushMatrix(); + while (*s != '\0') + { + txfRenderGlyph(font, *s); + s++; + } + glPopMatrix(); + glTranslatef(0, -(1 + font->max_ascent + font->max_descent), 0); + } + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); +} + + +ConsoleStreamBuf::setConsole(Console* c) +{ + console = c; +} + +int ConsoleStreamBuf::overflow(int c) +{ + if (console != NULL) + console->print((char) c); + return c; +} diff --git a/src/console.h b/src/console.h new file mode 100644 index 00000000..f1477e1a --- /dev/null +++ b/src/console.h @@ -0,0 +1,95 @@ +// console.h +// +// Copyright (C) 2001, Chris Laurel +// +// Text console class for OpenGL. The console supports both printf +// and C++ operator style mechanisms for output. +// +// 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. + +#ifndef _CONSOLE_H_ +#define _CONSOLE_H_ + +#include +#include +#include "gl.h" +#include "texfont.h" + +using namespace std; + + +class Console; + +// Custom streambuf class to support C++ operator style output. The +// output is completely unbuffered so that it can coexist with printf +// style output which the Console class also supports. +class ConsoleStreamBuf : public std::streambuf +{ + public: + ConsoleStreamBuf() : console(NULL) { setbuf(0, 0); }; + + setConsole(Console*); + + int overflow(int c = EOF); + + private: + Console* console; +}; + + +class Console : public std::ostream +{ + public: + Console(int rows, int cols); + ~Console(); + + void setFont(TexFont*); + TexFont* getFont(); + + void setScale(float, float); + + void render(); + void clear(); + void home(); + void scrollUp(); + void scrollDown(); + void cursorRight(); + void cursorLeft(); + void CR(); + void LF(); + + inline void setChar(char c); + void setCharAt(char c, int row, int col); + + void print(char); + void print(char*); + void printf(char*, ...); + + // Console& operator<<(string); + + private: + int nRows; + int nColumns; + char** text; + + TexFont* font; + + int cursorRow; + int cursorColumn; + + float xscale, yscale; + + ConsoleStreamBuf sbuf; +}; + + +void Console::setChar(char c) +{ + text[cursorRow][cursorColumn] = c; +} + + +#endif // _CONSOLE_H_ diff --git a/src/constellation.cpp b/src/constellation.cpp new file mode 100644 index 00000000..9e46162e --- /dev/null +++ b/src/constellation.cpp @@ -0,0 +1,165 @@ +// constellation.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include "celestia.h" +#include "constellation.h" + +using namespace std; + + +struct Constellation_s { + char *name; + char *gen; + char *abbr; +}; + +static struct Constellation_s constellationInfo[] = { + { "Aries", "Arietis", "Ari" }, + { "Taurus", "Tauri", "Tau" }, + { "Gemini", "Geminorum", "Gem" }, + { "Cancer", "Cancri", "Cnc" }, + { "Leo", "Leonis", "Leo" }, + { "Virgo", "Virginis", "Vir" }, + { "Libra", "Librae", "Lib" }, + { "Scorpius", "Scorpii", "Sco" }, + { "Sagittarius", "Sagittarii", "Sgr" }, + { "Capricornus", "Capricornii", "Cap" }, + { "Aquarius", "Aquarii", "Aqr" }, + { "Pisces", "Piscium", "Psc" }, + { "Ursa Major", "Ursae Majoris", "UMa" }, + { "Ursa Minor", "Ursae Minoris", "UMi" }, + { "Bootes", "Bootis", "Boo" }, + { "Orion", "Orionis", "Ori" }, + { "Canis Major", "Canis Majoris", "CMa" }, + { "Canis Minor", "Canis Minoris", "CMi" }, + { "Lepus", "Leporis", "Lep" }, + { "Perseus", "Persei", "Per" }, + { "Andromeda", "Andromedae", "And" }, + { "Cassiopeia", "Cassiopeiae", "Cas" }, + { "Cepheus", "Cephei", "Cep" }, + { "Cetus", "Ceti", "Cet" }, + { "Pegasus", "Pegasi", "Peg" }, + { "Carina", "Carinae", "Car" }, + { "Puppis", "Puppis", "Pup" }, + { "Vela", "Velorum", "Vel" }, + { "Hercules", "Herculis", "Her" }, + { "Hydra", "Hydrae", "Hya" }, + { "Centaurus", "Centauri", "Cen" }, + { "Lupus", "Lupi", "Lup" }, + { "Ara", "Arae", "Ara" }, + { "Ophiuchus", "Ophiuchi", "Oph" }, + { "Serpens", "Serpentis", "Ser" }, + { "Aquila", "Aquilae", "Aql" }, + { "Auriga", "Aurigae", "Aur" }, + { "Corona Australis", "Coronae Australis", "CrA" }, + { "Corona Borealias", "Coronae Borealis", "CrB" }, + { "Corvus", "Corvi", "Crv" }, + { "Crater", "Crateris", "Crt" }, + { "Cygnus", "Cyngi", "Cyg" }, + { "Delphinus", "Delphini", "Del" }, + { "Draco", "Draconis", "Dra" }, + { "Equuleus", "Equulei", "Equ" }, + { "Eridanus", "Eridani", "Eri" }, + { "Lyra", "Lyrae", "Lyr" }, + { "Piscis Austrinus", "Piscis Austrini", "PsA" }, + { "Sagitta", "Sagittae", "Sge" }, + { "Triangulum", "Trianguli", "Tri" }, + { "Antlia", "Antliae", "Ant" }, + { "Apus", "Apodis", "Aps" }, + { "Caelum", "Caeli", "Cae" }, + { "Camelopardalis", "Camelopardalis", "Cam" }, + { "Canes Venatici", "Canum Venaticorum", "CVn" }, + { "Chamaeleon", "Chamaeleontis", "Cha" }, + { "Circinus", "Circini", "Cir" }, + { "Columba", "Columbae", "Col" }, + { "Coma Berenices", "Comae Berenices", "Com" }, + { "Crux", "Crucis", "Cru" }, + { "Dorado", "Doradus", "Dor" }, + { "Fornax", "Fornacis", "For" }, + { "Grus", "Gruis", "Gru" }, + { "Horologium", "Horologii", "Hor" }, + { "Hydrus", "Hydri", "Hyi" }, + { "Indus", "Indi", "Ind" }, + { "Lacerta", "Lacertae", "Lac" }, + { "Leo Minor", "Leonis Minoris", "LMi" }, + { "Lynx", "Lyncis", "Lyn" }, + { "Microscopium", "Microscopii", "Mic" }, + { "Monoceros", "Monocerotis", "Mon" }, + { "Mensa", "Mensae", "Men" }, + { "Musca", "Muscae", "Mus" }, + { "Norma", "Normae", "Nor" }, + { "Octans", "Octantis", "Oct" }, + { "Pavo", "Pavonis", "Pav" }, + { "Phoenix", "Phoenicis", "Phe" }, + { "Pictor", "Pictoris", "Pic" }, + { "Pyxis", "Pyxidis", "Pyx" }, + { "Reticulum", "Reticuli", "Ret" }, + { "Sculptor", "Sculptoris", "Scl" }, + { "Scutum", "Scuti", "Sct" }, + { "Sextans", "Sextantis", "Sex" }, + { "Telescopium", "Telescopii", "Tel" }, + { "Triangulum Australe", "Trianguli Australis", "TrA" }, + { "Tucana", "Tucanae", "Tuc" }, + { "Volans", "Volantis", "Vol" }, + { "Vulpecula", "Vulpeculae", "Vul" } +}; + +static Constellation **constellations = NULL; + + +Constellation::Constellation(char *_name, char *_genitive, char *_abbrev) +{ + name = string(_name); + genitive = string(_genitive); + abbrev = string(_abbrev); +} + +Constellation *Constellation::getConstellation(unsigned int n) +{ + if (constellations == NULL) + initialize(); + + if (constellations == NULL || + n >= sizeof(constellationInfo) / sizeof(constellationInfo[0])) + return NULL; + else + return constellations[n]; +} + +string Constellation::getName() +{ + return name; +} + +string Constellation::getGenitive() +{ + return genitive; +} + +string Constellation::getAbbreviation() +{ + return abbrev; +} + +void Constellation::initialize() +{ + int nConstellations = sizeof(constellationInfo) / sizeof(constellationInfo[0]); + constellations = new Constellation* [nConstellations]; + + if (constellations != NULL) + { + for (int i = 0; i < nConstellations; i++) + { + constellations[i] = new Constellation(constellationInfo[i].name, + constellationInfo[i].gen, + constellationInfo[i].abbr); + } + } +} diff --git a/src/constellation.h b/src/constellation.h new file mode 100644 index 00000000..4d3d96c0 --- /dev/null +++ b/src/constellation.h @@ -0,0 +1,34 @@ +// constellation.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _CONSTELLATION_H_ +#define _CONSTELLATION_H_ +#include + +class Constellation +{ +public: + static Constellation *getConstellation(unsigned int); + + std::string getName(); + std::string getGenitive(); + std::string getAbbreviation(); + +private: + Constellation(char *_name, char *_genitive, char *_abbrev); + static void initialize(); + + std::string name; + std::string genitive; + std::string abbrev; +}; + +#endif // _CONSTELLATION_H_ + + diff --git a/src/debug.cpp b/src/debug.cpp new file mode 100644 index 00000000..95760b31 --- /dev/null +++ b/src/debug.cpp @@ -0,0 +1,42 @@ +// debug.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifdef _MSC_VER +#include +#endif +#include +#include + + +void DebugPrint(char *format, ...) +{ + va_list args; + va_start(args, format); + +#ifdef _MSC_VER + char buf[1024]; + vsprintf(buf, format, args); + OutputDebugString(buf); +#else + vfprintf(stderr, format, args); +#endif + + va_end(args); +} + + +void Log(char *format, ...) +{ + va_list args; + va_start(args, format); + + vfprintf(stdout, format, args); + + va_end(args); +} diff --git a/src/dispmap.cpp b/src/dispmap.cpp new file mode 100644 index 00000000..aeef8a68 --- /dev/null +++ b/src/dispmap.cpp @@ -0,0 +1,44 @@ +// dispmap.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 "dispmap.h" + + +DisplacementMap::DisplacementMap(int w, int h) : + width(w), height(h), disp(NULL) +{ + disp = new float[width * height]; +} + +DisplacementMap::~DisplacementMap() +{ + if (disp != NULL) + delete[] disp; +} + + +void DisplacementMap::clear() +{ + int size = width * height; + for (int i = 0; i < size; i++) + disp[i] = 0.0f; +} + + +void DisplacementMap::generate(DisplacementMapFunc func, void* info) +{ + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + disp[i * width + j] = func((float) j / (float) width, + (float) i / (float) height, info); + } + } +} diff --git a/src/dispmap.h b/src/dispmap.h new file mode 100644 index 00000000..86c6c4ba --- /dev/null +++ b/src/dispmap.h @@ -0,0 +1,50 @@ +// dispmap.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _DISPMAP_H_ +#define _DISPMAP_H_ + +#include +#include "vecmath.h" + + +typedef float (*DisplacementMapFunc)(float, float, void*); + +class DisplacementMap +{ + public: + DisplacementMap(int w, int h); + ~DisplacementMap(); + int getWidth() const { return width; }; + int getHeight() const { return height; }; + inline float getDisplacement(int x, int y) const; + inline void setDisplacement(int x, int y, float d); + void generate(DisplacementMapFunc func, void* info = NULL); + void clear(); + + private: + int width; + int height; + float* disp; +}; + +// extern DisplacementMap* LoadDisplacementMap(std::string filename); + + +float DisplacementMap::getDisplacement(int x, int y) const +{ + return disp[y * width + x]; +} + +void DisplacementMap::setDisplacement(int x, int y, float d) +{ + disp[y * width + x] = d; +} + +#endif // _DISPMAP_H_ diff --git a/src/filetype.cpp b/src/filetype.cpp new file mode 100644 index 00000000..6f7ac4bd --- /dev/null +++ b/src/filetype.cpp @@ -0,0 +1,62 @@ +// filetype.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include "filetype.h" + +using namespace std; + + +static const string JPEGExt(".jpg"); +static const string BMPExt(".bmp"); +static const string TargaExt(".tga"); +static const string ThreeDSExt(".3ds"); +static const string CelestiaTextureExt(".ctx"); +static const string CelestiaMeshExt(".cms"); + + +static int compareIgnoringCase(const string& s1, const string& s2) +{ + string::const_iterator i1 = s1.begin(); + string::const_iterator i2 = s2.begin(); + + while (i1 != s1.end() && i2 != s2.end()) + { + if (toupper(*i1) != toupper(*i2)) + return (toupper(*i1) < toupper(*i2)) ? -1 : 1; + ++i1; + ++i2; + } + + return s2.size() - s1.size(); +} + + +ContentType DetermineFileType(const string& filename) +{ + int extPos = filename.length() - 4; + if (extPos < 0) + extPos = 0; + string ext = string(filename, extPos, 4); + + if (compareIgnoringCase(JPEGExt, ext) == 0) + return Content_JPEG; + else if (compareIgnoringCase(BMPExt, ext) == 0) + return Content_BMP; + else if (compareIgnoringCase(TargaExt, ext) == 0) + return Content_Targa; + else if (compareIgnoringCase(ThreeDSExt, ext) == 0) + return Content_3DStudio; + else if (compareIgnoringCase(CelestiaTextureExt, ext) == 0) + return Content_CelestiaTexture; + else if (compareIgnoringCase(CelestiaMeshExt, ext) == 0) + return Content_CelestiaMesh; + else + return Content_Unknown; +} diff --git a/src/filetype.h b/src/filetype.h new file mode 100644 index 00000000..4027abd3 --- /dev/null +++ b/src/filetype.h @@ -0,0 +1,28 @@ +// filetype.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _FILETYPE_H_ +#define _FILETYPE_H_ + +#include + +enum ContentType { + Content_JPEG, + Content_BMP, + Content_GIF, + Content_Targa, + Content_CelestiaTexture, + Content_3DStudio, + Content_CelestiaMesh, + Content_Unknown +}; + +ContentType DetermineFileType(const std::string& filename); + +#endif // _FILETYPE_H_ diff --git a/src/gl.h b/src/gl.h new file mode 100644 index 00000000..dbd6bbed --- /dev/null +++ b/src/gl.h @@ -0,0 +1,32 @@ +// gl.h +// +// Why is this file necessary? Because Microsoft requires us to include +// windows.h before including the GL headers, even though GL is a +// cross-platform API. So, we encapsulate the resulting ifdef nonsense +// in this file. +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _GL_H_ +#define _GL_H_ + +#ifdef _MSC_VER +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include +#endif // _MSC_VER + +#include +#include + +#endif // _GL_H_ + diff --git a/src/glext.cpp b/src/glext.cpp new file mode 100644 index 00000000..aedd7fd7 --- /dev/null +++ b/src/glext.cpp @@ -0,0 +1,228 @@ +// glext.cpp + +#include +#include "gl.h" +#include "glext.h" + + +// ARB_texture_compression +PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glCompressedTexImage3DARB; +PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; +PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glCompressedTexImage1DARB; +PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glCompressedTexSubImage3DARB; +PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glCompressedTexSubImage2DARB; +PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glCompressedTexSubImage1DARB; + +// ARB_multitexture command function pointers +PFNGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB; +PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB; +PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB; +PFNGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB; +PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; +PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; + +// NV_register_combiners command function pointers +PFNGLCOMBINERPARAMETERFVNVPROC glCombinerParameterfvNV; +PFNGLCOMBINERPARAMETERIVNVPROC glCombinerParameterivNV; +PFNGLCOMBINERPARAMETERFNVPROC glCombinerParameterfNV; +PFNGLCOMBINERPARAMETERINVPROC glCombinerParameteriNV; +PFNGLCOMBINERINPUTNVPROC glCombinerInputNV; +PFNGLCOMBINEROUTPUTNVPROC glCombinerOutputNV; +PFNGLFINALCOMBINERINPUTNVPROC glFinalCombinerInputNV; +PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC glGetCombinerInputParameterfvNV; +PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC glGetCombinerInputParameterivNV; +PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC glGetCombinerOutputParameterfvNV; +PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC glGetCombinerOutputParameterivNV; +PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC glGetFinalCombinerInputParameterfvNV; +PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC glGetFinalCombinerInputParameterivNV; + +// EXT_paletted_texture command function pointers +PFNGLCOLORTABLEEXTPROC glColorTableEXT; + +// WGL_EXT_swap_control command function pointers +PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; +PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; + +// extern void Alert(const char *szFormat, ...); + + +void Alert(const char *szFormat, ...) +{ +} + +#if 0 +// Check for required extensions and initialize them if present +bool InitGLExtensions(void) +{ +#if 0 + if (!extensionSupported("GL_EXT_bgra")) { + Alert("Required OpenGL extension GL_EXT_bgra not supported"); + return false; + } +#endif + + if (!extensionSupported("GL_ARB_multitexture")) { + Alert("Required OpenGL extension GL_ARB_multitexture not supported"); + return false; + } + +#if 0 + if (!extensionSupported("GL_EXT_texture_env_combine")) { + Alert("Required OpenGL extension GL_EXT_texture_env_combine not supported"); + return false; + } + + if (!extensionSupported("GL_NV_register_combiners")) { + Alert("Required OpenGL extension GL_NV_register_combiners not supported"); + return false; + } + + if (!extensionSupported("GL_EXT_texture_cube_map")) { + Alert("Required OpenGL extension GL_EXT_texture_cube_map not supported"); + return false; + } + + if (!extensionSupported("GL_EXT_separate_specular_color")) { + Alert("Required OpenGL extension GL_EXT_separate_specular_color not supported"); + return false; + } + + if (!extensionSupported("WGL_EXT_swap_control")) { + Alert("Required OpenGL extension WGL_EXT_swap_control not supported"); + return false; + } +#endif + + initMultiTexture(); +#if 0 + initRegisterCombiners(); + initSwapControl(); +#endif + + return true; +} +#endif + +// ARB_multitexture +void InitExtMultiTexture() +{ + glMultiTexCoord2iARB = + (PFNGLMULTITEXCOORD2IARBPROC) wglGetProcAddress("glMultiTexCoord2iARB"); + glMultiTexCoord2fARB = + (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB"); + glMultiTexCoord3fARB = + (PFNGLMULTITEXCOORD3FARBPROC) wglGetProcAddress("glMultiTexCoord3fARB"); + glMultiTexCoord3fvARB = + (PFNGLMULTITEXCOORD3FVARBPROC) wglGetProcAddress("glMultiTexCoord3fvARB"); + glActiveTextureARB = + (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB"); + glClientActiveTextureARB = + (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB"); +} + + +// ARB_texture_compression +void InitExtTextureCompression() +{ + glCompressedTexImage3DARB = + (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) + wglGetProcAddress("glCompressedTexImage3DARB"); + glCompressedTexImage2DARB = + (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) + wglGetProcAddress("glCompressedTexImage2DARB"); + glCompressedTexImage1DARB = + (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) + wglGetProcAddress("glCompressedTexImage1DARB"); + glCompressedTexSubImage3DARB = + (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) + wglGetProcAddress("glCompressedTexSubImage3DARB"); + glCompressedTexSubImage2DARB = + (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) + wglGetProcAddress("glCompressedTexSubImage2DARB"); + glCompressedTexSubImage1DARB = + (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) + wglGetProcAddress("glCompressedTexSubImage1DARB"); +} + + +// NV_register_combiners +void InitExtRegisterCombiners() +{ + /* Retrieve all NV_register_combiners routines. */ + glCombinerParameterfvNV = + (PFNGLCOMBINERPARAMETERFVNVPROC) + wglGetProcAddress("glCombinerParameterfvNV"); + glCombinerParameterivNV = + (PFNGLCOMBINERPARAMETERIVNVPROC) + wglGetProcAddress("glCombinerParameterivNV"); + glCombinerParameterfNV = + (PFNGLCOMBINERPARAMETERFNVPROC) + wglGetProcAddress("glCombinerParameterfNV"); + glCombinerParameteriNV = + (PFNGLCOMBINERPARAMETERINVPROC) + wglGetProcAddress("glCombinerParameteriNV"); + glCombinerInputNV = + (PFNGLCOMBINERINPUTNVPROC) + wglGetProcAddress("glCombinerInputNV"); + glCombinerOutputNV = + (PFNGLCOMBINEROUTPUTNVPROC) + wglGetProcAddress("glCombinerOutputNV"); + glFinalCombinerInputNV = + (PFNGLFINALCOMBINERINPUTNVPROC) + wglGetProcAddress("glFinalCombinerInputNV"); + glGetCombinerInputParameterfvNV = + (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) + wglGetProcAddress("glGetCombinerInputParameterfvNV"); + glGetCombinerInputParameterivNV = + (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) + wglGetProcAddress("glGetCombinerInputParameterivNV"); + glGetCombinerOutputParameterfvNV = + (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) + wglGetProcAddress("glGetCombinerOutputParameterfvNV"); + glGetCombinerOutputParameterivNV = + (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) + wglGetProcAddress("glGetCombinerOutputParameterivNV"); + glGetFinalCombinerInputParameterfvNV = + (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) + wglGetProcAddress("glGetFinalCombinerInputParameterfvNV"); + glGetFinalCombinerInputParameterivNV = + (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) + wglGetProcAddress("glGetFinalCombinerInputParameterivNV"); +} + + +void InitExtPalettedTexture() +{ + // glColorTableEXT = (void *) wglGetProcAddress("glColorTableEXT"); +} + + +void InitExtSwapControl() +{ + wglSwapIntervalEXT = + (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT"); + wglGetSwapIntervalEXT = + (PFNWGLGETSWAPINTERVALEXTPROC) wglGetProcAddress("wglGetSwapIntervalEXT"); +} + + +bool ExtensionSupported(char *ext) +{ + char *extensions = (char *) glGetString(GL_EXTENSIONS); + + if (extensions == NULL) + return false; + + int len = strlen(ext); + for (;;) { + if (strncmp(extensions, ext, len) == 0) + return true; + extensions = strchr(extensions, ' '); + if (extensions != NULL) + extensions++; + else + break; + } + + return false; +} diff --git a/src/glext.h b/src/glext.h new file mode 100644 index 00000000..f2bc5003 --- /dev/null +++ b/src/glext.h @@ -0,0 +1,318 @@ +/* glext.h */ + +#ifndef _GLEXT_H_ +#define _GLEXT_H_ + +/* EXT_rescale_normal defines from */ +#ifndef GL_EXT_rescale_normal +#define GL_RESCALE_NORMAL_EXT 0x803A +#endif + +/* EXT_texture_edge_clamp defines from */ +#ifndef GL_EXT_texture_edge_clamp +#define GL_CLAMP_TO_EDGE_EXT 0x812F +#endif + +/* EXT_bgra defines from */ +#ifndef GL_EXT_bgra +#define GL_BGR_EXT 0x80E0 +#define GL_BGRA_EXT 0x80E1 +#endif + +/* GL_ARB_texture_compression */ +#ifndef GL_ARB_texture_compression +#define GL_ARB_texture_compression 1 + +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define GL_TEXTURE_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 + +#if 0 +extern void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +extern void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *); +extern void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *); +extern void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); +extern void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *); +extern void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *); +extern void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, void *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRY * PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img); +#endif + +/* GL_EXT_texture_compression_s3tc */ +#ifndef GL_EXT_texture_compression_s3tc +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif + +/* ARB_multitexture defines and prototypes from */ +#ifndef GL_ARB_multitexture +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +typedef void (APIENTRY * PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); +typedef void (APIENTRY * PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRY * PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRY * PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target); +typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum target); +#endif + +/* EXT_texture_cube_map defines from */ +#ifndef GL_EXT_texture_cube_map +#define GL_NORMAL_MAP_EXT 0x8511 +#define GL_REFLECTION_MAP_EXT 0x8512 +#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C +#endif + +/* EXT_separate_specular_color defines from */ +#ifndef GL_EXT_separate_specular_color +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif + +/* EXT_texture_env_combine defines from */ +#ifndef GL_EXT_texture_env_combine + +// Accepted by the parameter of TexEnvf, TexEnvi, TexEnvfv, +// and TexEnviv when the parameter value is TEXTURE_ENV_MODE +#define GL_COMBINE_EXT 0x8570 + +// Accepted by the parameter of TexEnvf, TexEnvi, TexEnvfv, +// and TexEnviv when the parameter value is TEXTURE_ENV +#define GL_COMBINE_RGB_EXT 0x8571 +#define GL_COMBINE_ALPHA_EXT 0x8572 +#define GL_SOURCE0_RGB_EXT 0x8580 +#define GL_SOURCE1_RGB_EXT 0x8581 +#define GL_SOURCE2_RGB_EXT 0x8582 +#define GL_SOURCE0_ALPHA_EXT 0x8588 +#define GL_SOURCE1_ALPHA_EXT 0x8589 +#define GL_SOURCE2_ALPHA_EXT 0x858A +#define GL_OPERAND0_RGB_EXT 0x8590 +#define GL_OPERAND1_RGB_EXT 0x8591 +#define GL_OPERAND2_RGB_EXT 0x8592 +#define GL_OPERAND0_ALPHA_EXT 0x8598 +#define GL_OPERAND1_ALPHA_EXT 0x8599 +#define GL_OPERAND2_ALPHA_EXT 0x859A +#define GL_RGB_SCALE_EXT 0x8573 + +// Accepted by the parameter of TexEnvf, TexEnvi, TexEnvfv, +// and TexEnviv when the parameter value is COMBINE_RGB_EXT +// or COMBINE_ALPHA_EXT +#define GL_ADD_SIGNED_EXT 0x8574 +#define GL_INTERPOLATE_EXT 0x8575 + +// Accepted by the parameter of TexEnvf, TexEnvi, TexEnvfv, +// and TexEnviv when the parameter value is SOURCE0_RGB_EXT, +// SOURCE1_RGB_EXT, SOURCE2_RGB_EXT, SOURCE0_ALPHA_EXT, +// SOURCE1_ALPHA_EXT, or SOURCE2_ALPHA_EXT +#define GL_CONSTANT_EXT 0x8576 +#define GL_PRIMARY_COLOR_EXT 0x8577 +#define GL_PREVIOUS_EXT 0x8578 + +#endif // GL_EXT_texture_env_combine + + +/* NV_register_combiners defines and prototypes from */ +#ifndef GL_NV_register_combiners +#define GL_REGISTER_COMBINERS_NV 0x8522 +#define GL_COMBINER0_NV 0x8550 +#define GL_COMBINER1_NV 0x8551 +#define GL_COMBINER2_NV 0x8552 +#define GL_COMBINER3_NV 0x8553 +#define GL_COMBINER4_NV 0x8554 +#define GL_COMBINER5_NV 0x8555 +#define GL_COMBINER6_NV 0x8556 +#define GL_COMBINER7_NV 0x8557 +#define GL_VARIABLE_A_NV 0x8523 +#define GL_VARIABLE_B_NV 0x8524 +#define GL_VARIABLE_C_NV 0x8525 +#define GL_VARIABLE_D_NV 0x8526 +#define GL_VARIABLE_E_NV 0x8527 +#define GL_VARIABLE_F_NV 0x8528 +#define GL_VARIABLE_G_NV 0x8529 +/* GL_ZERO */ +#define GL_CONSTANT_COLOR0_NV 0x852A +#define GL_CONSTANT_COLOR1_NV 0x852B +/* GL_FOG */ +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D +#define GL_SPARE0_NV 0x852E +#define GL_SPARE1_NV 0x852F +/* GL_TEXTURE0_ARB */ +/* GL_TEXTURE1_ARB */ +#define GL_UNSIGNED_IDENTITY_NV 0x8536 +#define GL_UNSIGNED_INVERT_NV 0x8537 +#define GL_EXPAND_NORMAL_NV 0x8538 +#define GL_EXPAND_NEGATE_NV 0x8539 +#define GL_HALF_BIAS_NORMAL_NV 0x853A +#define GL_HALF_BIAS_NEGATE_NV 0x853B +#define GL_SIGNED_IDENTITY_NV 0x853C +#define GL_SIGNED_NEGATE_NV 0x853D +#define GL_E_TIMES_F_NV 0x8531 +#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 +/* GL_NONE */ +#define GL_SCALE_BY_TWO_NV 0x853E +#define GL_SCALE_BY_FOUR_NV 0x853F +#define GL_SCALE_BY_ONE_HALF_NV 0x8540 +#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 +#define GL_DISCARD_NV 0x8530 +#define GL_COMBINER_INPUT_NV 0x8542 +#define GL_COMBINER_MAPPING_NV 0x8543 +#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 +#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 +#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 +#define GL_COMBINER_MUX_SUM_NV 0x8547 +#define GL_COMBINER_SCALE_NV 0x8548 +#define GL_COMBINER_BIAS_NV 0x8549 +#define GL_COMBINER_AB_OUTPUT_NV 0x854A +#define GL_COMBINER_CD_OUTPUT_NV 0x854B +#define GL_COMBINER_SUM_OUTPUT_NV 0x854C +#define GL_MAX_GENERAL_COMBINERS_NV 0x854D +#define GL_NUM_GENERAL_COMBINERS_NV 0x854E +#define GL_COLOR_SUM_CLAMP_NV 0x854F + +typedef void (APIENTRY * PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRY * PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRY * PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRY * PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRY * PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRY * PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +typedef void (APIENTRY * PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRY * PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRY * PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +typedef void (APIENTRY * PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +typedef void (APIENTRY * PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); +typedef void (APIENTRY * PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRY * PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); +#endif + +/* EXT_paletted_texture defines and prototypes from */ +#ifndef GL_EXT_paletted_texture +#define GL_COLOR_INDEX1_EXT 0x80E2 +#define GL_COLOR_INDEX2_EXT 0x80E3 +#define GL_COLOR_INDEX4_EXT 0x80E4 +#define GL_COLOR_INDEX8_EXT 0x80E5 +#define GL_COLOR_INDEX12_EXT 0x80E6 +#define GL_COLOR_INDEX16_EXT 0x80E7 +typedef void (APIENTRY * PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid * table); +PFNGLCOLORTABLEEXTPROC glColorTableEXT; +#endif + +/* WGL_EXT_swap_control defines and prototypes from */ +#ifndef WGL_EXT_swap_control +typedef int (APIENTRY * PFNWGLSWAPINTERVALEXTPROC) (int); +typedef int (APIENTRY * PFNWGLGETSWAPINTERVALEXTPROC) (void); +#endif + +/* OpenGL 1.2 defines and prototypes from */ +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif + +#ifdef _WIN32 + +/* ARB_texture_compression command function pointers */ +extern PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glCompressedTexImage3DARB; +extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; +extern PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glCompressedTexImage1DARB; +extern PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glCompressedTexSubImage3DARB; +extern PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glCompressedTexSubImage2DARB; +extern PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glCompressedTexSubImage1DARB; + +/* ARB_multitexture command function pointers */ +extern PFNGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB; +extern PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB; +extern PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB; +extern PFNGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB; +extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; +extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; + +/* NV_register_combiners command function pointers */ +extern PFNGLCOMBINERPARAMETERFVNVPROC glCombinerParameterfvNV; +extern PFNGLCOMBINERPARAMETERIVNVPROC glCombinerParameterivNV; +extern PFNGLCOMBINERPARAMETERFNVPROC glCombinerParameterfNV; +extern PFNGLCOMBINERPARAMETERINVPROC glCombinerParameteriNV; +extern PFNGLCOMBINERINPUTNVPROC glCombinerInputNV; +extern PFNGLCOMBINEROUTPUTNVPROC glCombinerOutputNV; +extern PFNGLFINALCOMBINERINPUTNVPROC glFinalCombinerInputNV; +extern PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC glGetCombinerInputParameterfvNV; +extern PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC glGetCombinerInputParameterivNV; +extern PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC glGetCombinerOutputParameterfvNV; +extern PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC glGetCombinerOutputParameterivNV; +extern PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC glGetFinalCombinerInputParameterfvNV; +extern PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC glGetFinalCombinerInputParameterivNV; + +/* EXT_paletted_texture command function pointers */ +extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; + +/* WGL_EXT_swap_control command function pointers */ +extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; +extern PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; + +#endif + +extern bool ExtensionSupported(char *ext); +extern void InitExtRegisterCombiners(); +extern void InitExtMultiTexture(); +extern void InitExtPalettedTextures(); +extern void InitExtSwapControl(); +extern void InitExtTextureCompression(); + +#endif // _GLEXT_H_ diff --git a/src/gui.cpp b/src/gui.cpp new file mode 100644 index 00000000..f707b919 --- /dev/null +++ b/src/gui.cpp @@ -0,0 +1,152 @@ +// gui.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 "gl.h" +#include "gui.h" + +using namespace std; +using namespace gui; + + +/**** GraphicsContext ****/ + +GraphicsContext::GraphicsContext() : + font(NULL) +{ +} + +TexFont* GraphicsContext::getFont() const +{ + return font; +} + +void GraphicsContext::setFont(TexFont* _font) +{ + font = _font; +} + + +/**** Component ****/ + +Component::Component() : + position(0, 0), + size(0, 0), + parent(NULL) +{ +} + +Point2f Component::getPosition() const +{ + return position; +} + +Vec2f Component::getSize() const +{ + return size; +} + +void Component::reshape(Point2f _position, Vec2f _size) +{ + position = _position; + size = _size; +} + +Component* Component::getParent() const +{ + return parent; +} + +void Component::setParent(Component* c) +{ + parent = c; +} + + +/**** Container ****/ + +Container::Container() : Component() +{ +} + +int Container::getComponentCount() const +{ + return components.size(); +} + +Component* Container::getComponent(int n) const +{ + if (n >= 0 && n < components.size()) + return components[n]; + else + return NULL; +} + +void Container::addComponent(Component* c) +{ + // ASSERT(c->getParent() == NULL) + components.insert(components.end(), c); + c->setParent(this); +} + +void Container::render(GraphicsContext& gc) +{ + glPushMatrix(); + glTranslatef(getPosition().x, getPosition().y, 0); + vector::iterator iter = components.begin(); + while (iter != components.end()) + { + (*iter)->render(gc); + iter++; + } + glPopMatrix(); +} + + +/**** Button ****/ + +Button::Button(string _label) : label(_label) +{ +} + +string Button::getLabel() const +{ + return label; +} + +void Button::setLabel(string _label) +{ + label = _label; +} + +void Button::render(GraphicsContext& gc) +{ + glBegin(GL_LINE_LOOP); + Point2f pos = getPosition(); + Vec2f sz = getSize(); + glVertex3f(pos.x, pos.y, 0); + glVertex3f(pos.x + sz.x, pos.y, 0); + glVertex3f(pos.x + sz.x, pos.y + sz.y, 0); + glVertex3f(pos.x, pos.y + sz.y, 0); + glEnd(); + + int maxAscent = 0, maxDescent = 0, stringWidth = 0; + txfGetStringMetrics(gc.getFont(), label, + stringWidth, maxAscent, maxDescent); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, gc.getFont()->texobj); + glPushMatrix(); + glTranslatef(pos.x + (sz.x - stringWidth) / 2, + pos.y + (sz.y - (maxDescent)) / 2, + 0); + txfRenderString(gc.getFont(), label); + glPopMatrix(); + glDisable(GL_TEXTURE_2D); +} + diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 00000000..45ffef8f --- /dev/null +++ b/src/gui.h @@ -0,0 +1,84 @@ +// gui.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _GUI_H_ +#define _GUI_H_ + +#include +#include +#include "vecmath.h" +#include "texfont.h" + + +namespace gui +{ + class GraphicsContext + { + public: + GraphicsContext(); + TexFont* getFont() const; + void setFont(TexFont*); + + private: + TexFont* font; + }; + + + class Component + { + public: + Component(); + + Point2f getPosition() const; + Vec2f getSize() const; + void reshape(Point2f, Vec2f); + Component* getParent() const; + virtual void render(GraphicsContext&) = 0; + + // protected: + void setParent(Component*); + + private: + Point2f position; + Vec2f size; + Component* parent; + }; + + + class Container : public Component + { + public: + Container(); + + int getComponentCount() const; + Component* getComponent(int) const; + void addComponent(Component*); + void render(GraphicsContext&); + + private: + std::vector components; + }; + + + class Button : public Component + { + public: + Button(std::string); + + std::string getLabel() const; + void setLabel(std::string); + void render(GraphicsContext&); + + private: + std::string label; + }; + +}; + +#endif // _GUI_H_ diff --git a/src/mathlib.h b/src/mathlib.h new file mode 100644 index 00000000..74cb6c5e --- /dev/null +++ b/src/mathlib.h @@ -0,0 +1,115 @@ +// mathlib.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _MATHLIB_H_ +#define _MATHLIB_H_ + +#include +#include + +#define PI 3.14159265358979323846 + +template class Math +{ +public: + static inline void sincos(T, T&, T&); + static inline T frand(); + static inline T sfrand(); + static inline T lerp(T t, T a, T b); + static inline T clamp(T t); + +private: + // This class is static and should not be instantiated + Math() {}; +}; + + +typedef Math Mathf; +typedef Math Mathd; + + +template T degToRad(T d) +{ + return d / 180 * static_cast(PI); +} + +template T radToDeg(T r) +{ + return r * 180 / static_cast(PI); +} + +template T abs(T x) +{ + return (x < 0) ? -x : x; +} + +template T square(T x) +{ + return x * x; +} + +template T clamp(T x) +{ + if (x < 0) + return 0; + else if (x > 1) + return 1; + else + return x; +} + +template T circleArea(T r) +{ + return (T) PI * r * r; +} + +template T sphereArea(T r) +{ + return 4 * (T) PI * r * r; +} + +template void Math::sincos(T angle, T& s, T& c) +{ + s = (T) sin(angle); + c = (T) cos(angle); +} + + +// return a random float in [0, 1] +template T Math::frand() +{ + return (T) (rand() & 0x7fff) / (T) 32767; +} + + +// return a random float in [-1, 1] +template T Math::sfrand() +{ + return (T) (rand() & 0x7fff) / (T) 32767 * 2 - 1; +} + + +template T Math::lerp(T t, T a, T b) +{ + return a + t * (b - a); +} + + +// return t clamped to [0, 1] +template T Math::clamp(T t) +{ + if (t < 0) + return 0; + else if (t > 1) + return 1; + else + return t; +} + +#endif // _MATHLIB_H_ diff --git a/src/mesh.h b/src/mesh.h new file mode 100644 index 00000000..490c0b8a --- /dev/null +++ b/src/mesh.h @@ -0,0 +1,20 @@ +// mesh.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _MESH_H_ +#define _MESH_H_ + + +class Mesh +{ + public: + virtual void render() = 0; +}; + +#endif // _MESH_H_ diff --git a/src/meshmanager.cpp b/src/meshmanager.cpp new file mode 100644 index 00000000..35189588 --- /dev/null +++ b/src/meshmanager.cpp @@ -0,0 +1,160 @@ +// meshmanager.cpp +// +// Copyright (C) 2001 Chris Laurel +// +// 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 +#include +#include "celestia.h" +#include "mathlib.h" +#include "parser.h" + +#include "3dsread.h" +#include "3dsmesh.h" +#include "spheremesh.h" +#include "perlin.h" +#include "filetype.h" +#include "meshmanager.h" + +using namespace std; + + +static Mesh* LoadCelestiaMesh(const string& filename); + + +MeshManager::~MeshManager() +{ + // TODO: Clean up +} + + +bool MeshManager::find(string name, Mesh** mesh) +{ + return findResource(name, (void**) mesh); +} + + +Mesh* MeshManager::load(string name) +{ + ContentType fileType = DetermineFileType(name); + Mesh* mesh = NULL; + + if (fileType == Content_3DStudio) + { + Mesh3DS* mesh3 = NULL; + M3DScene* scene = Read3DSFile(baseDir + '\\' + name); + if (scene != NULL) + { + mesh3 = new Mesh3DS(*scene); + mesh3->normalize(); + delete scene; + } + mesh = mesh3; + } + else if (fileType == Content_CelestiaMesh) + { + mesh = LoadCelestiaMesh(baseDir + '\\' + name); + } + + addResource(name, (void*) mesh); + + return mesh; +} + + +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*) ¶ms); +} diff --git a/src/meshmanager.h b/src/meshmanager.h new file mode 100644 index 00000000..4126e2bd --- /dev/null +++ b/src/meshmanager.h @@ -0,0 +1,32 @@ +// meshmanager.h +// +// Copyright (C) 2001 Chris Laurel +// +// 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. + +#ifndef _MESHMANAGER_H_ +#define _MESHMANAGER_H_ + +#include +#include +#include "mesh.h" +#include "resmanager.h" + + +class MeshManager : public ResourceManager +{ + public: + MeshManager() : ResourceManager() {}; + MeshManager(string _baseDir) : ResourceManager(_baseDir) {}; + MeshManager(char* _baseDir) : ResourceManager(_baseDir) {}; + ~MeshManager(); + + bool find(string name, Mesh**); + Mesh* load(string name); +}; + +#endif // _MESHMANAGER_H_ + diff --git a/src/observer.cpp b/src/observer.cpp new file mode 100644 index 00000000..8a2de320 --- /dev/null +++ b/src/observer.cpp @@ -0,0 +1,84 @@ +// observer.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 "observer.h" + +#define LY 9466411842000.000 + + +Observer::Observer() : orientation(0, 0, 0, 1), + velocity(0, 0, 0) +{ +} + + +UniversalCoord Observer::getPosition() const +{ + return position; +} + + +Point3d Observer::getRelativePosition(Point3d& p) const +{ + BigFix x(p.x); + BigFix y(p.y); + BigFix z(p.z); + double dx = (double) (position.x - x); + double dy = (double) (position.y - y); + double dz = (double) (position.z - z); + + return Point3d(dx / LY, dy / LY, dz / LY); +} + + +Quatf Observer::getOrientation() const +{ + return orientation; +} + + +void Observer::setOrientation(Quatf q) +{ + orientation = q; +} + + +Vec3d Observer::getVelocity() const +{ + return velocity; +} + + +void Observer::setVelocity(Vec3d v) +{ + velocity = v; +} + + +void Observer::setPosition(Point3d p) +{ + position = UniversalCoord(p); +} + + +void Observer::setPosition(UniversalCoord p) +{ + position = p; +} + + +void Observer::update(double dt) +{ + BigFix x(velocity.x * dt); + BigFix y(velocity.y * dt); + BigFix z(velocity.z * dt); + position.x = position.x + x; + position.y = position.y + y; + position.z = position.z + z; +} diff --git a/src/observer.h b/src/observer.h new file mode 100644 index 00000000..ed0dc85c --- /dev/null +++ b/src/observer.h @@ -0,0 +1,58 @@ +// observer.h +// +// Copyright (C) 2001, Chris Laurel +// +// Because of the vastness of interstellar space, floats and doubles aren't +// sufficient when we need to represent distances to millimeter accuracy. +// BigFix is a high precision (128 bit) fixed point type used to represent +// the position of an observer in space. However, it's not practical to use +// high-precision numbers for the positions of everything. To get around +// this problem, object positions are stored at two different scales--light +// years for stars, and kilometers for objects within a star system. +// +// 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. + +#ifndef _OBSERVER_H_ +#define _OBSERVER_H_ + +#include "bigfix.h" +#include "vecmath.h" +#include "univcoord.h" +#include "quaternion.h" + + +class Observer +{ +public: + Observer(); + + // The getPosition method returns the observer's position in light + // years. + UniversalCoord getPosition() const; + + // getRelativePosition returns in units of kilometers the difference + // between the position of the observer and a location specified in + // light years. + Point3d getRelativePosition(Point3d&) const; + + Quatf getOrientation() const; + void setOrientation(Quatf); + Vec3d getVelocity() const; + void setVelocity(Vec3d); + + void setPosition(BigFix x, BigFix y, BigFix z); + void setPosition(UniversalCoord); + void setPosition(Point3d); + + void update(double dt); + +private: + UniversalCoord position; + Quatf orientation; + Vec3d velocity; +}; + +#endif // _OBSERVER_H_ diff --git a/src/orbit.cpp b/src/orbit.cpp new file mode 100644 index 00000000..18c11f91 --- /dev/null +++ b/src/orbit.cpp @@ -0,0 +1,81 @@ +// orbit.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include "mathlib.h" +#include "orbit.h" + + +EllipticalOrbit::EllipticalOrbit(double _semiMajorAxis, + double _eccentricity, + double _inclination, + double _ascendingNode, + double _argOfPeriapsis, + double _trueAnomaly, + double _period, + double _epoch) : + semiMajorAxis(_semiMajorAxis), + eccentricity(_eccentricity), + inclination(_inclination), + ascendingNode(_ascendingNode), + argOfPeriapsis(_argOfPeriapsis), + trueAnomaly(_trueAnomaly), + period(_period), + epoch(_epoch) +{ +} + + +// First four terms of a series solution to Kepler's equation +// for orbital motion. This only works for small eccentricities, +// and in fact the series diverges for e > 0.6627434 +static double solveKeplerSeries(double M, double e) +{ +#if 0 + return M + e * (sin(M) + + e * ((0.5 * sin(2 * M)) + + e * ((0.325 * sin(3 * M) - 0.125 * sin(M)) + + e * ((1.0 / 3.0 * sin(4 * M) - 1.0 / 6.0 * sin(2 * M)))))); +#endif + return (M + + e * sin(M) + + e * e * 0.5 * sin(2 * M) + + e * e * e * (0.325 * sin(3 * M) - 0.125 * sin(M)) + + e * e * e * e * (1.0 / 3.0 * sin(4 * M) - 1.0 / 6.0 * sin(2 * M))); + +} + + +// Return the offset from the barycenter +Point3d EllipticalOrbit::positionAtTime(double t) const +{ + t = t - epoch; + double meanMotion = 2.0 * PI / period; + double meanAnomaly = trueAnomaly + t * meanMotion - argOfPeriapsis; + + // TODO: calculate the *real* eccentric anomaly. This is a reasonable + // approximation only for nearly circular orbits + double eccAnomaly = meanAnomaly; + // eccAnomaly = solveKeplerSeries(meanAnomaly, eccentricity); + + double x = semiMajorAxis * (cos(eccAnomaly) - eccentricity); + double z = semiMajorAxis * sqrt(1 - square(eccentricity)) * sin(eccAnomaly); + + Mat3d R = (Mat3d::yrotation(ascendingNode) * + Mat3d::xrotation(inclination) * + Mat3d::yrotation(argOfPeriapsis)); + + return Point3d(x, 0, z) * R; +} + + +double EllipticalOrbit::getPeriod() const +{ + return period; +} diff --git a/src/orbit.h b/src/orbit.h new file mode 100644 index 00000000..12986765 --- /dev/null +++ b/src/orbit.h @@ -0,0 +1,45 @@ +// orbit.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _ORBIT_H_ +#define _ORBIT_H_ + +#include "vecmath.h" + + +class Orbit +{ +public: + virtual Point3d positionAtTime(double) const = 0; + virtual double getPeriod() const = 0; +}; + + +class EllipticalOrbit : public Orbit +{ +public: + EllipticalOrbit(double, double, double, double, double, double, double, + double _epoch = 2451545.0); + + // Compute the orbit for a specified Julian date + Point3d positionAtTime(double) const; + double getPeriod() const; + +private: + double semiMajorAxis; + double eccentricity; + double inclination; + double ascendingNode; + double argOfPeriapsis; + double trueAnomaly; + double period; + double epoch; +}; + +#endif // _ORBIT_H_ diff --git a/src/packdb.cpp b/src/packdb.cpp new file mode 100644 index 00000000..905bc4e1 --- /dev/null +++ b/src/packdb.cpp @@ -0,0 +1,446 @@ +// packdb.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include +#include + +#define SPECTRAL_O 0 +#define SPECTRAL_B 1 +#define SPECTRAL_A 2 +#define SPECTRAL_F 3 +#define SPECTRAL_G 4 +#define SPECTRAL_K 5 +#define SPECTRAL_M 6 +#define SPECTRAL_R 7 +#define SPECTRAL_S 8 +#define SPECTRAL_N 9 +#define SPECTRAL_WC 10 +#define SPECTRAL_WN 11 + +// Stellar remnants +#define SPECTRAL_WHITE_DWARF 16 +#define SPECTRAL_NEUTRON_STAR 32 + +#define SPECTRAL_UNKNOWN 255 + +#define LUM_Ia0 0 +#define LUM_Ia 1 +#define LUM_Ib 2 +#define LUM_II 3 +#define LUM_III 4 +#define LUM_IV 5 +#define LUM_V 6 +#define LUM_VI 7 + +#define ID_NONE -1 + +#define HD_CATALOG 0x00000000 +#define HIPPARCOS_CATALOG 0x10000000 + +#define BINWRITE(fp, n) fwrite(&(n), sizeof(n), 1, (fp)) + + +typedef struct { + char colorType; + char subType; + char luminosity; + float colorIndex; +} SpectralType; + +typedef struct { + int HIP; /* HIPPARCOS catalogue number */ + int HD; /* HD catalogue number */ + float appMag; /* Apparent magnitude */ + float RA; /* 0 -- 24 hours */ + float dec; /* -90 -- +90 degrees */ + float parallax; /* in milliarcseconds */ + char spectral[13]; + unsigned char parallaxError; +} Star; + +typedef struct { + int HD; + char *commonName; + char *altName; +} HDNameEnt; + +/* Hardcoded file names */ +#define HIPPARCOS_MAIN_DB "hip_main.dat" +#define COMMON_NAMES_DB "hdnames.dat" + +HDNameEnt *hdNames; +int nHDNames; +Star *Stars; +int nStars; + + +int CompareHDNameEnt(const void *a, const void *b) +{ + int hda = ((HDNameEnt *) a)->HD; + int hdb = ((HDNameEnt *) b)->HD; + + if (hda < hdb) + return -1; + else if (hda > hdb) + return 1; + else + return 0; +} + + +unsigned short PackSpectralType(char *spectralType) +{ + unsigned short packed = 0; + unsigned short letter; + unsigned short number; + unsigned short luminosity = LUM_V; + int i = 0; + + // Subdwarves (luminosity class VI) are prefixed with sd + if (spectralType[i] == 's' && spectralType[i + 1] == 'd') + { + luminosity = LUM_VI; + i += 2; + } + + switch (spectralType[i]) + { + case 'O': + letter = SPECTRAL_O; + break; + case 'B': + letter = SPECTRAL_B; + break; + case 'A': + letter = SPECTRAL_A; + break; + case 'F': + letter = SPECTRAL_F; + break; + case 'G': + letter = SPECTRAL_G; + break; + case 'K': + letter = SPECTRAL_K; + break; + case 'M': + letter = SPECTRAL_M; + break; + case 'R': + letter = SPECTRAL_R; + break; + case 'N': + letter = SPECTRAL_N; + break; + case 'S': + letter = SPECTRAL_S; + break; + case 'W': + i++; + if (spectralType[i] == 'C') + letter = SPECTRAL_WC; + else if (spectralType[i] == 'N') + letter = SPECTRAL_WN; + else + i--; + break; + case 'D': + letter = SPECTRAL_WHITE_DWARF; + break; + default: + letter = SPECTRAL_UNKNOWN; + break; + } + + if (letter == SPECTRAL_WHITE_DWARF) + return letter << 8; + + i++; + if (spectralType[i] >= '0' && spectralType[i] <= '9') + number = spectralType[i] - '0'; + else + number = 0; + + if (luminosity != LUM_VI) + { + i++; + luminosity = LUM_V; + while (i < 13 && spectralType[i] != '\0') { + if (spectralType[i] == 'I') { + if (spectralType[i + 1] == 'I') { + if (spectralType[i + 2] == 'I') { + luminosity = LUM_III; + } else { + luminosity = LUM_II; + } + } else if (spectralType[i + 1] == 'V') { + luminosity = LUM_IV; + } else if (spectralType[i + 1] == 'a') { + if (spectralType[i + 2] == '0') + luminosity = LUM_Ia0; + else + luminosity = LUM_Ia; + } else if (spectralType[i + 1] == 'b') { + luminosity = LUM_Ib; + } else { + luminosity = LUM_Ib; + } + break; + } else if (spectralType[i] == 'V') { + if (spectralType[i + 1] == 'I') + luminosity = LUM_VI; + else + luminosity = LUM_V; + break; + } + i++; + } + } + + return (letter << 8) | (number << 4) | luminosity; +} + + +HDNameEnt *ReadCommonNames(FILE *fp) +{ + char buf[256]; + int i; + + hdNames = (HDNameEnt *) malloc(sizeof(HDNameEnt) * 3000); + if (hdNames == NULL) + return NULL; + + for (i = 0; ; i++) { + char *name1, *name2, len; + if (fgets(buf, 256, fp) == NULL) + break; + + /* Strip trailing newline */ + len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + name1 = index(buf, ':'); + if (name1 == NULL) + break; + name1[0] = '\0'; + name1++; + name2 = index(name1, ':'); + if (name2 == NULL) + break; + name2[0] = '\0'; + name2++; + + { + int hd; + if (sscanf(buf, "%d", &hd) != 1) + break; + hdNames[i].HD = hd; + if (name1[0] != '\0') { + hdNames[i].commonName = (char *) malloc(strlen(name1) + 1); + strcpy(hdNames[i].commonName, name1); + } else if (name2[0] != '\0') { + hdNames[i].commonName = (char *) malloc(strlen(name2) + 1); + strcpy(hdNames[i].commonName, name2); + } + } + } + + nHDNames = i; + qsort(hdNames, nHDNames, sizeof(HDNameEnt), CompareHDNameEnt); + + return hdNames; +} + + +char *LookupName(int HD) +{ + HDNameEnt key; + HDNameEnt *found; + + key.HD = HD; + found = (HDNameEnt *) bsearch((void *) &key, (void *) hdNames, + nHDNames, sizeof(HDNameEnt), + CompareHDNameEnt); + if (found == NULL) + return NULL; + else + return found->commonName; +} + + +void WriteStar(FILE *fp, Star *star) +{ + unsigned short spectralType = PackSpectralType(star->spectral); + short appMag = (short) (star->appMag * 256); + unsigned int catalog_no; + + if (star->HD != ID_NONE) + catalog_no = star->HD | HD_CATALOG; + else + catalog_no = star->HIP | HIPPARCOS_CATALOG; + BINWRITE(fp, catalog_no); + BINWRITE(fp, star->RA); + BINWRITE(fp, star->dec); + BINWRITE(fp, star->parallax); + BINWRITE(fp, appMag); + BINWRITE(fp, spectralType); + BINWRITE(fp, star->parallaxError); +} + +#define HIPPARCOS_RECORD_LENGTH 512 + +Star *ReadHipparcosCatalog(FILE *fp) +{ + char buf[HIPPARCOS_RECORD_LENGTH]; + int i; + int maxStars = 120000; + Star *stars; + int nBright = 0, nGood = 0; + char nameBuf[20]; + + fprintf(stderr, "Attempting to allocate %d bytes\n", maxStars * sizeof(Star)); + stars = (Star *) malloc(maxStars * sizeof(Star)); + if (stars == NULL) { + fprintf(stderr, "Unable to allocate memory for stars.\n"); + return NULL; + } + + for (i = 0; ; i++) { + int hh, mm, deg; + float seconds; + float parallaxError; + char degSign; + + if (fgets(buf, HIPPARCOS_RECORD_LENGTH, fp) == NULL) + break; + sscanf(buf + 2, "%d", &stars[i].HIP); + if (sscanf(buf + 390, "%d", &stars[i].HD) != 1) + stars[i].HD = ID_NONE; + sscanf(buf + 41, "%f", &stars[i].appMag); + sscanf(buf + 79, "%f", &stars[i].parallax); + sscanf(buf + 17, "%d %d %f", &hh, &mm, &seconds); + stars[i].RA = hh + (float) mm / 60.0f + (float) seconds / 3600.0f; + sscanf(buf + 29, "%c%d %d %f", °Sign, °, &mm, &seconds); + stars[i].dec = deg + (float) mm / 60.0f + (float) seconds / 3600.0f; + if (degSign == '-') + stars[i].dec = -stars[i].dec; + sscanf(buf + 435, "%12s", &stars[i].spectral); + sscanf(buf + 119, "%f", ¶llaxError); + if (stars[i].parallax <= 0 || parallaxError / stars[i].parallax > 1) + { + stars[i].parallaxError = (unsigned char) 255; + } + else + { + stars[i].parallaxError = + (unsigned char) (parallaxError / stars[i].parallax * 200); + } + + if (/* stars[i].appMag < 4.0f */ + stars[i].parallax > 0 && 3260 / stars[i].parallax < 20) { + nBright++; +#if 0 + if (parallaxError / stars[i].parallax > 0.25f || + parallaxError / stars[i].parallax < 0.0f) { +#endif + if (0) { + char *name = LookupName(stars[i].HD); + + if (name == NULL) { + if (stars[i].HD != ID_NONE) { + sprintf(nameBuf, "HD%d", stars[i].HD); + name = nameBuf; + } else { + sprintf(nameBuf, "HIP%d", stars[i].HIP); + name = nameBuf; + } + } + printf("%-20s %5.2f %6.2f %3d%% %12s %5.2f %5.2f\n", + name, + stars[i].appMag, + 3260.0f / stars[i].parallax, + (int) (100.0f * parallaxError / stars[i].parallax), + stars[i].spectral, + stars[i].RA, stars[i].dec); + } else { + nGood++; + } + } + } + + nStars = i; + printf("Stars: %d, Bright: %d, Good: %d\n", nStars, nBright, nGood); + + return stars; +} + + +int main(int argc, char *argv[]) +{ + FILE *fp; + + fp = fopen(COMMON_NAMES_DB, "r"); + if (fp == NULL) { + fprintf(stderr, "Error opening %s\n", COMMON_NAMES_DB); + return 1; + } + hdNames = ReadCommonNames(fp); + fclose(fp); + fp = NULL; + if (hdNames == NULL) { + fprintf(stderr, "Error reading names file.\n"); + return 1; + } + + fp = fopen(HIPPARCOS_MAIN_DB, "r"); + if (fp == NULL) { + fprintf(stderr, "Error opening %s\n", HIPPARCOS_MAIN_DB); + return 1; + } + Stars = ReadHipparcosCatalog(fp); + fclose(fp); + if (Stars == NULL) { + fprintf(stderr, "Error reading HIPPARCOS database."); + return 1; + } +#if 0 + { + int i; + + for (i = 0; i < nStars; i++) { + if (Stars[i].spectral[0] == 'O') { + char *name = LookupName(Stars[i].HD); + if (name != NULL) + printf("%s ", name); + printf("%6d %6.3f %6.3f %s\n", + Stars[i].HD, Stars[i].RA, Stars[i].dec, Stars[i].spectral); + } + } + } +#endif + + { + int i; + + FILE *fp = fopen("out", "wb"); + if (fp == NULL) { + fprintf(stderr, "Error opening output file.\n"); + exit(1); + } + + BINWRITE(fp, nStars); + for (i = 0; i < nStars; i++) + WriteStar(fp, &Stars[i]); + + fclose(fp); + } + printf("Stars in catalog = %d\n", nStars); +} diff --git a/src/packnames.cpp b/src/packnames.cpp new file mode 100644 index 00000000..19da2252 --- /dev/null +++ b/src/packnames.cpp @@ -0,0 +1,125 @@ +// packnames.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include +#include "constellation.h" +#include "starname.h" + + +static char *greekAlphabet[] = +{ + "Alpha", + "Beta", + "Gamma", + "Delta", + "Epsilon", + "Zeta", + "Eta", + "Theta", + "Iota", + "Kappa", + "Lambda", + "Mu", + "Nu", + "Xi", + "Omicron", + "Pi", + "Rho", + "Sigma", + "Tau", + "Upsilon", + "Phi", + "Chi", + "Psi", + "Omega" +}; + + +int main(int argc, char *argv[]) +{ + string s; + + for (;;) + { + unsigned int catalogNumber; + char sep; + + cin >> catalogNumber; + if (cin.eof()) + { + break; + } + else if (cin.bad()) + { + cerr << "Error reading names file.\n"; + break; + } + + cin >> sep; + if (sep != ':') + { + cerr < "Missing ':' in names file.\n"; + break; + } + + // Get the rest of the line + getline(cin, s); + + int nextSep = s.find_first_of(':'); + if (nextSep == string::npos) + { + cerr << "Missing ':' in names file.\n"; + break; + } + + string common, designation; + string conAbbr; + string conName; + string bayerLetter; + + if (nextSep != 0) + common = s.substr(0, nextSep); + designation = s.substr(nextSep + 1, string::npos); + + if (designation != "") + { + nextSep = designation.find_last_of(' '); + if (nextSep != string::npos) + { + bayerLetter = designation.substr(0, nextSep); + conAbbr = designation.substr(nextSep + 1, string::npos); + } + } + + Constellation *constel; + for (int i = 0; i < 88; i++) + { + constel = Constellation::getConstellation(i); + if (constel == NULL) + { + cerr << "Error getting constellation " << i << '\n'; + break; + } + if (constel->getAbbreviation() == conAbbr) + { + conName = constel->getName(); + break; + } + } + + if (constel != NULL && bayerLetter != "") + { + StarName sn(common, bayerLetter, constel); + cout << sn.getDesignation() << ' ' << constel->getAbbreviation() << '\n'; + } + + + } +} diff --git a/src/parser.cpp b/src/parser.cpp new file mode 100644 index 00000000..66da2097 --- /dev/null +++ b/src/parser.cpp @@ -0,0 +1,524 @@ +// parser.cpp +// +// Copyright (C) 2001 Chris Laurel +// +// 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 "parser.h" + + +/****** Value method implementations *******/ + +Value::Value(double d) +{ + type = NumberType; + data.d = d; +} + +Value::Value(string s) +{ + type = StringType; + data.s = new string(s); +} + +Value::Value(Array* a) +{ + type = ArrayType; + data.a = a; +} + +Value::Value(Hash* h) +{ + type = HashType; + data.h = h; +} + +Value::Value(bool b) +{ + type = BooleanType; + data.d = b ? 1.0 : 0.0; +} + +Value::~Value() +{ + if (type == StringType) + { + delete data.s; + } + else if (type == ArrayType) + { + if (data.a != NULL) + { + for (int i = 0; i < data.a->size(); i++) + delete (*data.a)[i]; + delete data.a; + } + } + else if (type == HashType) + { + if (data.h != NULL) + { +#if 0 + Hash::iterator iter = data.h->begin(); + while (iter != data.h->end()) + { + delete iter->second; + iter++; + } +#endif + delete data.h; + } + } +} + +Value::ValueType Value::getType() const +{ + return type; +} + +double Value::getNumber() const +{ + // ASSERT(type == NumberType); + return data.d; +} + +string Value::getString() const +{ + // ASSERT(type == StringType); + return *data.s; +} + +Array* Value::getArray() const +{ + // ASSERT(type == ArrayType); + return data.a; +} + +Hash* Value::getHash() const +{ + // ASSERT(type == HashType); + return data.h; +} + +bool Value::getBoolean() const +{ + // ASSERT(type == BooleanType); + return (data.d != 0.0); +} + + +/****** Parser method implementation ******/ + +Parser::Parser(Tokenizer* _tokenizer) : + tokenizer(_tokenizer) +{ +} + + +Array* Parser::readArray() +{ + Tokenizer::TokenType tok = tokenizer->nextToken(); + if (tok != Tokenizer::TokenBeginArray) + { + tokenizer->pushBack(); + return NULL; + } + + Array* array = new Array(); + + Value* v = readValue(); + while (v != NULL) + { + array->insert(array->end(), v); + v = readValue(); + } + + tok = tokenizer->nextToken(); + if (tok != Tokenizer::TokenEndArray) + { + tokenizer->pushBack(); + delete array; + return NULL; + } + + return array; +} + + +#if 0 +Hash* Parser::readHash() +{ + Tokenizer::TokenType tok = tokenizer->nextToken(); + if (tok != Tokenizer::TokenBeginGroup) + { + tokenizer->pushBack(); + return NULL; + } + + Hash* hash = new Hash(); + + tok = tokenizer->nextToken(); + while (tok != Tokenizer::TokenEndGroup) + { + if (tok != Tokenizer::TokenName) + { + tokenizer->pushBack(); + delete hash; + return NULL; + } + string name = tokenizer->getNameValue(); + + Value* value = readValue(); + if (value == NULL) + { + delete hash; + return NULL; + } + + hash->insert(Hash::value_type(name, value)); + + tok = tokenizer->nextToken(); + } + + return hash; +} +#endif + +Hash* Parser::readHash() +{ + Tokenizer::TokenType tok = tokenizer->nextToken(); + if (tok != Tokenizer::TokenBeginGroup) + { + tokenizer->pushBack(); + return NULL; + } + + Hash* hash = new Hash(); + + tok = tokenizer->nextToken(); + while (tok != Tokenizer::TokenEndGroup) + { + if (tok != Tokenizer::TokenName) + { + tokenizer->pushBack(); + delete hash; + return NULL; + } + string name = tokenizer->getNameValue(); + + Value* value = readValue(); + if (value == NULL) + { + delete hash; + return NULL; + } + + hash->addValue(name, *value); + + tok = tokenizer->nextToken(); + } + + return hash; +} + + +Value* Parser::readValue() +{ + Tokenizer::TokenType tok = tokenizer->nextToken(); + switch (tok) + { + case Tokenizer::TokenNumber: + return new Value(tokenizer->getNumberValue()); + + case Tokenizer::TokenString: + return new Value(tokenizer->getStringValue()); + + case Tokenizer::TokenName: + if (tokenizer->getNameValue() == "false") + return new Value(false); + else if (tokenizer->getNameValue() == "true") + return new Value(true); + else + { + tokenizer->pushBack(); + return NULL; + } + + case Tokenizer::TokenBeginArray: + tokenizer->pushBack(); + { + Array* array = readArray(); + if (array == NULL) + return NULL; + else + return new Value(array); + } + + case Tokenizer::TokenBeginGroup: + tokenizer->pushBack(); + { + Hash* hash = readHash(); + if (hash == NULL) + return NULL; + else + return new Value(hash); + } + + default: + tokenizer->pushBack(); + return NULL; + } +} + + +#if 0 +// TODO: Move all these get* functions into a Hash class. + +bool getNumber(Hash* h, string name, double& val) +{ + Hash::iterator iter = h->find(name); + if (iter == h->end()) + return false; + + Value* v = iter->second; + if (v->getType() != Value::NumberType) + return false; + + val = v->getNumber(); + + return true; +} + +bool getNumber(Hash* h, string name, float& val) +{ + double dval; + + if (!getNumber(h, name, dval)) + { + return false; + } + else + { + val = (float) dval; + return true; + } +} + +bool getString(Hash* h, string name, string& val) +{ + Hash::iterator iter = h->find(name); + if (iter == h->end()) + return false; + + Value* v = iter->second; + if (v->getType() != Value::StringType) + return false; + + val = v->getString(); + + return true; +} + +bool getBoolean(Hash* h, string name, bool& val) +{ + Hash::iterator iter = h->find(name); + if (iter == h->end()) + return false; + + Value* v = iter->second; + if (v->getType() != Value::BooleanType) + return false; + + val = v->getBoolean(); + + return true; +} + +bool getVector(Hash* h, string name, Vec3d& val) +{ + Hash::iterator iter = h->find(name); + if (iter == h->end()) + return false; + + Value* v = iter->second; + if (v->getType() != Value::ArrayType) + return false; + + Array* arr = v->getArray(); + if (arr->size() != 3) + return false; + + Value* x = (*arr)[0]; + Value* y = (*arr)[1]; + Value* z = (*arr)[2]; + + if (x->getType() != Value::NumberType || + y->getType() != Value::NumberType || + z->getType() != Value::NumberType) + return false; + + val = Vec3d((float) x->getNumber(), + (float) y->getNumber(), + (float) z->getNumber()); + + return true; +} + +bool getVector(Hash* h, string name, Vec3f& val) +{ + Vec3d vecVal; + + if (!getVector(h, name, vecVal)) + return false; + + val = Vec3f((float) vecVal.x, (float) vecVal.y, (float) vecVal.z); + + return true; +} + +bool getColor(Hash* h, string name, Color& val) +{ + Vec3d vecVal; + + if (!getVector(h, name, vecVal)) + return false; + + val = Color((float) vecVal.x, (float) vecVal.y, (float) vecVal.z); + + return true; +} +#endif + + +AssociativeArray::AssociativeArray() +{ +} + +AssociativeArray::~AssociativeArray() +{ +#if 0 + Hash::iterator iter = data.h->begin(); + while (iter != data.h->end()) + { + delete iter->second; + iter++; + } +#endif + for (map::iterator iter = assoc.begin(); iter != assoc.end(); iter++) + delete iter->second; +} + +Value* AssociativeArray::getValue(string key) const +{ + map::const_iterator iter = assoc.find(key); + if (iter == assoc.end()) + return NULL; + else + return iter->second; +} + +void AssociativeArray::addValue(string key, Value& val) +{ + assoc.insert(map::value_type(key, &val)); +} + +bool AssociativeArray::getNumber(string key, double& val) const +{ + Value* v = getValue(key); + if (v == NULL || v->getType() != Value::NumberType) + return false; + + val = v->getNumber(); + + return true; +} + +bool AssociativeArray::getNumber(string key, float& val) const +{ + double dval; + + if (!getNumber(key, dval)) + { + return false; + } + else + { + val = (float) dval; + return true; + } +} + +bool AssociativeArray::getString(string key, string& val) const +{ + Value* v = getValue(key); + if (v == NULL || v->getType() != Value::StringType) + return false; + + val = v->getString(); + + return true; +} + +bool AssociativeArray::getBoolean(string key, bool& val) const +{ + Value* v = getValue(key); + if (v == NULL || v->getType() != Value::BooleanType) + return false; + + val = v->getBoolean(); + + return true; +} + +bool AssociativeArray::getVector(string key, Vec3d& val) const +{ + Value* v = getValue(key); + if (v == NULL || v->getType() != Value::ArrayType) + return false; + + Array* arr = v->getArray(); + if (arr->size() != 3) + return false; + + Value* x = (*arr)[0]; + Value* y = (*arr)[1]; + Value* z = (*arr)[2]; + + if (x->getType() != Value::NumberType || + y->getType() != Value::NumberType || + z->getType() != Value::NumberType) + return false; + + val = Vec3d((float) x->getNumber(), + (float) y->getNumber(), + (float) z->getNumber()); + + return true; +} + +bool AssociativeArray::getVector(string key, Vec3f& val) const +{ + Vec3d vecVal; + + if (!getVector(key, vecVal)) + return false; + + val = Vec3f((float) vecVal.x, (float) vecVal.y, (float) vecVal.z); + + return true; +} + +bool AssociativeArray::getColor(string key, Color& val) const +{ + Vec3d vecVal; + + if (!getVector(key, vecVal)) + return false; + + val = Color((float) vecVal.x, (float) vecVal.y, (float) vecVal.z); + + return true; +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 00000000..a300b415 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,96 @@ +// parser.h +// +// Copyright (C) 2001 Chris Laurel +// +// 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. + +#ifndef _PARSER_H_ +#define _PARSER_H_ + +#include +#include +#include "vecmath.h" +#include "color.h" +#include "tokenizer.h" + +class Value; + +class AssociativeArray +{ + public: + AssociativeArray(); + ~AssociativeArray(); + + Value* getValue(string) const; + void addValue(string, Value&); + + bool getNumber(string, double&) const; + bool getNumber(string, float&) const; + bool getString(string, string&) const; + bool getBoolean(string, bool&) const; + bool getVector(string, Vec3d&) const; + bool getVector(string, Vec3f&) const; + bool getColor(string, Color&) const; + + private: + map assoc; +}; + +typedef vector Array; +typedef AssociativeArray Hash; + +class Value +{ +public: + enum ValueType { + NumberType = 0, + StringType = 1, + ArrayType = 2, + HashType = 3, + BooleanType = 4 + }; + + Value(double); + Value(string); + Value(Array*); + Value(Hash*); + Value(bool); + ~Value(); + + ValueType getType() const; + + double getNumber() const; + string getString() const; + Array* getArray() const; + Hash* getHash() const; + bool getBoolean() const; + +private: + ValueType type; + + union { + string* s; + double d; + Array* a; + Hash* h; + } data; +}; + + +class Parser +{ +public: + Parser(Tokenizer*); + + Array* readArray(); + Hash* readHash(); + Value* readValue(); + +private: + Tokenizer* tokenizer; +}; + +#endif // _PARSER_H_ diff --git a/src/perlin.cpp b/src/perlin.cpp new file mode 100644 index 00000000..5d7fba46 --- /dev/null +++ b/src/perlin.cpp @@ -0,0 +1,333 @@ +#include +#include +#include + +#include "mathlib.h" +#include "vecmath.h" +#include "perlin.h" + + +float bias(float a, float b) +{ + return (float) pow(a, log(b) / log(0.5)); +} + +float gain(float a, float b) +{ + float p = (float) (log(1.0 - b) / log(0.5)); + + if (a < 0.001f) + return 0.0f; + else if (a > 0.999f) + return 1.0f; + + if (a < 0.5f) + return (float) pow(2 * a, p) / 2; + else + return 1.0f - (float) pow(2 * (1.0 - a), p) / 2; +} + +float noise(float vec[], int len) +{ + switch (len) { + case 0: + return 0.; + case 1: + return noise1(vec[0]); + case 2: + return noise2(vec); + default: + return noise3(vec); + } +} + + +float turbulence(float v[], float freq) +{ + float t, vec[3]; + + for (t = 0. ; freq >= 1. ; freq /= 2) { + vec[0] = freq * v[0]; + vec[1] = freq * v[1]; + vec[2] = freq * v[2]; + t += (float) fabs(noise3(vec)) / freq; + } + return t; +} + + +float turbulence(Point2f& p, float freq) +{ + float t; + float vec[2]; + + for (t = 0.0f; freq >= 1.0f; freq *= 0.5f) + { + vec[0] = freq * p.x; + vec[1] = freq * p.y; + t += (float) fabs(noise2(vec)) / freq; + } + + return t; +} + + +float turbulence(Point3f& p, float freq) +{ + float t; + float vec[3]; + + for (t = 0.0f; freq >= 1.0f; freq *= 0.5f) + { + vec[0] = freq * p.x; + vec[1] = freq * p.y; + vec[2] = freq * p.z; + t += (float) fabs(noise3(vec)) / freq; + } + + return t; +} + + +float fractalsum(float v[], float freq) +{ + float t; + float vec[3]; + + for (t = 0.0f ; freq >= 1.0f ; freq /= 2.0f) { + vec[0] = freq * v[0]; + vec[1] = freq * v[1]; + vec[2] = freq * v[2]; + t += noise3(vec) / freq; + } + + return t; +} + + +float fractalsum(Point2f& p, float freq) +{ + float t; + float vec[2]; + + for (t = 0.0f; freq >= 1.0f; freq *= 0.5f) + { + vec[0] = freq * p.x; + vec[1] = freq * p.y; + t += noise2(vec) / freq; + } + + return t; +} + + +float fractalsum(Point3f& p, float freq) +{ + float t; + float vec[3]; + + for (t = 0.0f; freq >= 1.0f; freq *= 0.5f) + { + vec[0] = freq * p.x; + vec[1] = freq * p.y; + vec[2] = freq * p.z; + t += noise3(vec) / freq; + } + + return t; +} + + +/* noise functions over 1, 2, and 3 dimensions */ + +#define B 0x100 +#define BM 0xff + +#define N 0x1000 +#define NP 12 /* 2^N */ +#define NM 0xfff + +static int p[B + B + 2]; +static float g3[B + B + 2][3]; +static float g2[B + B + 2][2]; +static float g1[B + B + 2]; + +static bool initialized = false; + +static void init(void); + +#define s_curve(t) ( t * t * (3.0f - 2.0f * t) ) + +#define setup(i, b0, b1, r0, r1) \ + t = vec[i] + N;\ + b0 = ((int)t) & BM;\ + b1 = (b0+1) & BM;\ + r0 = t - (int)t;\ + r1 = r0 - 1.0f; + +float noise1(float arg) +{ + if (!initialized) + init(); + + int bx0, bx1; + float rx0, rx1, t, u, v, vec[1]; + + vec[0] = arg; + + setup(0, bx0, bx1, rx0, rx1); + + u = rx0 * g1[p[bx0]]; + v = rx1 * g1[p[bx1]]; + + return Mathf::lerp(s_curve(rx0), u, v); +} + +float noise2(float vec[2]) +{ + int bx0, bx1, by0, by1, b00, b10, b01, b11; + float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; + int i, j; + + if (!initialized) + init(); + + setup(0, bx0,bx1, rx0,rx1); + setup(1, by0,by1, ry0,ry1); + + i = p[ bx0 ]; + j = p[ bx1 ]; + + b00 = p[ i + by0 ]; + b10 = p[ j + by0 ]; + b01 = p[ i + by1 ]; + b11 = p[ j + by1 ]; + + sx = s_curve(rx0); + sy = s_curve(ry0); + +#define at2(rx,ry) ( rx * q[0] + ry * q[1] ) + + q = g2[ b00 ] ; u = at2(rx0,ry0); + q = g2[ b10 ] ; v = at2(rx1,ry0); + a = Mathf::lerp(sx, u, v); + + q = g2[ b01 ] ; u = at2(rx0,ry1); + q = g2[ b11 ] ; v = at2(rx1,ry1); + b = Mathf::lerp(sx, u, v); + + return Mathf::lerp(sy, a, b); +} + +float noise3(float vec[3]) +{ + if (!initialized) + init(); + + int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; + float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; + int i, j; + + setup(0, bx0,bx1, rx0,rx1); + setup(1, by0,by1, ry0,ry1); + setup(2, bz0,bz1, rz0,rz1); + + i = p[ bx0 ]; + j = p[ bx1 ]; + + b00 = p[ i + by0 ]; + b10 = p[ j + by0 ]; + b01 = p[ i + by1 ]; + b11 = p[ j + by1 ]; + + t = s_curve(rx0); + sy = s_curve(ry0); + sz = s_curve(rz0); + +#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) + + q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0); + q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0); + a = Mathf::lerp(t, u, v); + + q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0); + q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0); + b = Mathf::lerp(t, u, v); + + c = Mathf::lerp(sy, a, b); + + q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1); + q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1); + a = Mathf::lerp(t, u, v); + + q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1); + q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1); + b = Mathf::lerp(t, u, v); + + d = Mathf::lerp(sy, a, b); + + return Mathf::lerp(sz, c, d); +} + +static void normalize2(float v[2]) +{ + float s = (float) sqrt(v[0] * v[0] + v[1] * v[1]); + v[0] = v[0] / s; + v[1] = v[1] / s; +} + +static void normalize3(float v[3]) +{ + float s = (float) sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] = v[0] / s; + v[1] = v[1] / s; + v[2] = v[2] / s; +} + + +static void init() +{ + int i, j, k; + + for (i = 0; i < B; i++) + { + g1[i] = Mathf::sfrand(); + + g2[i][0] = Mathf::sfrand(); + g2[i][1] = Mathf::sfrand(); + normalize2(g2[i]); + + g3[i][0] = Mathf::sfrand(); + g3[i][1] = Mathf::sfrand(); + g3[i][2] = Mathf::sfrand(); + normalize3(g3[i]); + } + + // Fill the permutation array with values . . . + for (i = 0; i < B; i++) + p[i] = i; + + // . . . and then shuffle it + for (i = 0; i < B; i++) + { + k = p[i]; + j = rand() % B; + p[i] = p[j]; + p[j] = k; + } + + // Duplicate values to accelerate table lookups + for (i = 0; i < B + 2; i++) + { + p[B + i] = p[i]; + g1[B + i] = g1[i]; + g2[B + i][0] = g2[i][0]; + g2[B + i][1] = g2[i][1]; + g3[B + i][0] = g3[i][0]; + g3[B + i][1] = g3[i][1]; + g3[B + i][2] = g3[i][2]; + } + + initialized = true; +} + diff --git a/src/perlin.h b/src/perlin.h new file mode 100644 index 00000000..445cc43b --- /dev/null +++ b/src/perlin.h @@ -0,0 +1,19 @@ +// perlin.h + +#ifndef _PERLIN_H_ +#define _PERLIN_H_ + +extern float noise(float vec[], int len); + +extern float noise1(float arg); +extern float noise2(float vec[]); +extern float noise3(float vec[]); + +extern float turbulence(float v[], float freq); +extern float turbulence(Point2f& p, float freq); +extern float turbulence(Point3f& p, float freq); +extern float fractalsum(float v[], float freq); +extern float fractalsum(Point2f& p, float freq); +extern float fractalsum(Point3f& p, float freq); + +#endif // _PERLIN_H_ diff --git a/src/quaternion.h b/src/quaternion.h new file mode 100644 index 00000000..bf4102f6 --- /dev/null +++ b/src/quaternion.h @@ -0,0 +1,595 @@ +// quaternion.h +// +// Copyright (C) 2000, Chris Laurel +// +// Template-ized quaternion math library. +// +// 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. + +#ifndef _QUATERNION_H_ +#define _QUATERNION_H_ + +#include "mathlib.h" +#include "vecmath.h" + + +template class Quaternion +{ +public: + inline Quaternion(); + inline Quaternion(const Quaternion&); + inline Quaternion(T); + inline Quaternion(const Vector3&); + inline Quaternion(T, const Vector3&); + inline Quaternion(T, T, T, T); + + Quaternion(Matrix3&); + + inline Quaternion& operator+=(Quaternion); + inline Quaternion& operator-=(Quaternion); + inline Quaternion& operator*=(T); + Quaternion& operator*=(Quaternion); + + inline Quaternion operator~(); // conjugate + inline Quaternion operator-(); + inline Quaternion operator+(); + + void setAxisAngle(Vector3 axis, T angle); + + void getAxisAngle(Vector3& axis, T& angle) const; + Matrix4 toMatrix4() const; + Matrix3 toMatrix3() const; + + static Quaternion slerp(Quaternion, Quaternion, T); + + void rotate(Vector3 axis, T angle); + void xrotate(T angle); + void yrotate(T angle); + void zrotate(T angle); + + bool isPure() const; + bool isReal() const; + T normalize(); + + friend Quaternion operator+(Quaternion, Quaternion); + friend Quaternion operator-(Quaternion, Quaternion); + friend Quaternion operator*(Quaternion, Quaternion); + friend Quaternion operator*(T, Quaternion); + friend Quaternion operator*(Vector3, Quaternion); + + friend bool operator==(Quaternion, Quaternion); + friend bool operator!=(Quaternion, Quaternion); + + friend T real(Quaternion); + friend Vector3 imag(Quaternion); + + // private: + T w, x, y, z; +}; + + +typedef Quaternion Quatf; +typedef Quaternion Quatd; + + +template Quaternion::Quaternion() : w(0), x(0), y(0), z(0) +{ +} + +template Quaternion::Quaternion(const Quaternion& q) : + w(q.w), x(q.x), y(q.y), z(q.z) +{ +} + +template Quaternion::Quaternion(T re) : + w(re), x(0), y(0), z(0) +{ +} + +// Create a 'pure' quaternion +template Quaternion::Quaternion(const Vector3& im) : + w(0), x(im.x), y(im.y), z(im.z) +{ +} + +template Quaternion::Quaternion(T re, const Vector3& im) : + w(re), x(im.x), y(im.y), z(im.z) +{ +} + +template Quaternion::Quaternion(T _w, T _x, T _y, T _z) : + w(_w), x(_x), y(_y), z(_z) +{ +} + +// Create a quaternion from a rotation matrix +template Quaternion::Quaternion(Matrix3& m) +{ + T trace = m[0][0] + m[1][1] + m[2][2]; + T root; + + if (trace > 0) + { + root = (T) sqrt(trace + 1); + w = (T) 0.5 * root; + root = (T) 0.5 / root; + x = (m[2][1] - m[1][2]) * root; + y = (m[0][2] - m[2][0]) * root; + z = (m[1][0] - m[0][1]) * root; + } + else + { + int i = 0; + if (m[1][1] > m[1][1]) + i = 1; + if (m[2][2] > m[1][1]) + i = 2; + int j = (i == 2) ? 0 : i + 1; + int k = (j == 2) ? 0 : j + 1; + + root = (T) sqrt(m[i][i] - m[j][j] - m[k][k] + 1); + T* xyz[3] = { &x, &y, &z }; + *xyz[i] = (T) 0.5 * root; + root = (T) 0.5 / root; + w = (m[k][j] - m[j][k]) * root; + *xyz[j] = (m[j][i] + m[i][j]) * root; + *xyz[k] = (m[k][i] + m[i][k]) * root; + } +} + + +template Quaternion& Quaternion::operator+=(Quaternion a) +{ + x += a.x; y += a.y; z += a.z; w += a.w; + return *this; +} + +template Quaternion& Quaternion::operator-=(Quaternion a) +{ + x -= a.x; y -= a.y; z -= a.z; w -= a.w; + return *this; +} + +template Quaternion& Quaternion::operator*=(Quaternion q) +{ + *this = Quaternion(w * q.w - x * q.x - y * q.y - z * q.z, + w * q.x + x * q.w + y * q.z - z * q.y, + w * q.y + y * q.w + z * q.x - x * q.z, + w * q.z + z * q.w + x * q.y - y * q.x); + + return *this; +} + +template Quaternion& Quaternion::operator*=(T s) +{ + x *= s; y *= s; z *= s; w *= s; + return *this; +} + +// conjugate operator +template Quaternion Quaternion::operator~() +{ + return Quaternion(w, -x, -y, -z); +} + +template Quaternion Quaternion::operator-() +{ + return Quaternion(-w, -x, -y, -z); +} + +template Quaternion Quaternion::operator+() +{ + return *this; +} + + +template Quaternion operator+(Quaternion a, Quaternion b) +{ + return Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z); +} + +template Quaternion operator-(Quaternion a, Quaternion b) +{ + return Quaternion(a.w - b.w, a.x - b.x, a.y - b.y, a.z - b.z); +} + +template Quaternion operator*(Quaternion a, Quaternion b) +{ + return Quaternion(a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, + a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, + a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z, + a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x); +} + +template Quaternion operator*(T s, Quaternion q) +{ + return Quaternion(s * q.w, s * q.x, s * q.y, s * q.z); +} + +template Quaternion operator*(Quaternion q, T s) +{ + return Quaternion(s * q.w, s * q.x, s * q.y, s * q.z); +} + +// equivalent to multiplying by the quaternion (0, v) +template Quaternion operator*(Vector3 v, Quaternion q) +{ + return Quaternion(-v.x * q.x - v.y * q.y - v.z * q.z, + v.x * q.w + v.y * q.z - v.z * q.y, + v.y * q.w + v.z * q.x - v.x * q.z, + v.z * q.w + v.x * q.y - v.y * q.x); +} + +template Quaternion operator/(Quaternion q, T s) +{ + return q * (1 / s); +} + +template Quaternion operator/(Quaternion a, Quaternion b) +{ + return a * (~b / abs(b)); +} + + +template bool operator==(Quaternion a, Quaternion b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; +} + +template bool operator!=(Quaternion a, Quaternion b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; +} + + +// elementary functions +template Quaternion conjugate(Quaternion q) +{ + return Quaternion(q.w, -q.x, -q.y, -q.z); +} + +template T norm(Quaternion q) +{ + return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; +} + +template T abs(Quaternion q) +{ + return (T) sqrt(norm(q)); +} + +template Quaternion exp(Quaternion q) +{ + if (q.isReal()) + { + return Quaternion((T) exp(q.w)); + } + else + { + T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + T s = (T) sin(l); + T c = (T) cos(l); + T e = (T) exp(q.w); + T t = e * s / l; + return Quaternion(e * c, t * q.x, t * q.y, t * q.z); + } +} + +template Quaternion log(Quaternion q) +{ + if (q.isReal()) + { + if (q.w > 0) + { + return Quaternion((T) log(q.w)); + } + else if (q.w < 0) + { + // The log of a negative purely real quaternion has + // infinitely many values, all of the form (ln(-w), PI * I), + // where I is any unit vector. We arbitrarily choose an I + // of (1, 0, 0) here and whereever else a similar choice is + // necessary. Geometrically, the set of roots is a sphere + // of radius PI centered at ln(-w) on the real axis. + return Quaternion((T) log(-q.w), (T) PI, 0, 0); + } + else + { + // error . . . ln(0) not defined + return Quaternion(0); + } + } + else + { + T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + T r = (T) sqrt(l * l + q.w * q.w); + T theta = (T) atan2(l, q.w); + T t = theta / l; + return Quaternion((T) log(r), t * q.x, t * q.y, t * q.z); + } +} + + +template Quaternion pow(Quaternion q, T s) +{ + return exp(s * log(q)); +} + + +template Quaternion pow(Quaternion q, Quaternion p) +{ + return exp(p * log(q)); +} + + +template Quaternion sin(Quaternion q) +{ + if (q.isReal()) + { + return Quaternion((T) sin(q.w)); + } + else + { + T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + T m = q.w; + T s = (T) sin(m); + T c = (T) cos(m); + T il = 1 / l; + T e0 = (T) exp(-l); + T e1 = (T) exp(l); + + T c0 = (T) -0.5 * e0 * il * c; + T c1 = (T) 0.5 * e1 * il * c; + + return Quaternion((T) 0.5 * e0 * s, c0 * q.x, c0 * q.y, c0 * q.z) + + Quaternion((T) 0.5 * e1 * s, c1 * q.x, c1 * q.y, c1 * q.z); + } +} + +template Quaternion cos(Quaternion q) +{ + if (q.isReal()) + { + return Quaternion((T) cos(q.w)); + } + else + { + T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + T m = q.w; + T s = (T) sin(m); + T c = (T) cos(m); + T il = 1 / l; + T e0 = (T) exp(-l); + T e1 = (T) exp(l); + + T c0 = (T) 0.5 * e0 * il * s; + T c1 = (T) -0.5 * e1 * il * s; + + return Quaternion((T) 0.5 * e0 * c, c0 * q.x, c0 * q.y, c0 * q.z) + + Quaternion((T) 0.5 * e1 * c, c1 * q.x, c1 * q.y, c1 * q.z); + } +} + +template Quaternion sqrt(Quaternion q) +{ + // In general, the square root of a quaternion has two values, one + // of which is the negative of the other. However, any negative purely + // real quaternion has an infinite number of square roots. + // This function returns the positive root for positive reals and + // the root on the positive i axis for negative reals. + if (q.isReal()) + { + if (q.w >= 0) + return Quaternion((T) sqrt(q.w), 0, 0, 0); + else + return Quaternion(0, (T) sqrt(-q.w), 0, 0); + } + else + { + T b = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z); + T r = (T) sqrt(q.w * q.w + b * b); + if (q.w >= 0) + { + T m = (T) sqrt((T) 0.5 * (r + q.w)); + T l = b / (2 * m); + T t = l / b; + return Quaternion(m, q.x * t, q.y * t, q.z * t); + } + else + { + T l = (T) sqrt((T) 0.5 * (r - q.w)); + T m = b / (2 * l); + T t = l / b; + return Quaternion(m, q.x * t, q.y * t, q.z * t); + } + } +} + +template T real(Quaternion q) +{ + return q.w; +} + +template Vector3 imag(Quaternion q) +{ + return Vector3(q.x, q.y, q.z); +} + + +// Quaternion methods + +template bool Quaternion::isReal() const +{ + return (x == 0 && y == 0 && z == 0); +} + +template bool Quaternion::isPure() const +{ + return w == 0; +} + +template T Quaternion::normalize() +{ + T s = abs(*this); + T invs = (T) 1 / (T) s; + x *= invs; + y *= invs; + z *= invs; + w *= invs; + + return s; +} + +// Set to the unit quaternion representing an axis angle rotation. Assume +// that axis is a unit vector +template void Quaternion::setAxisAngle(Vector3 axis, T angle) +{ + T s, c; + + Math::sincos(angle * (T) 0.5, s, c); + x = s * axis.x; + y = s * axis.y; + z = s * axis.z; + w = c; +} + + +// Assuming that this a unit quaternion, return the in axis/angle form the +// orientation which it represents. +template void Quaternion::getAxisAngle(Vector3& axis, + T& angle) const +{ + // The quaternion has the form: + // w = cos(angle/2), (x y z) = sin(angle/2)*axis + + T magSquared = x * x + y * y + z * z; + if (magSquared > (T) 1e-10) + { + T s = (T) 1 / (T) sqrt(magSquared); + axis.x = x * s; + axis.y = y * s; + axis.z = z * s; + if (w <= -1 || w >= 1) + angle = 0; + else + angle = (T) acos(w) * 2; + } + else + { + // The angle is zero, so we pick an arbitrary unit axis + axis.x = 1; + axis.y = 0; + axis.z = 0; + angle = 0; + } +} + + +// Convert this (assumed to be normalized) quaternion to a rotation matrix +template Matrix4 Quaternion::toMatrix4() const +{ + T wx = w * x * 2; + T wy = w * y * 2; + T wz = w * z * 2; + T xx = x * x * 2; + T xy = x * y * 2; + T xz = x * z * 2; + T yy = y * y * 2; + T yz = y * z * 2; + T zz = z * z * 2; + + return Matrix4(Vector4(1 - yy - zz, xy + wz, xz - wy, 0), + Vector4(xy - wz, 1 - xx - zz, yz + wx, 0), + Vector4(xz + wy, yz - wx, 1 - xx - yy, 0), + Vector4(0, 0, 0, 1)); +} + + +// Convert this (assumed to be normalized) quaternion to a rotation matrix +template Matrix3 Quaternion::toMatrix3() const +{ + T wx = w * x * 2; + T wy = w * y * 2; + T wz = w * z * 2; + T xx = x * x * 2; + T xy = x * y * 2; + T xz = x * z * 2; + T yy = y * y * 2; + T yz = y * z * 2; + T zz = z * z * 2; + + return Matrix3(Vector3(1 - yy - zz, xy + wz, xz - wy), + Vector3(xy - wz, 1 - xx - zz, yz + wx), + Vector3(xz + wy, yz - wx, 1 - xx - yy)); +} + + +template T dot(Quaternion a, Quaternion b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; +} + + +template Quaternion Quaternion::slerp(Quaternion q0, + Quaternion q1, + T t) +{ + T c = dot(q0, q1); + T angle = (T) acos(c); + + if (abs(angle) < (T) 1.0e-5) + return q0; + + T s = (T) sin(angle); + T is = (T) 1.0 / s; + + return q0 * ((T) sin((1 - t) * angle) * is) + + q1 * ((T) sin(t * angle) * is); +} + + +// Assuming that this is a unit quaternion representing an orientation, +// apply a rotation of angle radians about the specfied axis +template void Quaternion::rotate(Vector3 axis, T angle) +{ + Quaternion q; + q.setAxisAngle(axis, angle); + *this = q * *this; +} + + +// Assuming that this is a unit quaternion representing an orientation, +// apply a rotation of angle radians about the x-axis +template void Quaternion::xrotate(T angle) +{ + T s, c; + + Math::sincos(angle * (T) 0.5, s, c); + *this = Quaternion(c, s, 0, 0) * *this; +} + +// Assuming that this is a unit quaternion representing an orientation, +// apply a rotation of angle radians about the y-axis +template void Quaternion::yrotate(T angle) +{ + T s, c; + + Math::sincos(angle * (T) 0.5, s, c); + *this = Quaternion(c, 0, s, 0) * *this; +} + +// Assuming that this is a unit quaternion representing an orientation, +// apply a rotation of angle radians about the z-axis +template void Quaternion::zrotate(T angle) +{ + T s, c; + + Math::sincos(angle * (T) 0.5, s, c); + *this = Quaternion(c, 0, 0, s) * *this; +} + + +#endif // _QUATERNION_H_ diff --git a/src/readstars.cpp b/src/readstars.cpp new file mode 100644 index 00000000..fc8ed970 --- /dev/null +++ b/src/readstars.cpp @@ -0,0 +1,81 @@ +// readstars.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include + +#define MAX_STARS 120000 + +#define PI 3.1415926535898 + +#include "basictypes.h" +#include "stellarclass.h" +#include "star.h" + + +int main(int argc, char *argv[]) +{ + Star *stars = new Star[MAX_STARS]; + int nStars = 0; + float brightest = 100000; + + while (nStars < MAX_STARS) { + uint32 catNo = 0; + float RA = 0, dec = 0, parallax = 0; + int16 appMag; + uint16 stellarClass; + + cin.read((void *) &catNo, sizeof catNo); + cin.read((void *) &RA, sizeof RA); + cin.read((void *) &dec, sizeof dec); + cin.read((void *) ¶llax, sizeof parallax); + cin.read((void *) &appMag, sizeof appMag); + cin.read((void *) &stellarClass, sizeof stellarClass); + if (!cin.good()) + break; + + Star *star = &stars[nStars]; + + // Compute distance based on parallax + double distance = 3.26 / (parallax > 0.0 ? parallax / 1000.0 : 1e-6); + + // Convert from RA, dec spherical to cartesian coordinates + double theta = RA / 24.0 * PI * 2; + double phi = (1.0 - dec / 90.0) * PI / 2; + double x = cos(theta) * sin(phi) * distance; + double y = cos(phi) * distance; + double z = sin(theta) * sin(phi) * distance; + star->setPosition((float) x, (float) y, (float) z); + + // Use apparent magnitude and distance to determine the absolute + // magnitude of the star. + star->setAbsoluteMagnitude((float) (appMag / 256.0 + 5 - + 5 * log10(distance / 3.26))); + + StellarClass sc((StellarClass::StarType) (stellarClass >> 12), + (StellarClass::SpectralClass)(stellarClass >> 8 & 0xf), + (unsigned int) (stellarClass >> 4 & 0xf), + (StellarClass::LuminosityClass) (stellarClass & 0xf)); + star->setStellarClass(sc); + + star->setCatalogNumber(catNo); + + if (parallax > 0.0 && star->getAbsoluteMagnitude() < brightest) + { + brightest = star->getAbsoluteMagnitude(); + cout << brightest << ' ' << sc << '\n'; + } + + nStars++; + } + + cout << nStars << '\n'; + cout << sizeof(StellarClass) << '\n'; + cout << sizeof(stars[0]) << '\n'; +} diff --git a/src/render.cpp b/src/render.cpp new file mode 100644 index 00000000..e097d156 --- /dev/null +++ b/src/render.cpp @@ -0,0 +1,1385 @@ +// render.cpp +// +// Copyright (C) 2001, Chris Laurel +// +// 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 +#include "gl.h" +#include "astro.h" +#include "glext.h" +#include "vecgl.h" +#include "perlin.h" +#include "spheremesh.h" +#include "texfont.h" +#include "console.h" +#include "gui.h" +#include "render.h" + +using namespace std; + +#define FOV 45.0f +#define NEAR_DIST 0.5f +#define FAR_DIST 3000.0f + +#define RENDER_DISTANCE 10.0f + +// Static meshes and textures used by all instances of Simulation + +static bool commonDataInitialized = false; + +#define SPHERE_LODS 4 + +static SphereMesh* sphereMesh[SPHERE_LODS]; +static SphereMesh* asteroidMesh = NULL; + +static CTexture* starTex = NULL; +static CTexture* glareTex = NULL; +static CTexture* ringsTex = NULL; +static CTexture* shadowTex = NULL; + +static TexFont* font; + + +Renderer::Renderer() : + windowWidth(0), + windowHeight(0), + fov(FOV), + renderMode(GL_FILL), + labelMode(NoLabels), + ambientLightLevel(0.1f), + console(NULL), + nSimultaneousTextures(1) +{ + textureManager = new TextureManager("textures"); + meshManager = new MeshManager("models"); + console = new Console(30, 100); +} + + +Renderer::~Renderer() +{ +} + + +static void BlueTextureEval(float u, float v, float w, + unsigned char *pixel) +{ + float t = turbulence(Point2f(u, v), 32) + 0.0f; + if (t > 1) + t = 1; + + int pixVal = (int) (t * 255.99f); + pixel[0] = 0; + pixel[1] = 0; + pixel[2] = pixVal; +} + +static void StarTextureEval(float u, float v, float w, + unsigned char *pixel) +{ + float r = 1 - (float) sqrt(u * u + v * v); + if (r < 0) + { + r = 0; + } + else if (r < 0.25f) + { + r = 4.0f * r; + } + else + { + r = 1; + } + + int pixVal = (int) (r * 255.99f); + pixel[0] = pixVal; + pixel[1] = pixVal; + pixel[2] = pixVal; +} + +static void GlareTextureEval(float u, float v, float w, + unsigned char *pixel) +{ + float r = 1 - (float) sqrt(u * u + v * v); + if (r < 0) + r = 0; + + int pixVal = (int) (r * 255.99f); + pixel[0] = pixVal; + pixel[1] = pixVal; + pixel[2] = pixVal; +} + +static void ShadowTextureEval(float u, float v, float w, + unsigned char *pixel) +{ + float r = (float) sqrt(u * u + v * v); + + int pixVal = r < 0.95f ? 0 : 255; + pixel[0] = pixVal; + pixel[1] = pixVal; + pixel[2] = pixVal; +} + + +static float AsteroidDisplacementFunc(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)); + + // return 0.5f; + return fractalsum(Point3f(x + 10, y + 10, z + 10), 1) * 0.75f; +} + + +static float calcPixelSize(float fovY, float windowHeight) +{ + return 2 * NEAR_DIST * (float) tan(degToRad(fovY / 2.0)) / (float) windowHeight; +} + + +bool Renderer::init(int winWidth, int winHeight) +{ + // Initialize static meshes and textures common to all instances of Renderer + if (!commonDataInitialized) + { + sphereMesh[0] = new SphereMesh(1.0f, 11, 10); + sphereMesh[1] = new SphereMesh(1.0f, 21, 20); + sphereMesh[2] = new SphereMesh(1.0f, 31, 30); + sphereMesh[3] = new SphereMesh(1.0f, 41, 40); + asteroidMesh = new SphereMesh(Vec3f(0.7f, 1.1f, 1.0f), + 21, 20, + AsteroidDisplacementFunc, + NULL); + + starTex = CreateProceduralTexture(64, 64, GL_RGB, StarTextureEval); + starTex->bindName(); + + glareTex = CreateJPEGTexture("textures\\glare.jpg"); + if (glareTex == NULL) + glareTex = CreateProceduralTexture(64, 64, GL_RGB, GlareTextureEval); + glareTex->bindName(); + + shadowTex = CreateProceduralTexture(256, 256, GL_RGB, ShadowTextureEval); + shadowTex->bindName(); + + ringsTex = CreateJPEGTexture("textures\\rings.jpg", + CTexture::ColorChannel | CTexture::AlphaChannel); + if (ringsTex != NULL) + ringsTex->bindName(); + + // font = txfLoadFont("fonts\\helvetica_14b.txf"); + font = txfLoadFont("fonts\\default.txf"); + if (font != NULL) + txfEstablishTexture(font, 0, GL_TRUE); + + if (ExtensionSupported("GL_ARB_multitexture")) + InitExtMultiTexture(); + + + commonDataInitialized = true; + } + + cout << "GL extensions supported:\n"; + cout << glGetString(GL_EXTENSIONS) << '\n'; + + // Get GL extension information + if (ExtensionSupported("GL_ARB_multitexture")) + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &nSimultaneousTextures); + + cout << "Simultaneous textures supported: " << nSimultaneousTextures << '\n'; + + glLoadIdentity(); + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + glEnable(GL_COLOR_MATERIAL); + glEnable(GL_LIGHTING); + + // We need this enabled because we use glScale, but only + // with uniform scale factors + // TODO: Do a proper check for this extension before enabling + glEnable(GL_RESCALE_NORMAL_EXT); + + console->setFont(font); + + resize(winWidth, winHeight); + + return true; +} + + +void Renderer::resize(int width, int height) +{ + windowWidth = width; + windowHeight = height; + // glViewport(windowWidth, windowHeight); +} + + +float Renderer::getFieldOfView() +{ + return fov; +} + + +void Renderer::setFieldOfView(float _fov) +{ + fov = _fov; +} + + +void Renderer::setRenderMode(int _renderMode) +{ + renderMode = _renderMode; +} + + +Vec3f Renderer::getPickRay(int winX, int winY) +{ + float aspectRatio = (float) windowWidth / (float) windowHeight; + float nearPlaneHeight = 2 * NEAR_DIST * (float) tan(degToRad(fov / 2.0)); + float nearPlaneWidth = nearPlaneHeight * aspectRatio; + + float x = nearPlaneWidth * ((float) winX / (float) windowWidth - 0.5f); + float y = nearPlaneHeight * (0.5f - (float) winY / (float) windowHeight); + Vec3f pickDirection = Vec3f(x, y, -NEAR_DIST); + pickDirection.normalize(); + + return pickDirection; +} + + +Console* Renderer::getConsole() +{ + return console; +} + + +int Renderer::getLabelMode() const +{ + return labelMode; +} + + +void Renderer::setLabelMode(int _labelMode) +{ + labelMode = _labelMode; +} + + +void Renderer::addLabelledStar(Star* star) +{ + labelledStars.insert(labelledStars.end(), star); +} + + +void Renderer::clearLabelledStars() +{ + labelledStars.clear(); +} + + +float Renderer::getAmbientLightLevel() const +{ + return ambientLightLevel; +} + + +void Renderer::setAmbientLightLevel(float level) +{ + ambientLightLevel = level; +} + + +void Renderer::addLabel(string text, Color color, Point3f pos) +{ + double winX, winY, winZ; + int view[4] = { 0, 0, 0, 0 }; + view[0] = -windowWidth / 2; + view[1] = -windowHeight / 2; + view[2] = windowWidth; + view[3] = windowHeight; + if (gluProject(pos.x, pos.y, pos.z, + modelMatrix, + projMatrix, + view, + &winX, &winY, &winZ) != GL_FALSE) + { + Label l; + l.text = text; + l.color = color; + l.position = Point3f((float) winX, (float) winY, (float) winZ); + labels.insert(labels.end(), l); + } +} + + +void Renderer::clearLabels() +{ + labels.clear(); +} + + +void Renderer::render(const Observer& observer, + const StarDatabase& starDB, + const VisibleStarSet& visset, + SolarSystem* solarSystem, + const Selection& sel, + double now) +{ + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + // Compute the size of a pixel + pixelSize = calcPixelSize(fov, windowHeight); + + // Set up the projection + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(fov, + (float) windowWidth / (float) windowHeight, + NEAR_DIST, FAR_DIST); + + // Set the modelview matrix + glMatrixMode(GL_MODELVIEW); + + // Create the ambient light source. For realistic space rendering + // this should be black. + { + float ambientColor[4]; + ambientColor[0] = ambientColor[1] = ambientColor[2] = ambientLightLevel; + ambientColor[3] = 1.0f; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor); + } + + // Set up the camera + Point3f observerPos = (Point3f) observer.getPosition(); + glPushMatrix(); + glRotate(~observer.getOrientation()); + // Get the model matrix *before* translation + glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); + glPushMatrix(); + glTranslatef(-observerPos.x, -observerPos.y, -observerPos.z); + + glDisable(GL_LIGHTING); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + clearLabels(); + renderList.clear(); + + // Render stars + renderStars(starDB, visset, observer); + if ((labelMode & StarLabels) != 0) + labelStars(labelledStars, starDB, observer); + + glPopMatrix(); + + glPolygonMode(GL_FRONT, renderMode); + glPolygonMode(GL_BACK, renderMode); + + // Render planets, moons, asteroids, etc. Stars close and large enough + // to have discernible surface detail are also placed in renderList. + // planetParticles.clear(); + Star* sun = NULL; + if (solarSystem != NULL) + sun = starDB.find(solarSystem->getStarNumber()); + if (sun != NULL) + { + renderPlanetarySystem(*sun, + *solarSystem->getPlanets(), + observer, + Mat4d::identity(), now, + (labelMode & PlanetLabels) != 0); + glBindTexture(GL_TEXTURE_2D, starTex->getName()); + // renderParticles(planetParticles, observer.getOrientation()); + + // The call to renderSolarSystem filled renderList with visible + // planetary bodies. Sort it by distance, then render each entry. + sort(renderList.begin(), renderList.end()); + + int nEntries = renderList.size(); + + // Determine how to split up the depth buffer. Each body with an + // apparent size greater than one pixel is allocated its own + // depth buffer range. This means that overlapping objects + // may not be handled correctly, but such an occurrence would be + // extremely rare, unless we expand the simulation to include + // docking spaceships etc. In that case, this technique would have + // to be modified to let overlapping objects share a depth buffer + // range. + int nDepthBuckets = 1; + for (int i = 0; i < nEntries; i++) + { + if (renderList[i].discSizeInPixels > 1) + nDepthBuckets++; + } + float depthRange = 1.0f / (float) nDepthBuckets; + + int depthBucket = nDepthBuckets - 1; + i = nEntries - 1; + + // Set up the depth bucket. + glDepthRange(depthBucket * depthRange, (depthBucket + 1) * depthRange); + + // Render all the bodies in the render list. + for (i = nEntries - 1; i >= 0; i--) + { + if (renderList[i].body != NULL) + { + renderPlanet(*renderList[i].body, + renderList[i].position, + renderList[i].sun, + renderList[i].distance, + renderList[i].appMag, + now, + observer.getOrientation()); + } + else if (renderList[i].star != NULL) + { + renderStar(*renderList[i].star, + renderList[i].position, + renderList[i].distance, + renderList[i].appMag, + observer.getOrientation()); + } + + // If this body is larger than a pixel, we rendered it as a mesh + // instead of just a particle. We move to the next depth buffer + // bucket before proceeding with further rendering. + if (renderList[i].discSizeInPixels > 1) + { + depthBucket--; + glDepthRange(depthBucket * depthRange, (depthBucket + 1) * depthRange); + } + } + + // reset the depth range + glDepthRange(0, 1); + + if ((labelMode & PlanetOrbits) != 0) + { + // At this point, we're not rendering into the depth buffer + // so we'll set the far plane to be way out there. If we don't + // do this, the orbits either suffer from clipping by the far + // plane, or else get clipped to close to the viewer. + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(fov, + (float) windowWidth / (float) windowHeight, + NEAR_DIST, 1000000); + + // Set the modelview matrix + glMatrixMode(GL_MODELVIEW); + + Star* sun = starDB.find(solarSystem->getStarNumber()); + Point3f starPos = sun->getPosition(); + // Compute the position of the observer relative to the star + Vec3d opos = observer.getPosition() - Point3d((double) starPos.x, + (double) starPos.y, + (double) starPos.z); + + // At the solar system scale, we'll handle all calculations in + // AU instead of light years. + opos = Vec3d(astro::lightYearsToAU(opos.x) * 100, + astro::lightYearsToAU(opos.y) * 100, + astro::lightYearsToAU(opos.z) * 100); + glTranslated(-opos.x, -opos.y, -opos.z); + + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + + // Render orbits + PlanetarySystem* planets = solarSystem->getPlanets(); + int nBodies = planets->getSystemSize(); + for (i = 0; i < nBodies; i++) + { + Body* body = planets->getBody(i); + + // Only show orbits for major bodies or selected objects + if (body->getRadius() > 1000 || body == sel.body) + { + if (body == sel.body) + glColor4f(1, 0, 0, 1); + else + glColor4f(0, 0, 1, 1); + glBegin(GL_LINE_LOOP); + int nSteps = 100; + double dt = body->getOrbit()->getPeriod() / (double) nSteps; + for (int j = 0; j < nSteps; j++) + { + Point3d p = body->getOrbit()->positionAtTime(j * dt); + glVertex3f(astro::kilometersToAU((float) p.x * 100), + astro::kilometersToAU((float) p.y * 100), + astro::kilometersToAU((float) p.z * 100)); + } + glEnd(); + } + } + } + } + + glPopMatrix(); + + glEnable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glPolygonMode(GL_FRONT, GL_FILL); + glPolygonMode(GL_BACK, GL_FILL); + + renderLabels(); + + glColor4f(0.8f, 0.8f, 1.0f, 1); + console->setScale(2.0f / (float) windowWidth, 2.0f / (float) windowHeight); + console->render(); + + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_LIGHTING); +} + + +static void renderParticle(Point3f& center, + Vec3f& v0, + Vec3f& v1, + Vec3f& v2, + Vec3f& v3, + float size) +{ + glTexCoord2f(0, 0); + glVertex(center + (v0 * size)); + glTexCoord2f(1, 0); + glVertex(center + (v1 * size)); + glTexCoord2f(1, 1); + glVertex(center + (v2 * size)); + glTexCoord2f(0, 1); + glVertex(center + (v3 * size)); +} + + +static void renderRingSystem(float innerRadius, + float outerRadius, + float beginAngle, + float endAngle, + int nSections) +{ + float angle = endAngle - beginAngle; + + glBegin(GL_QUAD_STRIP); + for (int i = 0; i <= nSections; i++) + { + float t = (float) i / (float) nSections; + float theta = beginAngle + t * angle; + float s = (float) sin(theta); + float c = (float) cos(theta); + glTexCoord2f(0, 0); + glVertex3f(c * innerRadius, 0, s * innerRadius); + glTexCoord2f(1, 0); + glVertex3f(c * outerRadius, 0, s * outerRadius); + } + glEnd(); +} + + +// If the an object occupies a pixel or less of screen space, we don't +// render its mesh at all and just display a starlike point instead. +// Switching between the particle and mesh renderings of an object is +// jarring, however . . . so we'll blend in the particle view of the +// object to smooth things out, making it dimmer as the disc size approaches +// 4 pixels. +void Renderer::renderBodyAsParticle(Point3f position, + float appMag, + float discSizeInPixels, + Color color, + const Quatf& orientation, + bool useHaloes) +{ + if (discSizeInPixels < 4 || useHaloes) + { + float r = 1, g = 1, b = 1; + float a = 1; + + if (discSizeInPixels > 1) + { + a = 0.5f * (4 - discSizeInPixels); + if (a > 1) + a = 1; + } + else + { + a = clamp(1.0f - appMag / 6.0f); + } + + // We scale up the particle by a factor of 3 so that it's more visible--the + // texture we use has fuzzy edges, and if we render it in just one pixel, + // it's likely to disappear. Also, the render distance is scaled by a factor + // of 0.1 so that we're rendering in front of any mesh that happens to be + // sharing this depth bucket. What we really want is to render the particle + // with the frontmost z value in this depth bucket, and scaling the render + // distance is just hack to accomplish this. There are cases where it will + // fail and a more robust method should be implemented. + float size = pixelSize * 3.0f * RENDER_DISTANCE * 0.1f; + Point3f center(position.x * 0.1f, position.y * 0.1f, position.z * 0.1f); + Mat3f m = orientation.toMatrix3(); + Vec3f v0 = Vec3f(-1, -1, 0) * m; + Vec3f v1 = Vec3f( 1, -1, 0) * m; + Vec3f v2 = Vec3f( 1, 1, 0) * m; + Vec3f v3 = Vec3f(-1, 1, 0) * m; + + glBindTexture(GL_TEXTURE_2D, starTex->getName()); + glColor(color, a); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex(center + (v0 * size)); + glTexCoord2f(1, 0); + glVertex(center + (v1 * size)); + glTexCoord2f(1, 1); + glVertex(center + (v2 * size)); + glTexCoord2f(0, 1); + glVertex(center + (v3 * size)); + glEnd(); + + // If the object is brighter than magnitude 1, add a halo around it to + // make it appear more brilliant. This is a hack to compensate for the + // limited dynamic range of monitors. + // + // TODO: Currently, this is extremely broken. Stars look fine, but planets + // look ridiculous with bright haloes. + if (useHaloes && appMag < 1.0f) + { + a = 0.4f * clamp((appMag - 1) * -0.8f); + // size *= (3 - (appMag - 1)) * 2; + // size = RENDER_DISTANCE * 0.001f * (3 - (appMag - 1)) * 1; + // size = discSizeInPixels * 3 * pixelSize; + // size *= 30.0f; + float s = RENDER_DISTANCE * 0.0001f * (3 - (appMag - 1)) * 2; + if (s > size * 3) + size = s; + else + size = size * 3; + float realSize = discSizeInPixels * (pixelSize / NEAR_DIST) * RENDER_DISTANCE * 0.1f; + if (size < realSize * 10) + size = realSize * 10; + glBindTexture(GL_TEXTURE_2D, glareTex->getName()); + glColor(color, a); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex(center + (v0 * size)); + glTexCoord2f(1, 0); + glVertex(center + (v1 * size)); + glTexCoord2f(1, 1); + glVertex(center + (v2 * size)); + glTexCoord2f(0, 1); + glVertex(center + (v3 * size)); + glEnd(); + } + } +} + + +void Renderer::renderPlanet(const Body& body, + Point3f pos, + Vec3f sunDirection, + float distance, + float appMag, + double now, + Quatf orientation) +{ + float discSizeInPixels = body.getRadius() / distance / (pixelSize / NEAR_DIST); + + if (discSizeInPixels > 1) + { + // Enable depth buffering + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + + sunDirection.normalize(); + + // Set up the light source for the sun + glLightDirection(GL_LIGHT0, sunDirection); + glLightColor(GL_LIGHT0, GL_DIFFUSE, Vec3f(1.0f, 1.0f, 1.0f)); + glEnable(GL_LIGHT0); + + // Get the texture . . . + CTexture* tex = NULL; + if (body.getTexture() != "") + { + if (!textureManager->find(body.getTexture(), &tex)) + tex = textureManager->load(body.getTexture()); + } + + if (tex == NULL) + { + glDisable(GL_TEXTURE_2D); + } + else + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex->getName()); + } + + if (tex == NULL || body.getAppearanceFlag(Body::BlendTexture)) + glColor(body.getColor()); + else + glColor4f(1, 1, 1, 1); + + glDisable(GL_BLEND); + glEnable(GL_LIGHTING); + glPushMatrix(); + glTranslate(pos); + glRotatef(radToDeg(body.getObliquity()), 1, 0, 0); + + double planetRotation = 0.0; + // Watch out for the precision limits of floats when computing planet + // rotation . . . + { + double hours = now / 3600.0; + double rotations = hours / (double) body.getRotationPeriod(); + int wholeRotations = (int) rotations; + double remainder = rotations - wholeRotations; + planetRotation = -remainder * 2 * PI; + glRotatef((float) (-remainder * 360.0), 0, 1, 0); + } + + float discSize = body.getRadius() / distance * RENDER_DISTANCE; + + // Apply a scale factor which depends on the apparent size of the + // planet and its oblateness. Since the oblateness is usually quite + // small, the potentially nonuniform scale factor shouldn't mess up + // the lighting calculations enough to cause a problem. + // TODO: Figure out a better way to render ellipsoids than applying + // a nonunifom scale factor to a sphere. It just makes me nervous. + glScalef(discSize, discSize * (1.0f - body.getOblateness()), discSize); + + Mesh* mesh = NULL; + if (body.getMesh() == "") + { + int lod = 0; + if (discSizeInPixels < 10) + lod = 0; + else if (discSizeInPixels < 50) + lod = 1; + else if (discSizeInPixels < 200) + lod = 2; + else + lod = 3; + + if (body.getRadius() < 50) + mesh = asteroidMesh; + else + mesh = sphereMesh[lod]; + } + else + { + if (!meshManager->find(body.getMesh(), &mesh)) + mesh = meshManager->load(body.getMesh()); + } + + if (mesh != NULL) + mesh->render(); + + // If the planet has a ring system, render it. + if (body.getRings() != NULL) + { + RingSystem* rings = body.getRings(); + float inner = rings->innerRadius / body.getRadius(); + float outer = rings->outerRadius / body.getRadius(); + int nSections = 100; + + // Convert the sun direction to the planet's coordinate system + Mat4f planetMat = Mat4f::xrotation((float) body.getObliquity()) * + Mat4f::yrotation((float) planetRotation); + Vec3f localSunDir = sunDirection * planetMat; + + // Ring Illumination + // Since a ring system is composed of millions of individual particles, + // it's not at all realistic to model it as a flat Lambertian surface. + // We'll approximate the llumination function by assuming that the ring + // system contains Lambertian particles, and that the brightness at some + // point in the ring system is proportional to the illuminated fraction + // of a particle there. In fact, we'll simplify things further and set + // the illumination of the entire ring system to the same value, computing + // the illuminated fraction of a hypothetical particle located at the center + // of the planet. This approximation breaks down when you get close to the + // planet . . . + float ringIllumination = 0.0f; + { + // Compute the direction from the viewer to the planet in the + // planet's coordinate system + Vec3f viewVec = (Point3f(0, 0, 0) - pos) * planetMat; + viewVec.normalize(); + float illumFraction = (1.0f + viewVec * localSunDir) / 2.0f; + + // Just use the illuminated fraction for now . . . + ringIllumination = illumFraction; + } + + // If we have multi-texture support, we'll use the second texture unit + // to render the shadow of the planet on the rings. This is a bit of + // a hack, and assumes that the planet is nearly spherical in shape, and + // only works for a planet illuminated by a single sun where the distance + // to the sun is very large relative to its diameter. + if (nSimultaneousTextures > 1) + { + glActiveTextureARB(GL_TEXTURE1_ARB); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, shadowTex->getName()); + + float sPlane[4] = { 0, 0, 0, 0.5f }; + float tPlane[4] = { 0, 0, 0, 0.5f }; + + // Compute the projection vectors based on the sun direction. + // I'm being a little careless here--if the sun direction lies + // along the y-axis, this will fail. It's unlikely that a planet + // would ever orbit underneath its sun (an orbital inclination of + // 90 degrees), but this should be made more robust anyway. + Vec3f axis = Vec3f(0, 1, 0) ^ localSunDir; + float angle = (float) acos(Vec3f(0, 1, 0) * localSunDir); + Mat4f mat = Mat4f::rotation(axis, -angle); + Vec3f sAxis = Vec3f(0.5f, 0, 0) * mat; + Vec3f tAxis = Vec3f(0, 0, 0.5f) * mat; + + sPlane[0] = sAxis.x; sPlane[1] = sAxis.y; sPlane[2] = sAxis.z; + tPlane[0] = tAxis.x; tPlane[1] = tAxis.y; tPlane[2] = tAxis.z; + + glEnable(GL_TEXTURE_GEN_S); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_S, GL_EYE_PLANE, sPlane); + glEnable(GL_TEXTURE_GEN_T); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + glTexGenfv(GL_T, GL_EYE_PLANE, tPlane); + + glActiveTextureARB(GL_TEXTURE0_ARB); + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (ringsTex != NULL) + glBindTexture(GL_TEXTURE_2D, ringsTex->getName()); + else + glDisable(GL_TEXTURE_2D); + + // Perform our own lighting for the rings. + // TODO: Don't forget about light source color (required when we start paying + // attention to star color.) + glDisable(GL_LIGHTING); + { + Vec3f litColor(rings->color.red(), rings->color.green(), rings->color.blue()); + litColor = litColor * ringIllumination + Vec3f(1, 1, 1) * ambientLightLevel; + glColor4f(litColor.x, litColor.y, litColor.z, 1.0f); + } + + // This gets tricky . . . we render the rings in two parts. One part + // is potentially shadowed by the planet, and we need to render that part + // with the projected shadow texture enabled. The other part isn't shadowed, + // but will appear so if we don't first disable the shadow texture. The problem + // is that the shadow texture will affect anything along the line between the + // sun and the planet, regardless of whether it's in front or behing the planet. + + // Compute the angle of the sun projected on the ring plane + float sunAngle = (float) atan2(localSunDir.z, localSunDir.x); + + // Render the potentially shadowed side + // glNormal3f(0, 1, 0); + renderRingSystem(inner, outer, + (float) (sunAngle + PI / 2), (float) (sunAngle + 3 * PI / 2), + nSections / 2); + // glNormal3f(0, -1, 0); + renderRingSystem(inner, outer, + (float) (sunAngle + 3 * PI / 2), (float) (sunAngle + PI / 2), + nSections / 2); + + // Disable the second texture unit if it was used + if (nSimultaneousTextures > 1) + { + glActiveTextureARB(GL_TEXTURE1_ARB); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glActiveTextureARB(GL_TEXTURE0_ARB); + } + + // Render the unshadowed side + // glNormal3f(0, 1, 0); + renderRingSystem(inner, outer, + (float) (sunAngle - PI / 2), (float) (sunAngle + PI / 2), + nSections / 2); + // glNormal3f(0, -1, 0); + renderRingSystem(inner, outer, + (float) (sunAngle + PI / 2), (float) (sunAngle - PI / 2), + nSections / 2); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + + glPopMatrix(); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glDisable(GL_LIGHTING); + glEnable(GL_BLEND); + } + + renderBodyAsParticle(pos, + appMag, + discSizeInPixels, + body.getColor(), + orientation, + false); +#if 0 + // If the size of the planetary disc is under a pixel, we don't + // render the mesh for the planet and just display a starlike point instead. + // Switching between the particle and mesh renderings of a body is + // jarring, however . . . so we'll blend in the particle view of the + // body to smooth things out, making it dimmer as the disc size approaches + // 4 pixels. + if (discSizeInPixels < 4) + { + float r = 1, g = 1, b = 1; + float a = 1; + + if (discSizeInPixels > 1) + { + a = 0.5f * (4 - discSizeInPixels); + if (a > 1) + a = 1; + } + else + { + a = clamp(1.0f - appMag / 6.0f); + } + + // We scale up the particle by a factor of 3 so that it's more visible--the + // texture we use has fuzzy edges, and if we render it in just one pixel, + // it's likely to disappear. Also, the render distance is scaled by a factor + // of 0.1 so that we're rendering in front of any mesh that happens to be + // sharing this depth bucket. What we really want is to render the particle + // with the frontmost z value in this depth bucket, and scaling the render + // distance is just hack to accomplish this. There are cases where it will + // fail and a more robust method should be implemented. + float size = pixelSize * 3.0f * RENDER_DISTANCE * 0.1f; + Point3f center(pos.x * 0.1f, pos.y * 0.1f, pos.z * 0.1f); + Mat3f m = orientation.toMatrix3(); + Vec3f v0 = Vec3f(-1, -1, 0) * m; + Vec3f v1 = Vec3f( 1, -1, 0) * m; + Vec3f v2 = Vec3f( 1, 1, 0) * m; + Vec3f v3 = Vec3f(-1, 1, 0) * m; + + glBindTexture(GL_TEXTURE_2D, starTex->getName()); + glColor(body.getColor(), a); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex(center + (v0 * size)); + glTexCoord2f(1, 0); + glVertex(center + (v1 * size)); + glTexCoord2f(1, 1); + glVertex(center + (v2 * size)); + glTexCoord2f(0, 1); + glVertex(center + (v3 * size)); + glEnd(); + } +#endif +} + + +#if 1 +void Renderer::renderStar(const Star& star, + Point3f pos, + float distance, + float appMag, + Quatf orientation) +{ + Color color = star.getStellarClass().getApparentColor(); + float radius = star.getRadius(); + float discSizeInPixels = radius / distance / (pixelSize / NEAR_DIST); + float discSize = radius / distance * RENDER_DISTANCE; + + if (discSizeInPixels > 1) + { + // Enable depth buffering + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + + glDisable(GL_BLEND); + glPushMatrix(); + glTranslate(pos); + + glColor(color); + glScalef(discSize, discSize, discSize); + + char* textureName = NULL; + switch (star.getStellarClass().getSpectralClass()) + { + case StellarClass::Spectral_O: + case StellarClass::Spectral_B: + textureName = "bstar.jpg"; + break; + case StellarClass::Spectral_A: + case StellarClass::Spectral_F: + textureName = "astar.jpg"; + break; + case StellarClass::Spectral_G: + case StellarClass::Spectral_K: + textureName = "gstar.jpg"; + break; + case StellarClass::Spectral_M: + case StellarClass::Spectral_R: + case StellarClass::Spectral_S: + case StellarClass::Spectral_N: + textureName = "mstar.jpg"; + break; + default: + textureName = "astar.jpg"; + break; + } + + CTexture* tex = NULL; + if (!textureManager->find(textureName, &tex)) + tex = textureManager->load(textureName); + if (tex == NULL) + { + glDisable(GL_TEXTURE_2D); + } + else + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex->getName()); + } + + int lod = 0; + if (discSizeInPixels < 10) + lod = 0; + else if (discSizeInPixels < 50) + lod = 1; + else if (discSizeInPixels < 200) + lod = 2; + else + lod = 3; + sphereMesh[lod]->render();; + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glPopMatrix(); + } + + renderBodyAsParticle(pos, + appMag, + discSizeInPixels, + color, + orientation, + true); +} +#endif + + +void Renderer::renderPlanetarySystem(const Star& sun, + const PlanetarySystem& solSystem, + const Observer& observer, + Mat4d& frame, + double now, + bool showLabels) +{ + float size = pixelSize * 3.0f; + + Point3f starPos = sun.getPosition(); + Point3d observerPos = astro::heliocentricPosition(observer.getPosition(), starPos); + + int nBodies = solSystem.getSystemSize(); + for (int i = 0; i < nBodies; i++) + { + Body* body = solSystem.getBody(i); + Point3d localPos = body->getOrbit()->positionAtTime(now / 86400.0); + Mat4d newFrame = Mat4d::xrotation(-body->getObliquity()) * Mat4d::translation(localPos) * frame; + Point3d bodyPos = Point3d(0, 0, 0) * newFrame; + bodyPos = body->getHeliocentricPosition(now / 86400.0); + double distanceFromSun = bodyPos.distanceTo(Point3d(0, 0, 0)); + + // We now have the positions of the observer and the planet relative + // to the sun. From these, compute the position of the planet + // relative to the observer. + Vec3d posd = bodyPos - observerPos; + + double distanceFromObserver = posd.length(); + float appMag = body->getApparentMagnitude(sun, + bodyPos - Point3d(0, 0, 0), + posd); + + // Scale the position of the body so that it lies at RENDER_DISTANCE units + // from the observer. + if (distanceFromObserver > 0.0) + posd *= (RENDER_DISTANCE / distanceFromObserver); + Vec3f pos((float) posd.x, (float) posd.y, (float) posd.z); + + float s = (float) RENDER_DISTANCE * size; + + // Compute the size of the planet/moon disc in pixels + float discSize = (body->getRadius() / (float) distanceFromObserver) / (pixelSize / NEAR_DIST); + + if (discSize > 1 || appMag < 6.0f) + { + RenderListEntry rle; + rle.body = body; + rle.star = NULL; + rle.position = Point3f(pos.x, pos.y, pos.z); + rle.sun = Vec3f((float) -bodyPos.x, (float) -bodyPos.y, (float) -bodyPos.z); + rle.distance = distanceFromObserver; + rle.discSizeInPixels = discSize; + rle.appMag = appMag; + renderList.insert(renderList.end(), rle); + } +#if 0 + else + { + float r = 1, g = 1, b = 1; + float a = clamp(1.0f - appMag / 6.0f); + + Particle p; + p.center = Point3f(pos.x, pos.y, pos.z); + p.size = (float) RENDER_DISTANCE * size; + p.color = Color(body->getColor(), a); + planetParticles.insert(planetParticles.end(), p); + } +#endif + + if (showLabels && (pos * conjugate(observer.getOrientation()).toMatrix3()).z < 0) + { + addLabel(body->getName(), + Color(0.0f, 1.0f, 0.0f), + Point3f(pos.x, pos.y, pos.z)); + } + + if (appMag < 5.0f) + { + const PlanetarySystem* satellites = body->getSatellites(); + if (satellites != NULL) + { + // Only show labels for satellites if the planet is nearby. + bool showSatelliteLabels = showLabels && (distanceFromObserver < 25000000); + renderPlanetarySystem(sun, *satellites, observer, newFrame, now, + showSatelliteLabels); + } + } + + } +} + + +void Renderer::renderStars(const StarDatabase& starDB, + const VisibleStarSet& visset, + const Observer& observer) +{ + vector* vis = visset.getVisibleSet(); + int nStars = vis->size(); + Point3f observerPos = (Point3f) observer.getPosition(); + Vec3f relPos; + + float size = pixelSize * 3.0f; + Mat3f m = conjugate(observer.getOrientation()).toMatrix3().transpose(); + Vec3f v0 = Vec3f(-1, -1, 0) * m; + Vec3f v1 = Vec3f( 1, -1, 0) * m; + Vec3f v2 = Vec3f( 1, 1, 0) * m; + Vec3f v3 = Vec3f(-1, 1, 0) * m; + + starParticles.clear(); + glareParticles.clear(); + + for (int i = 0; i < nStars; i++) + { + Star* star = starDB.getStar((*vis)[i]); + Point3f pos = star->getPosition(); + float distance = pos.distanceTo(observerPos); + + Color starColor = star->getStellarClass().getApparentColor(); + float alpha = 0.0f; + float renderDistance = distance; + float s = renderDistance * size; + float discSizeInPixels = 0.0f; + + // Special handling for stars less than one light year away . . . + // We can't just go ahead and render a nearby star in the usual way + // for two reasons: + // * It may be clipped by the near plane + // * It may be large enough that we should render it as a mesh instead + // of a particle + // It's possible that the second condition might apply for stars further + // than one light year away if the star is huge, the fov is very small, + // and the resolution is high. We'll ignore this for now and use the + // most inexpensive test possible . . . + if (distance < 1.0f) + { + // Compute the position of the observer relative to the star. + // This is a much more accurate (and expensive) distance + // calculation than the previous one which used the observer's + // position rounded off to floats. + relPos = pos - observer.getPosition(); + distance = relPos.length(); + + float f = RENDER_DISTANCE / distance; + renderDistance = RENDER_DISTANCE; + pos = observerPos + relPos * f; + + float radius = star->getRadius(); + // s = renderDistance * size + astro::kilometersToLightYears(radius * f); + discSizeInPixels = radius / astro::lightYearsToKilometers(distance) / + (pixelSize / NEAR_DIST); + } + + float appMag = astro::lumToAppMag(star->getLuminosity(), distance); + + alpha = clamp(1.0f - appMag / 6.0f); + + if (discSizeInPixels <= 1) + { + Particle p; + p.center = pos; + p.size = renderDistance * size; + p.color = Color(starColor, alpha); + starParticles.insert(starParticles.end(), p); + + // If the star is brighter than magnitude 1, add a halo around it to + // make it appear more brilliant. This is a hack to compensate for the + // limited dynamic range of monitors. + if (appMag < 1.0f) + { + alpha = 0.4f * clamp((appMag - 1) * -0.8f); + s = renderDistance * 0.001f * (3 - (appMag - 1)) * 2; + + if (s > p.size * 3) + p.size = s; + else + p.size = p.size * 3; + p.color = Color(starColor, alpha); + glareParticles.insert(glareParticles.end(), p); + } + } + else + { + RenderListEntry rle; + rle.star = star; + rle.body = NULL; + + // Objects in the render list are always rendered relative to a viewer + // at the origin--this is different than for distance stars. + float scale = RENDER_DISTANCE / distance; + rle.position = Point3f(relPos.x * scale, relPos.y * scale, relPos.z * scale); + + rle.distance = astro::lightYearsToKilometers(distance); + rle.discSizeInPixels = discSizeInPixels; + rle.appMag = appMag; + renderList.insert(renderList.end(), rle); + } + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, starTex->getName()); + renderParticles(starParticles, observer.getOrientation()); + glBindTexture(GL_TEXTURE_2D, glareTex->getName()); + renderParticles(glareParticles, observer.getOrientation()); +} + + +void Renderer::labelStars(const vector& stars, + const StarDatabase& starDB, + const Observer& observer) +{ + Point3f observerPos = (Point3f) observer.getPosition(); + Vec3f relPos; + + for (vector::const_iterator iter = stars.begin(); iter != stars.end(); iter++) + { + Star* star = *iter; + Point3f pos = star->getPosition(); + float distance = pos.distanceTo(observerPos); + float appMag = astro::lumToAppMag(star->getLuminosity(), distance); + + if (appMag < 6.0f) + { + Vec3f rpos = pos - observerPos; + if ((rpos * conjugate(observer.getOrientation()).toMatrix3()).z < 0) + { + addLabel(starDB.getStarName(star->getCatalogNumber()), + Color(0.3f, 0.3f, 1.0f), + Point3f(rpos.x, rpos.y, rpos.z)); + } + } + } +} + + +void Renderer::renderParticles(const vector& particles, + Quatf orientation) +{ + int nParticles = particles.size(); + + Mat3f m = orientation.toMatrix3(); + Vec3f v0 = Vec3f(-1, -1, 0) * m; + Vec3f v1 = Vec3f( 1, -1, 0) * m; + Vec3f v2 = Vec3f( 1, 1, 0) * m; + Vec3f v3 = Vec3f(-1, 1, 0) * m; + + glBegin(GL_QUADS); + for (int i = 0; i < nParticles; i++) + { + Point3f center = particles[i].center; + float size = particles[i].size; + + glColor(particles[i].color); + glTexCoord2f(0, 0); + glVertex(center + (v0 * size)); + glTexCoord2f(1, 0); + glVertex(center + (v1 * size)); + glTexCoord2f(1, 1); + glVertex(center + (v2 * size)); + glTexCoord2f(0, 1); + glVertex(center + (v3 * size)); + } + glEnd(); +} + + +void Renderer::renderLabels() +{ + float xscale = 2.0f / (float) windowWidth; + float yscale = 2.0f / (float) windowHeight; + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, font->texobj); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glScalef(xscale, yscale, 1); + + for (int i = 0; i < labels.size(); i++) + { + glColor(labels[i].color); + glPushMatrix(); + glTranslatef((int) labels[i].position.x, + (int) labels[i].position.y, + -1); + txfRenderString(font, labels[i].text); + glPopMatrix(); + } + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); +} diff --git a/src/render.h b/src/render.h new file mode 100644 index 00000000..c7ce1cf6 --- /dev/null +++ b/src/render.h @@ -0,0 +1,201 @@ +// render.h +// +// Copyright (C) 2001, Chris Laurel +// +// 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. + +#ifndef _RENDER_H_ +#define _RENDER_H_ + +#include +#include +#include "stardb.h" +#include "visstars.h" +#include "observer.h" +#include "solarsys.h" +#include "texmanager.h" +#include "meshmanager.h" +#include "console.h" +#include "selection.h" + + +class Renderer +{ + public: + Renderer(); + ~Renderer(); + + bool init(int, int); + void shutdown() {}; + void resize(int, int); + + float getFieldOfView(); + void setFieldOfView(float); + + void setRenderMode(int); + + void render(const Observer&, + const StarDatabase&, + const VisibleStarSet&, + SolarSystem*, + const Selection& sel, + double now); + + // Convert window coordinates to a ray for picking + Vec3f getPickRay(int winX, int winY); + + Console* getConsole(); + + enum { + NoLabels = 0, + StarLabels = 1, + PlanetLabels = 2, + PlanetOrbits = 4 + }; + int getLabelMode() const; + void setLabelMode(int); + void addLabelledStar(Star*); + void clearLabelledStars(); + float getAmbientLightLevel() const; + void setAmbientLightLevel(float); + + typedef struct { + string text; + Color color; + Point3f position; + } Label; + + void addLabel(string, Color, Point3f); + void clearLabels(); + + public: + // Internal types + // TODO: Figure out how to make these private. Even with a friend + // + struct Particle + { + Point3f center; + float size; + Color color; + float pad0, pad1, pad2; + }; + + typedef struct _RenderListEntry + { + Star* star; + Body* body; + Point3f position; + Vec3f sun; + float distance; + float discSizeInPixels; + float appMag; + + bool operator<(const _RenderListEntry& r) + { + return distance < r.distance; + } + } RenderListEntry; + + private: + void renderStars(const StarDatabase& starDB, + const VisibleStarSet& visset, + const Observer& observer); + void renderPlanetarySystem(const Star& sun, + const PlanetarySystem& solSystem, + const Observer& observer, + Mat4d& frame, + double now, + bool showLabels = false); + void renderPlanet(const Body& body, + Point3f pos, + Vec3f sunDirection, + float distance, + float appMag, + double now, + Quatf orientation); + void renderStar(const Star& star, + Point3f pos, + float distance, + float appMag, + Quatf orientation); + void renderBodyAsParticle(Point3f center, + float appMag, + float discSizeInPixels, + Color color, + const Quatf& orientation, + bool useHaloes); + void labelStars(const vector& stars, + const StarDatabase& starDB, + const Observer& observer); + void renderParticles(const vector& particles, + Quatf orientation); + void renderLabels(); + + + private: + int windowWidth; + int windowHeight; + float fov; + float pixelSize; + + TextureManager* textureManager; + MeshManager* meshManager; + Console* console; + + int renderMode; + int labelMode; + float ambientLightLevel; + + vector renderList; + vector starParticles; + vector glareParticles; + vector planetParticles; + vector