2020-10-21 17:24:01 +02:00

788 lines
18 KiB
C++

/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005-2008 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* 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 (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include "rfx_state.h"
// static members initialization
// the empty strings are "padding" for compatibility with RM enum
const char *RfxState::RenderStatesStrings[] = {
"GL_CurrentColor", "GL_SecondaryColor", "", "GL_ClearColor",
"GL_ClearDepth", "GL_ShadeModel", "GL_FrontFace", "GL_CullMode",
"GL_EdgeFlag",
"GL_DepthNear", "GL_DepthFar", "", "GL_FogColor", "GL_FogDensity", "GL_FogStart",
"GL_FogEnd", "GL_FogMode", "GL_PointSize", "GL_PointMin", "GL_PointMax",
"GL_PointSmooth", "GL_LineWidth", "GL_LineSmooth", "GL_PolyFrontMode",
"GL_PolyBackMode", "GL_PolySmooth", "GL_PolyOffsetFactor",
"GL_PolyOffsetUnits", "GL_PolyOffsetPoint", "GL_PolyOffsetLine",
"GL_PolyOffsetFill",
"GL_AlphaEnable", "GL_AlphaFunction", "GL_AlphaReference",
"GL_DepthEnable", "GL_DepthFunction", "GL_BlendEnable", "GL_BlendColor",
"GL_BlendSourceRGB", "GL_BlendDestRGB", "GL_BlendSourceAlpha",
"GL_BlendDestAlpha", "GL_BlendEquation", "GL_WriteMaskColor", "GL_WriteMaskDepth",
"GL_VertexProgramTwoSideARB", "GL_StencilEnable", "GL_StencilFunction",
"GL_StencilValueMask", "GL_StencilReference", "GL_StencilFail",
"GL_StencilPassDepthFail", "GL_StencilPassDepthPass", "GL_WriteMaskStencil",
"GL_ClearStencil"
};
const char *RfxState::RenderFunctionStrings[] = {
"NEVER", "LESS", "EQUAL", "LESS_EQUAL", "GREATER", "NOT_EQUAL",
"GREATER_EQUAL", "ALWAYS"
};
const char *RfxState::RenderColorStrings[] = {
"ZERO", "ONE", "SRC_COLOR", "INV_SRC_COLOR", "DEST_COLOR",
"INV_DEST_COLOR", "SRC_ALPHA", "INV_SRC_ALPHA", "DEST_ALPHA",
"INV_DEST_ALPHA", "CONST_COLOR", "INV_CONST_COLOR", "CONST_ALPHA",
"INV_CONST_ALPHA", "SRC_ALPHA_SATURATE"
};
const char *RfxState::TextureStatesStrings[] = {
"GL_TEXTURE_WRAP_S", "GL_TEXTURE_WRAP_T", "GL_TEXTURE_WRAP_R",
"GL_TEXTURE_MIN_FILTER", "GL_TEXTURE_MAG_FILTER",
"GL_TEXTURE_BORDER_COLOR", "GL_TEXTURE_MAX_ANISOTROPY_EXT",
"GL_TEXTURE_LOD_BIAS"
};
const char *RfxState::TextureWrapStrings[] = {
"GL_CLAMP", "GL_CLAMP_TO_EDGE", "GL_REPEAT", "GL_CLAMP_TO_BORDER",
"GL_MIRRORED_REPEAT"
};
// the empty string in 3rd position is for compatibility with RM enum
const char *RfxState::TextureFilterStrings[] = {
"GL_NEAREST", "GL_LINEAR", "", "GL_NEAREST_MIPMAP_NEAREST",
"GL_NEAREST_MIPMAP_LINEAR", "GL_LINEAR_MIPMAP_NEAREST",
"GL_LINEAR_MIPMAP_LINEAR"
};
RfxState::RfxState(StateType _type, int _state, long _value)
: state(_state), value(_value), type(_type)
{
}
void RfxState::SetEnvironment(GLint target)
{
if (type == RFX_SAMPLERSTATE)
SetTextureEnvironment(target);
else
SetGLEnvironment();
}
void RfxState::SetTextureEnvironment(GLint target)
{
switch (state) {
case GL_TextureWrapS:
glTexParameteri(target, GL_TEXTURE_WRAP_S, GLWrapMode());
break;
case GL_TextureWrapT:
glTexParameteri(target, GL_TEXTURE_WRAP_T, GLWrapMode());
break;
case GL_TextureWrapR:
glTexParameteri(target, GL_TEXTURE_WRAP_R, GLWrapMode());
break;
case GL_TextureMinify:
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GLFilterMode());
break;
case GL_TextureMagnify:
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GLFilterMode());
break;
case GL_TextureBorderColor:
glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, DecodeColor(value));
break;
case GL_TextureMaxAnisotropyEXT:
glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, value);
break;
case GL_TextureLODBias:
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, value);
break;
default:
// do nothing, unsupported state
break;
}
}
inline GLint RfxState::GLWrapMode()
{
switch ((TextureWrapRfx)value) {
case GL_CLAMP_RFX:
return GL_CLAMP;
case GL_CLAMP_TO_EDGE_RFX:
return GL_CLAMP_TO_EDGE;
case GL_REPEAT_RFX:
return GL_REPEAT;
case GL_CLAMP_TO_BORDER_RFX:
return GL_CLAMP_TO_BORDER;
case GL_MIRRORED_REPEAT_RFX:
return GL_MIRRORED_REPEAT;
default:
return GL_CLAMP;
}
}
inline GLint RfxState::GLFilterMode()
{
switch ((TextureFilterRfx)value) {
case GL_NEAREST_RFX:
return GL_NEAREST;
case GL_LINEAR_RFX:
return GL_LINEAR;
case GL_NEAREST_MIPMAP_NEAREST_RFX:
return GL_NEAREST_MIPMAP_NEAREST;
case GL_NEAREST_MIPMAP_LINEAR_RFX:
return GL_NEAREST_MIPMAP_LINEAR;
case GL_LINEAR_MIPMAP_NEAREST_RFX:
return GL_LINEAR_MIPMAP_NEAREST;
case GL_LINEAR_MIPMAP_LINEAR_RFX:
return GL_LINEAR_MIPMAP_LINEAR;
default:
return GL_NEAREST;
}
}
inline GLint RfxState::GLFunctionMode()
{
switch ((FunctionRfx)value) {
case NEVER_RFX:
return GL_NEVER;
case LESS_RFX:
return GL_LESS;
case EQUAL_RFX:
return GL_EQUAL;
case LESS_EQUAL_RFX:
return GL_LEQUAL;
case GREATER_RFX:
return GL_GREATER;
case NOT_EQUAL_RFX:
return GL_NOTEQUAL;
case GREATER_EQUAL_RFX:
return GL_GEQUAL;
case ALWAYS_RFX:
return GL_ALWAYS;
default:
return GL_ALWAYS;
}
}
inline GLint RfxState::GLColorMode()
{
switch ((ColorRfx)value) {
case ZERO:
return GL_ZERO;
case ONE:
return GL_ONE;
case SRC_COLOR:
return GL_SRC_COLOR;
case INV_SRC_COLOR:
return GL_ONE_MINUS_SRC_COLOR;
case DEST_COLOR:
return GL_DST_COLOR;
case INV_DEST_COLOR:
return GL_ONE_MINUS_DST_COLOR;
case SRC_ALPHA:
return GL_SRC_ALPHA;
case INV_SRC_ALPHA:
return GL_ONE_MINUS_SRC_ALPHA;
case DEST_ALPHA:
return GL_DST_ALPHA;
case INV_DEST_ALPHA:
return GL_ONE_MINUS_DST_ALPHA;
case CONST_COLOR:
return GL_CONSTANT_COLOR;
case INV_CONST_COLOR:
return GL_ONE_MINUS_CONSTANT_COLOR;
case CONST_ALPHA:
return GL_CONSTANT_ALPHA;
case INV_CONST_ALPHA:
return GL_ONE_MINUS_CONSTANT_ALPHA;
case SRC_ALPHA_SATURATE:
return GL_SRC_ALPHA_SATURATE;
default:
return GL_ZERO;
}
}
void RfxState::SetGLEnvironment()
{
switch (state) {
case GL_CurrentColor: {
GLfloat *res = DecodeColor(value);
glColor3f(res[0], res[1], res[2]);
delete res;
}
case GL_SecondaryColor: {
GLfloat *res = DecodeColor(value);
glSecondaryColor3f(res[0], res[1], res[2]);
delete res;
break;
}
case GL_ClearColor: {
GLfloat *res = DecodeColor(value);
glClearColor(res[0], res[1], res[2], res[3]);
delete res;
break;
}
case GL_ClearDepth:
glClearDepth(value);
break;
case GL_ShadeModel:
glShadeModel((value == 1)? GL_FLAT : GL_SMOOTH);
break;
case GL_FrontFace:
glFrontFace((value == 1)? GL_CCW : GL_CW);
break;
case GL_CullMode:
if (value == 1) {
glDisable(GL_CULL_FACE);
} else {
glEnable(GL_CULL_FACE);
glCullFace((value == 2)? GL_FRONT :
((value == 3)? GL_BACK : GL_FRONT_AND_BACK));
}
break;
case GL_EdgeFlag:
glEdgeFlag(value);
break;
case GL_DepthNear:
case GL_DepthFar: {
GLfloat range[2];
glGetFloatv(GL_DEPTH_RANGE, range);
if (state == GL_DepthNear)
glDepthRange(value, range[1]);
else
glDepthRange(range[0], value);
break;
}
case GL_FogColor: {
glFogfv(GL_FOG_COLOR, DecodeColor(value));
break;
}
case GL_FogDensity:
glFogi(GL_FOG_DENSITY, value);
break;
case GL_FogStart:
glFogi(GL_FOG_START, value);
break;
case GL_FogEnd:
glFogi(GL_FOG_END, value);
break;
case GL_FogMode:
glEnable(GL_FOG);
switch ((GLint)value) {
case 1: // NONE
glDisable(GL_FOG);
break;
case 2: // LINEAR
glFogi(GL_FOG_MODE, GL_LINEAR);
break;
case 3: // EXP
glFogi(GL_FOG_MODE, GL_EXP);
break;
case 4: // EXP2
glFogi(GL_FOG_MODE, GL_EXP2);
break;
default: // UNKNOWN
break;
}
break;
case GL_PointSize:
glPointSize(value);
break;
case GL_PointMin:
glPointParameterf(GL_POINT_SIZE_MIN, value);
break;
case GL_PointMax:
glPointParameterf(GL_POINT_SIZE_MAX_ARB, value);
break;
case GL_PointSmooth:
GLEnableDisable(GL_POINT_SMOOTH);
break;
case GL_LineWidth:
glLineWidth(value);
break;
case GL_LineSmooth:
GLEnableDisable(GL_LINE_SMOOTH);
break;
case GL_PolyFrontMode:
glPolygonMode(GL_FRONT, (value == 1)? GL_POINT :
((value == 2)? GL_LINE : GL_FILL));
break;
case GL_PolyBackMode:
glPolygonMode(GL_BACK, (value == 1)? GL_POINT :
((value == 2)? GL_LINE : GL_FILL));
break;
case GL_PolySmooth:
GLEnableDisable(GL_POLYGON_SMOOTH);
break;
case GL_PolyOffsetFactor: {
GLfloat units;
glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
glPolygonOffset(value, units);
break;
}
case GL_PolyOffsetUnits: {
GLfloat factor;
glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
glPolygonOffset(factor, value);
break;
}
case GL_PolyOffsetPoint:
GLEnableDisable(GL_POLYGON_OFFSET_POINT);
break;
case GL_PolyOffsetLine:
GLEnableDisable(GL_POLYGON_OFFSET_LINE);
break;
case GL_PolyOffsetFill:
GLEnableDisable(GL_POLYGON_OFFSET_FILL);
break;
case GL_AlphaEnable:
GLEnableDisable(GL_ALPHA_TEST);
break;
case GL_AlphaFunction: {
GLfloat ref;
glGetFloatv(GL_ALPHA_TEST_REF, &ref);
glAlphaFunc(GLFunctionMode(), ref);
break;
}
case GL_AlphaReference: {
GLint func;
glGetIntegerv(GL_ALPHA_TEST_FUNC, &func);
glAlphaFunc(func, value);
break;
}
case GL_DepthEnable:
GLEnableDisable(GL_DEPTH_TEST);
break;
case GL_DepthFunction:
glDepthFunc(GLFunctionMode());
break;
case GL_BlendEnable:
GLEnableDisable(GL_BLEND);
break;
case GL_BlendColor: {
GLfloat *res = DecodeColor(value);
glBlendColor(res[0], res[1], res[2], res[3]);
delete res;
break;
}
case GL_BlendSourceRGB:
case GL_BlendDestRGB:
case GL_BlendSourceAlpha:
case GL_BlendDestAlpha: {
GLint srcdst[4];
glGetIntegerv(GL_BLEND_SRC_RGB, &srcdst[0]);
glGetIntegerv(GL_BLEND_DST_RGB, &srcdst[1]);
glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcdst[2]);
glGetIntegerv(GL_BLEND_DST_ALPHA, &srcdst[3]);
glBlendFuncSeparate(
((state == GL_BlendSourceRGB)? GLColorMode() : srcdst[0]),
((state == GL_BlendDestRGB)? GLColorMode() : srcdst[1]),
((state == GL_BlendSourceAlpha)? GLColorMode() : srcdst[2]),
((state == GL_BlendDestAlpha)? GLColorMode() : srcdst[3]));
break;
}
case GL_BlendEquation:
switch ((GLint)value) {
case 1: // ADD
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
break;
case 2: // SUBTRACT
glBlendEquationSeparate(GL_FUNC_SUBTRACT, GL_FUNC_SUBTRACT);
break;
case 3: // REV_SUBTRACT
glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT);
break;
case 4: // MIN
glBlendEquationSeparate(GL_MIN, GL_MIN);
break;
case 5: // MAX
glBlendEquationSeparate(GL_MAX, GL_MAX);
break;
}
break;
case GL_WriteMaskColor: {
GLint val = (GLint)value;
GLboolean par[4];
par[3] = (val > 8)? GL_TRUE : GL_FALSE;
par[2] = (val -= (8 * par[3]) > 4)? GL_TRUE : GL_FALSE;
par[1] = (val -= (4 * par[2]) > 2)? GL_TRUE : GL_FALSE;
par[0] = (val -= (2 * par[1]) > 1)? GL_TRUE : GL_FALSE;
glColorMask(par[0], par[1], par[2], par[3]);
break;
}
case GL_WriteMaskDepth:
glDepthMask(value);
break;
case GL_VertexProgramTwoSideARB:
GLEnableDisable(GL_VERTEX_PROGRAM_TWO_SIDE_ARB);
break;
case GL_StencilEnable:
GLEnableDisable(GL_STENCIL_TEST);
break;
case GL_StencilFunction:
case GL_StencilValueMask:
case GL_StencilReference: {
GLint StFun[3];
glGetIntegerv(GL_STENCIL_FUNC, &StFun[0]);
glGetIntegerv(GL_STENCIL_VALUE_MASK, &StFun[1]);
glGetIntegerv(GL_STENCIL_REF, &StFun[2]);
glStencilFunc(
(state == GL_StencilFunction)? GLFunctionMode() : StFun[0],
(state == GL_StencilValueMask)? value : StFun[1],
(state == GL_StencilReference)? value : StFun[2]);
break;
}
case GL_StencilFail:
case GL_StencilPassDepthFail:
case GL_StencilPassDepthPass: {
GLint StOp[3];
glGetIntegerv(GL_STENCIL_FAIL, &StOp[0]);
glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &StOp[1]);
glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &StOp[2]);
// thanks god at least these values are equivalent to OpenGL ones,
// no mapping needed.
glStencilOp(
(state == GL_StencilFail)? value : StOp[0],
(state == GL_StencilPassDepthFail)? value : StOp[1],
(state == GL_StencilPassDepthPass)? value : StOp[2]);
break;
}
case GL_WriteMaskStencil:
glStencilMask(value);
break;
case GL_ClearStencil:
glClearStencil(value);
break;
default:
// do nothing, unsupported state
break;
}
}
GLfloat* RfxState::DecodeColor(long val)
{
// decodes a color stored in a 32bit integer
// RM seems to "pack" an RGBA color this way:
// R: (0, 255) * 2^0 +
// G: (0, 255) * 2^8 +
// B: (0, 255) * 2^16 +
// A: (-1, -128) U (0, 127) * 2^24
enum Offsets { _R = 1, _G = 256, _B = 65536, _A = 16777216 };
GLfloat *color = new GLfloat[4];
// Alpha needs special care due to its range.
// remove Alpha component from value and remap in range [0, 255]
if (val > 0) {
color[3] = (val % _A == 0)? (short)(val / _A) : 0;
} else {
color[3] = 0.0f;
long negVal = val;
while (negVal < 0) {
color[3] -= 1.0f;
negVal += _A;
}
}
val -= (long)(_A * color[3]);
color[3] += ((color[3] < 0)? 256.0f : 0.0f);
// R, G and B components are easier to parse
color[2] = (val > _B)? (short)(val / _B) : 0;
color[1] = ((val -= (int)(_B * color[2])) > _G)? (short)(val / _G) : 0;
color[0] = ((val -= (int)(_G * color[1])) > _R)? (short)(val) : 0;
// now normalize in [0, 1] range
for (int i = 0; i < 4; ++i)
color[i] /= 255.0f;
return color;
}
inline void RfxState::GLEnableDisable(GLint GLmode)
{
if (value)
glEnable(GLmode);
else
glDisable(GLmode);
}
/***
* conversion functions from enum to strings for gui use
*/
QString RfxState::GetTextureValue()
{
switch (state) {
case GL_TextureWrapS:
case GL_TextureWrapT:
case GL_TextureWrapR:
return TextureWrapStrings[value - 1];
case GL_TextureMinify:
case GL_TextureMagnify:
return TextureFilterStrings[value];
case GL_TextureBorderColor: {
return ColorToString(DecodeColor(value));
}
case GL_TextureMaxAnisotropyEXT:
case GL_TextureLODBias:
return QString().setNum(value);
default:
return "";
}
}
QString RfxState::GetRenderState()
{
// enum values are not contiguous, so play with offsets
// when looking up in strings table
if (state < 10)
return RenderStatesStrings[state - 1];
else if (state > 13 && state < 36)
return RenderStatesStrings[9 + (state - 14)];
else if (state > 40)
return RenderStatesStrings[31 + (state - 41)];
else
return "";
}
QString RfxState::GetRenderValue()
{
switch (state) {
case GL_CurrentColor:
case GL_SecondaryColor:
case GL_ClearColor:
case GL_FogColor:
case GL_BlendColor:
return ColorToString(DecodeColor(value));
case GL_ClearDepth:
case GL_DepthNear:
case GL_DepthFar:
case GL_FogDensity:
case GL_FogStart:
case GL_FogEnd:
case GL_PointSize:
case GL_PointMin:
case GL_PointMax:
case GL_LineWidth:
case GL_PolyOffsetFactor:
case GL_PolyOffsetUnits:
case GL_AlphaReference:
case GL_StencilValueMask:
case GL_StencilReference:
case GL_ClearStencil:
case GL_WriteMaskStencil:
return QString().setNum(value);
case GL_EdgeFlag:
case GL_PointSmooth:
case GL_LineSmooth:
case GL_PolySmooth:
case GL_PolyOffsetPoint:
case GL_PolyOffsetLine:
case GL_PolyOffsetFill:
case GL_AlphaEnable:
case GL_DepthEnable:
case GL_BlendEnable:
case GL_WriteMaskDepth:
case GL_VertexProgramTwoSideARB:
case GL_StencilEnable:
return (value == 1)? "TRUE" : "FALSE";
case GL_ShadeModel:
return (value == 1)? "FLAT_SHADE" : "SMOOTH_SHADE";
case GL_FrontFace:
return (value == 1)? "CCW" : "CW";
case GL_CullMode:
switch (value) {
case 1:
return "NONE";
case 2:
return "FRONT";
case 3:
return "BACK";
case 4:
return "FRONT_AND_BACK";
default:
return "";
}
case GL_FogMode:
switch (value) {
case 1:
return "NONE";
case 2:
return "LINEAR";
case 3:
return "EXP";
case 4:
return "EXP2";
default:
return "";
}
case GL_PolyFrontMode:
case GL_PolyBackMode:
return (value == 1)? "POINTS" : ((value == 2)? "LINES" : "FILL");
case GL_AlphaFunction:
case GL_DepthFunction:
case GL_StencilFunction:
return RenderFunctionStrings[value - 1];
case GL_BlendSourceRGB:
case GL_BlendDestRGB:
case GL_BlendSourceAlpha:
case GL_BlendDestAlpha:
return RenderColorStrings[value - 1];
case GL_BlendEquation:
switch (value) {
case 1:
return "ADD";
case 2:
return "SUBTRACT";
case 3:
return "REV_SUBTRACT";
case 4:
return "MIN";
case 5:
return "MAX";
default:
return "";
}
case GL_StencilFail:
case GL_StencilPassDepthFail:
case GL_StencilPassDepthPass:
switch (value) {
case GL_ZERO:
return "ZERO";
case GL_KEEP:
return "KEEP";
case GL_REPLACE:
return "REPLACE";
case GL_INCR:
return "INCR";
case GL_DECR:
return "DECR";
case GL_INVERT:
return "INVERT";
case GL_INCR_WRAP:
return "INCR_WRAP";
case GL_DECR_WRAP:
return "DECR_WRAP";
default:
return "";
}
case GL_WriteMaskColor: {
GLint val = (GLint)value;
QString retCol;
if (val > 8) {
retCol.append("ALPHA ");
val -= 8;
}
if (val > 4) {
retCol.append("BLUE ");
val -= 4;
}
if (val > 2) {
retCol.append("GREEN ");
val -= 2;
}
if (val > 1) {
retCol.append("RED");
val -= 1;
}
return retCol;
}
default:
return "";
}
}