* 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
{
eBrushTypeUNKNOWN = 0,
eBrushTypeQuake,
eBrushTypeQuake2,
eBrushTypeQuake3,
@ -117,7 +116,8 @@ public:
INTEGER_CONSTANT( Version, 1 );
STRING_CONSTANT( Name, "brush" );
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 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 "ibrush.h"
class EntityCreator;
@ -62,7 +61,6 @@ class MapFormat
public:
INTEGER_CONSTANT( Version, 2 );
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.
virtual void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const = 0;

View File

@ -57,7 +57,7 @@ MapDoom3Dependencies() :
m_patchDoom3Module( "doom3" ){
}
BrushCreator& getBrushDoom3(){
return GlobalBrushModule::getTable();
return GlobalBrushCreator();
}
PatchCreator& getPatchDoom3(){
return *m_patchDoom3Module.getTable();
@ -228,6 +228,7 @@ MapDependencies() :
class MapQ3API : public TypeSystemRef, public MapFormat, public PrimitiveParser
{
mutable bool m_formatDetected;
public:
typedef MapFormat Type;
STRING_CONSTANT( Name, "mapq3" );
@ -247,36 +248,38 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
if ( string_equal( primitive, "patchDef2" ) ) {
return GlobalPatchModule::getTable().createPatch();
}
if( !m_detectedFormat ){
if( !m_formatDetected ){
EBrushType detectedFormat;
if ( string_equal( primitive, "brushDef" ) ) {
m_detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n";
detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "detectedFormat = eBrushTypeQuake3BP\n";
}
else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) {
m_detectedFormat = eBrushTypeQuake3Valve220;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3Valve220\n";
detectedFormat = eBrushTypeQuake3Valve220;
globalErrorStream() << "detectedFormat = eBrushTypeQuake3Valve220\n";
}
else if ( string_equal( primitive, "(" ) ) {
m_detectedFormat = eBrushTypeQuake3;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3\n";
detectedFormat = eBrushTypeQuake3;
globalErrorStream() << "detectedFormat = eBrushTypeQuake3\n";
}
else{
globalErrorStream() << "Format is not detected\n";
}
if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){
Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" );
return g_nullNode;
}
m_formatDetected = true;
if( detectedFormat != GlobalBrushCreator().getFormat() ){
GlobalBrushCreator().toggleFormat( detectedFormat );
}
}
switch ( GlobalBrushModule::getTable().getCurrentFormat() )
switch ( GlobalBrushCreator().getFormat() )
{
case eBrushTypeQuake3:
case eBrushTypeQuake3Valve220:
tokeniser.ungetToken(); // (
case eBrushTypeQuake3BP:
return GlobalBrushModule::getTable().createBrush();
return GlobalBrushCreator().createBrush();
default:
break;
}
@ -288,6 +291,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const {
Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream );
m_formatDetected = false;
Map_Read( root, tokeniser, entityTable, *this );
tokeniser.release();
}
@ -305,6 +309,7 @@ MapQ3Module g_MapQ3Module;
class MapQ1API : public TypeSystemRef, public MapFormat, public PrimitiveParser
{
mutable bool m_formatDetected;
public:
typedef MapFormat Type;
STRING_CONSTANT( Name, "mapq1" );
@ -320,36 +325,38 @@ MapFormat* getTable(){
scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
const char* primitive = tokeniser.getToken();
if ( primitive != 0 ) {
if( !m_detectedFormat ){
if( !m_formatDetected ){
EBrushType detectedFormat;
if ( string_equal( primitive, "brushDef" ) ) {
m_detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n";
detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "detectedFormat = eBrushTypeQuake3BP\n";
}
else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) {
m_detectedFormat = eBrushTypeValve220;
globalErrorStream() << "m_detectedFormat = eBrushTypeValve220\n";
detectedFormat = eBrushTypeValve220;
globalErrorStream() << "detectedFormat = eBrushTypeValve220\n";
}
else if ( string_equal( primitive, "(" ) ) {
m_detectedFormat = eBrushTypeQuake;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake\n";
detectedFormat = eBrushTypeQuake;
globalErrorStream() << "detectedFormat = eBrushTypeQuake\n";
}
else{
globalErrorStream() << "Format is not detected\n";
}
if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){
Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" );
return g_nullNode;
}
m_formatDetected = true;
if( detectedFormat != GlobalBrushCreator().getFormat() ){
GlobalBrushCreator().toggleFormat( detectedFormat );
}
}
switch ( GlobalBrushModule::getTable().getCurrentFormat() )
switch ( GlobalBrushCreator().getFormat() )
{
case eBrushTypeQuake:
case eBrushTypeValve220:
tokeniser.ungetToken(); // (
case eBrushTypeQuake3BP:
return GlobalBrushModule::getTable().createBrush();
return GlobalBrushCreator().createBrush();
default:
break;
}
@ -360,6 +367,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
}
void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const {
Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream );
m_formatDetected = false;
Map_Read( root, tokeniser, entityTable, *this );
tokeniser.release();
}
@ -394,7 +402,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
if ( primitive != 0 ) {
if ( string_equal( primitive, "(" ) ) {
tokeniser.ungetToken(); // (
return GlobalBrushModule::getTable().createBrush();
return GlobalBrushCreator().createBrush();
}
}
@ -420,6 +428,7 @@ MapHalfLifeModule g_MapHalfLifeModule;
class MapQ2API : public TypeSystemRef, public MapFormat, public PrimitiveParser
{
mutable bool m_formatDetected;
public:
typedef MapFormat Type;
STRING_CONSTANT( Name, "mapq2" );
@ -434,36 +443,38 @@ MapFormat* getTable(){
scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
const char* primitive = tokeniser.getToken();
if ( primitive != 0 ) {
if( !m_detectedFormat ){
if( !m_formatDetected ){
EBrushType detectedFormat;
if ( string_equal( primitive, "brushDef" ) ) {
m_detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3BP\n";
detectedFormat = eBrushTypeQuake3BP;
globalErrorStream() << "detectedFormat = eBrushTypeQuake3BP\n";
}
else if ( string_equal( primitive, "(" ) && tokeniser.bufferContains( " [ " ) && tokeniser.bufferContains( " ] " ) ) {
m_detectedFormat = eBrushTypeQuake3Valve220;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake3Valve220\n";
detectedFormat = eBrushTypeQuake3Valve220;
globalErrorStream() << "detectedFormat = eBrushTypeQuake3Valve220\n";
}
else if ( string_equal( primitive, "(" ) ) {
m_detectedFormat = eBrushTypeQuake2;
globalErrorStream() << "m_detectedFormat = eBrushTypeQuake2\n";
detectedFormat = eBrushTypeQuake2;
globalErrorStream() << "detectedFormat = eBrushTypeQuake2\n";
}
else{
globalErrorStream() << "Format is not detected\n";
}
if( m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ){
Tokeniser_unexpectedError( tokeniser, primitive, "#different-brush-format" );
return g_nullNode;
}
m_formatDetected = true;
if( detectedFormat != GlobalBrushCreator().getFormat() ){
GlobalBrushCreator().toggleFormat( detectedFormat );
}
}
switch ( GlobalBrushModule::getTable().getCurrentFormat() )
switch ( GlobalBrushCreator().getFormat() )
{
case eBrushTypeQuake2:
case eBrushTypeQuake3Valve220:
tokeniser.ungetToken(); // (
case eBrushTypeQuake3BP:
return GlobalBrushModule::getTable().createBrush();
return GlobalBrushCreator().createBrush();
default:
break;
}
@ -474,6 +485,7 @@ scene::Node& parsePrimitive( Tokeniser& tokeniser ) const {
}
void readGraph( scene::Node& root, TextInputStream& inputStream, EntityCreator& entityTable ) const {
Tokeniser& tokeniser = GlobalScripLibModule::getTable().m_pfnNewSimpleTokeniser( inputStream );
m_formatDetected = false;
Map_Read( root, tokeniser, entityTable, *this );
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 ){
removeScale();
Texdef_Assign( m_projection, hShift, vShift, hScale, vScale, rotation );
// if( hShift || vShift ){
// Texdef_normalise( m_projection, m_shader.width(), m_shader.height() );
// }
addScale();
}
@ -568,6 +571,7 @@ void shift( float s, float t ){
ASSERT_MESSAGE( texdef_sane( m_projection.m_texdef ), "FaceTexdef::shift: bad texdef" );
removeScale();
Texdef_Shift( m_projection, s, t );
// Texdef_normalise( m_projection, m_shader.width(), m_shader.height() );
addScale();
}
@ -582,15 +586,20 @@ void rotate( float angle ){
Texdef_Rotate( m_projection, angle );
addScale();
}
///ProjectTexture along 'direction' with parameters, defined by texdef_t
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 );
}
///ProjectTexture along 'normal' with parameters, defined by TextureProjection
void ProjectTexture( const Plane3& plane, const TextureProjection& projection, const Vector3& 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 ){
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() );
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 ){
Matrix4 basis;
Normal_GetTransform( normal, basis );
m_projection.m_basis_s = Vector3( basis.xx(), basis.yx(), basis.zx() );
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 ){
@ -869,6 +884,21 @@ void Brush_textureChanged();
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
{
public:
@ -984,7 +1014,7 @@ Face( const Face& other, FaceObserver* observer ) :
m_shader.attach( *this );
m_plane.copy( other.m_plane );
planepts_assign( m_move_planepts, other.m_move_planepts );
m_texdef.setBasis( m_plane.plane3().normal() );
// m_texdef.setBasis( m_plane.plane3().normal() );
planeChanged();
updateFiltered();
}
@ -1190,9 +1220,12 @@ void texdefChanged(){
void GetTexdef( TextureProjection& projection ) const {
projection = m_texdef.normalised();
}
void SetTexdef( const TextureProjection& projection ){
void SetTexdef( const TextureProjection& projection, bool resetBasis = false ){
undoSave();
m_texdef.setTexdef( projection );
if( resetBasis ){
m_texdef.setBasis( m_plane.plane3().normal() );
}
texdefChanged();
}
@ -1242,6 +1275,11 @@ void ProjectTexture( const TextureProjection& projection, const Vector3& normal
texdefChanged();
}
void Convert( TexdefTypeId in, TexdefTypeId out ){
m_texdef.Convert( in, out, m_plane.plane3() );
texdefChanged();
}
void FitTexture( float s_repeat, float t_repeat ){
undoSave();
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;
FacePlane::m_type = type;
g_bp_globals.m_texdefTypeId = TEXDEFTYPEID_QUAKE;
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;
}
g_bp_globals.m_texdefTypeId = BrushType_getTexdefType( type );
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 );
//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 ){
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 );
@ -239,7 +239,7 @@ void Texdef_basisForNormal( const TextureProjection& projection, const Vector3&
ComputeAxisBase( normal, vector4_to_vector3( basis.x() ), vector4_to_vector3( basis.y() ) );
vector4_to_vector3( basis.z() ) = normal;
matrix4_transpose( basis );
//DebugAxisBase(normal);
//DebugAxisBase( normal );
}
else if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
basis = g_matrix4_identity;
@ -407,7 +407,7 @@ void Texdef_Rotate( texdef_t& td, float angle ){
td.rotate += angle;
td.rotate = static_cast<float>( float_to_integer( td.rotate ) % 360 );
}
#if 0
// NOTE: added these from Ritual's Q3Radiant
void ClearBounds( Vector3& mins, Vector3& maxs ){
mins[0] = mins[1] = mins[2] = 99999;
@ -429,7 +429,7 @@ void AddPointToBounds( const Vector3& v, Vector3& mins, Vector3& maxs ){
}
}
}
#endif
template<typename Element>
inline BasicVector3<Element> vector3_inverse( const BasicVector3<Element>& self ){
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;
float g_texdef_default_scale;
#if 0
// compute a determinant using Sarrus rule
//++timo "inline" this with a macro
// 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][2] = SarrusDet( M[0], M[1], D[1] ) / det;
}
#endif
//++timo replace everywhere texX by texS etc. ( ----> and in q3map !)
// 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
@ -552,7 +534,13 @@ void ComputeAxisBase( const BasicVector3<Element>& normal, BasicVector3<Element>
#endif
}
#if 0 // texdef conversion
#if 0
#ifdef _DEBUG
//#define DBG_BP
#endif
// texdef conversion
void FaceToBrushPrimitFace( face_t *f ){
Vector3 texX,texY;
Vector3 proj;
@ -617,7 +605,6 @@ void EmitBrushPrimitTextureCoordinates( face_t * f, Winding * w ){
{
x = vector3_dot( w.point_at( i ),texX );
y = vector3_dot( w.point_at( i ),texY );
#if 0
#ifdef DBG_BP
if ( g_bp_globals.bNeedConvert ) {
// 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
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];
@ -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
void FakeTexCoordsToTexMat( const texdef_t& texdef, brushprimit_texdef_t& bp_texdef ){
#if 1
double r = degrees_to_radians( -texdef.rotate );
double c = cos( 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[0][2] = -texdef.shift[0];
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";
}
@ -808,7 +780,7 @@ void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y ){
f->brushprimit_texdef.coords[1][2] -= t;
}
#endif
#if 0
// TTimo: FIXME: I don't like that, it feels broken
// (and it's likely that it's not used anymore)
// 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
void BrushPrimitFaceToFace( face_t *face ){
@ -972,6 +944,17 @@ void ApplyMatrix_BrushPrimit( face_t *f, Vector3 matrix[3], Vector3& origin ){
TextureLockTransformation_BrushPrimit( f );
}
#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!
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 );
BPMatCopy( aux,A );
}
#endif
#if 0 // camera-relative texture shift
// get the relative axes of the current texturing
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
#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 ){
bp_td = bp_other;
@ -1208,11 +1204,10 @@ void Texdef_Assign( TextureProjection& projection, const float* hShift, const fl
}
else
{
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;
// }
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 );
}
}
@ -1242,6 +1237,9 @@ void Texdef_Rotate( TextureProjection& projection, float angle ){
}
else
{
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
Valve220_rotate( projection, 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 );
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(){
@ -1344,7 +1346,7 @@ void ShiftScaleRotate_toFace( const texdef_t& shiftScaleRotate, TextureProjectio
}
}
#if 0
inline void print_vector3( const Vector3& v ){
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;
}
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 a10, double a11, double a12,
double a20, double a21, double a22 ){
@ -1488,7 +1581,6 @@ std::size_t planeNormalIndex( const Vector3& normal ) {
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 ){
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
}
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
#if 1
// 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";
DoubleVector3 texX, texY;
DoubleVector3 points[3];
DoubleVector3 st[3];
ComputeAxisBase( plane.normal(), texX, texY );
const DoubleVector3 anchor = plane.normal() * plane.dist();
points[0] = anchor;
points[1] = texX + anchor;
points[2] = texY + anchor;
const DoubleVector3 anchor = plane.normal() * plane.dist();
DoubleVector3 points[3] = { anchor, anchor + texX, anchor + texY };
DoubleVector3 st[3];
Matrix4 local2tex;
Texdef_Construct_local2tex( projection, width, height, plane.normal(), local2tex );
for ( std::size_t i = 0; i < 3; ++i )
{
DoubleVector3 texcoord = matrix4_transformed_point( local2tex, points[i] );
st[i][0] = texcoord[0];
st[i][1] = texcoord[1];
for ( std::size_t i = 0; i < 3; ++i ){
st[i] = matrix4_transformed_point( local2tex, points[i] );
matrix4_transform_point( identity2transformed, points[i] );
}
double xyI[2], xyJ[2], xyK[2];
double stI[2], stJ[2], stK[2];
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][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";
}
#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 ) {
// 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";
}
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() << "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() << "220: projection.m_basis_s: " << projection.m_basis_s << " projection.m_basis_t: " << projection.m_basis_t << "\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";
#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";
@ -1746,67 +1800,30 @@ void Texdef_transformLocked( TextureProjection& projection, std::size_t width, s
Matrix4 identity2stIdentity;
Texdef_basisForNormal( projection, plane.normal(), identity2stIdentity );
//globalOutputStream() << "identity2stIdentity: " << identity2stIdentity << "\n";
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_HALFLIFE ) {
matrix4_transform_direction( identity2transformed, projection.m_basis_s );
matrix4_transform_direction( identity2transformed, projection.m_basis_t );
}
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";
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 ){
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 );
}
else{ //ap
else{ //AP
Matrix4 xyz2st;
Normal_GetTransform( normal, xyz2st ); //Texdef_basisForNormal for ap
Normal_GetTransform( normal, xyz2st ); //Texdef_basisForNormal for AP
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 ){
//texdef_t texdef;
//Q3_to_BP( texdef, (float)width, (float)height, normal, projection.m_brushprimit_texdef );
inline void BPTexdef_fromST011( TextureProjection& projection, const Plane3& plane, const Matrix4& local2tex ){
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];
const DoubleVector3 anchor = plane.normal() * plane.dist();
const DoubleVector3 points[3] = { anchor, anchor + texX, anchor + texY };
DoubleVector3 st[3];
points[0] = anchor;
points[1] = texX + anchor;
points[2] = texY + anchor;
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];
for ( std::size_t i = 0; i < 3; ++i ){
st[i] = matrix4_transformed_point( local2tex, points[i] );
//globalOutputStream() << st[i] << "\n";
}
// 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][2] = float_mod( st[0][0], 1.0 );
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[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 );
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 ){
if ( g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES ) {
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;
Texdef_Construct_local2tex( other_proj, width, height, other_normal, 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
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 );
BPTexdef_fromST011( projection, plane, local2tex );
}
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 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 );
template <typename Element>
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 ){
}
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(){
return ( new BrushNode )->node();
}
EBrushType getCurrentFormat() const {
EBrushType getFormat() const {
return Brush::m_type;
}
void toggleFormat( EBrushType type ) const {
Brush_toggleFormat( type );
}
void Brush_forEachFace( scene::Node& brush, const BrushFaceDataCallback& callback ){
::Brush_forEachFace( *Node_getBrush( brush ), FaceCallback( BrushFaceDataFromFaceCaller( callback ) ) );
}

View File

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

View File

@ -24,7 +24,6 @@
#include "debugging/debugging.h"
#include "imap.h"
MapModules& ReferenceAPI_getMapModules();
#include "iselection.h"
#include "iundo.h"
#include "ibrush.h"
@ -675,9 +674,48 @@ scene::Node& node(){
void MergeMap( scene::Node& node ){
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 ){
NodeSmartReference node( ( new BasicContainer )->node() );
EBrushType brush_type = GlobalBrushCreator().getFormat();
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_mergeClonedNames();
MergeMap( node );
@ -1113,26 +1151,10 @@ void Map_LoadFile( const char *filename ){
{
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;
Map_UpdateTitle( g_map );
g_map.m_resource = GlobalReferenceCache().capture( g_map.m_name.c_str() );
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() );
}
@ -1144,9 +1166,7 @@ void Map_LoadFile( const char *filename ){
//GlobalEntityCreator().printStatistics();
//
// move the view to a start position
//
/* move the view to a start position */
Map_StartPosition();
g_currentMap = &g_map;
@ -1663,24 +1683,20 @@ bool Map_ImportFile( const char* filename ){
}
{
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;
}
EBrushType brush_type = GlobalBrushCreator().getFormat();
Resource* resource = GlobalReferenceCache().capture( filename );
resource->refresh(); // avoid loading old version if map has changed on disk since last import
if ( !resource->load() ) {
GlobalReferenceCache().release( filename );
if ( brush_type != GlobalBrushCreator().getFormat() ) {
GlobalBrushCreator().toggleFormat( brush_type );
}
goto tryDecompile;
}
if ( format && /*format->m_detectedFormat &&*/ format->m_detectedFormat != GlobalBrushModule::getTable().getCurrentFormat() ) {
GlobalReferenceCache().release( filename );
goto tryDecompile;
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( "" ) );
Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) );
@ -1713,7 +1729,7 @@ tryDecompile:
output.push_string( "\" -fs_game " );
output.push_string( gamename_get() );
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" ) ) {
output.push_string( " -readmap " );
}
@ -1730,13 +1746,21 @@ tryDecompile:
output.push_string( "_converted.map" );
filename = output.c_str();
EBrushType brush_type = GlobalBrushCreator().getFormat();
// open
Resource* resource = GlobalReferenceCache().capture( filename );
resource->refresh(); // avoid loading old version if map has changed on disk since last import
if ( !resource->load() ) {
GlobalReferenceCache().release( filename );
if ( brush_type != GlobalBrushCreator().getFormat() ) {
GlobalBrushCreator().toggleFormat( brush_type );
}
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( "" ) );
Node_getTraversable( *resource->getNode() )->traverse( CloneAll( clone ) );
Map_gatherNamespaced( clone );

View File

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