celestia/src/tools/cmod/cmodview/modelviewwidget.h

263 lines
5.7 KiB
C++

// cmoddview - An application for previewing cmod and other 3D file formats
// supported by Celestia.
//
// Copyright (C) 2010, Chris Laurel <claurel@gmail.com>
//
// 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.
#pragma once
#include <memory>
#include <QColor>
#include <QGLWidget>
#include <QHash>
#include <QList>
#include <QMouseEvent>
#include <QObject>
#include <QPoint>
#include <QSet>
#include <QString>
#include <QWheelEvent>
#include <QWidget>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <celmodel/material.h>
#include <celmodel/mesh.h>
namespace cmod
{
class Model;
}
class MaterialLibrary;
class GLFrameBufferObject;
class GLShaderProgram;
class LightingEnvironment
{
public:
LightingEnvironment() : lightCount(0), shadowCount(0) {}
unsigned int lightCount;
unsigned int shadowCount;
};
class ShaderKey
{
public:
ShaderKey() : m_info(0u) {}
enum {
LightCountMask = 0x0000f,
SpecularMask = 0x00010,
DiffuseMapMask = 0x00100,
SpecularMapMask = 0x00200,
NormalMapMask = 0x00400,
EmissiveMapMask = 0x00800,
AnyMapMask = 0x00f00,
CompressedNormalMapMask = 0x01000,
ShadowCountMask = 0xf0000,
};
static ShaderKey Create(const cmod::Material* material,
const LightingEnvironment* lighting,
const cmod::VertexDescription* vertexDesc);
unsigned int hash() const
{
return m_info;
}
bool operator==(const ShaderKey& other) const
{
return m_info == other.m_info;
}
bool hasSpecular() const
{
return (m_info & SpecularMask) != 0;
}
bool hasMaps() const
{
return (m_info & AnyMapMask) != 0;
}
bool hasDiffuseMap() const
{
return (m_info & DiffuseMapMask) != 0;
}
bool hasSpecularMap() const
{
return (m_info & SpecularMapMask) != 0;
}
bool hasEmissiveMap() const
{
return (m_info & EmissiveMapMask) != 0;
}
bool hasNormalMap() const
{
return (m_info & NormalMapMask) != 0;
}
bool hasCompressedNormalMap() const
{
return (m_info & CompressedNormalMapMask) != 0;
}
unsigned int lightSourceCount() const
{
return m_info & LightCountMask;
}
unsigned int shadowCount() const
{
return (m_info & ShadowCountMask) >> 16;
}
private:
ShaderKey(unsigned int info) : m_info(info) {}
private:
unsigned int m_info;
};
inline unsigned int qHash(const ShaderKey& key)
{
return qHash(key.hash());
}
class ModelViewWidget : public QGLWidget
{
Q_OBJECT
public:
ModelViewWidget(QWidget *parent);
~ModelViewWidget();
void setModel(std::unique_ptr<cmod::Model>&& model, const QString& modelDir);
cmod::Model* model() { return m_model.get(); }
const cmod::Model* model() const { return m_model.get(); }
void resetCamera();
enum RenderStyle
{
NormalStyle,
WireFrameStyle,
};
enum RenderPath
{
FixedFunctionPath = 0,
OpenGL2Path = 1,
};
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent* event);
void select(const Eigen::Vector2f& point);
QSet<const cmod::PrimitiveGroup*> selection()
{
return m_selection;
}
RenderStyle renderStyle() const
{
return m_renderStyle;
}
RenderPath renderPath() const
{
return m_renderPath;
}
QColor backgroundColor() const
{
return m_backgroundColor;
}
Eigen::Affine3d cameraTransform() const;
void setMaterial(unsigned int index, const cmod::Material& material);
struct LightSource
{
Eigen::Vector3d direction;
Eigen::Vector3f color;
float intensity;
};
bool isLightingEnabled() const
{
return m_lightingEnabled;
}
signals:
void selectionChanged();
void contextCreated();
public slots:
void setBackgroundColor(const QColor& color);
void setRenderPath(RenderPath path);
void setRenderStyle(RenderStyle style);
void setLighting(bool enable);
void setAmbientLight(bool enable);
void setShadows(bool enable);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
private:
void renderModel(cmod::Model* model);
void renderSelection(cmod::Model* model);
void renderDepthOnly(cmod::Model* model);
void renderShadow(unsigned int lightIndex);
void bindMaterial(const cmod::Material* material,
const LightingEnvironment* lighting,
const cmod::VertexDescription* vertexDesc);
void setupDefaultLightSources();
GLShaderProgram* createShader(const ShaderKey& shaderKey);
private:
std::unique_ptr<cmod::Model> m_model;
double m_modelBoundingRadius;
Eigen::Vector3d m_cameraPosition;
Eigen::Quaterniond m_cameraOrientation;
QPoint m_lastMousePosition;
QPoint m_mouseDownPosition;
RenderStyle m_renderStyle;
RenderPath m_renderPath;
MaterialLibrary* m_materialLibrary;
QSet<const cmod::PrimitiveGroup*> m_selection;
QHash<ShaderKey, GLShaderProgram*> m_shaderCache;
QColor m_backgroundColor;
QList<LightSource> m_lightSources;
Eigen::Quaterniond m_lightOrientation;
QList<GLFrameBufferObject*> m_shadowBuffers;
bool m_lightingEnabled;
bool m_ambientLightEnabled;
bool m_shadowsEnabled;
};