Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 208, fix vertex click, misc. upgrades #209

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
8 changes: 7 additions & 1 deletion NifSkope.pro
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ HEADERS += \
src/ui/widgets/refrbrowser.h \
src/ui/widgets/uvedit.h \
src/ui/widgets/valueedit.h \
src/ui/widgets/vertexpaintwidget.h \
src/ui/widgets/xmlcheck.h \
src/ui/about_dialog.h \
src/ui/checkablemessagebox.h \
Expand Down Expand Up @@ -270,6 +271,7 @@ SOURCES += \
src/ui/widgets/refrbrowser.cpp \
src/ui/widgets/uvedit.cpp \
src/ui/widgets/valueedit.cpp \
src/ui/widgets/vertexpaintwidget.cpp \
src/ui/widgets/xmlcheck.cpp \
src/ui/about_dialog.cpp \
src/ui/checkablemessagebox.cpp \
Expand Down Expand Up @@ -298,7 +300,8 @@ FORMS += \
src/ui/settingsgeneral.ui \
src/ui/settingsrender.ui \
src/ui/settingsresources.ui \
src/ui/widgets/lightingwidget.ui
src/ui/widgets/lightingwidget.ui \
src/ui/widgets/vertexpaintwidget.ui


###############################
Expand Down Expand Up @@ -346,6 +349,9 @@ gli {
}

zlib {
macx {
DEFINES += Z_HAVE_UNISTD_H
}
!*msvc*:QMAKE_CFLAGS += -isystem ../nifskope/lib/zlib
!*msvc*:QMAKE_CXXFLAGS += -isystem ../nifskope/lib/zlib
else:INCLUDEPATH += lib/zlib
Expand Down
Binary file added res/icon/paint-verts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions res/nifskope.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@
<file alias="skinned">icon/skinned.png</file>
<file alias="collapse">icon/collapse.png</file>
<file alias="expand">icon/expand.png</file>
<file alias="paintVerts">icon/paint-verts.png</file>
</qresource>
</RCC>
20 changes: 20 additions & 0 deletions src/data/niftypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,16 @@ class Color4
return c;
}

Color4 operator*( const Color4& o ) const
{
Color4 c( *this );
c.rgba[0] *= o.rgba[0];
c.rgba[1] *= o.rgba[1];
c.rgba[2] *= o.rgba[2];
c.rgba[3] *= o.rgba[3];
return c;
}

//! Add-equals operator
Color4 & operator+=( const Color4 & o )
{
Expand Down Expand Up @@ -1452,6 +1462,7 @@ class Color4

friend class NifIStream;
friend class NifOStream;
friend class ByteColor4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting issue here


friend QDataStream & operator>>( QDataStream & ds, Color4 & c );
};
Expand All @@ -1461,6 +1472,15 @@ class ByteColor4 : public Color4
public:
//! Default constructor
ByteColor4() { rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0; }
static ByteColor4 fromColor4(const Color4& c)
{
ByteColor4 o;
o.rgba[0] = c.rgba[0];
o.rgba[1] = c.rgba[1];
o.rgba[2] = c.rgba[2];
o.rgba[3] = c.rgba[3];
return o;
}
};


Expand Down
170 changes: 86 additions & 84 deletions src/gl/bsshape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,13 @@ void BSShape::drawShapes( NodeList * secondPass, bool presort )
return;

auto nif = static_cast<const NifModel *>(iBlock.model());

bool drawPolygons = true;
if ( Node::SELECTING ) {
if ( scene->selMode & Scene::SelObject ) {
if ( scene->actionMode & Scene::Object ) {
int s_nodeId = ID2COLORKEY( nodeId );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting seems to be all over the shop here.

glColor4ubv( (GLubyte *)&s_nodeId );
} else {
glColor4f( 0, 0, 0, 1 );
} else {
drawPolygons = false;
}
}

Expand All @@ -384,85 +384,87 @@ void BSShape::drawShapes( NodeList * secondPass, bool presort )
glMultMatrix( viewTrans() );
}

// Render polygon fill slightly behind alpha transparency and wireframe
if ( !drawSecond ) {
glEnable( GL_POLYGON_OFFSET_FILL );
glPolygonOffset( 1.0f, 2.0f );
}

glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, transVerts.constData() );

if ( !Node::SELECTING ) {
glEnableClientState( GL_NORMAL_ARRAY );
glNormalPointer( GL_FLOAT, 0, transNorms.constData() );

bool doVCs = (bssp && (bssp->getFlags2() & ShaderFlags::SLSF2_Vertex_Colors));
// Always do vertex colors for FO4 if colors present
if ( nifVersion == 130 && hasVertexColors && colors.count() )
doVCs = true;

if ( transColors.count() && (scene->options & Scene::DoVertexColors) && doVCs ) {
glEnableClientState( GL_COLOR_ARRAY );
glColorPointer( 4, GL_FLOAT, 0, transColors.constData() );
} else if ( !hasVertexColors && (bslsp && bslsp->hasVertexColors) ) {
// Correctly blacken the mesh if SLSF2_Vertex_Colors is still on
// yet "Has Vertex Colors" is not.
glColor( Color3( 0.0f, 0.0f, 0.0f ) );
} else {
glColor( Color3( 1.0f, 1.0f, 1.0f ) );
}
}


if ( !Node::SELECTING )
shader = scene->renderer->setupProgram( this, shader );

if ( isDoubleSided ) {
glCullFace( GL_FRONT );
glDrawElements( GL_TRIANGLES, triangles.count() * 3, GL_UNSIGNED_SHORT, triangles.constData() );
glCullFace( GL_BACK );
}

if ( !isLOD ) {
glDrawElements( GL_TRIANGLES, triangles.count() * 3, GL_UNSIGNED_SHORT, triangles.constData() );
} else if ( triangles.count() ) {
auto lod0 = nif->get<uint>( iBlock, "LOD0 Size" );
auto lod1 = nif->get<uint>( iBlock, "LOD1 Size" );
auto lod2 = nif->get<uint>( iBlock, "LOD2 Size" );

auto lod0tris = triangles.mid( 0, lod0 );
auto lod1tris = triangles.mid( lod0, lod1 );
auto lod2tris = triangles.mid( lod0 + lod1, lod2 );

// If Level2, render all
// If Level1, also render Level0
switch ( scene->lodLevel ) {
case Scene::Level2:
if ( lod2tris.count() )
glDrawElements( GL_TRIANGLES, lod2tris.count() * 3, GL_UNSIGNED_SHORT, lod2tris.constData() );
case Scene::Level1:
if ( lod1tris.count() )
glDrawElements( GL_TRIANGLES, lod1tris.count() * 3, GL_UNSIGNED_SHORT, lod1tris.constData() );
case Scene::Level0:
default:
if ( lod0tris.count() )
glDrawElements( GL_TRIANGLES, lod0tris.count() * 3, GL_UNSIGNED_SHORT, lod0tris.constData() );
break;
}
}

if ( !Node::SELECTING )
scene->renderer->stopProgram();

glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );

glDisable( GL_POLYGON_OFFSET_FILL );


if ( scene->selMode & Scene::SelVertex ) {
if (drawPolygons) {

// Render polygon fill slightly behind alpha transparency and wireframe
if ( !drawSecond ) {
glEnable( GL_POLYGON_OFFSET_FILL );
glPolygonOffset( 1.0f, 2.0f );
}

glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, transVerts.constData() );

if ( !Node::SELECTING ) {
glEnableClientState( GL_NORMAL_ARRAY );
glNormalPointer( GL_FLOAT, 0, transNorms.constData() );

bool doVCs = (bssp && (bssp->getFlags2() & ShaderFlags::SLSF2_Vertex_Colors));
// Always do vertex colors for FO4 if colors present
if ( nifVersion == 130 && hasVertexColors && colors.count() )
doVCs = true;

if ( transColors.count() && (scene->options & Scene::DoVertexColors) && doVCs ) {
glEnableClientState( GL_COLOR_ARRAY );
glColorPointer( 4, GL_FLOAT, 0, transColors.constData() );
} else if ( !hasVertexColors && (bslsp && bslsp->hasVertexColors) ) {
// Correctly blacken the mesh if SLSF2_Vertex_Colors is still on
// yet "Has Vertex Colors" is not.
glColor( Color3( 0.0f, 0.0f, 0.0f ) );
} else {
glColor( Color3( 1.0f, 1.0f, 1.0f ) );
}
}


if ( !Node::SELECTING )
shader = scene->renderer->setupProgram( this, shader );

if ( isDoubleSided ) {
glCullFace( GL_FRONT );
glDrawElements( GL_TRIANGLES, triangles.count() * 3, GL_UNSIGNED_SHORT, triangles.constData() );
glCullFace( GL_BACK );
}

if ( !isLOD ) {
glDrawElements( GL_TRIANGLES, triangles.count() * 3, GL_UNSIGNED_SHORT, triangles.constData() );
} else if ( triangles.count() ) {
auto lod0 = nif->get<uint>( iBlock, "LOD0 Size" );
auto lod1 = nif->get<uint>( iBlock, "LOD1 Size" );
auto lod2 = nif->get<uint>( iBlock, "LOD2 Size" );

auto lod0tris = triangles.mid( 0, lod0 );
auto lod1tris = triangles.mid( lod0, lod1 );
auto lod2tris = triangles.mid( lod0 + lod1, lod2 );

// If Level2, render all
// If Level1, also render Level0
switch ( scene->lodLevel ) {
case Scene::Level2:
if ( lod2tris.count() )
glDrawElements( GL_TRIANGLES, lod2tris.count() * 3, GL_UNSIGNED_SHORT, lod2tris.constData() );
case Scene::Level1:
if ( lod1tris.count() )
glDrawElements( GL_TRIANGLES, lod1tris.count() * 3, GL_UNSIGNED_SHORT, lod1tris.constData() );
case Scene::Level0:
default:
if ( lod0tris.count() )
glDrawElements( GL_TRIANGLES, lod0tris.count() * 3, GL_UNSIGNED_SHORT, lod0tris.constData() );
break;
}
}

if ( !Node::SELECTING )
scene->renderer->stopProgram();

glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );

glDisable( GL_POLYGON_OFFSET_FILL );
}

if ( scene->actionMode & Scene::Vertex ) {
drawVerts();
}

Expand Down Expand Up @@ -515,7 +517,7 @@ void BSShape::drawSelection() const
if ( scene->options & Scene::ShowNodes )
Node::drawSelection();

if ( isHidden() || !(scene->selMode & Scene::SelObject) )
if ( isHidden() || !(scene->actionMode & Scene::Object) )
return;

auto idx = scene->currentIndex;
Expand Down
28 changes: 21 additions & 7 deletions src/gl/glcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,23 +384,37 @@ template <typename T> bool interpolate( T & value, const QModelIndex & array, fl
{
// Quadratic
/*
In general, for keyframe values v1 = 0, v2 = 1 it appears that
setting v1's corresponding "Backward" value to 1 and v2's
corresponding "Forward" to 1 results in a linear interpolation.
*/
Interpolate X, Y, and Z values independently, along a segment between
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 for improving docs

two points, at an arbitrary time "x", using an Hermite Cubic spline.
* The "v1" keyframe is the one previous in time to "x",
* The "v2" keyframe is the next one,
* The segment's backward derivative, "tangent 1" is stored as part of "v1"
* The segment's forward derivative, "tangent 2" is stored as part of "v2"
N.B. v2's backward derivate does not "belong" to the segment with v1,
but rather to the segment with v3. Otherwise said, the key at t=0.0
can have a forward derivative, but it will not be used; the final key's
backward derivative will also not be used. The segment between time 1 and 2
uses time 1's backward derivative and 2's forward derivative, not the 1's
forward derivative and 2's backward derivative.

The XYZ vectors used in the derivatives, if directed from V1 to V2, can appear
as linear interpolation, however if their magnitude is not correct, then
temporally there will be a speed up/down, even if the spacial trajectory is
a straight line.
*/

// Tangent 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

float t1 = nif->get<float>( frames.child( last, 0 ), "Backward" );
T t1 = nif->get<T>( frames.child( last, 0 ), "Backward" );
// Tangent 2
float t2 = nif->get<float>( frames.child( next, 0 ), "Forward" );
T t2 = nif->get<T>( frames.child( next, 0 ), "Forward" );

float x2 = x * x;
float x3 = x2 * x;

// Cubic Hermite spline
// x(t) = (2t^3 - 3t^2 + 1)P1 + (-2t^3 + 3t^2)P2 + (t^3 - 2t^2 + t)T1 + (t^3 - t^2)T2

value = v1 * (2.0f * x3 - 3.0f * x2 + 1.0f) + v2 * (-2.0f * x3 + 3.0f * x2) + t1 * (x3 - 2.0f * x2 + x) + t2 * (x3 - x2);
value = v1 * (2.0f * x3 - 3.0f * x2 + 1.0f) + v2 * (-2.0f * x3 + 3.0f * x2) + t1 * (x3 - 2.0f * x2 + x) + t2 * (x3 - x2);

} return true;

Expand Down
Loading