ldtypes.cpp

Sun, 24 Mar 2013 18:03:33 +0200

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Sun, 24 Mar 2013 18:03:33 +0200
changeset 63
aa40ce18f869
parent 62
915fc477cb6a
child 64
ada4679d5bce
permissions
-rw-r--r--

Implemented the inline action to expose inlining to the user. Also added a `deep inline` action to inline subfile recursively down into polygons and lines only.

/*
 *  LDForge: LDraw parts authoring CAD
 *  Copyright (C) 2013 Santeri `arezey` Piippo
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "common.h"
#include "ldtypes.h"
#include "file.h"
#include "misc.h"

char const* g_saObjTypeNames[] = {
	"unidentified",
	"unknown",
	"empty",
	"comment",
	"subfile",
	"line",
	"triangle",
	"quadrilateral",
	"condline",
	"vertex",
};

char const* g_saObjTypeIcons[] = {
	"error",
	"error",
	"empty",
	"comment",
	"subfile",
	"line",
	"triangle",
	"quad",
	"condline",
	"vertex"
};

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
// LDObject constructors
LDObject::LDObject () {
	commonInit ();
}

void LDObject::commonInit () {
	qObjListEntry = nullptr;
}

LDGibberish::LDGibberish () {
	commonInit ();
	dColor = -1;
}

LDGibberish::LDGibberish (str _zContent, str _zReason) {
	zContents = _zContent;
	zReason = _zReason;
	dColor = -1;
	
	commonInit ();
}

LDEmpty::LDEmpty () {
	commonInit ();
	dColor = -1;
}

LDComment::LDComment () {
	commonInit ();
	dColor = -1;
}

LDSubfile::LDSubfile () {
	commonInit ();
}

LDLine::LDLine () {
	commonInit ();
}

LDTriangle::LDTriangle () {
	commonInit ();
}

LDQuad::LDQuad () {
	commonInit ();
}

LDCondLine::LDCondLine () {
	commonInit ();
}

LDVertex::LDVertex () {
	commonInit ();
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
ulong LDObject::getIndex () {
	if (!g_CurrentFile)
		return -1u;
	
	// TODO: shouldn't rely on g_CurrentFile
	for (ulong i = 0; i < g_CurrentFile->objects.size(); ++i) {
		if (g_CurrentFile->objects[i] == this)
			return i;
	}
	
	return -1u;
}

// =============================================================================
str LDComment::getContents () {
	return str::mkfmt ("0 %s", zText.chars ());
}

str LDSubfile::getContents () {
	str val = str::mkfmt ("1 %d %s ", dColor, vPosition.getStringRep (false).chars ());
	
	for (short i = 0; i < 9; ++i)
		val.appendformat ("%s ", ftoa (faMatrix[i]).chars());
	
	val += zFileName;
	return val;
}

str LDLine::getContents () {
	str val = str::mkfmt ("2 %d", dColor);
	
	for (ushort i = 0; i < 2; ++i)
		val.appendformat (" %s", vaCoords[i].getStringRep (false).chars ());
	
	return val;
}

str LDTriangle::getContents () {
	str val = str::mkfmt ("3 %d", dColor);
	
	for (ushort i = 0; i < 3; ++i)
		val.appendformat (" %s", vaCoords[i].getStringRep (false).chars ());
	
	return val;
}

str LDQuad::getContents () {
	str val = str::mkfmt ("4 %d", dColor);
	
	for (ushort i = 0; i < 4; ++i)
		val.appendformat (" %s", vaCoords[i].getStringRep (false).chars ());
	
	return val;
}

str LDCondLine::getContents () {
	str val = str::mkfmt ("5 %d", dColor);
	
	// Add the coordinates
	for (ushort i = 0; i < 4; ++i)
		val.appendformat (" %s", vaCoords[i].getStringRep (false).chars ());
	
	return val;
}

str LDGibberish::getContents () {
	return zContents;
}

str LDVertex::getContents () {
	return str::mkfmt ("0 !LDFORGE VERTEX %d %s", dColor, vPosition.getStringRep (false).chars());
}

str LDEmpty::getContents () {
	return str ();
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void LDQuad::splitToTriangles () {
	// Find the index of this quad
	long lIndex = getIndex (g_CurrentFile);
	
	if (lIndex == -1) {
		// couldn't find it?
		logf (LOG_Error, "LDQuad::splitToTriangles: Couldn't find quad %p in "
			"current object list!!\n", this);
		return;
	}
	
	// Create the two triangles based on this quadrilateral:
	// 0---3     0---3    3
	// |   |     |  /    /|
	// |   |  =  | /    / |
	// |   |     |/    /  |
	// 1---2     1    1---2
	LDTriangle* tri1 = new LDTriangle;
	tri1->vaCoords[0] = vaCoords[0];
	tri1->vaCoords[1] = vaCoords[1];
	tri1->vaCoords[2] = vaCoords[3];
	
	LDTriangle* tri2 = new LDTriangle;
	tri2->vaCoords[0] = vaCoords[1];
	tri2->vaCoords[1] = vaCoords[2];
	tri2->vaCoords[2] = vaCoords[3];
	
	printf ("triangles: %p %p\n", tri1, tri2);
	
	// The triangles also inherit the quad's color
	tri1->dColor = tri2->dColor = dColor;
	
	// Replace the quad with the first triangle and add the second triangle
	// after the first one.
	g_CurrentFile->objects[lIndex] = tri1;
	g_CurrentFile->objects.insert (g_CurrentFile->objects.begin() + lIndex + 1, tri2);
	
	// Delete this quad now, it has been split.
	delete this;
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
void LDObject::replace (LDObject* replacement) {
	// Replace all instances of the old object with the new object
	for (ulong i = 0; i < g_CurrentFile->objects.size(); ++i) {
		if (g_CurrentFile->objects[i] == this)
			g_CurrentFile->objects[i] = replacement;
	}
	
	// Remove the old object
	delete this;
}

LDLine::LDLine (vertex v1, vertex v2) {
	commonInit ();
	
	vaCoords[0] = v1;
	vaCoords[1] = v2;
}

LDObject::~LDObject () {}
LDComment::~LDComment () {}
LDCondLine::~LDCondLine () {}
LDEmpty::~LDEmpty () {}
LDGibberish::~LDGibberish () {}
LDLine::~LDLine () {}
LDQuad::~LDQuad () {}
LDSubfile::~LDSubfile () {}
LDTriangle::~LDTriangle () {}
LDVertex::~LDVertex () {}

#define ADD_TYPE(T,N) \
	case OBJ_##T: \
			{ \
				LD##T* newobj = static_cast<LD##T*> (obj)->makeClone (); \
				for (short i = 0; i < N; ++i) \
					newobj->vaCoords[i].transform (matrix, pos); \
				\
				objs.push_back (newobj); \
			} \
			break;

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
static uint g_uTabs = 0;
vector<LDObject*> LDSubfile::inlineContents (bool bDeepInline, double* matrix, vertex pos, bool bCache) {
	// If we have this cached, just return that.
	if (bDeepInline && objCache.size ())
		return objCache;
	
	vector<LDObject*> objs;
	
	for (ulong i = 0; i < pFile->objects.size(); ++i) {
		LDObject* obj = pFile->objects[i];
		
		switch (obj->getType()) {
		case OBJ_Comment:
		case OBJ_Empty:
		case OBJ_Gibberish:
		case OBJ_Unidentified:
		case OBJ_Vertex:
			break; // Skip non-essentials
		
		ADD_TYPE (Line, 2)
		ADD_TYPE (Triangle, 3)
		ADD_TYPE (Quad, 4)
		ADD_TYPE (CondLine, 4)
		
		case OBJ_Subfile:
			{
				LDSubfile* ref = static_cast<LDSubfile*> (obj);
				
				// Got another sub-file reference, inline it if we're deep-inlining. If not,
				// just add it into the objects normally.
				if (bDeepInline) {
					double faNewMatrix[9];
					
					for (short i = 0; i < 9; ++i)
						faNewMatrix[i] = matrix[i] * ref->faMatrix[i];
					
					vertex vNewPos = ref->vPosition;
					vNewPos.transform (matrix, pos);
					
					// Only cache immediate subfiles, this is not one. Yay recursion!
					g_uTabs++;
					vector<LDObject*> otherobjs = ref->inlineContents (true, faNewMatrix, vNewPos, false);
					g_uTabs--;
					
					for (ulong i = 0; i < otherobjs.size(); ++i)
						objs.push_back (otherobjs[i]);
				} else {
					LDSubfile* clone = ref->makeClone ();
					clone->vPosition.transform (matrix, pos);
					
					for (short i = 0; i < 9; ++i)
						clone->faMatrix[i] *= matrix[i];
					
					objs.push_back (clone);
				}
			}
			
			break;
		}
	}
	
	// If we cache this stuff, keep it around
	if (bCache)
		objCache = objs;
	
	return objs;
}

// =============================================================================
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// =============================================================================
long LDObject::getIndex (OpenFile* pFile) {
	long lIndex;
	
	for (lIndex = 0; lIndex < (long)pFile->objects.size(); ++lIndex)
		if (pFile->objects[lIndex] == this)
			return lIndex;
	
	return -1;
}

mercurial