flightgear/utils/fgpanel/GL_utils.cxx
2022-10-20 20:29:11 +08:00

375 lines
11 KiB
C++

//
// 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.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <iostream>
#include <math.h>
#include <string.h>
#include "GL_utils.hxx"
const float PI (3.1415926535897932384626433832795);
GL_utils::GL_utils () {
Matrix Tmp;
memset (&Tmp, 0x0, sizeof (Matrix));
int i;
for (i = GL_UTILS_MODELVIEW; i < GL_UTILS_LAST; ++i) {
m_Current_Matrix_Mode = (GLenum_Mode) i;
m_Matrix[m_Current_Matrix_Mode].push (Tmp);
glLoadIdentity ();
}
m_Current_Matrix_Mode = GL_utils::GL_UTILS_UNSET;
}
GL_utils::~GL_utils () {}
GL_utils&
GL_utils::instance () {
static GL_utils* const The_Instance (new GL_utils);
return *The_Instance;
}
//
///
/// \brief Load a shader, check for compile errors, print error messages to std error
/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
/// \param shader_src Shader source string
/// \return A new shader object on success, 0 on failure
//
GLuint
GL_utils::load_shader (GLenum type, const char *shader_src) {
GLint compiled;
// Create the shader object
GLuint shader (glCreateShader (type));
if (shader == 0) {
cerr << "Error creating shader" << endl;
return 0;
}
// Load the shader source
glShaderSource (shader, 1, &shader_src, NULL);
// Compile the shader
glCompileShader (shader);
// Check the compile status
glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint info_len (0);
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1) {
char* info_log ((char *) malloc (sizeof (char) * info_len));
glGetShaderInfoLog (shader, info_len, NULL, info_log);
cerr << "Error compiling shader:" << endl << info_log << endl;
free (info_log);
}
glDeleteShader (shader);
return 0;
}
return shader;
}
//
///
/// \brief Load a vertex and fragment shader, create a program object, link program.
// Errors output to std error.
/// \param vertShaderSrc Vertex shader source code
/// \param fragShaderSrc Fragment shader source code
/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
//
GLuint
GL_utils::load_program (const char *vert_shader_src, const char *frag_shader_src) {
GLint linked;
// Load the vertex/fragment shaders
GLuint vertex_shader (load_shader (GL_VERTEX_SHADER, vert_shader_src));
if (vertex_shader == 0) {
cerr << "Error loading vertex shader" << endl;
return 0;
}
GLuint fragment_shader (load_shader (GL_FRAGMENT_SHADER, frag_shader_src));
if (fragment_shader == 0) {
cerr << "Error loading fragment shader" << endl;
glDeleteShader (vertex_shader);
return 0;
}
// Create the program object
GLuint program_object (glCreateProgram ());
if (program_object == 0) {
cerr << "Error creating program" << endl;
return 0;
}
glAttachShader (program_object, vertex_shader);
glAttachShader (program_object, fragment_shader);
// Link the program
glLinkProgram (program_object);
// Check the link status
glGetProgramiv (program_object, GL_LINK_STATUS, &linked);
if (!linked) {
GLint info_len (0);
glGetProgramiv (program_object, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1) {
char* info_log ((char *) malloc (sizeof (char) * info_len));
glGetProgramInfoLog (program_object, info_len, NULL, info_log);
cerr << "Error linking program:" << endl << info_log << endl;
free (info_log);
}
glDeleteProgram (program_object);
return 0;
}
// Free up no longer needed shader resources
glDeleteShader (vertex_shader);
glDeleteShader (fragment_shader);
return program_object;
}
void
GL_utils::glMatrixMode (const GLenum_Mode mode) {
if (mode < GL_UTILS_LAST) {
m_Current_Matrix_Mode = mode;
}
}
void
GL_utils::glLoadIdentity () {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
memset (&(m_Matrix[m_Current_Matrix_Mode].top ()), 0x0, sizeof (Matrix));
m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] = 1.0f;
m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] = 1.0f;
m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] = 1.0f;
m_Matrix[m_Current_Matrix_Mode].top ().m[3][3] = 1.0f;
}
}
void
GL_utils::gluOrtho2D (const GLfloat left,
const GLfloat right,
const GLfloat bottom,
const GLfloat top) {
GL_utils::glOrtho (left, right, bottom, top, -1.0f, 1.0f);
}
void
GL_utils::glOrtho (const GLfloat left,
const GLfloat right,
const GLfloat bottom,
const GLfloat top,
const GLfloat nearVal,
const GLfloat farVal) {
const GLfloat Delta_X (right - left);
const GLfloat Delta_Y (top - bottom);
const GLfloat Delta_Z (farVal - nearVal);
Matrix Ortho;
if ((Delta_X == 0.0f) || (Delta_Y == 0.0f) || (Delta_Z == 0.0f) || (m_Current_Matrix_Mode < GL_UTILS_LAST)) {
return;
}
memset (&Ortho, 0x0, sizeof (Matrix));
Ortho.m[0][0] = 2.0f / Delta_X;
Ortho.m[3][0] = -(right + left) / Delta_X;
Ortho.m[1][1] = 2.0f / Delta_Y;
Ortho.m[3][1] = -(top + bottom) / Delta_Y;
Ortho.m[2][2] = -2.0f / Delta_Z;
Ortho.m[3][2] = -(nearVal + farVal) / Delta_Z;
Ortho.m[3][3] = 1.0f;
GL_utils::glMultMatrixf (Ortho.m);
}
void
GL_utils::glTranslatef (const GLfloat x, const GLfloat y, const GLfloat z) {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
m_Matrix[m_Current_Matrix_Mode].top ().m[3][0] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][0] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][0] * z);
m_Matrix[m_Current_Matrix_Mode].top ().m[3][1] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][1] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][1] * z);
m_Matrix[m_Current_Matrix_Mode].top ().m[3][2] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][2] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][2] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] * z);
m_Matrix[m_Current_Matrix_Mode].top ().m[3][3] += (m_Matrix[m_Current_Matrix_Mode].top ().m[0][3] * x +
m_Matrix[m_Current_Matrix_Mode].top ().m[1][3] * y +
m_Matrix[m_Current_Matrix_Mode].top ().m[2][3] * z);
}
}
void
GL_utils::glRotatef (const GLfloat angle, const GLfloat x, const GLfloat y, const GLfloat z) {
const GLfloat xx (x * x);
const GLfloat yy (y * y);
const GLfloat zz (z * z);
const GLfloat Mag (sqrtf (xx + yy + zz));
if ((Mag > 0.0f) && (m_Current_Matrix_Mode < GL_UTILS_LAST)) {
const GLfloat Sin_Angle (sinf (-angle * PI / 180.0f));
const GLfloat Cos_Angle (cosf (angle * PI / 180.0f));
const GLfloat xy (x * y);
const GLfloat yz (y * z);
const GLfloat zx (z * x);
const GLfloat xs (x * Sin_Angle);
const GLfloat ys (y * Sin_Angle);
const GLfloat zs (z * Sin_Angle);
const GLfloat One_Minus_Cos (1.0f - Cos_Angle);
Matrix Rot;
// x /= mag;
// y /= mag;
// z /= mag;
Rot.m[0][0] = (One_Minus_Cos * xx) + Cos_Angle;
Rot.m[0][1] = (One_Minus_Cos * xy) - zs;
Rot.m[0][2] = (One_Minus_Cos * zx) + ys;
Rot.m[0][3] = 0.0f;
Rot.m[1][0] = (One_Minus_Cos * xy) + zs;
Rot.m[1][1] = (One_Minus_Cos * yy) + Cos_Angle;
Rot.m[1][2] = (One_Minus_Cos * yz) - xs;
Rot.m[1][3] = 0.0f;
Rot.m[2][0] = (One_Minus_Cos * zx) - ys;
Rot.m[2][1] = (One_Minus_Cos * yz) + xs;
Rot.m[2][2] = (One_Minus_Cos * zz) + Cos_Angle;
Rot.m[2][3] = 0.0f;
Rot.m[3][0] = 0.0f;
Rot.m[3][1] = 0.0f;
Rot.m[3][2] = 0.0f;
Rot.m[3][3] = 1.0f;
GL_utils::glMultMatrixf (Rot.m);
}
}
void
GL_utils::glScalef (GLfloat x, GLfloat y, GLfloat z) {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
Matrix Scale;
Scale.m[0][0] = x;
Scale.m[0][1] = 0.0f;
Scale.m[0][2] = 0.0f;
Scale.m[0][3] = 0.0f;
Scale.m[1][0] = 0.0f;
Scale.m[1][1] = y;
Scale.m[1][2] = 0.0f;
Scale.m[1][3] = 0.0f;
Scale.m[2][0] = 0.0f;
Scale.m[2][1] = 0.0f;
Scale.m[2][2] = z;
Scale.m[2][3] = 0.0f;
Scale.m[3][0] = 0.0f;
Scale.m[3][1] = 0.0f;
Scale.m[3][2] = 0.0f;
Scale.m[3][3] = 1.0f;
GL_utils::glMultMatrixf (Scale.m);
}
}
void
GL_utils::glMultMatrixf (const GLfloat m[4][4]) {
Matrix Tmp;
for (int i = 0; i < 4; ++i) {
Tmp.m[i][0] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][0] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][0] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][0] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][0]);
Tmp.m[i][1] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][1] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][1] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][1] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][1]);
Tmp.m[i][2] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][2] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][2] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][2] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][2]);
Tmp.m[i][3] = (m[i][0] * m_Matrix[m_Current_Matrix_Mode].top ().m[0][3] +
m[i][1] * m_Matrix[m_Current_Matrix_Mode].top ().m[1][3] +
m[i][2] * m_Matrix[m_Current_Matrix_Mode].top ().m[2][3] +
m[i][3] * m_Matrix[m_Current_Matrix_Mode].top ().m[3][3]);
}
memcpy (&(m_Matrix[m_Current_Matrix_Mode].top ()), &Tmp, sizeof (Matrix));
}
void
GL_utils::glPushMatrix () {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
m_Matrix[m_Current_Matrix_Mode].push (m_Matrix[m_Current_Matrix_Mode].top ());
}
}
void
GL_utils::glPopMatrix () {
if (m_Current_Matrix_Mode < GL_UTILS_LAST) {
m_Matrix[m_Current_Matrix_Mode].pop ();
}
}
GLfloat*
GL_utils::get_top_matrix (const GL_utils::GLenum_Mode mode) {
if (mode < GL_UTILS_LAST) {
return &(m_Matrix[mode].top ().m[0][0]);
} else {
return NULL;
}
}
void
GL_utils::Debug (const GL_utils::GLenum_Mode mode) const {
if (mode < GL_UTILS_LAST) {
for (int l = 0; l < 4; ++l) {
cout << " ";
for (int c = 0; c < 4; ++c) {
cout << m_Matrix[mode].top ().m[c][l] << " ";
}
cout << endl;
}
}
}