* Valve220: use face projection by default

* Valve220: Project {axial, ortho, cam, from face} functions
	* conversions between AP, BP and Valve220 brush types; conversions to Brush Primitives and Valve220 formats are lossless
	* detect brush format and automatically convert to current one on map Import and Paste
	* Valve220: fixed Reset function, implemented Rotate one
	* Valve220: fix overwriting basis on brush clone/map import ( in Face( Face ) constructor )
	* BP: fix: normalize shift values during import, arbitrary projections and face->fit
	* Valve220: fix texture lock for scaling, fix for negative texdef.scale
This commit is contained in:
Garux 2017-10-02 18:00:40 +03:00
parent 65e6d4a560
commit f4149f1549
11 changed files with 422 additions and 302 deletions

View File

@ -29,7 +29,6 @@
enum EBrushType enum EBrushType
{ {
eBrushTypeUNKNOWN = 0,
eBrushTypeQuake, eBrushTypeQuake,
eBrushTypeQuake2, eBrushTypeQuake2,
eBrushTypeQuake3, eBrushTypeQuake3,
@ -117,7 +116,8 @@ public:
INTEGER_CONSTANT( Version, 1 ); INTEGER_CONSTANT( Version, 1 );
STRING_CONSTANT( Name, "brush" ); STRING_CONSTANT( Name, "brush" );
virtual scene::Node& createBrush() = 0; virtual scene::Node& createBrush() = 0;
virtual EBrushType getCurrentFormat() const = 0; virtual EBrushType getFormat() const = 0;
virtual void toggleFormat( EBrushType type ) const = 0;
virtual void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ) = 0; virtual void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ) = 0;
virtual bool Brush_addFace( scene::Node& brush, const _QERFaceData& faceData ) = 0; virtual bool Brush_addFace( scene::Node& brush, const _QERFaceData& faceData ) = 0;
}; };

View File

@ -46,7 +46,6 @@ virtual void exportTokens( TokenWriter& writer ) const = 0;
}; };
#include "iscenegraph.h" #include "iscenegraph.h"
#include "ibrush.h"
class EntityCreator; class EntityCreator;
@ -62,7 +61,6 @@ class MapFormat
public: public:
INTEGER_CONSTANT( Version, 2 ); INTEGER_CONSTANT( Version, 2 );
STRING_CONSTANT( Name, "map" ); STRING_CONSTANT( Name, "map" );
mutable EBrushType m_detectedFormat;
/// \brief Read a map graph into \p root from \p outputStream, using \p entityTable to create entities. /// \brief Read a map graph into \p root from \p outputStream, using \p entityTable to create entities.
virtual void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const = 0; virtual void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const = 0;

View File

@ -57,7 +57,7 @@ MapDoom3Dependencies() :
m_patchDoom3Module( "doom3" ){ m_patchDoom3Module( "doom3" ){
} }
BrushCreator& getBrushDoom3(){ BrushCreator& getBrushDoom3(){
return GlobalBrushModule::getTable(); return GlobalBrushCreator();
} }
PatchCreator& getPatchDoom3(){ PatchCreator& getPatchDoom3(){
return *m_patchDoom3Module.getTable(); return *m_patchDoom3Module.getTable();
@ -228,6 +228,7 @@ MapDependencies() :
class MapQ3API : public TypeSystemRef, public MapFormat, public PrimitiveParser class MapQ3API : public TypeSystemRef, public MapFormat, public PrimitiveParser
{ {
mutable bool m_formatDetected;
public: public:
typedef MapFormat Type; typedef MapFormat Type;
STRING_CONSTANT( Name, "mapq3" ); STRING_CONSTANT( Name, "mapq3" );
@ -247,36 +248,38 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
if ( string_equal( primitive, "patchDef2" ) ) { if ( string_equal( primitive, "patchDef2" ) ) {
return GlobalPatchModule::getTable().createPatch(); return GlobalPatchModule::getTable().createPatch();
} }
if( !m_detectedFormat ){ if( !m_formatDetected ){
EBrushType detectedFormat;
if ( string_equal( primitive, "brushDef" ) ) { if ( string_equal( primitive, "brushDef" ) ) {
m_detectedFormat = eBrushTypeQuake3BP; detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake3BP\n";
} }
else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) { else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) {
m_detectedFormat = eBrushTypeQuake3Valve220; detectedFormat = eBrushTypeQuake3Valve220;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3Valve220\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake3Valve220\n";
} }
else if ( string_equal( primitive, "(" ) ) { else if ( string_equal( primitive, "(" ) ) {
m_detectedFormat = eBrushTypeQuake3; detectedFormat = eBrushTypeQuake3;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake3\n";
} }
else{ else{
globalErrorStream() << "Format is not detected\n"; globalErrorStream() << "Format is not detected\n";
}
if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){
Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" ); Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" );
return g_nullNode; return g_nullNode;
} }
m_formatDetected = true;
if( detectedFormat != GlobalBrushCreator().getFormat() ){
GlobalBrushCreator().toggleFormat( detectedFormat );
}
} }
switch ( GlobalBrushModule::getTable().getCurrentFormat() ) switch ( GlobalBrushCreator().getFormat() )
{ {
case eBrushTypeQuake3: case eBrushTypeQuake3:
case eBrushTypeQuake3Valve220: case eBrushTypeQuake3Valve220:
tokeniser.ungetToken(); // ( tokeniser.ungetToken(); // (
case eBrushTypeQuake3BP: case eBrushTypeQuake3BP:
return GlobalBrushModule::getTable().createBrush(); return GlobalBrushCreator().createBrush();
default: default:
break; break;
} }
@ -288,6 +291,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const { void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const {
Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream ); Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream );
m_formatDetected = false;
Map_Read( root, tokeniser, entityTable, *this ); Map_Read( root, tokeniser, entityTable, *this );
tokeniser.release(); tokeniser.release();
} }
@ -305,6 +309,7 @@ MapQ3Module g_MapQ3Module;
class MapQ1API : public TypeSystemRef, public MapFormat, public PrimitiveParser class MapQ1API : public TypeSystemRef, public MapFormat, public PrimitiveParser
{ {
mutable bool m_formatDetected;
public: public:
typedef MapFormat Type; typedef MapFormat Type;
STRING_CONSTANT( Name, "mapq1" ); STRING_CONSTANT( Name, "mapq1" );
@ -320,36 +325,38 @@ MapFormat* getTable(){
scene::Node& parsePrimitive( Tokeniser& tokeniser ) const { scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
const char* primitive = tokeniser.getToken(); const char* primitive = tokeniser.getToken();
if ( primitive != 0 ) { if ( primitive != 0 ) {
if( !m_detectedFormat ){ if( !m_formatDetected ){
EBrushType detectedFormat;
if ( string_equal( primitive, "brushDef" ) ) { if ( string_equal( primitive, "brushDef" ) ) {
m_detectedFormat = eBrushTypeQuake3BP; detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake3BP\n";
} }
else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) { else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) {
m_detectedFormat = eBrushTypeValve220; detectedFormat = eBrushTypeValve220;
globalErrorStream() << "m_detectedFormat = eBrushTypeValve220\n"; globalErrorStream() << "detectedFormat = eBrushTypeValve220\n";
} }
else if ( string_equal( primitive, "(" ) ) { else if ( string_equal( primitive, "(" ) ) {
m_detectedFormat = eBrushTypeQuake; detectedFormat = eBrushTypeQuake;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake\n";
} }
else{ else{
globalErrorStream() << "Format is not detected\n"; globalErrorStream() << "Format is not detected\n";
}
if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){
Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" ); Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" );
return g_nullNode; return g_nullNode;
} }
m_formatDetected = true;
if( detectedFormat != GlobalBrushCreator().getFormat() ){
GlobalBrushCreator().toggleFormat( detectedFormat );
}
} }
switch ( GlobalBrushModule::getTable().getCurrentFormat() ) switch ( GlobalBrushCreator().getFormat() )
{ {
case eBrushTypeQuake: case eBrushTypeQuake:
case eBrushTypeValve220: case eBrushTypeValve220:
tokeniser.ungetToken(); // ( tokeniser.ungetToken(); // (
case eBrushTypeQuake3BP: case eBrushTypeQuake3BP:
return GlobalBrushModule::getTable().createBrush(); return GlobalBrushCreator().createBrush();
default: default:
break; break;
} }
@ -360,6 +367,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
} }
void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const { void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const {
Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream ); Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream );
m_formatDetected = false;
Map_Read( root, tokeniser, entityTable, *this ); Map_Read( root, tokeniser, entityTable, *this );
tokeniser.release(); tokeniser.release();
} }
@ -394,7 +402,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
if ( primitive != 0 ) { if ( primitive != 0 ) {
if ( string_equal( primitive, "(" ) ) { if ( string_equal( primitive, "(" ) ) {
tokeniser.ungetToken(); // ( tokeniser.ungetToken(); // (
return GlobalBrushModule::getTable().createBrush(); return GlobalBrushCreator().createBrush();
} }
} }
@ -420,6 +428,7 @@ MapHalfLifeModule g_MapHalfLifeModule;
class MapQ2API : public TypeSystemRef, public MapFormat, public PrimitiveParser class MapQ2API : public TypeSystemRef, public MapFormat, public PrimitiveParser
{ {
mutable bool m_formatDetected;
public: public:
typedef MapFormat Type; typedef MapFormat Type;
STRING_CONSTANT( Name, "mapq2" ); STRING_CONSTANT( Name, "mapq2" );
@ -434,36 +443,38 @@ MapFormat* getTable(){
scene::Node& parsePrimitive( Tokeniser& tokeniser ) const { scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
const char* primitive = tokeniser.getToken(); const char* primitive = tokeniser.getToken();
if ( primitive != 0 ) { if ( primitive != 0 ) {
if( !m_detectedFormat ){ if( !m_formatDetected ){
EBrushType detectedFormat;
if ( string_equal( primitive, "brushDef" ) ) { if ( string_equal( primitive, "brushDef" ) ) {
m_detectedFormat = eBrushTypeQuake3BP; detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake3BP\n";
} }
else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) { else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) {
m_detectedFormat = eBrushTypeQuake3Valve220; detectedFormat = eBrushTypeQuake3Valve220;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3Valve220\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake3Valve220\n";
} }
else if ( string_equal( primitive, "(" ) ) { else if ( string_equal( primitive, "(" ) ) {
m_detectedFormat = eBrushTypeQuake2; detectedFormat = eBrushTypeQuake2;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake2\n"; globalErrorStream() << "detectedFormat = eBrushTypeQuake2\n";
} }
else{ else{
globalErrorStream() << "Format is not detected\n"; globalErrorStream() << "Format is not detected\n";
}
if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){
Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" ); Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" );
return g_nullNode; return g_nullNode;
} }
m_formatDetected = true;
if( detectedFormat != GlobalBrushCreator().getFormat() ){
GlobalBrushCreator().toggleFormat( detectedFormat );
}
} }
switch ( GlobalBrushModule::getTable().getCurrentFormat() ) switch ( GlobalBrushCreator().getFormat() )
{ {
case eBrushTypeQuake2: case eBrushTypeQuake2:
case eBrushTypeQuake3Valve220: case eBrushTypeQuake3Valve220:
tokeniser.ungetToken(); // ( tokeniser.ungetToken(); // (
case eBrushTypeQuake3BP: case eBrushTypeQuake3BP:
return GlobalBrushModule::getTable().createBrush(); return GlobalBrushCreator().createBrush();
default: default:
break; break;
} }
@ -474,6 +485,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
} }
void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const { void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const {
Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream ); Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream );
m_formatDetected = false;
Map_Read( root, tokeniser, entityTable, *this ); Map_Read( root, tokeniser, entityTable, *this );
tokeniser.release(); tokeniser.release();
} }

View File

@ -561,6 +561,9 @@ void setTexdef( const TextureProjection& projection ){
void setTexdef( const float* hShift, const float* vShift, const float* hScale, const float* vScale, const float* rotation ){ void setTexdef( const float* hShift, const float* vShift, const float* hScale, const float* vScale, const float* rotation ){
removeScale(); removeScale();
Texdef_Assign( m_projection, hShift, vShift, hScale, vScale, rotation ); Texdef_Assign( m_projection, hShift, vShift, hScale, vScale, rotation );
// if( hShift || vShift ){
// Texdef_normalise( m_projection, m_shader.width(), m_shader.height() );
// }
addScale(); addScale();
} }
@ -568,6 +571,7 @@ void shift( float s, float t ){
ASSERT_MESSAGE( texdef_sane( m_projection.m_texdef ), "FaceTexdef::shift: bad texdef" ); ASSERT_MESSAGE( texdef_sane( m_projection.m_texdef ), "FaceTexdef::shift: bad texdef" );
removeScale(); removeScale();
Texdef_Shift( m_projection, s, t ); Texdef_Shift( m_projection, s, t );
// Texdef_normalise( m_projection, m_shader.width(), m_shader.height() );
addScale(); addScale();
} }
@ -582,15 +586,20 @@ void rotate( float angle ){
Texdef_Rotate( m_projection, angle ); Texdef_Rotate( m_projection, angle );
addScale(); addScale();
} }
///ProjectTexture along 'direction' with parameters, defined by texdef_t
void ProjectTexture( const Plane3& plane, const texdef_t& texdef, const Vector3* direction ){ void ProjectTexture( const Plane3& plane, const texdef_t& texdef, const Vector3* direction ){
Texdef_ProjectTexture( m_projection, m_shader.width(), m_shader.height(), plane, texdef, direction ); Texdef_ProjectTexture( m_projection, m_shader.width(), m_shader.height(), plane, texdef, direction );
} }
///ProjectTexture along 'normal' with parameters, defined by TextureProjection
void ProjectTexture( const Plane3& plane, const TextureProjection& projection, const Vector3& normal ){ void ProjectTexture( const Plane3& plane, const TextureProjection& projection, const Vector3& normal ){
Texdef_ProjectTexture( m_projection, m_shader.width(), m_shader.height(), plane, projection, normal ); Texdef_ProjectTexture( m_projection, m_shader.width(), m_shader.height(), plane, projection, normal );
} }
void Convert( TexdefTypeId in, TexdefTypeId out, const Plane3& plane ){
Texdef_Convert( in, out, plane, m_projection, m_shader.width(), m_shader.height() );
m_scaleApplied = true;
}
void fit( const Vector3& normal, const Winding& winding, float s_repeat, float t_repeat ){ void fit( const Vector3& normal, const Winding& winding, float s_repeat, float t_repeat ){
Texdef_FitTexture( m_projection, m_shader.width(), m_shader.height(), normal, winding, s_repeat, t_repeat ); Texdef_FitTexture( m_projection, m_shader.width(), m_shader.height(), normal, winding, s_repeat, t_repeat );
} }
@ -610,12 +619,18 @@ TextureProjection normalised() const {
tmp.removeScale( m_shader.width(), m_shader.height() ); tmp.removeScale( m_shader.width(), m_shader.height() );
return TextureProjection( m_projection.m_texdef, tmp, m_projection.m_basis_s, m_projection.m_basis_t ); return TextureProjection( m_projection.m_texdef, tmp, m_projection.m_basis_s, m_projection.m_basis_t );
} }
#if 0 /* axial projection */
void setBasis( const Vector3& normal ){ void setBasis( const Vector3& normal ){
Matrix4 basis; Matrix4 basis;
Normal_GetTransform( normal, basis ); Normal_GetTransform( normal, basis );
m_projection.m_basis_s = Vector3( basis.xx(), basis.yx(), basis.zx() ); m_projection.m_basis_s = Vector3( basis.xx(), basis.yx(), basis.zx() );
m_projection.m_basis_t = Vector3( -basis.xy(), -basis.yy(), -basis.zy() ); m_projection.m_basis_t = Vector3( -basis.xy(), -basis.yy(), -basis.zy() );
} }
#else /* face projection */
void setBasis( const Vector3& normal ){
ComputeAxisBase( normal, m_projection.m_basis_s, m_projection.m_basis_t );
}
#endif
}; };
inline void planepts_print( const PlanePoints& planePoints, TextOutputStream& ostream ){ inline void planepts_print( const PlanePoints& planePoints, TextOutputStream& ostream ){
@ -869,6 +884,21 @@ void Brush_textureChanged();
extern bool g_brush_texturelock_enabled; extern bool g_brush_texturelock_enabled;
inline TexdefTypeId BrushType_getTexdefType( EBrushType type ){
switch ( type )
{
case eBrushTypeQuake3BP:
case eBrushTypeDoom3:
case eBrushTypeQuake4:
return TEXDEFTYPEID_BRUSHPRIMITIVES;
case eBrushTypeValve220:
case eBrushTypeQuake3Valve220:
return TEXDEFTYPEID_HALFLIFE;
default:
return TEXDEFTYPEID_QUAKE;
}
}
class FaceObserver class FaceObserver
{ {
public: public:
@ -984,7 +1014,7 @@ Face( const Face& other, FaceObserver* observer ) :
m_shader.attach( *this ); m_shader.attach( *this );
m_plane.copy( other.m_plane ); m_plane.copy( other.m_plane );
planepts_assign( m_move_planepts, other.m_move_planepts ); planepts_assign( m_move_planepts, other.m_move_planepts );
m_texdef.setBasis( m_plane.plane3().normal() ); // m_texdef.setBasis( m_plane.plane3().normal() );
planeChanged(); planeChanged();
updateFiltered(); updateFiltered();
} }
@ -1190,9 +1220,12 @@ void texdefChanged(){
void GetTexdef( TextureProjection& projection ) const { void GetTexdef( TextureProjection& projection ) const {
projection = m_texdef.normalised(); projection = m_texdef.normalised();
} }
void SetTexdef( const TextureProjection& projection ){ void SetTexdef( const TextureProjection& projection, bool resetBasis = false ){
undoSave(); undoSave();
m_texdef.setTexdef( projection ); m_texdef.setTexdef( projection );
if( resetBasis ){
m_texdef.setBasis( m_plane.plane3().normal() );
}
texdefChanged(); texdefChanged();
} }
@ -1242,6 +1275,11 @@ void ProjectTexture( const TextureProjection& projection, const Vector3& normal
texdefChanged(); texdefChanged();
} }
void Convert( TexdefTypeId in, TexdefTypeId out ){
m_texdef.Convert( in, out, m_plane.plane3() );
texdefChanged();
}
void FitTexture( float s_repeat, float t_repeat ){ void FitTexture( float s_repeat, float t_repeat ){
undoSave(); undoSave();
m_texdef.fit( m_plane.plane3().normal(), m_winding, s_repeat, t_repeat ); m_texdef.fit( m_plane.plane3().normal(), m_winding, s_repeat, t_repeat );
@ -1920,13 +1958,7 @@ static void constructStatic( EBrushType type ){
Face::m_type = type; Face::m_type = type;
FacePlane::m_type = type; FacePlane::m_type = type;
g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_QUAKE; g_bp_globals.m_texdefTypeId = BrushType_getTexdefType( type );
if ( m_type == eBrushTypeQuake3BP || m_type == eBrushTypeDoom3 || m_type == eBrushTypeQuake4 ) {
g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_BRUSHPRIMITIVES;
}
else if ( m_type == eBrushTypeValve220 || m_type == eBrushTypeQuake3Valve220 ) {
g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_HALFLIFE;
}
m_state_point = GlobalShaderCache().capture( "$POINT" ); m_state_point = GlobalShaderCache().capture( "$POINT" );
} }

View File

@ -203,7 +203,7 @@ inline void Texdef_normalise( texdef_t& texdef, float width, float height ){
texdef.shift[1] = float_mod( texdef.shift[1], height ); texdef.shift[1] = float_mod( texdef.shift[1], height );
//globalOutputStream() << "normalise: " << texdef.shift[0] << " " << texdef.shift[1] << " " << texdef.scale[0] << " " << texdef.scale[1] << " " << texdef.rotate << "\n"; //globalOutputStream() << "normalise: " << texdef.shift[0] << " " << texdef.shift[1] << " " << texdef.scale[0] << " " << texdef.scale[1] << " " << texdef.rotate << "\n";
} }
/// this is supposed to work with brushprimit_texdef_t.removeScale()'d
inline void BPTexdef_normalise( brushprimit_texdef_t& bp_texdef, float width, float height ){ inline void BPTexdef_normalise( brushprimit_texdef_t& bp_texdef, float width, float height ){
bp_texdef.coords[0][2] = float_mod( bp_texdef.coords[0][2], width ); bp_texdef.coords[0][2] = float_mod( bp_texdef.coords[0][2], width );
bp_texdef.coords[1][2] = float_mod( bp_texdef.coords[1][2], height ); bp_texdef.coords[1][2] = float_mod( bp_texdef.coords[1][2], height );
@ -407,7 +407,7 @@ void Texdef_Rotate( texdef_t& td, float angle ){
td.rotate += angle; td.rotate += angle;
td.rotate = static_cast<float>( float_to_integer( td.rotate ) % 360 ); td.rotate = static_cast<float>( float_to_integer( td.rotate ) % 360 );
} }
#if 0
// NOTE: added these from Ritual's Q3Radiant // NOTE: added these from Ritual's Q3Radiant
void ClearBounds( Vector3& mins, Vector3& maxs ){ void ClearBounds( Vector3& mins, Vector3& maxs ){
mins[0] = mins[1] = mins[2] = 99999; mins[0] = mins[1] = mins[2] = 99999;
@ -429,7 +429,7 @@ void AddPointToBounds( const Vector3& v, Vector3& mins, Vector3& maxs ){
} }
} }
} }
#endif
template<typename Element> template<typename Element>
inline BasicVector3<Element> vector3_inverse( const BasicVector3<Element>& self ){ inline BasicVector3<Element> vector3_inverse( const BasicVector3<Element>& self ){
return BasicVector3<Element>( return BasicVector3<Element>(
@ -439,28 +439,10 @@ inline BasicVector3<Element> vector3_inverse( const BasicVector3<Element>& self
); );
} }
// low level functions .. put in mathlib?
#define BPMatCopy( a,b ) {b[0][0] = a[0][0]; b[0][1] = a[0][1]; b[0][2] = a[0][2]; b[1][0] = a[1][0]; b[1][1] = a[1][1]; b[1][2] = a[1][2]; }
// apply a scale transformation to the BP matrix
#define BPMatScale( m,sS,sT ) {m[0][0] *= sS; m[1][0] *= sS; m[0][1] *= sT; m[1][1] *= sT; }
// apply a translation transformation to a BP matrix
#define BPMatTranslate( m,s,t ) {m[0][2] += m[0][0] * s + m[0][1] * t; m[1][2] += m[1][0] * s + m[1][1] * t; }
// 2D homogeneous matrix product C = A*B
void BPMatMul( float A[2][3], float B[2][3], float C[2][3] );
// apply a rotation (degrees)
void BPMatRotate( float A[2][3], float theta );
#ifdef _DEBUG
void BPMatDump( float A[2][3] );
#endif
#ifdef _DEBUG
//#define DBG_BP
#endif
bp_globals_t g_bp_globals; bp_globals_t g_bp_globals;
float g_texdef_default_scale; float g_texdef_default_scale;
#if 0
// compute a determinant using Sarrus rule // compute a determinant using Sarrus rule
//++timo "inline" this with a macro //++timo "inline" this with a macro
// NOTE : the three vectors are understood as columns of the matrix // NOTE : the three vectors are understood as columns of the matrix
@ -502,7 +484,7 @@ void MatrixForPoints( Vector3 M[3], Vector3 D[2], brushprimit_texdef_t *T ){
T->coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; T->coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det;
T->coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; T->coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det;
} }
#endif
//++timo replace everywhere texX by texS etc. ( ----> and in q3map !) //++timo replace everywhere texX by texS etc. ( ----> and in q3map !)
// NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME ! // NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME !
// WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0 // WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
@ -552,7 +534,13 @@ void ComputeAxisBase( const BasicVector3<Element>& normal, BasicVector3<Element>
#endif #endif
} }
#if 0 // texdef conversion #if 0
#ifdef _DEBUG
//#define DBG_BP
#endif
// texdef conversion
void FaceToBrushPrimitFace( face_t *f ){ void FaceToBrushPrimitFace( face_t *f ){
Vector3 texX,texY; Vector3 texX,texY;
Vector3 proj; Vector3 proj;
@ -617,7 +605,6 @@ void EmitBrushPrimitTextureCoordinates( face_t * f, Winding * w ){
{ {
x = vector3_dot( w.point_at( i ),texX ); x = vector3_dot( w.point_at( i ),texX );
y = vector3_dot( w.point_at( i ),texY ); y = vector3_dot( w.point_at( i ),texY );
#if 0
#ifdef DBG_BP #ifdef DBG_BP
if ( g_bp_globals.bNeedConvert ) { if ( g_bp_globals.bNeedConvert ) {
// check we compute the same ST as the traditional texture computation used before // check we compute the same ST as the traditional texture computation used before
@ -632,7 +619,6 @@ void EmitBrushPrimitTextureCoordinates( face_t * f, Winding * w ){
} }
} }
} }
#endif
#endif #endif
w.point_at( i )[3] = f->brushprimit_texdef.coords[0][0] * x + f->brushprimit_texdef.coords[0][1] * y + f->brushprimit_texdef.coords[0][2]; w.point_at( i )[3] = f->brushprimit_texdef.coords[0][0] * x + f->brushprimit_texdef.coords[0][1] * y + f->brushprimit_texdef.coords[0][2];
w.point_at( i )[4] = f->brushprimit_texdef.coords[1][0] * x + f->brushprimit_texdef.coords[1][1] * y + f->brushprimit_texdef.coords[1][2]; w.point_at( i )[4] = f->brushprimit_texdef.coords[1][0] * x + f->brushprimit_texdef.coords[1][1] * y + f->brushprimit_texdef.coords[1][2];
@ -733,7 +719,6 @@ void TexMatToFakeTexCoords( const brushprimit_texdef_t& bp_texdef, texdef_t& tex
// compute back the texture matrix from fake shift scale rot // compute back the texture matrix from fake shift scale rot
void FakeTexCoordsToTexMat( const texdef_t& texdef, brushprimit_texdef_t& bp_texdef ){ void FakeTexCoordsToTexMat( const texdef_t& texdef, brushprimit_texdef_t& bp_texdef ){
#if 1
double r = degrees_to_radians( -texdef.rotate ); double r = degrees_to_radians( -texdef.rotate );
double c = cos( r ); double c = cos( r );
double s = sin( r ); double s = sin( r );
@ -745,19 +730,6 @@ void FakeTexCoordsToTexMat( const texdef_t& texdef, brushprimit_texdef_t& bp_tex
bp_texdef.coords[1][1] = static_cast<float>( y * c ); bp_texdef.coords[1][1] = static_cast<float>( y * c );
bp_texdef.coords[0][2] = -texdef.shift[0]; bp_texdef.coords[0][2] = -texdef.shift[0];
bp_texdef.coords[1][2] = texdef.shift[1]; bp_texdef.coords[1][2] = texdef.shift[1];
#else
double r = degrees_to_radians( texdef.rotate );
double c = cos( r );
double s = sin( r );
double x = 1.0f / texdef.scale[0];
double y = 1.0f / texdef.scale[1];
bp_texdef.coords[0][0] = static_cast<float>( x * c );
bp_texdef.coords[1][0] = static_cast<float>( -y * s );
bp_texdef.coords[0][1] = static_cast<float>( x * s );
bp_texdef.coords[1][1] = static_cast<float>( y * c );
bp_texdef.coords[0][2] = -texdef.shift[0];
bp_texdef.coords[1][2] = texdef.shift[1];
#endif
// globalOutputStream() << "[ " << bp_texdef.coords[0][0] << " " << bp_texdef.coords[0][1] << " ][ " << bp_texdef.coords[1][0] << " " << bp_texdef.coords[1][1] << " ]\n"; // globalOutputStream() << "[ " << bp_texdef.coords[0][0] << " " << bp_texdef.coords[0][1] << " ][ " << bp_texdef.coords[1][0] << " " << bp_texdef.coords[1][1] << " ]\n";
} }
@ -808,7 +780,7 @@ void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y ){
f->brushprimit_texdef.coords[1][2] -= t; f->brushprimit_texdef.coords[1][2] -= t;
} }
#endif #endif
#if 0
// TTimo: FIXME: I don't like that, it feels broken // TTimo: FIXME: I don't like that, it feels broken
// (and it's likely that it's not used anymore) // (and it's likely that it's not used anymore)
// best fitted 2D vector is x.X+y.Y // best fitted 2D vector is x.X+y.Y
@ -836,7 +808,7 @@ void ComputeBest2DVector( Vector3& v, Vector3& X, Vector3& Y, int &x, int &y ){
} }
} }
} }
#endif
#if 0 // texdef conversion #if 0 // texdef conversion
void BrushPrimitFaceToFace( face_t *face ){ void BrushPrimitFaceToFace( face_t *face ){
@ -972,6 +944,17 @@ void ApplyMatrix_BrushPrimit( face_t *f, Vector3 matrix[3], Vector3& origin ){
TextureLockTransformation_BrushPrimit( f ); TextureLockTransformation_BrushPrimit( f );
} }
#endif #endif
#if 0
// low level functions .. put in mathlib?
#define BPMatCopy( a,b ) {b[0][0] = a[0][0]; b[0][1] = a[0][1]; b[0][2] = a[0][2]; b[1][0] = a[1][0]; b[1][1] = a[1][1]; b[1][2] = a[1][2]; }
// apply a scale transformation to the BP matrix
#define BPMatScale( m,sS,sT ) {m[0][0] *= sS; m[1][0] *= sS; m[0][1] *= sT; m[1][1] *= sT; }
// apply a translation transformation to a BP matrix
#define BPMatTranslate( m,s,t ) {m[0][2] += m[0][0] * s + m[0][1] * t; m[1][2] += m[1][0] * s + m[1][1] * t; }
// 2D homogeneous matrix product C = A*B
void BPMatMul( float A[2][3], float B[2][3], float C[2][3] );
// apply a rotation (degrees)
void BPMatRotate( float A[2][3], float theta );
// don't do C==A! // don't do C==A!
void BPMatMul( float A[2][3], float B[2][3], float C[2][3] ){ void BPMatMul( float A[2][3], float B[2][3], float C[2][3] ){
@ -1004,7 +987,7 @@ void BPMatRotate( float A[2][3], float theta ){
BPMatMul( A, m, aux ); BPMatMul( A, m, aux );
BPMatCopy( aux,A ); BPMatCopy( aux,A );
} }
#endif
#if 0 // camera-relative texture shift #if 0 // camera-relative texture shift
// get the relative axes of the current texturing // get the relative axes of the current texturing
void BrushPrimit_GetRelativeAxes( face_t *f, Vector3& vecS, Vector3& vecT ){ void BrushPrimit_GetRelativeAxes( face_t *f, Vector3& vecS, Vector3& vecT ){
@ -1082,6 +1065,19 @@ void ShiftTextureRelative_Camera( face_t *f, int x, int y ){
} }
#endif #endif
#include "math/quaternion.h"
void Valve220_rotate( TextureProjection& projection, float angle ){
// globalOutputStream() << angle << " angle\n";
// globalOutputStream() << projection.m_texdef.rotate << " projection.m_texdef.rotate\n";
const Matrix4 rotmat = matrix4_rotation_for_axisangle( vector3_cross( projection.m_basis_s, projection.m_basis_t ), degrees_to_radians( -angle ) );
matrix4_transform_direction( rotmat, projection.m_basis_s );
matrix4_transform_direction( rotmat, projection.m_basis_t );
vector3_normalise( projection.m_basis_s );
vector3_normalise( projection.m_basis_t );
// globalOutputStream() << projection.m_basis_s << " projection.m_basis_s\n";
// globalOutputStream() << projection.m_basis_t << " projection.m_basis_t\n";
}
void BPTexdef_Assign( brushprimit_texdef_t& bp_td, const brushprimit_texdef_t& bp_other ){ void BPTexdef_Assign( brushprimit_texdef_t& bp_td, const brushprimit_texdef_t& bp_other ){
bp_td = bp_other; bp_td = bp_other;
@ -1208,11 +1204,10 @@ void Texdef_Assign( TextureProjection& projection, const float* hShift, const fl
} }
else else
{ {
if ( rotation && g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
Valve220_rotate( projection, *rotation - projection.m_texdef.rotate );
}
Texdef_Assign( projection.m_texdef, hShift, vShift, hScale, vScale, rotation ); Texdef_Assign( projection.m_texdef, hShift, vShift, hScale, vScale, rotation );
// if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
// projection.m_basis_s = other.m_basis_s;
// projection.m_basis_t = other.m_basis_t;
// }
} }
} }
@ -1242,6 +1237,9 @@ void Texdef_Rotate( TextureProjection& projection, float angle ){
} }
else else
{ {
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
Valve220_rotate( projection, angle );
}
Texdef_Rotate( projection.m_texdef, angle ); Texdef_Rotate( projection.m_texdef, angle );
} }
} }
@ -1304,7 +1302,11 @@ void Texdef_FitTexture( TextureProjection& projection, std::size_t width, std::s
matrix4_premultiply_by_matrix4( st2tex, matrix ); matrix4_premultiply_by_matrix4( st2tex, matrix );
Texdef_fromTransform( projection, (float)width, (float)height, st2tex ); Texdef_fromTransform( projection, (float)width, (float)height, st2tex );
Texdef_normalise( projection, (float)width, (float)height ); //Texdef_normalise( projection, (float)width, (float)height );
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES )
BPTexdef_normalise( projection.m_brushprimit_texdef, 1.f, 1.f ); /* scaleApplied is! */
else
Texdef_normalise( projection.m_texdef, (float)width, (float)height );
} }
float Texdef_getDefaultTextureScale(){ float Texdef_getDefaultTextureScale(){
@ -1344,7 +1346,7 @@ void ShiftScaleRotate_toFace( const texdef_t& shiftScaleRotate, TextureProjectio
} }
} }
#if 0
inline void print_vector3( const Vector3& v ){ inline void print_vector3( const Vector3& v ){
globalOutputStream() << "( " << v.x() << " " << v.y() << " " << v.z() << " )\n"; globalOutputStream() << "( " << v.x() << " " << v.y() << " " << v.z() << " )\n";
} }
@ -1447,6 +1449,97 @@ inline Matrix4 matrix4_reflection_for_plane45( const Plane3& plane, const Vector
return swap; return swap;
} }
void Texdef_transformLocked_original( TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, const Matrix4& identity2transformed, const Vector3 centroid ){
// globalOutputStream() << "\t\t----------------------\n";
// globalOutputStream() << "AP: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
// globalOutputStream() << "BP: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
// globalOutputStream() << "width:" << width << " height" << height << "\n";
//globalOutputStream() << "identity2transformed: " << identity2transformed << "\n";
//globalOutputStream() << "plane.normal(): " << plane.normal() << "\n";
#if 0
Vector3 normalTransformed( matrix4_transformed_direction( identity2transformed, plane.normal() ) );
#else //preserves scale in BP while scaling, but not shift //fixes QNAN
Matrix4 maa( matrix4_affine_inverse( identity2transformed ) );
matrix4_transpose( maa );
//Vector4 vec4 = matrix4_transformed_vector4( maa, Vector4( plane.normal(), 0 ) );
//Vector3 normalTransformed( vector3_normalised( vector4_to_vector3( vec4 ) ) );
Vector3 normalTransformed( vector3_normalised( matrix4_transformed_direction( maa, plane.normal() ) ) );
#endif
//globalOutputStream() << "normalTransformed: " << normalTransformed << "\n";
// identity: identity space
// transformed: transformation
// stIdentity: base st projection space before transformation
// stTransformed: base st projection space after transformation
// stOriginal: original texdef space
// stTransformed2stOriginal = stTransformed -> transformed -> identity -> stIdentity -> stOriginal
Matrix4 identity2stIdentity;
Texdef_basisForNormal( projection, plane.normal(), identity2stIdentity );
//globalOutputStream() << "identity2stIdentity: " << identity2stIdentity << "\n";
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
matrix4_transform_direction( maa, projection.m_basis_s );
matrix4_transform_direction( maa, projection.m_basis_t );
}
Matrix4 transformed2stTransformed;
Texdef_basisForNormal( projection, normalTransformed, transformed2stTransformed );
// globalOutputStream() << "transformed2stTransformed: " << transformed2stTransformed << "\n";
Matrix4 stTransformed2identity( matrix4_affine_inverse( matrix4_multiplied_by_matrix4( transformed2stTransformed, identity2transformed ) ) );
// globalOutputStream() << "stTransformed2identity: " << stTransformed2identity << "\n";
Vector3 originalProjectionAxis( vector4_to_vector3( matrix4_affine_inverse( identity2stIdentity ).z() ) );
Vector3 transformedProjectionAxis( vector4_to_vector3( stTransformed2identity.z() ) );
Matrix4 stIdentity2stOriginal;
Texdef_toTransform( projection, (float)width, (float)height, stIdentity2stOriginal );
// globalOutputStream() << "stIdentity2stOriginal: " << stIdentity2stOriginal << "\n";
Matrix4 identity2stOriginal( matrix4_multiplied_by_matrix4( stIdentity2stOriginal, identity2stIdentity ) );
// globalOutputStream() << "identity2stOriginal: " << identity2stOriginal << "\n";
//globalOutputStream() << "originalProj: " << originalProjectionAxis << "\n";
//globalOutputStream() << "transformedProj: " << transformedProjectionAxis << "\n";
double dot = vector3_dot( originalProjectionAxis, transformedProjectionAxis );
//globalOutputStream() << "dot: " << dot << "\n";
if ( dot == 0 ) {
// The projection axis chosen for the transformed normal is at 90 degrees
// to the transformed projection axis chosen for the original normal.
// This happens when the projection axis is ambiguous - e.g. for the plane
// 'X == Y' the projection axis could be either X or Y.
//globalOutputStream() << "flipped\n";
#if 0
globalOutputStream() << "projection off by 90\n";
globalOutputStream() << "normal: ";
print_vector3( plane.normal() );
globalOutputStream() << "original projection: ";
print_vector3( originalProjectionAxis );
globalOutputStream() << "transformed projection: ";
print_vector3( transformedProjectionAxis );
#endif
Matrix4 identityCorrected = matrix4_reflection_for_plane45( plane, originalProjectionAxis, transformedProjectionAxis );
identity2stOriginal = matrix4_multiplied_by_matrix4( identity2stOriginal, identityCorrected );
}
else if( dot != dot ){ //catch QNAN: happens on scaling cuboid on Z and sometimes on rotating (in bp mode) //and in making seamless to self or parallel
return;
}
Matrix4 stTransformed2stOriginal = matrix4_multiplied_by_matrix4( identity2stOriginal, stTransformed2identity );
// globalOutputStream() << "stTransformed2stOriginal: " << stTransformed2stOriginal << "\n";
Texdef_fromTransform( projection, (float)width, (float)height, stTransformed2stOriginal );
// globalOutputStream() << "AP: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
// globalOutputStream() << "BP: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
Texdef_normalise( projection, (float)width, (float)height );
// globalOutputStream() << "AP norm: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
// globalOutputStream() << "BP norm: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
}
#endif
double Det3x3( double a00, double a01, double a02, double Det3x3( double a00, double a01, double a02,
double a10, double a11, double a12, double a10, double a11, double a12,
double a20, double a21, double a22 ){ double a20, double a21, double a22 ){
@ -1488,7 +1581,6 @@ std::size_t planeNormalIndex( const Vector3& normal ) {
return bestIndex; return bestIndex;
} }
#include "math/quaternion.h"
void Texdef_transformLocked( TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, const Matrix4& identity2transformed, const Vector3 centroid ){ void Texdef_transformLocked( TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, const Matrix4& identity2transformed, const Vector3 centroid ){
if( identity2transformed == g_matrix4_identity ){ if( identity2transformed == g_matrix4_identity ){
@ -1496,31 +1588,22 @@ void Texdef_transformLocked( TextureProjection& projection, std::size_t width, s
return; //TODO FIXME !!! this (and whole pipeline?) is called with g_matrix4_identity after every transform //now only on freezeTransform, it seems return; //TODO FIXME !!! this (and whole pipeline?) is called with g_matrix4_identity after every transform //now only on freezeTransform, it seems
} }
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) { if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
#if 1
// globalOutputStream() << "identity2transformed: " << identity2transformed << "\n"; // globalOutputStream() << "identity2transformed: " << identity2transformed << "\n";
// globalOutputStream() << "BP in: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n"; // globalOutputStream() << "BP in: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
DoubleVector3 texX, texY; DoubleVector3 texX, texY;
DoubleVector3 points[3];
DoubleVector3 st[3];
ComputeAxisBase( plane.normal(), texX, texY ); ComputeAxisBase( plane.normal(), texX, texY );
const DoubleVector3 anchor = plane.normal() * plane.dist();
points[0] = anchor; const DoubleVector3 anchor = plane.normal() * plane.dist();
points[1] = texX + anchor; DoubleVector3 points[3] = { anchor, anchor + texX, anchor + texY };
points[2] = texY + anchor; DoubleVector3 st[3];
Matrix4 local2tex; Matrix4 local2tex;
Texdef_Construct_local2tex( projection, width, height, plane.normal(), local2tex ); Texdef_Construct_local2tex( projection, width, height, plane.normal(), local2tex );
for ( std::size_t i = 0; i < 3; ++i ) for ( std::size_t i = 0; i < 3; ++i ){
{ st[i] = matrix4_transformed_point( local2tex, points[i] );
DoubleVector3 texcoord = matrix4_transformed_point( local2tex, points[i] );
st[i][0] = texcoord[0];
st[i][1] = texcoord[1];
matrix4_transform_point( identity2transformed, points[i] ); matrix4_transform_point( identity2transformed, points[i] );
} }
double xyI[2], xyJ[2], xyK[2]; double xyI[2], xyJ[2], xyK[2];
double stI[2], stJ[2], stK[2]; double stI[2], stJ[2], stK[2];
double D, D0, D1, D2; double D, D0, D1, D2;
@ -1570,39 +1653,10 @@ void Texdef_transformLocked( TextureProjection& projection, std::size_t width, s
); );
projection.m_brushprimit_texdef.coords[i][0] = D0 / D; projection.m_brushprimit_texdef.coords[i][0] = D0 / D;
projection.m_brushprimit_texdef.coords[i][1] = D1 / D; projection.m_brushprimit_texdef.coords[i][1] = D1 / D;
projection.m_brushprimit_texdef.coords[i][2] = fmod( D2 / D, 1 ); projection.m_brushprimit_texdef.coords[i][2] = fmod( D2 / D, 1.0 );
} }
// globalOutputStream() << "BP out: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n"; // globalOutputStream() << "BP out: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
} }
#else
globalOutputStream() << "\t\t**********\n";
globalOutputStream() << "identity2transformed: " << identity2transformed << "\n";
Matrix4 maa( matrix4_affine_inverse( identity2transformed ) );
matrix4_transpose( maa );
Vector3 normalTransformed( vector3_normalised( matrix4_transformed_direction( maa, plane.normal() ) ) );
Matrix4 xyz2st;
Texdef_basisForNormal( projection, plane.normal(), xyz2st );
globalOutputStream() << "plane.normal() " << plane.normal() << "\n";
globalOutputStream() << "normalTransformed " << normalTransformed << "\n";
globalOutputStream() << "Texdef_basisForNormal " << xyz2st << "\n";
Matrix4 local2tex;
Texdef_toTransform( projection, (float)width, (float)height, local2tex );
globalOutputStream() << "BP: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
globalOutputStream() << "Texdef_toTransform " << local2tex << "\n";
local2tex = matrix4_multiplied_by_matrix4( matrix4_transposed( xyz2st ), local2tex );
globalOutputStream() << "Texdef_toTransform rebased " << local2tex << "\n";
local2tex = matrix4_multiplied_by_matrix4( identity2transformed, local2tex );
globalOutputStream() << "Texdef_toTransform rebased transformed " << local2tex << "\n";
Texdef_basisForNormal( projection, normalTransformed, xyz2st );
globalOutputStream() << "NEW Texdef_basisForNormal " << xyz2st << "\n";
//local2tex = matrix4_multiplied_by_matrix4( matrix4_affine_inverse( xyz2st ), local2tex );
local2tex = matrix4_multiplied_by_matrix4( xyz2st, local2tex );
globalOutputStream() << "Texdef_toTransform rebased transformed back to basis" << local2tex << "\n";
Texdef_fromTransform( projection, (float)width, (float)height, local2tex );
globalOutputStream() << "BP NEW: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
#endif // 0
} }
else if( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_QUAKE ) { else if( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_QUAKE ) {
// globalOutputStream() << "\t\t***: " << centroid << "\n"; // globalOutputStream() << "\t\t***: " << centroid << "\n";
@ -1716,23 +1770,23 @@ void Texdef_transformLocked( TextureProjection& projection, std::size_t width, s
// globalOutputStream() << "AP new: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n"; // globalOutputStream() << "AP new: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
} }
else{ //TEXDEFTYPEID_HALFLIFE else{ //TEXDEFTYPEID_HALFLIFE
// globalOutputStream() << "\t\t----------------------\n";
// globalOutputStream() << "AP: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n"; // globalOutputStream() << "AP: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
// globalOutputStream() << "BP: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n"; // globalOutputStream() << "220: projection.m_basis_s: " << projection.m_basis_s << " projection.m_basis_t: " << projection.m_basis_t << "\n";
// globalOutputStream() << "width:" << width << " height" << height << "\n";
//globalOutputStream() << "identity2transformed: " << identity2transformed << "\n"; //globalOutputStream() << "identity2transformed: " << identity2transformed << "\n";
/* hack: is often broken with niggative scale */
if( projection.m_texdef.scale[0] < 0 ){
projection.m_texdef.scale[0] *= -1.f;
projection.m_basis_s *= -1.f;
}
if( projection.m_texdef.scale[1] < 0 ){
projection.m_texdef.scale[1] *= -1.f;
projection.m_basis_t *= -1.f;
}
//globalOutputStream() << "plane.normal(): " << plane.normal() << "\n"; //globalOutputStream() << "plane.normal(): " << plane.normal() << "\n";
#if 0
Vector3 normalTransformed( matrix4_transformed_direction( identity2transformed, plane.normal() ) );
#else //preserves scale in BP while scaling, but not shift //fixes QNAN
Matrix4 maa( matrix4_affine_inverse( identity2transformed ) ); Matrix4 maa( matrix4_affine_inverse( identity2transformed ) );
matrix4_transpose( maa ); matrix4_transpose( maa );
//Vector4 vec4 = matrix4_transformed_vector4( maa, Vector4( plane.normal(), 0 ) );
//Vector3 normalTransformed( vector3_normalised( vector4_to_vector3( vec4 ) ) );
Vector3 normalTransformed( vector3_normalised( matrix4_transformed_direction( maa, plane.normal() ) ) ); Vector3 normalTransformed( vector3_normalised( matrix4_transformed_direction( maa, plane.normal() ) ) );
#endif
//globalOutputStream() << "normalTransformed: " << normalTransformed << "\n"; //globalOutputStream() << "normalTransformed: " << normalTransformed << "\n";
@ -1746,67 +1800,30 @@ void Texdef_transformLocked( TextureProjection& projection, std::size_t width, s
Matrix4 identity2stIdentity; Matrix4 identity2stIdentity;
Texdef_basisForNormal( projection, plane.normal(), identity2stIdentity ); Texdef_basisForNormal( projection, plane.normal(), identity2stIdentity );
//globalOutputStream() << "identity2stIdentity: " << identity2stIdentity << "\n";
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) { matrix4_transform_direction( maa, projection.m_basis_s );
matrix4_transform_direction( identity2transformed, projection.m_basis_s ); matrix4_transform_direction( maa, projection.m_basis_t );
matrix4_transform_direction( identity2transformed, projection.m_basis_t );
}
Matrix4 transformed2stTransformed; Matrix4 transformed2stTransformed;
Texdef_basisForNormal( projection, normalTransformed, transformed2stTransformed ); Texdef_basisForNormal( projection, normalTransformed, transformed2stTransformed );
// globalOutputStream() << "transformed2stTransformed: " << transformed2stTransformed << "\n";
Matrix4 stTransformed2identity( matrix4_affine_inverse( matrix4_multiplied_by_matrix4( transformed2stTransformed, identity2transformed ) ) ); Matrix4 stTransformed2identity( matrix4_affine_inverse( matrix4_multiplied_by_matrix4( transformed2stTransformed, identity2transformed ) ) );
// globalOutputStream() << "stTransformed2identity: " << stTransformed2identity << "\n";
Vector3 originalProjectionAxis( vector4_to_vector3( matrix4_affine_inverse( identity2stIdentity ).z() ) );
Vector3 transformedProjectionAxis( vector4_to_vector3( stTransformed2identity.z() ) );
Matrix4 stIdentity2stOriginal; Matrix4 stIdentity2stOriginal;
Texdef_toTransform( projection, (float)width, (float)height, stIdentity2stOriginal ); Texdef_toTransform( projection, (float)width, (float)height, stIdentity2stOriginal );
// globalOutputStream() << "stIdentity2stOriginal: " << stIdentity2stOriginal << "\n";
Matrix4 identity2stOriginal( matrix4_multiplied_by_matrix4( stIdentity2stOriginal, identity2stIdentity ) ); Matrix4 identity2stOriginal( matrix4_multiplied_by_matrix4( stIdentity2stOriginal, identity2stIdentity ) );
// globalOutputStream() << "identity2stOriginal: " << identity2stOriginal << "\n";
//globalOutputStream() << "originalProj: " << originalProjectionAxis << "\n";
//globalOutputStream() << "transformedProj: " << transformedProjectionAxis << "\n";
double dot = vector3_dot( originalProjectionAxis, transformedProjectionAxis );
//globalOutputStream() << "dot: " << dot << "\n";
if ( dot == 0 ) {
// The projection axis chosen for the transformed normal is at 90 degrees
// to the transformed projection axis chosen for the original normal.
// This happens when the projection axis is ambiguous - e.g. for the plane
// 'X == Y' the projection axis could be either X or Y.
//globalOutputStream() << "flipped\n";
#if 0
globalOutputStream() << "projection off by 90\n";
globalOutputStream() << "normal: ";
print_vector3( plane.normal() );
globalOutputStream() << "original projection: ";
print_vector3( originalProjectionAxis );
globalOutputStream() << "transformed projection: ";
print_vector3( transformedProjectionAxis );
#endif
Matrix4 identityCorrected = matrix4_reflection_for_plane45( plane, originalProjectionAxis, transformedProjectionAxis );
identity2stOriginal = matrix4_multiplied_by_matrix4( identity2stOriginal, identityCorrected );
}
else if( dot != dot ){ //catch QNAN: happens on scaling cuboid on Z and sometimes on rotating (in bp mode) //and in making seamless to self or parallel
return;
}
Matrix4 stTransformed2stOriginal = matrix4_multiplied_by_matrix4( identity2stOriginal, stTransformed2identity ); Matrix4 stTransformed2stOriginal = matrix4_multiplied_by_matrix4( identity2stOriginal, stTransformed2identity );
// globalOutputStream() << "stTransformed2stOriginal: " << stTransformed2stOriginal << "\n";
Texdef_fromTransform( projection, (float)width, (float)height, stTransformed2stOriginal ); Texdef_fromTransform( projection, (float)width, (float)height, stTransformed2stOriginal );
// globalOutputStream() << "AP: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
// globalOutputStream() << "BP: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
Texdef_normalise( projection, (float)width, (float)height ); Texdef_normalise( projection, (float)width, (float)height );
// globalOutputStream() << "AP norm: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
// globalOutputStream() << "BP norm: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n"; projection.m_texdef.scale[0] /= vector3_length( projection.m_basis_s );
projection.m_texdef.scale[1] /= vector3_length( projection.m_basis_t );
vector3_normalise( projection.m_basis_s );
vector3_normalise( projection.m_basis_t );
} }
} }
#if 1 #if 0
void Q3_to_matrix( const texdef_t& texdef, float width, float height, const Vector3& normal, Matrix4& matrix ){ void Q3_to_matrix( const texdef_t& texdef, float width, float height, const Vector3& normal, Matrix4& matrix ){
Normal_GetTransform( normal, matrix ); Normal_GetTransform( normal, matrix );
@ -1852,98 +1869,70 @@ void Texdef_Construct_local2tex4projection( const texdef_t& texdef, std::size_t
matrix4_multiply_by_matrix4( local2tex, basis ); matrix4_multiply_by_matrix4( local2tex, basis );
} }
else{ //ap else{ //AP
Matrix4 xyz2st; Matrix4 xyz2st;
Normal_GetTransform( normal, xyz2st ); //Texdef_basisForNormal for ap Normal_GetTransform( normal, xyz2st ); //Texdef_basisForNormal for AP
matrix4_multiply_by_matrix4( local2tex, xyz2st ); matrix4_multiply_by_matrix4( local2tex, xyz2st );
} }
} }
} }
void Texdef_ProjectTexture( TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, const texdef_t& texdef, const Vector3* direction ){ inline void BPTexdef_fromST011( TextureProjection& projection, const Plane3& plane, const Matrix4& local2tex ){
//texdef_t texdef;
//Q3_to_BP( texdef, (float)width, (float)height, normal, projection.m_brushprimit_texdef );
DoubleVector3 texX, texY; DoubleVector3 texX, texY;
// compute axis base
ComputeAxisBase( plane.normal(), texX, texY ); ComputeAxisBase( plane.normal(), texX, texY );
// compute projection vector
const DoubleVector3 anchor = plane.normal() * plane.dist();
// (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane // (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane
// (1,0) in plane axis base is texX in world coordinates + projection on the affine plane // (1,0) in plane axis base is texX in world coordinates + projection on the affine plane
// (0,1) in plane axis base is texY in world coordinates + projection on the affine plane // (0,1) in plane axis base is texY in world coordinates + projection on the affine plane
// use old texture code to compute the ST coords of these points // use old texture code to compute the ST coords of these points
// ST of (0,0) (1,0) (0,1) // ST of (0,0) (1,0) (0,1)
DoubleVector3 points[3]; const DoubleVector3 anchor = plane.normal() * plane.dist();
const DoubleVector3 points[3] = { anchor, anchor + texX, anchor + texY };
DoubleVector3 st[3]; DoubleVector3 st[3];
points[0] = anchor; for ( std::size_t i = 0; i < 3; ++i ){
points[1] = texX + anchor; st[i] = matrix4_transformed_point( local2tex, points[i] );
points[2] = texY + anchor; //globalOutputStream() << st[i] << "\n";
Matrix4 local2tex;
Texdef_Construct_local2tex4projection( texdef, width, height, plane.normal(), direction, local2tex );
for ( std::size_t i = 0; i < 3; ++i )
{
DoubleVector3 texcoord = matrix4_transformed_point( local2tex, points[i] );
//globalOutputStream() << texcoord << "\n";
st[i][0] = texcoord[0];
st[i][1] = texcoord[1];
} }
// compute texture matrix // compute texture matrix
projection.m_brushprimit_texdef.coords[0][2] = st[0][0]; projection.m_brushprimit_texdef.coords[0][2] = float_mod( st[0][0], 1.0 );
projection.m_brushprimit_texdef.coords[1][2] = st[0][1]; projection.m_brushprimit_texdef.coords[1][2] = float_mod( st[0][1], 1.0 );
projection.m_brushprimit_texdef.coords[0][0] = st[1][0] - st[0][0]; projection.m_brushprimit_texdef.coords[0][0] = st[1][0] - st[0][0];
projection.m_brushprimit_texdef.coords[1][0] = st[1][1] - st[0][1]; projection.m_brushprimit_texdef.coords[1][0] = st[1][1] - st[0][1];
projection.m_brushprimit_texdef.coords[0][1] = st[2][0] - st[0][0]; projection.m_brushprimit_texdef.coords[0][1] = st[2][0] - st[0][0];
projection.m_brushprimit_texdef.coords[1][1] = st[2][1] - st[0][1]; projection.m_brushprimit_texdef.coords[1][1] = st[2][1] - st[0][1];
}
Texdef_normalise( projection, (float)width, (float)height ); void Texdef_ProjectTexture( TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, const texdef_t& texdef, const Vector3* direction ){
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
//texdef_t texdef;
//Q3_to_BP( texdef, (float)width, (float)height, normal, projection.m_brushprimit_texdef );
Matrix4 local2tex;
Texdef_Construct_local2tex4projection( texdef, width, height, plane.normal(), direction, local2tex );
BPTexdef_fromST011( projection, plane, local2tex );
}
else if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
Texdef_Assign( projection.m_texdef, texdef );
if( direction ){ //arbitrary
ComputeAxisBase( *direction, projection.m_basis_s, projection.m_basis_t );
}
else{ //AP
Matrix4 basis;
Normal_GetTransform( plane.normal(), basis );
projection.m_basis_s = Vector3( basis.xx(), basis.yx(), basis.zx() );
projection.m_basis_t = Vector3( -basis.xy(), -basis.yy(), -basis.zy() );
}
}
} }
void Texdef_ProjectTexture( TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, TextureProjection other_proj, const Vector3& other_normal ){ void Texdef_ProjectTexture( TextureProjection& projection, std::size_t width, std::size_t height, const Plane3& plane, TextureProjection other_proj, const Vector3& other_normal ){
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) { if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
other_proj.m_brushprimit_texdef.addScale( width, height ); other_proj.m_brushprimit_texdef.addScale( width, height );
DoubleVector3 texX, texY;
// compute axis base
ComputeAxisBase( plane.normal(), texX, texY );
// compute projection vector
const DoubleVector3 anchor = plane.normal() * plane.dist();
// (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane
// (1,0) in plane axis base is texX in world coordinates + projection on the affine plane
// (0,1) in plane axis base is texY in world coordinates + projection on the affine plane
// use old texture code to compute the ST coords of these points
// ST of (0,0) (1,0) (0,1)
DoubleVector3 points[3];
DoubleVector3 st[3];
points[0] = anchor;
points[1] = texX + anchor;
points[2] = texY + anchor;
Matrix4 local2tex; Matrix4 local2tex;
Texdef_Construct_local2tex( other_proj, width, height, other_normal, local2tex ); Texdef_Construct_local2tex( other_proj, width, height, other_normal, local2tex );
for ( std::size_t i = 0; i < 3; ++i ) BPTexdef_fromST011( projection, plane, local2tex );
{
DoubleVector3 texcoord = matrix4_transformed_point( local2tex, points[i] );
//globalOutputStream() << texcoord << "\n";
st[i][0] = texcoord[0];
st[i][1] = texcoord[1];
}
// compute texture matrix
projection.m_brushprimit_texdef.coords[0][2] = st[0][0];
projection.m_brushprimit_texdef.coords[1][2] = st[0][1];
projection.m_brushprimit_texdef.coords[0][0] = st[1][0] - st[0][0];
projection.m_brushprimit_texdef.coords[1][0] = st[1][1] - st[0][1];
projection.m_brushprimit_texdef.coords[0][1] = st[2][0] - st[0][0];
projection.m_brushprimit_texdef.coords[1][1] = st[2][1] - st[0][1];
Texdef_normalise( projection, (float)width, (float)height );
} }
else else
{ {
@ -1954,3 +1943,65 @@ void Texdef_ProjectTexture( TextureProjection& projection, std::size_t width, st
} }
} }
} }
/// g_bp_globals.m_texdefTypeId == 'in' during this
void Texdef_Convert( TexdefTypeId in, TexdefTypeId out, const Plane3& plane, TextureProjection& projection, std::size_t width, std::size_t height ) {
switch( out ) {
case TEXDEFTYPEID_QUAKE: {
texdef_t texdef;
projection.m_texdef = texdef;
TexDef_Construct_Default( projection );
}
break;
case TEXDEFTYPEID_BRUSHPRIMITIVES:
{
Matrix4 local2tex;
Texdef_Construct_local2tex( projection, width, height, plane.normal(), local2tex );
BPTexdef_fromST011( projection, plane, local2tex );
BPTexdef_normalise( projection.m_brushprimit_texdef, (float)width, (float)height );
}
break;
case TEXDEFTYPEID_HALFLIFE:
if( in == TEXDEFTYPEID_QUAKE ) {
Matrix4 basis;
Normal_GetTransform( plane.normal(), basis );
projection.m_basis_s = Vector3( basis.xx(), basis.yx(), basis.zx() );
projection.m_basis_t = Vector3( -basis.xy(), -basis.yy(), -basis.zy() );
Valve220_rotate( projection, projection.m_texdef.rotate );
}
else if( in == TEXDEFTYPEID_BRUSHPRIMITIVES ){
// globalOutputStream() << "BP: ( " << projection.m_brushprimit_texdef.coords[0][0] << " " << projection.m_brushprimit_texdef.coords[0][1] << " " << projection.m_brushprimit_texdef.coords[0][2] << " ) ( " << projection.m_brushprimit_texdef.coords[1][0] << " " << projection.m_brushprimit_texdef.coords[1][1] << " " << projection.m_brushprimit_texdef.coords[1][2] << " )\n";
#if 0
projection.m_texdef.scale[0] = 1.0 / ( vector2_length( Vector2( projection.m_brushprimit_texdef.coords[0][0], projection.m_brushprimit_texdef.coords[0][1] ) ) * (double)width );
projection.m_texdef.scale[1] = 1.0 / ( vector2_length( Vector2( projection.m_brushprimit_texdef.coords[1][0], projection.m_brushprimit_texdef.coords[1][1] ) ) * (double)height );
projection.m_texdef.shift[0] = projection.m_brushprimit_texdef.coords[0][2] * (float)width;
projection.m_texdef.shift[1] = projection.m_brushprimit_texdef.coords[1][2] * (float)height;
projection.m_texdef.rotate = static_cast<float>( -radians_to_degrees( arctangent_yx( projection.m_brushprimit_texdef.coords[0][1], projection.m_brushprimit_texdef.coords[0][0] ) ) );
if( projection.m_brushprimit_texdef.coords[0][0] * projection.m_brushprimit_texdef.coords[1][1] < 0 )
projection.m_texdef.rotate = -projection.m_texdef.rotate;
DoubleVector3 texX, texY;
ComputeAxisBase( plane.normal(), texX, texY );
projection.m_basis_s = vector3_normalised( texX * static_cast<double>( projection.m_brushprimit_texdef.coords[0][0] ) + texY * static_cast<double>( projection.m_brushprimit_texdef.coords[0][1] ) );
projection.m_basis_t = vector3_normalised( texX * static_cast<double>( projection.m_brushprimit_texdef.coords[1][0] ) + texY * static_cast<double>( projection.m_brushprimit_texdef.coords[1][1] ) );
#else
/* more reliable values this way, but broken tex lock, if S scale is negative */
DoubleVector3 texX, texY;
ComputeAxisBase( plane.normal(), texX, texY );
projection.m_basis_s = vector3_normalised( texX * static_cast<double>( projection.m_brushprimit_texdef.coords[0][0] ) + texY * static_cast<double>( projection.m_brushprimit_texdef.coords[0][1] ) );
projection.m_basis_t = vector3_normalised( texX * static_cast<double>( projection.m_brushprimit_texdef.coords[1][0] ) + texY * static_cast<double>( projection.m_brushprimit_texdef.coords[1][1] ) );
projection.m_brushprimit_texdef.removeScale( width, height );
TexMatToFakeTexCoords( projection.m_brushprimit_texdef, projection.m_texdef );
projection.m_texdef.shift[0] *= -1.f;
projection.m_texdef.rotate *= -1.f;
if( projection.m_brushprimit_texdef.coords[0][0] < 0 )
projection.m_basis_s *= -1.f;
if( projection.m_brushprimit_texdef.coords[1][1] < 0 )
projection.m_basis_t *= -1.f;
#endif
// globalOutputStream() << "AP: scale( " << projection.m_texdef.scale[0] << " " << projection.m_texdef.scale[1] << " ) shift( " << projection.m_texdef.shift[0] << " " << projection.m_texdef.shift[1] << " ) rotate: " << projection.m_texdef.rotate << "\n";
}
break;
default:
break;
}
}

View File

@ -134,6 +134,7 @@ struct bp_globals_t
extern bp_globals_t g_bp_globals; extern bp_globals_t g_bp_globals;
extern float g_texdef_default_scale; extern float g_texdef_default_scale;
void Texdef_Convert( TexdefTypeId in, TexdefTypeId out, const Plane3& plane, TextureProjection& projection, std::size_t width, std::size_t height );
//void ComputeAxisBase( const Vector3& normal, Vector3& texS, Vector3& texT ); //void ComputeAxisBase( const Vector3& normal, Vector3& texS, Vector3& texT );
template <typename Element> template <typename Element>
void ComputeAxisBase( const BasicVector3<Element>& normal, BasicVector3<Element>& texS, BasicVector3<Element>& texT ); void ComputeAxisBase( const BasicVector3<Element>& normal, BasicVector3<Element>& texS, BasicVector3<Element>& texT );

View File

@ -497,7 +497,7 @@ public:
FaceSetTexdef( const TextureProjection& projection ) : m_projection( projection ){ FaceSetTexdef( const TextureProjection& projection ) : m_projection( projection ){
} }
void operator()( Face& face ) const { void operator()( Face& face ) const {
face.SetTexdef( m_projection ); face.SetTexdef( m_projection, true ); /* reset valve220 basis, once this chain is used for reset only atm */
} }
}; };

View File

@ -209,9 +209,12 @@ public:
scene::Node& createBrush(){ scene::Node& createBrush(){
return ( new BrushNode )->node(); return ( new BrushNode )->node();
} }
EBrushType getCurrentFormat() const { EBrushType getFormat() const {
return Brush::m_type; return Brush::m_type;
} }
void toggleFormat( EBrushType type ) const {
Brush_toggleFormat( type );
}
void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ){ void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ){
::Brush_forEachFace( *Node_getBrush( brush ), FaceCallback( BrushFaceDataFromFaceCaller( callback ) ) ); ::Brush_forEachFace( *Node_getBrush( brush ), FaceCallback( BrushFaceDataFromFaceCaller( callback ) ) );
} }

View File

@ -26,6 +26,5 @@
void Brush_clipperColourChanged(); void Brush_clipperColourChanged();
void Brush_unlatchPreferences(); void Brush_unlatchPreferences();
void Brush_toggleFormat( EBrushType type );
#endif #endif

View File

@ -24,7 +24,6 @@
#include "debugging/debugging.h" #include "debugging/debugging.h"
#include "imap.h" #include "imap.h"
MapModules& ReferenceAPI_getMapModules();
#include "iselection.h" #include "iselection.h"
#include "iundo.h" #include "iundo.h"
#include "ibrush.h" #include "ibrush.h"
@ -675,9 +674,48 @@ scene::Node& node(){
void MergeMap( scene::Node& node ){ void MergeMap( scene::Node& node ){
Node_getTraversable( node )->traverse( MapMergeEntities( scene::Path( makeReference( GlobalSceneGraph().root() ) ) ) ); Node_getTraversable( node )->traverse( MapMergeEntities( scene::Path( makeReference( GlobalSceneGraph().root() ) ) ) );
} }
class Convert_Faces {
const TexdefTypeId _in, _out;
public:
Convert_Faces( TexdefTypeId in, TexdefTypeId out )
: _in( in ), _out( out ) {
}
void operator()( Face& face ) const {
face.Convert( _in, _out );
}
};
#include "brushnode.h"
class Convert_Brushes : public scene::Traversable::Walker {
const Convert_Faces _convert_faces;
public:
Convert_Brushes( TexdefTypeId in, TexdefTypeId out )
: _convert_faces( in, out ) {
}
bool pre( scene::Node& node ) const {
if( node.isRoot() ) {
return false;
}
Brush* brush = Node_getBrush( node );
if( brush ) {
Brush_forEachFace( *brush, _convert_faces );
}
return true;
}
void post( scene::Node& node ) const {
}
};
void Map_ImportSelected( TextInputStream& in, const MapFormat& format ){ void Map_ImportSelected( TextInputStream& in, const MapFormat& format ){
NodeSmartReference node( ( new BasicContainer )->node() ); NodeSmartReference node( ( new BasicContainer )->node() );
EBrushType brush_type = GlobalBrushCreator().getFormat();
format.readGraph( node, in, GlobalEntityCreator() ); format.readGraph( node, in, GlobalEntityCreator() );
if ( brush_type != GlobalBrushCreator().getFormat() ) {
Node_getTraversable( *node.get_pointer() )->traverse( Convert_Brushes( BrushType_getTexdefType( GlobalBrushCreator().getFormat() ), BrushType_getTexdefType( brush_type ) ) );
GlobalBrushCreator().toggleFormat( brush_type );
}
Map_gatherNamespaced( node ); Map_gatherNamespaced( node );
Map_mergeClonedNames(); Map_mergeClonedNames();
MergeMap( node ); MergeMap( node );
@ -1113,26 +1151,10 @@ void Map_LoadFile( const char *filename ){
{ {
ScopeTimer timer( "map load" ); ScopeTimer timer( "map load" );
const MapFormat* format = NULL;
const char* moduleName = findModuleName( &GlobalFiletypes(), MapFormat::Name(), path_get_extension( filename ) );
if ( string_not_empty( moduleName ) ) {
format = ReferenceAPI_getMapModules().findModule( moduleName );
}
if ( format ) {
format->m_detectedFormat = eBrushTypeUNKNOWN;
}
g_map.m_name = filename; g_map.m_name = filename;
Map_UpdateTitle( g_map ); Map_UpdateTitle( g_map );
g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() ); g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() );
g_map.m_resource->attach( g_map ); g_map.m_resource->attach( g_map );
if ( format && format->m_detectedFormat && format->m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ) {
Map_Free();
Brush_toggleFormat( format->m_detectedFormat );
g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() );
g_map.m_resource->attach( g_map );
}
Node_getTraversable( GlobalSceneGraph().root() )->traverse( entity_updateworldspawn() ); Node_getTraversable( GlobalSceneGraph().root() )->traverse( entity_updateworldspawn() );
} }
@ -1144,9 +1166,7 @@ void Map_LoadFile( const char *filename ){
//GlobalEntityCreator().printStatistics(); //GlobalEntityCreator().printStatistics();
// /* move the view to a start position */
// move the view to a start position
//
Map_StartPosition(); Map_StartPosition();
g_currentMap = &g_map; g_currentMap = &g_map;
@ -1663,24 +1683,20 @@ bool Map_ImportFile( const char* filename ){
} }
{ {
const MapFormat* format = NULL; EBrushType brush_type = GlobalBrushCreator().getFormat();
const char* moduleName = findModuleName( &GlobalFiletypes(), MapFormat::Name(), path_get_extension( filename ) );
if ( string_not_empty( moduleName ) ) {
format = ReferenceAPI_getMapModules().findModule( moduleName );
}
if ( format ) {
format->m_detectedFormat = eBrushTypeUNKNOWN;
}
Resource* resource = GlobalReferenceCache().capture( filename ); Resource* resource = GlobalReferenceCache().capture( filename );
resource->refresh(); // avoid loading old version if map has changed on disk since last import resource->refresh(); // avoid loading old version if map has changed on disk since last import
if ( !resource->load() ) { if ( !resource->load() ) {
GlobalReferenceCache().release( filename ); GlobalReferenceCache().release( filename );
if ( brush_type != GlobalBrushCreator().getFormat() ) {
GlobalBrushCreator().toggleFormat( brush_type );
}
goto tryDecompile; goto tryDecompile;
} }
if ( format && /*format->m_detectedFormat &&*/ format->m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ) { if ( brush_type != GlobalBrushCreator().getFormat() ) {
GlobalReferenceCache().release( filename ); Node_getTraversable( *resource->getNode() )->traverse( Convert_Brushes( BrushType_getTexdefType( GlobalBrushCreator().getFormat() ), BrushType_getTexdefType( brush_type ) ) );
goto tryDecompile; GlobalBrushCreator().toggleFormat( brush_type );
} }
NodeSmartReference clone( NewMapRoot( "" ) ); NodeSmartReference clone( NewMapRoot( "" ) );
Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) ); Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) );
@ -1713,7 +1729,7 @@ tryDecompile:
output.push_string( "\" -fs_game " ); output.push_string( "\" -fs_game " );
output.push_string( gamename_get() ); output.push_string( gamename_get() );
output.push_string( " -convert -format " ); output.push_string( " -convert -format " );
output.push_string( Brush::m_type == eBrushTypeQuake3BP ? "map_bp" : "map" ); output.push_string( BrushType_getTexdefType( GlobalBrushCreator().getFormat() ) == TEXDEFTYPEID_QUAKE ? "map" : "map_bp" );
if ( extension_equal( path_get_extension( filename ), "map" ) ) { if ( extension_equal( path_get_extension( filename ), "map" ) ) {
output.push_string( " -readmap " ); output.push_string( " -readmap " );
} }
@ -1730,13 +1746,21 @@ tryDecompile:
output.push_string( "_converted.map" ); output.push_string( "_converted.map" );
filename = output.c_str(); filename = output.c_str();
EBrushType brush_type = GlobalBrushCreator().getFormat();
// open // open
Resource* resource = GlobalReferenceCache().capture( filename ); Resource* resource = GlobalReferenceCache().capture( filename );
resource->refresh(); // avoid loading old version if map has changed on disk since last import resource->refresh(); // avoid loading old version if map has changed on disk since last import
if ( !resource->load() ) { if ( !resource->load() ) {
GlobalReferenceCache().release( filename ); GlobalReferenceCache().release( filename );
if ( brush_type != GlobalBrushCreator().getFormat() ) {
GlobalBrushCreator().toggleFormat( brush_type );
}
return success; return success;
} }
if ( brush_type != GlobalBrushCreator().getFormat() ) {
Node_getTraversable( *resource->getNode() )->traverse( Convert_Brushes( BrushType_getTexdefType( GlobalBrushCreator().getFormat() ), BrushType_getTexdefType( brush_type ) ) );
GlobalBrushCreator().toggleFormat( brush_type );
}
NodeSmartReference clone( NewMapRoot( "" ) ); NodeSmartReference clone( NewMapRoot( "" ) );
Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) ); Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) );
Map_gatherNamespaced( clone ); Map_gatherNamespaced( clone );

View File

@ -548,8 +548,8 @@ static void OnBtnReset( GtkWidget *widget, gpointer data ){
} }
static void OnBtnProject( GtkWidget *widget, gpointer data ){ static void OnBtnProject( GtkWidget *widget, gpointer data ){
if ( g_bp_globals.m_texdefTypeId != TEXDEFTYPEID_BRUSHPRIMITIVES ) { if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_QUAKE ) {
globalErrorStream() << "function doesn't work for *brushes* in map formats other than BRUSHPRIMITIVES\n"; globalErrorStream() << "function doesn't work for *brushes*, having Axial Projection type\n";
//return; //return;
} }
getSurfaceInspector().exportData(); getSurfaceInspector().exportData();